+ * 注意:所有新增接口需遵循项目接口规范与异常处理规范。 + *
+ * * @author emotion-museum * @since 2025-07-16 */ @@ -89,4 +95,16 @@ public interface AuthService { * @param userId 用户ID */ void updateLastActiveTime(String userId); + + /** + * 重置密码(未登录场景) + * + *+ * 通过手机号与验证码(当前固定为123456)设置新密码。 + *
+ * + * @param request 重置密码请求 + * @return 重置密码响应 + */ + ResetPasswordResponse resetPassword(ResetPasswordRequest request); } diff --git a/backend/auth/server/src/main/java/com/emotionmuseum/auth/service/impl/AuthServiceImpl.java b/backend/auth/server/src/main/java/com/emotionmuseum/auth/service/impl/AuthServiceImpl.java index 633f4c7..dd2bacf 100644 --- a/backend/auth/server/src/main/java/com/emotionmuseum/auth/service/impl/AuthServiceImpl.java +++ b/backend/auth/server/src/main/java/com/emotionmuseum/auth/service/impl/AuthServiceImpl.java @@ -6,11 +6,13 @@ import com.emotionmuseum.common.result.ResultCode; import com.emotionmuseum.common.util.JwtUtil; import com.emotionmuseum.auth.request.LoginRequest; import com.emotionmuseum.auth.request.RegisterRequest; +import com.emotionmuseum.auth.request.ResetPasswordRequest; import com.emotionmuseum.auth.entity.User; import com.emotionmuseum.auth.mapper.UserMapper; import com.emotionmuseum.auth.service.AuthService; import com.emotionmuseum.auth.service.CaptchaService; import com.emotionmuseum.auth.response.LoginResponse; +import com.emotionmuseum.auth.response.ResetPasswordResponse; import com.emotionmuseum.auth.response.UserInfoResponse; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -239,6 +241,46 @@ public class AuthServiceImpl extends ServiceImpl+ * 校验验证码(当前固定为123456),按手机号查询用户,使用 PasswordEncoder(BCrypt) 加密新密码并更新。 + *
+ * + * @param request 重置密码请求 + * @return 重置密码响应 + */ + @Override + public ResetPasswordResponse resetPassword(ResetPasswordRequest request) { + // 校验验证码(本期约定固定为 123456) + if (!"123456".equals(request.getCaptcha())) { + throw new RuntimeException(ResultCode.CAPTCHA_ERROR.getMessage()); + } + + // 按手机号查找用户 + User user = baseMapper.selectByPhone(request.getPhone()); + if (user == null) { + throw new RuntimeException(ResultCode.USER_NOT_FOUND.getMessage()); + } + + // 获取加密器并加密新密码 + PasswordEncoder passwordEncoder = applicationContext.getBean(PasswordEncoder.class); + String encoded = passwordEncoder.encode(request.getNewPassword()); + + // 仅更新密码与更新时间(遵循仅更新非空字段原则) + User toUpdate = new User(); + toUpdate.setId(user.getId()); + toUpdate.setPassword(encoded); + updateById(toUpdate); + + log.info("用户重置密码成功: phone={}", request.getPhone()); + ResetPasswordResponse resp = new ResetPasswordResponse(); + resp.setSuccess(true); + resp.setMessage("重置密码成功"); + return resp; + } + @Override public void updateLastActiveTime(String userId) { baseMapper.updateLastActiveTime(userId); diff --git a/backend/gateway/src/main/resources/application.yml b/backend/gateway/src/main/resources/application.yml index 7e02045..e9dca6f 100644 --- a/backend/gateway/src/main/resources/application.yml +++ b/backend/gateway/src/main/resources/application.yml @@ -68,7 +68,7 @@ spring: predicates: - Path=/api/auth/** filters: - - StripPrefix=2 + - StripPrefix=1 # 认证服务路由 - 直接路径 - id: emotion-auth-direct diff --git a/web-new/.env.development b/web-new/.env.development deleted file mode 100644 index 9b723cd..0000000 --- a/web-new/.env.development +++ /dev/null @@ -1,7 +0,0 @@ -# 开发环境配置 -VITE_APP_ENV=dev -VITE_API_BASE_URL=https://dev-api.emotion-museum.com/api -VITE_WS_BASE_URL=wss://dev-api.emotion-museum.com -VITE_UPLOAD_URL=https://dev-api.emotion-museum.com/api/upload -VITE_DEBUG=true -VITE_MOCK=false diff --git a/web-new/.env.production b/web-new/.env.production deleted file mode 100644 index af844ed..0000000 --- a/web-new/.env.production +++ /dev/null @@ -1,7 +0,0 @@ -# 生产环境配置 -VITE_APP_ENV=prod -VITE_API_BASE_URL=https://api.emotion-museum.com/api -VITE_WS_BASE_URL=wss://api.emotion-museum.com -VITE_UPLOAD_URL=https://api.emotion-museum.com/api/upload -VITE_DEBUG=false -VITE_MOCK=false diff --git a/web-new/.eslintrc-auto-import.json b/web-new/.eslintrc-auto-import.json deleted file mode 100644 index 37982c4..0000000 --- a/web-new/.eslintrc-auto-import.json +++ /dev/null @@ -1,314 +0,0 @@ -{ - "globals": { - "Component": true, - "ComponentPublicInstance": true, - "ComputedRef": true, - "DirectiveBinding": true, - "EffectScope": true, - "ExtractDefaultPropTypes": true, - "ExtractPropTypes": true, - "ExtractPublicPropTypes": true, - "InjectionKey": true, - "MaybeRef": true, - "MaybeRefOrGetter": true, - "PropType": true, - "Ref": true, - "VNode": true, - "WritableComputedRef": true, - "acceptHMRUpdate": true, - "asyncComputed": true, - "autoResetRef": true, - "computed": true, - "computedAsync": true, - "computedEager": true, - "computedInject": true, - "computedWithControl": true, - "controlledComputed": true, - "controlledRef": true, - "createApp": true, - "createEventHook": true, - "createGlobalState": true, - "createInjectionState": true, - "createPinia": true, - "createReactiveFn": true, - "createReusableTemplate": true, - "createSharedComposable": true, - "createTemplatePromise": true, - "createUnrefFn": true, - "customRef": true, - "debouncedRef": true, - "debouncedWatch": true, - "defineAsyncComponent": true, - "defineComponent": true, - "defineStore": true, - "eagerComputed": true, - "effectScope": true, - "extendRef": true, - "getActivePinia": true, - "getCurrentInstance": true, - "getCurrentScope": true, - "h": true, - "ignorableWatch": true, - "inject": true, - "injectLocal": true, - "isDefined": true, - "isProxy": true, - "isReactive": true, - "isReadonly": true, - "isRef": true, - "makeDestructurable": true, - "mapActions": true, - "mapGetters": true, - "mapState": true, - "mapStores": true, - "mapWritableState": true, - "markRaw": true, - "nextTick": true, - "onActivated": true, - "onBeforeMount": true, - "onBeforeRouteLeave": true, - "onBeforeRouteUpdate": true, - "onBeforeUnmount": true, - "onBeforeUpdate": true, - "onClickOutside": true, - "onDeactivated": true, - "onErrorCaptured": true, - "onKeyStroke": true, - "onLongPress": true, - "onMounted": true, - "onRenderTracked": true, - "onRenderTriggered": true, - "onScopeDispose": true, - "onServerPrefetch": true, - "onStartTyping": true, - "onUnmounted": true, - "onUpdated": true, - "onWatcherCleanup": true, - "pausableWatch": true, - "provide": true, - "provideLocal": true, - "reactify": true, - "reactifyObject": true, - "reactive": true, - "reactiveComputed": true, - "reactiveOmit": true, - "reactivePick": true, - "readonly": true, - "ref": true, - "refAutoReset": true, - "refDebounced": true, - "refDefault": true, - "refThrottled": true, - "refWithControl": true, - "resolveComponent": true, - "resolveRef": true, - "resolveUnref": true, - "setActivePinia": true, - "setMapStoreSuffix": true, - "shallowReactive": true, - "shallowReadonly": true, - "shallowRef": true, - "storeToRefs": true, - "syncRef": true, - "syncRefs": true, - "templateRef": true, - "throttledRef": true, - "throttledWatch": true, - "toRaw": true, - "toReactive": true, - "toRef": true, - "toRefs": true, - "toValue": true, - "triggerRef": true, - "tryOnBeforeMount": true, - "tryOnBeforeUnmount": true, - "tryOnMounted": true, - "tryOnScopeDispose": true, - "tryOnUnmounted": true, - "unref": true, - "unrefElement": true, - "until": true, - "useActiveElement": true, - "useAnimate": true, - "useArrayDifference": true, - "useArrayEvery": true, - "useArrayFilter": true, - "useArrayFind": true, - "useArrayFindIndex": true, - "useArrayFindLast": true, - "useArrayIncludes": true, - "useArrayJoin": true, - "useArrayMap": true, - "useArrayReduce": true, - "useArraySome": true, - "useArrayUnique": true, - "useAsyncQueue": true, - "useAsyncState": true, - "useAttrs": true, - "useBase64": true, - "useBattery": true, - "useBluetooth": true, - "useBreakpoints": true, - "useBroadcastChannel": true, - "useBrowserLocation": true, - "useCached": true, - "useClipboard": true, - "useClipboardItems": true, - "useCloned": true, - "useColorMode": true, - "useConfirmDialog": true, - "useCounter": true, - "useCssModule": true, - "useCssVar": true, - "useCssVars": true, - "useCurrentElement": true, - "useCycleList": true, - "useDark": true, - "useDateFormat": true, - "useDebounce": true, - "useDebounceFn": true, - "useDebouncedRefHistory": true, - "useDeviceMotion": true, - "useDeviceOrientation": true, - "useDevicePixelRatio": true, - "useDevicesList": true, - "useDisplayMedia": true, - "useDocumentVisibility": true, - "useDraggable": true, - "useDropZone": true, - "useElementBounding": true, - "useElementByPoint": true, - "useElementHover": true, - "useElementSize": true, - "useElementVisibility": true, - "useEventBus": true, - "useEventListener": true, - "useEventSource": true, - "useEyeDropper": true, - "useFavicon": true, - "useFetch": true, - "useFileDialog": true, - "useFileSystemAccess": true, - "useFocus": true, - "useFocusWithin": true, - "useFps": true, - "useFullscreen": true, - "useGamepad": true, - "useGeolocation": true, - "useI18n": true, - "useId": true, - "useIdle": true, - "useImage": true, - "useInfiniteScroll": true, - "useIntersectionObserver": true, - "useInterval": true, - "useIntervalFn": true, - "useKeyModifier": true, - "useLastChanged": true, - "useLink": true, - "useLocalStorage": true, - "useMagicKeys": true, - "useManualRefHistory": true, - "useMediaControls": true, - "useMediaQuery": true, - "useMemoize": true, - "useMemory": true, - "useModel": true, - "useMounted": true, - "useMouse": true, - "useMouseInElement": true, - "useMousePressed": true, - "useMutationObserver": true, - "useNavigatorLanguage": true, - "useNetwork": true, - "useNow": true, - "useObjectUrl": true, - "useOffsetPagination": true, - "useOnline": true, - "usePageLeave": true, - "useParallax": true, - "useParentElement": true, - "usePerformanceObserver": true, - "usePermission": true, - "usePointer": true, - "usePointerLock": true, - "usePointerSwipe": true, - "usePreferredColorScheme": true, - "usePreferredContrast": true, - "usePreferredDark": true, - "usePreferredLanguages": true, - "usePreferredReducedMotion": true, - "usePrevious": true, - "useRafFn": true, - "useRefHistory": true, - "useResizeObserver": true, - "useRoute": true, - "useRouter": true, - "useScreenOrientation": true, - "useScreenSafeArea": true, - "useScriptTag": true, - "useScroll": true, - "useScrollLock": true, - "useSessionStorage": true, - "useShare": true, - "useSlots": true, - "useSorted": true, - "useSpeechRecognition": true, - "useSpeechSynthesis": true, - "useStepper": true, - "useStorage": true, - "useStorageAsync": true, - "useStyleTag": true, - "useSupported": true, - "useSwipe": true, - "useTemplateRef": true, - "useTemplateRefsList": true, - "useTextDirection": true, - "useTextSelection": true, - "useTextareaAutosize": true, - "useThrottle": true, - "useThrottleFn": true, - "useThrottledRefHistory": true, - "useTimeAgo": true, - "useTimeout": true, - "useTimeoutFn": true, - "useTimeoutPoll": true, - "useTimestamp": true, - "useTitle": true, - "useToNumber": true, - "useToString": true, - "useToggle": true, - "useTransition": true, - "useUrlSearchParams": true, - "useUserMedia": true, - "useVModel": true, - "useVModels": true, - "useVibrate": true, - "useVirtualList": true, - "useWakeLock": true, - "useWebNotification": true, - "useWebSocket": true, - "useWebWorker": true, - "useWebWorkerFn": true, - "useWindowFocus": true, - "useWindowScroll": true, - "useWindowSize": true, - "watch": true, - "watchArray": true, - "watchAtMost": true, - "watchDebounced": true, - "watchDeep": true, - "watchEffect": true, - "watchIgnorable": true, - "watchImmediate": true, - "watchOnce": true, - "watchPausable": true, - "watchPostEffect": true, - "watchSyncEffect": true, - "watchThrottled": true, - "watchTriggerable": true, - "watchWithFilter": true, - "whenever": true, - "ElMessage": true - } -} diff --git a/web-new/.eslintrc.cjs b/web-new/.eslintrc.cjs deleted file mode 100644 index 0a7f168..0000000 --- a/web-new/.eslintrc.cjs +++ /dev/null @@ -1,85 +0,0 @@ -/* eslint-env node */ -require('@rushstack/eslint-patch/modern-module-resolution') - -module.exports = { - root: true, - extends: [ - 'plugin:vue/vue3-essential', - 'eslint:recommended', - '@vue/eslint-config-typescript', - '@vue/eslint-config-prettier/skip-formatting', - './.eslintrc-auto-import.json' - ], - parserOptions: { - ecmaVersion: 'latest' - }, - env: { - node: true, - browser: true, - es2022: true - }, - globals: { - defineEmits: 'readonly', - defineProps: 'readonly', - defineExpose: 'readonly', - withDefaults: 'readonly' - }, - rules: { - // Vue规则 - 'vue/multi-word-component-names': 'off', - 'vue/no-v-html': 'off', - 'vue/require-default-prop': 'off', - 'vue/require-explicit-emits': 'off', - 'vue/html-self-closing': [ - 'error', - { - html: { - void: 'always', - normal: 'always', - component: 'always' - }, - svg: 'always', - math: 'always' - } - ], - - // TypeScript规则 - '@typescript-eslint/no-unused-vars': [ - 'error', - { - argsIgnorePattern: '^_', - varsIgnorePattern: '^_' - } - ], - '@typescript-eslint/no-explicit-any': 'warn', - '@typescript-eslint/ban-ts-comment': 'off', - '@typescript-eslint/prefer-ts-expect-error': 'error', - - // 通用规则 - 'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off', - 'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off', - 'no-unused-vars': 'off', // 使用TypeScript版本 - 'prefer-const': 'error', - 'no-var': 'error', - - // 代码风格 - 'eqeqeq': ['error', 'always'], - 'curly': ['error', 'all'], - 'brace-style': ['error', '1tbs'], - 'comma-dangle': ['error', 'never'], - 'quotes': ['error', 'single', { avoidEscape: true }], - 'semi': ['error', 'never'] - }, - overrides: [ - { - files: ['cypress/e2e/**/*.{cy,spec}.{js,ts,jsx,tsx}'], - extends: ['plugin:cypress/recommended'] - }, - { - files: ['src/**/__tests__/**/*', 'src/**/*.{test,spec}.*'], - env: { - vitest: true - } - } - ] -} diff --git a/web-new/.prettierrc b/web-new/.prettierrc deleted file mode 100644 index 9f1e535..0000000 --- a/web-new/.prettierrc +++ /dev/null @@ -1,15 +0,0 @@ -{ - "semi": false, - "singleQuote": true, - "tabWidth": 2, - "useTabs": false, - "trailingComma": "none", - "printWidth": 100, - "bracketSpacing": true, - "bracketSameLine": false, - "arrowParens": "avoid", - "endOfLine": "lf", - "vueIndentScriptAndStyle": false, - "htmlWhitespaceSensitivity": "ignore", - "embeddedLanguageFormatting": "auto" -} diff --git a/web-new/README.md b/web-new/README.md deleted file mode 100644 index 146f05a..0000000 --- a/web-new/README.md +++ /dev/null @@ -1,213 +0,0 @@ -# 情绪博物馆 Web 端 - -基于 Vue 3 + TypeScript + Vite 的现代化前端应用,为用户提供情绪记录和心理健康服务。 - -## ✨ 特性 - -- 🚀 **现代化技术栈**: Vue 3.4.21 + TypeScript 5.4.2 + Vite 5.1.6 -- 🎨 **优雅的UI**: Element Plus 2.6.1 + Tailwind CSS 3.4.1 -- 📱 **响应式设计**: 支持桌面端和移动端 -- 🔐 **完整的认证**: JWT Token + 自动刷新 -- 🌐 **实时通信**: 原生WebSocket + STOMP协议 -- 📊 **数据可视化**: ECharts 5.5.0 图表展示 -- 🌍 **国际化**: Vue I18n 多语言支持 -- 📦 **PWA支持**: 离线访问和桌面安装 -- 🧪 **完整测试**: Vitest + Cypress 测试覆盖 - -## 🏗️ 项目结构 - -``` -web-new/ -├── public/ # 静态资源 -├── src/ -│ ├── api/ # API接口定义 -│ ├── assets/ # 资源文件 -│ ├── components/ # 通用组件 -│ ├── composables/ # 组合式API -│ ├── config/ # 配置文件 -│ ├── i18n/ # 国际化 -│ ├── layouts/ # 布局组件 -│ ├── plugins/ # 插件 -│ ├── router/ # 路由配置 -│ ├── stores/ # 状态管理 -│ ├── types/ # 类型定义 -│ ├── utils/ # 工具函数 -│ ├── views/ # 页面组件 -│ ├── App.vue # 根组件 -│ └── main.ts # 入口文件 -├── tests/ # 测试文件 -├── .env # 环境变量 -├── package.json # 依赖配置 -├── vite.config.ts # Vite配置 -└── README.md # 项目文档 -``` - -## 🚀 快速开始 - -### 环境要求 - -- Node.js >= 18.0.0 -- npm >= 9.0.0 - -### 安装依赖 - -```bash -npm install -``` - -### 开发环境 - -```bash -npm run dev -``` - -### 构建生产版本 - -```bash -npm run build -``` - -### 预览生产版本 - -```bash -npm run preview -``` - -## 🧪 测试 - -### 运行单元测试 - -```bash -npm run test -``` - -### 运行E2E测试 - -```bash -npm run test:e2e -``` - -### 测试覆盖率 - -```bash -npm run test:coverage -``` - -## 📦 核心依赖 - -### 框架和工具 - -- **Vue 3.4.21**: 渐进式JavaScript框架 -- **TypeScript 5.4.2**: 类型安全的JavaScript -- **Vite 5.1.6**: 下一代前端构建工具 -- **Vue Router 4.3.0**: 官方路由管理器 -- **Pinia 2.1.7**: 官方状态管理库 - -### UI和样式 - -- **Element Plus 2.6.1**: Vue 3 UI组件库 -- **Tailwind CSS 3.4.1**: 实用优先的CSS框架 -- **@element-plus/icons-vue**: Element Plus图标 - -### 网络和通信 - -- **Axios 1.6.8**: HTTP客户端 -- **@stomp/stompjs 7.1.1**: WebSocket STOMP协议 - -### 数据可视化 - -- **ECharts 5.5.0**: 强大的图表库 -- **vue-echarts 6.7.3**: Vue ECharts组件 - -### 工具库 - -- **@vueuse/core 10.9.0**: Vue组合式工具集 -- **Day.js 1.11.10**: 轻量级日期库 -- **Lodash-es 4.17.21**: 实用工具库 - -## 🔧 开发工具 - -### 代码质量 - -- **ESLint 8.57.0**: 代码检查 -- **Prettier 3.2.5**: 代码格式化 -- **Husky 9.0.11**: Git钩子 -- **lint-staged 15.2.2**: 暂存文件检查 - -### 自动化 - -- **unplugin-auto-import**: 自动导入API -- **unplugin-vue-components**: 自动导入组件 -- **vite-plugin-pwa**: PWA支持 - -### 测试 - -- **Vitest 1.4.0**: 单元测试框架 -- **@vue/test-utils 2.4.5**: Vue组件测试工具 -- **Cypress 13.7.1**: E2E测试框架 - -## 🌍 环境配置 - -项目支持多环境配置: - -- **local**: 本地开发环境 -- **dev**: 开发服务器环境 -- **test**: 测试环境 -- **prod**: 生产环境 - -通过 `.env` 文件配置不同环境的参数。 - -## 📱 功能特性 - -### 核心功能 - -- **AI智能对话**: 与AI助手进行情绪交流 -- **情绪日记**: 记录和分析日常情绪 -- **数据可视化**: 情绪趋势和统计分析 -- **个人仪表盘**: 全面的个人数据展示 - -### 技术特性 - -- **响应式设计**: 适配各种设备尺寸 -- **暗色主题**: 支持明暗主题切换 -- **国际化**: 中英文语言切换 -- **PWA**: 支持离线访问和桌面安装 -- **实时通信**: WebSocket实时消息推送 - -## 🔐 安全特性 - -- **JWT认证**: 安全的用户认证机制 -- **Token刷新**: 自动Token刷新和过期处理 -- **权限控制**: 基于角色的访问控制 -- **路由守卫**: 页面访问权限验证 -- **XSS防护**: 内容安全策略 - -## 📈 性能优化 - -- **代码分割**: 按需加载减少初始包大小 -- **Tree Shaking**: 移除未使用的代码 -- **图片优化**: 支持WebP格式和懒加载 -- **缓存策略**: 合理的缓存配置 -- **Gzip压缩**: 减少传输大小 - -## 🤝 贡献指南 - -1. Fork 项目 -2. 创建功能分支 (`git checkout -b feature/AmazingFeature`) -3. 提交更改 (`git commit -m 'Add some AmazingFeature'`) -4. 推送到分支 (`git push origin feature/AmazingFeature`) -5. 打开 Pull Request - -## 📄 许可证 - -本项目采用 MIT 许可证 - 查看 [LICENSE](LICENSE) 文件了解详情。 - -## 📞 联系我们 - -- 项目地址: [GitHub](https://github.com/emotion-museum/web) -- 问题反馈: [Issues](https://github.com/emotion-museum/web/issues) -- 邮箱: contact@emotion-museum.com - ---- - -**情绪博物馆** - 记录情绪,分享心情的温暖空间 ❤️ diff --git a/web-new/auto-imports.d.ts b/web-new/auto-imports.d.ts deleted file mode 100644 index 429a8e4..0000000 --- a/web-new/auto-imports.d.ts +++ /dev/null @@ -1,310 +0,0 @@ -/* eslint-disable */ -/* prettier-ignore */ -// @ts-nocheck -// noinspection JSUnusedGlobalSymbols -// Generated by unplugin-auto-import -export {} -declare global { - const EffectScope: typeof import('vue')['EffectScope'] - const ElMessage: typeof import('element-plus/es')['ElMessage'] - const acceptHMRUpdate: typeof import('pinia')['acceptHMRUpdate'] - const asyncComputed: typeof import('@vueuse/core')['asyncComputed'] - const autoResetRef: typeof import('@vueuse/core')['autoResetRef'] - const computed: typeof import('vue')['computed'] - const computedAsync: typeof import('@vueuse/core')['computedAsync'] - const computedEager: typeof import('@vueuse/core')['computedEager'] - const computedInject: typeof import('@vueuse/core')['computedInject'] - const computedWithControl: typeof import('@vueuse/core')['computedWithControl'] - const controlledComputed: typeof import('@vueuse/core')['controlledComputed'] - const controlledRef: typeof import('@vueuse/core')['controlledRef'] - const createApp: typeof import('vue')['createApp'] - const createEventHook: typeof import('@vueuse/core')['createEventHook'] - const createGlobalState: typeof import('@vueuse/core')['createGlobalState'] - const createInjectionState: typeof import('@vueuse/core')['createInjectionState'] - const createPinia: typeof import('pinia')['createPinia'] - const createReactiveFn: typeof import('@vueuse/core')['createReactiveFn'] - const createReusableTemplate: typeof import('@vueuse/core')['createReusableTemplate'] - const createSharedComposable: typeof import('@vueuse/core')['createSharedComposable'] - const createTemplatePromise: typeof import('@vueuse/core')['createTemplatePromise'] - const createUnrefFn: typeof import('@vueuse/core')['createUnrefFn'] - const customRef: typeof import('vue')['customRef'] - const debouncedRef: typeof import('@vueuse/core')['debouncedRef'] - const debouncedWatch: typeof import('@vueuse/core')['debouncedWatch'] - const defineAsyncComponent: typeof import('vue')['defineAsyncComponent'] - const defineComponent: typeof import('vue')['defineComponent'] - const defineStore: typeof import('pinia')['defineStore'] - const eagerComputed: typeof import('@vueuse/core')['eagerComputed'] - const effectScope: typeof import('vue')['effectScope'] - const extendRef: typeof import('@vueuse/core')['extendRef'] - const getActivePinia: typeof import('pinia')['getActivePinia'] - const getCurrentInstance: typeof import('vue')['getCurrentInstance'] - const getCurrentScope: typeof import('vue')['getCurrentScope'] - const h: typeof import('vue')['h'] - const ignorableWatch: typeof import('@vueuse/core')['ignorableWatch'] - const inject: typeof import('vue')['inject'] - const injectLocal: typeof import('@vueuse/core')['injectLocal'] - const isDefined: typeof import('@vueuse/core')['isDefined'] - const isProxy: typeof import('vue')['isProxy'] - const isReactive: typeof import('vue')['isReactive'] - const isReadonly: typeof import('vue')['isReadonly'] - const isRef: typeof import('vue')['isRef'] - const makeDestructurable: typeof import('@vueuse/core')['makeDestructurable'] - const mapActions: typeof import('pinia')['mapActions'] - const mapGetters: typeof import('pinia')['mapGetters'] - const mapState: typeof import('pinia')['mapState'] - const mapStores: typeof import('pinia')['mapStores'] - const mapWritableState: typeof import('pinia')['mapWritableState'] - const markRaw: typeof import('vue')['markRaw'] - const nextTick: typeof import('vue')['nextTick'] - const onActivated: typeof import('vue')['onActivated'] - const onBeforeMount: typeof import('vue')['onBeforeMount'] - const onBeforeRouteLeave: typeof import('vue-router')['onBeforeRouteLeave'] - const onBeforeRouteUpdate: typeof import('vue-router')['onBeforeRouteUpdate'] - const onBeforeUnmount: typeof import('vue')['onBeforeUnmount'] - const onBeforeUpdate: typeof import('vue')['onBeforeUpdate'] - const onClickOutside: typeof import('@vueuse/core')['onClickOutside'] - const onDeactivated: typeof import('vue')['onDeactivated'] - const onErrorCaptured: typeof import('vue')['onErrorCaptured'] - const onKeyStroke: typeof import('@vueuse/core')['onKeyStroke'] - const onLongPress: typeof import('@vueuse/core')['onLongPress'] - const onMounted: typeof import('vue')['onMounted'] - const onRenderTracked: typeof import('vue')['onRenderTracked'] - const onRenderTriggered: typeof import('vue')['onRenderTriggered'] - const onScopeDispose: typeof import('vue')['onScopeDispose'] - const onServerPrefetch: typeof import('vue')['onServerPrefetch'] - const onStartTyping: typeof import('@vueuse/core')['onStartTyping'] - const onUnmounted: typeof import('vue')['onUnmounted'] - const onUpdated: typeof import('vue')['onUpdated'] - const onWatcherCleanup: typeof import('vue')['onWatcherCleanup'] - const pausableWatch: typeof import('@vueuse/core')['pausableWatch'] - const provide: typeof import('vue')['provide'] - const provideLocal: typeof import('@vueuse/core')['provideLocal'] - const reactify: typeof import('@vueuse/core')['reactify'] - const reactifyObject: typeof import('@vueuse/core')['reactifyObject'] - const reactive: typeof import('vue')['reactive'] - const reactiveComputed: typeof import('@vueuse/core')['reactiveComputed'] - const reactiveOmit: typeof import('@vueuse/core')['reactiveOmit'] - const reactivePick: typeof import('@vueuse/core')['reactivePick'] - const readonly: typeof import('vue')['readonly'] - const ref: typeof import('vue')['ref'] - const refAutoReset: typeof import('@vueuse/core')['refAutoReset'] - const refDebounced: typeof import('@vueuse/core')['refDebounced'] - const refDefault: typeof import('@vueuse/core')['refDefault'] - const refThrottled: typeof import('@vueuse/core')['refThrottled'] - const refWithControl: typeof import('@vueuse/core')['refWithControl'] - const resolveComponent: typeof import('vue')['resolveComponent'] - const resolveRef: typeof import('@vueuse/core')['resolveRef'] - const resolveUnref: typeof import('@vueuse/core')['resolveUnref'] - const setActivePinia: typeof import('pinia')['setActivePinia'] - const setMapStoreSuffix: typeof import('pinia')['setMapStoreSuffix'] - const shallowReactive: typeof import('vue')['shallowReactive'] - const shallowReadonly: typeof import('vue')['shallowReadonly'] - const shallowRef: typeof import('vue')['shallowRef'] - const storeToRefs: typeof import('pinia')['storeToRefs'] - const syncRef: typeof import('@vueuse/core')['syncRef'] - const syncRefs: typeof import('@vueuse/core')['syncRefs'] - const templateRef: typeof import('@vueuse/core')['templateRef'] - const throttledRef: typeof import('@vueuse/core')['throttledRef'] - const throttledWatch: typeof import('@vueuse/core')['throttledWatch'] - const toRaw: typeof import('vue')['toRaw'] - const toReactive: typeof import('@vueuse/core')['toReactive'] - const toRef: typeof import('vue')['toRef'] - const toRefs: typeof import('vue')['toRefs'] - const toValue: typeof import('vue')['toValue'] - const triggerRef: typeof import('vue')['triggerRef'] - const tryOnBeforeMount: typeof import('@vueuse/core')['tryOnBeforeMount'] - const tryOnBeforeUnmount: typeof import('@vueuse/core')['tryOnBeforeUnmount'] - const tryOnMounted: typeof import('@vueuse/core')['tryOnMounted'] - const tryOnScopeDispose: typeof import('@vueuse/core')['tryOnScopeDispose'] - const tryOnUnmounted: typeof import('@vueuse/core')['tryOnUnmounted'] - const unref: typeof import('vue')['unref'] - const unrefElement: typeof import('@vueuse/core')['unrefElement'] - const until: typeof import('@vueuse/core')['until'] - const useActiveElement: typeof import('@vueuse/core')['useActiveElement'] - const useAnimate: typeof import('@vueuse/core')['useAnimate'] - const useArrayDifference: typeof import('@vueuse/core')['useArrayDifference'] - const useArrayEvery: typeof import('@vueuse/core')['useArrayEvery'] - const useArrayFilter: typeof import('@vueuse/core')['useArrayFilter'] - const useArrayFind: typeof import('@vueuse/core')['useArrayFind'] - const useArrayFindIndex: typeof import('@vueuse/core')['useArrayFindIndex'] - const useArrayFindLast: typeof import('@vueuse/core')['useArrayFindLast'] - const useArrayIncludes: typeof import('@vueuse/core')['useArrayIncludes'] - const useArrayJoin: typeof import('@vueuse/core')['useArrayJoin'] - const useArrayMap: typeof import('@vueuse/core')['useArrayMap'] - const useArrayReduce: typeof import('@vueuse/core')['useArrayReduce'] - const useArraySome: typeof import('@vueuse/core')['useArraySome'] - const useArrayUnique: typeof import('@vueuse/core')['useArrayUnique'] - const useAsyncQueue: typeof import('@vueuse/core')['useAsyncQueue'] - const useAsyncState: typeof import('@vueuse/core')['useAsyncState'] - const useAttrs: typeof import('vue')['useAttrs'] - const useBase64: typeof import('@vueuse/core')['useBase64'] - const useBattery: typeof import('@vueuse/core')['useBattery'] - const useBluetooth: typeof import('@vueuse/core')['useBluetooth'] - const useBreakpoints: typeof import('@vueuse/core')['useBreakpoints'] - const useBroadcastChannel: typeof import('@vueuse/core')['useBroadcastChannel'] - const useBrowserLocation: typeof import('@vueuse/core')['useBrowserLocation'] - const useCached: typeof import('@vueuse/core')['useCached'] - const useClipboard: typeof import('@vueuse/core')['useClipboard'] - const useClipboardItems: typeof import('@vueuse/core')['useClipboardItems'] - const useCloned: typeof import('@vueuse/core')['useCloned'] - const useColorMode: typeof import('@vueuse/core')['useColorMode'] - const useConfirmDialog: typeof import('@vueuse/core')['useConfirmDialog'] - const useCounter: typeof import('@vueuse/core')['useCounter'] - const useCssModule: typeof import('vue')['useCssModule'] - const useCssVar: typeof import('@vueuse/core')['useCssVar'] - const useCssVars: typeof import('vue')['useCssVars'] - const useCurrentElement: typeof import('@vueuse/core')['useCurrentElement'] - const useCycleList: typeof import('@vueuse/core')['useCycleList'] - const useDark: typeof import('@vueuse/core')['useDark'] - const useDateFormat: typeof import('@vueuse/core')['useDateFormat'] - const useDebounce: typeof import('@vueuse/core')['useDebounce'] - const useDebounceFn: typeof import('@vueuse/core')['useDebounceFn'] - const useDebouncedRefHistory: typeof import('@vueuse/core')['useDebouncedRefHistory'] - const useDeviceMotion: typeof import('@vueuse/core')['useDeviceMotion'] - const useDeviceOrientation: typeof import('@vueuse/core')['useDeviceOrientation'] - const useDevicePixelRatio: typeof import('@vueuse/core')['useDevicePixelRatio'] - const useDevicesList: typeof import('@vueuse/core')['useDevicesList'] - const useDisplayMedia: typeof import('@vueuse/core')['useDisplayMedia'] - const useDocumentVisibility: typeof import('@vueuse/core')['useDocumentVisibility'] - const useDraggable: typeof import('@vueuse/core')['useDraggable'] - const useDropZone: typeof import('@vueuse/core')['useDropZone'] - const useElementBounding: typeof import('@vueuse/core')['useElementBounding'] - const useElementByPoint: typeof import('@vueuse/core')['useElementByPoint'] - const useElementHover: typeof import('@vueuse/core')['useElementHover'] - const useElementSize: typeof import('@vueuse/core')['useElementSize'] - const useElementVisibility: typeof import('@vueuse/core')['useElementVisibility'] - const useEventBus: typeof import('@vueuse/core')['useEventBus'] - const useEventListener: typeof import('@vueuse/core')['useEventListener'] - const useEventSource: typeof import('@vueuse/core')['useEventSource'] - const useEyeDropper: typeof import('@vueuse/core')['useEyeDropper'] - const useFavicon: typeof import('@vueuse/core')['useFavicon'] - const useFetch: typeof import('@vueuse/core')['useFetch'] - const useFileDialog: typeof import('@vueuse/core')['useFileDialog'] - const useFileSystemAccess: typeof import('@vueuse/core')['useFileSystemAccess'] - const useFocus: typeof import('@vueuse/core')['useFocus'] - const useFocusWithin: typeof import('@vueuse/core')['useFocusWithin'] - const useFps: typeof import('@vueuse/core')['useFps'] - const useFullscreen: typeof import('@vueuse/core')['useFullscreen'] - const useGamepad: typeof import('@vueuse/core')['useGamepad'] - const useGeolocation: typeof import('@vueuse/core')['useGeolocation'] - const useI18n: typeof import('vue-i18n')['useI18n'] - const useId: typeof import('vue')['useId'] - const useIdle: typeof import('@vueuse/core')['useIdle'] - const useImage: typeof import('@vueuse/core')['useImage'] - const useInfiniteScroll: typeof import('@vueuse/core')['useInfiniteScroll'] - const useIntersectionObserver: typeof import('@vueuse/core')['useIntersectionObserver'] - const useInterval: typeof import('@vueuse/core')['useInterval'] - const useIntervalFn: typeof import('@vueuse/core')['useIntervalFn'] - const useKeyModifier: typeof import('@vueuse/core')['useKeyModifier'] - const useLastChanged: typeof import('@vueuse/core')['useLastChanged'] - const useLink: typeof import('vue-router')['useLink'] - const useLocalStorage: typeof import('@vueuse/core')['useLocalStorage'] - const useMagicKeys: typeof import('@vueuse/core')['useMagicKeys'] - const useManualRefHistory: typeof import('@vueuse/core')['useManualRefHistory'] - const useMediaControls: typeof import('@vueuse/core')['useMediaControls'] - const useMediaQuery: typeof import('@vueuse/core')['useMediaQuery'] - const useMemoize: typeof import('@vueuse/core')['useMemoize'] - const useMemory: typeof import('@vueuse/core')['useMemory'] - const useModel: typeof import('vue')['useModel'] - const useMounted: typeof import('@vueuse/core')['useMounted'] - const useMouse: typeof import('@vueuse/core')['useMouse'] - const useMouseInElement: typeof import('@vueuse/core')['useMouseInElement'] - const useMousePressed: typeof import('@vueuse/core')['useMousePressed'] - const useMutationObserver: typeof import('@vueuse/core')['useMutationObserver'] - const useNavigatorLanguage: typeof import('@vueuse/core')['useNavigatorLanguage'] - const useNetwork: typeof import('@vueuse/core')['useNetwork'] - const useNow: typeof import('@vueuse/core')['useNow'] - const useObjectUrl: typeof import('@vueuse/core')['useObjectUrl'] - const useOffsetPagination: typeof import('@vueuse/core')['useOffsetPagination'] - const useOnline: typeof import('@vueuse/core')['useOnline'] - const usePageLeave: typeof import('@vueuse/core')['usePageLeave'] - const useParallax: typeof import('@vueuse/core')['useParallax'] - const useParentElement: typeof import('@vueuse/core')['useParentElement'] - const usePerformanceObserver: typeof import('@vueuse/core')['usePerformanceObserver'] - const usePermission: typeof import('@vueuse/core')['usePermission'] - const usePointer: typeof import('@vueuse/core')['usePointer'] - const usePointerLock: typeof import('@vueuse/core')['usePointerLock'] - const usePointerSwipe: typeof import('@vueuse/core')['usePointerSwipe'] - const usePreferredColorScheme: typeof import('@vueuse/core')['usePreferredColorScheme'] - const usePreferredContrast: typeof import('@vueuse/core')['usePreferredContrast'] - const usePreferredDark: typeof import('@vueuse/core')['usePreferredDark'] - const usePreferredLanguages: typeof import('@vueuse/core')['usePreferredLanguages'] - const usePreferredReducedMotion: typeof import('@vueuse/core')['usePreferredReducedMotion'] - const usePrevious: typeof import('@vueuse/core')['usePrevious'] - const useRafFn: typeof import('@vueuse/core')['useRafFn'] - const useRefHistory: typeof import('@vueuse/core')['useRefHistory'] - const useResizeObserver: typeof import('@vueuse/core')['useResizeObserver'] - const useRoute: typeof import('vue-router')['useRoute'] - const useRouter: typeof import('vue-router')['useRouter'] - const useScreenOrientation: typeof import('@vueuse/core')['useScreenOrientation'] - const useScreenSafeArea: typeof import('@vueuse/core')['useScreenSafeArea'] - const useScriptTag: typeof import('@vueuse/core')['useScriptTag'] - const useScroll: typeof import('@vueuse/core')['useScroll'] - const useScrollLock: typeof import('@vueuse/core')['useScrollLock'] - const useSessionStorage: typeof import('@vueuse/core')['useSessionStorage'] - const useShare: typeof import('@vueuse/core')['useShare'] - const useSlots: typeof import('vue')['useSlots'] - const useSorted: typeof import('@vueuse/core')['useSorted'] - const useSpeechRecognition: typeof import('@vueuse/core')['useSpeechRecognition'] - const useSpeechSynthesis: typeof import('@vueuse/core')['useSpeechSynthesis'] - const useStepper: typeof import('@vueuse/core')['useStepper'] - const useStorage: typeof import('@vueuse/core')['useStorage'] - const useStorageAsync: typeof import('@vueuse/core')['useStorageAsync'] - const useStyleTag: typeof import('@vueuse/core')['useStyleTag'] - const useSupported: typeof import('@vueuse/core')['useSupported'] - const useSwipe: typeof import('@vueuse/core')['useSwipe'] - const useTemplateRef: typeof import('vue')['useTemplateRef'] - const useTemplateRefsList: typeof import('@vueuse/core')['useTemplateRefsList'] - const useTextDirection: typeof import('@vueuse/core')['useTextDirection'] - const useTextSelection: typeof import('@vueuse/core')['useTextSelection'] - const useTextareaAutosize: typeof import('@vueuse/core')['useTextareaAutosize'] - const useThrottle: typeof import('@vueuse/core')['useThrottle'] - const useThrottleFn: typeof import('@vueuse/core')['useThrottleFn'] - const useThrottledRefHistory: typeof import('@vueuse/core')['useThrottledRefHistory'] - const useTimeAgo: typeof import('@vueuse/core')['useTimeAgo'] - const useTimeout: typeof import('@vueuse/core')['useTimeout'] - const useTimeoutFn: typeof import('@vueuse/core')['useTimeoutFn'] - const useTimeoutPoll: typeof import('@vueuse/core')['useTimeoutPoll'] - const useTimestamp: typeof import('@vueuse/core')['useTimestamp'] - const useTitle: typeof import('@vueuse/core')['useTitle'] - const useToNumber: typeof import('@vueuse/core')['useToNumber'] - const useToString: typeof import('@vueuse/core')['useToString'] - const useToggle: typeof import('@vueuse/core')['useToggle'] - const useTransition: typeof import('@vueuse/core')['useTransition'] - const useUrlSearchParams: typeof import('@vueuse/core')['useUrlSearchParams'] - const useUserMedia: typeof import('@vueuse/core')['useUserMedia'] - const useVModel: typeof import('@vueuse/core')['useVModel'] - const useVModels: typeof import('@vueuse/core')['useVModels'] - const useVibrate: typeof import('@vueuse/core')['useVibrate'] - const useVirtualList: typeof import('@vueuse/core')['useVirtualList'] - const useWakeLock: typeof import('@vueuse/core')['useWakeLock'] - const useWebNotification: typeof import('@vueuse/core')['useWebNotification'] - const useWebSocket: typeof import('@vueuse/core')['useWebSocket'] - const useWebWorker: typeof import('@vueuse/core')['useWebWorker'] - const useWebWorkerFn: typeof import('@vueuse/core')['useWebWorkerFn'] - const useWindowFocus: typeof import('@vueuse/core')['useWindowFocus'] - const useWindowScroll: typeof import('@vueuse/core')['useWindowScroll'] - const useWindowSize: typeof import('@vueuse/core')['useWindowSize'] - const watch: typeof import('vue')['watch'] - const watchArray: typeof import('@vueuse/core')['watchArray'] - const watchAtMost: typeof import('@vueuse/core')['watchAtMost'] - const watchDebounced: typeof import('@vueuse/core')['watchDebounced'] - const watchDeep: typeof import('@vueuse/core')['watchDeep'] - const watchEffect: typeof import('vue')['watchEffect'] - const watchIgnorable: typeof import('@vueuse/core')['watchIgnorable'] - const watchImmediate: typeof import('@vueuse/core')['watchImmediate'] - const watchOnce: typeof import('@vueuse/core')['watchOnce'] - const watchPausable: typeof import('@vueuse/core')['watchPausable'] - const watchPostEffect: typeof import('vue')['watchPostEffect'] - const watchSyncEffect: typeof import('vue')['watchSyncEffect'] - const watchThrottled: typeof import('@vueuse/core')['watchThrottled'] - const watchTriggerable: typeof import('@vueuse/core')['watchTriggerable'] - const watchWithFilter: typeof import('@vueuse/core')['watchWithFilter'] - const whenever: typeof import('@vueuse/core')['whenever'] -} -// for type re-export -declare global { - // @ts-ignore - export type { Component, ComponentPublicInstance, ComputedRef, DirectiveBinding, ExtractDefaultPropTypes, ExtractPropTypes, ExtractPublicPropTypes, InjectionKey, PropType, Ref, MaybeRef, MaybeRefOrGetter, VNode, WritableComputedRef } from 'vue' - import('vue') -} diff --git a/web-new/components.d.ts b/web-new/components.d.ts deleted file mode 100644 index efaa6ef..0000000 --- a/web-new/components.d.ts +++ /dev/null @@ -1,19 +0,0 @@ -/* eslint-disable */ -/* prettier-ignore */ -// @ts-nocheck -// Generated by unplugin-vue-components -// Read more: https://github.com/vuejs/core/pull/3399 -export {} - -declare module 'vue' { - export interface GlobalComponents { - EmojiPicker: typeof import('./src/components/emoji/EmojiPicker.vue')['default'] - ErrorBoundary: typeof import('./src/components/error/ErrorBoundary.vue')['default'] - FileUpload: typeof import('./src/components/upload/FileUpload.vue')['default'] - ImageUpload: typeof import('./src/components/upload/ImageUpload.vue')['default'] - NotificationCenter: typeof import('./src/components/notification/NotificationCenter.vue')['default'] - RichTextEditor: typeof import('./src/components/editor/RichTextEditor.vue')['default'] - RouterLink: typeof import('vue-router')['RouterLink'] - RouterView: typeof import('vue-router')['RouterView'] - } -} diff --git a/web-new/cypress.config.ts b/web-new/cypress.config.ts deleted file mode 100644 index bca8b62..0000000 --- a/web-new/cypress.config.ts +++ /dev/null @@ -1,126 +0,0 @@ -/** - * Cypress E2E 测试配置 - */ - -import { defineConfig } from 'cypress' - -export default defineConfig({ - e2e: { - // 基础URL - baseUrl: 'http://localhost:5173', - - // 测试文件位置 - specPattern: 'tests/e2e/**/*.cy.{js,jsx,ts,tsx}', - - // 支持文件位置 - supportFile: 'tests/e2e/support/e2e.ts', - - // 固件文件位置 - fixturesFolder: 'tests/e2e/fixtures', - - // 截图和视频配置 - screenshotsFolder: 'tests/e2e/screenshots', - videosFolder: 'tests/e2e/videos', - - // 视频录制 - video: true, - videoCompression: 32, - - // 截图配置 - screenshotOnRunFailure: true, - - // 视口配置 - viewportWidth: 1280, - viewportHeight: 720, - - // 等待配置 - defaultCommandTimeout: 10000, - requestTimeout: 10000, - responseTimeout: 10000, - pageLoadTimeout: 30000, - - // 重试配置 - retries: { - runMode: 2, - openMode: 0 - }, - - // 浏览器配置 - chromeWebSecurity: false, - - // 环境变量 - env: { - // API基础URL - apiUrl: 'http://localhost:3000/api', - - // 测试用户凭据 - testUser: { - username: 'testuser', - password: 'password123', - email: 'test@example.com' - }, - - // 测试管理员凭据 - adminUser: { - username: 'admin', - password: 'admin123', - email: 'admin@example.com' - } - }, - - setupNodeEvents(on, config) { - // 任务注册 - on('task', { - // 数据库清理任务 - clearDatabase() { - // 这里可以添加数据库清理逻辑 - return null - }, - - // 创建测试数据任务 - seedTestData() { - // 这里可以添加测试数据创建逻辑 - return null - }, - - // 日志输出任务 - log(message) { - console.log(message) - return null - } - }) - - // 文件处理 - on('before:browser:launch', (browser, launchOptions) => { - if (browser.name === 'chrome') { - // Chrome 特定配置 - launchOptions.args.push('--disable-dev-shm-usage') - launchOptions.args.push('--no-sandbox') - } - - return launchOptions - }) - - // 配置处理 - on('before:spec', (spec) => { - console.log(`Running spec: ${spec.name}`) - }) - - return config - } - }, - - component: { - // 组件测试配置 - devServer: { - framework: 'vue', - bundler: 'vite' - }, - - specPattern: 'src/**/*.cy.{js,jsx,ts,tsx,vue}', - supportFile: 'tests/e2e/support/component.ts', - - viewportWidth: 1000, - viewportHeight: 660 - } -}) diff --git a/web-new/index.html b/web-new/index.html deleted file mode 100644 index 8ee76b0..0000000 --- a/web-new/index.html +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - -没有找到相关表情
-{{ errorDetails }}
- 暂无通知
-将文件拖拽到此处,或点击上传
-{{ uploadHint }}
-{{ uploadHint }}
-{{ file.name }}
-{{ formatFileSize(file.size) }}
-{{ file.name }}
-{{ formatFileSize(file.size) }}
-记录情绪,分享心情的温暖空间
-
- 情绪博物馆
- - 记录情绪,分享心情的温暖空间。与AI对话,写下情绪日记,分析情感轨迹,让每一份情感都被珍藏。 -
- -探索情绪博物馆的强大功能
-{{ feature.description }}
-看看大家都在做什么
-- 加入我们,让每一份情感都被理解和珍藏 -
- -深入了解您的情绪变化趋势和心理健康状态
-{{ card.title }}
-{{ card.value }}
-{{ insight.content }}
-登录您的账户继续使用
-加入情绪博物馆,开始您的情绪记录之旅
-- {{ connectionStatusText }} -
-查看和管理您的聊天记录
-- 今天是您使用情绪博物馆的第 {{ totalDays }} 天 -
-{{ stat.title }}
-{{ stat.value }}
-{{ activity.title }}
-{{ formatTime(activity.time) }}
-{{ achievement.name }}
-- 已获得 {{ totalAchievements }} 个成就 -
-记录您的情绪变化,AI将为您提供专业的情感分析
-加载中...
-开始记录您的第一篇情绪日记吧
-- {{ diary.content }} -
- - -该日记可能已被删除或您没有访问权限
-{{ diaryForm.title || '无标题' }}
-{{ getEmotionLabel(diaryForm.emotion) }} ({{ diaryForm.mood }}/10)
-{{ diaryForm.isPublic ? '公开' : '私密' }}
-{{ diaryForm.tags.join(', ') }}
-- 抱歉,您访问的页面不存在或已被移除。请检查URL是否正确,或返回首页继续浏览。 -
- - -您可能想要访问:
-{{ userProfile?.bio || '这个人很懒,什么都没有留下...' }}
- -{{ userProfile?.username }}
-{{ userProfile?.nickname }}
-{{ getGenderText(userProfile?.gender) }}
-{{ userProfile?.birthday || '未设置' }}
-{{ userProfile?.location || '未设置' }}
-{{ userProfile?.email || '未绑定' }}
-{{ maskPhone(userProfile?.phone) || '未绑定' }}
-管理您的账户设置和偏好
-选择您喜欢的界面主题
-选择界面显示语言
-默认折叠侧边栏
-在桌面显示通知消息
-收到消息时播放提示音
-在移动设备上震动提醒
-导出您的所有数据
-清除本地缓存数据
-永久删除您的账户和所有数据
-版本 {{ appVersion }}
-- 记录情绪,分享心情的温暖空间。与AI对话,写下情绪日记,分析情感轨迹,让每一份情感都被珍藏。 -
-- 此操作将永久删除您的账户和所有数据,包括聊天记录、日记等,且无法恢复。 -
-