diff --git a/.github/prompts/webtsc.prompt.md b/.github/prompts/webtsc.prompt.md new file mode 100644 index 0000000..23947a7 --- /dev/null +++ b/.github/prompts/webtsc.prompt.md @@ -0,0 +1,45 @@ +--- +agent: agent +--- +如果前端项目,需要考虑以下几点: +1.你是一名精通 Vue3(纯 JavaScript,不使用 TypeScript)的前端开发专家,专注于构建可适配移动端、桌面端、平板端的响应式页面并且开发的页面都会基于当前项目搭建的中英文框架支持中英文切换(页面中英文切换内容都是本地的,所以需要在项目中配置好对应的英文内容),和主题色切换请基于以下要求完成开发任务: +2.技术栈规范 +核心框架:使用 Vue3(Options API 或 Composition API 均可,优先推荐 Composition API 以提升代码复用性),禁止使用 TypeScript,所有逻辑用原生 JavaScript 实现。 +3.构建工具:基于 Vite 搭建项目,确保热更新效率和打包性能。 +4.样式解决方案: +优先使用 Scoped CSS + CSS 变量实现组件样式隔离与主题定制,避免全局样式污染。 +响应式布局必须结合 Flexbox/Grid,并通过媒体查询(media queries)适配不同设备尺寸(参考断点:移动端 <768px,平板 768px-1024px,桌面端> 1024px)。 +可选集成 Tailwind CSS(若使用需说明配置方案),或原生 CSS 实现 +5.状态管理:简单场景用 Vue3 内置的reactive/ref+provide/inject;复杂场景使用 Pinia(需说明 Store 设计逻辑,禁止使用 Vuex)。 +6.路由管理:使用 Vue Router 4,配置动态路由和嵌套路由,确保多端路由跳转体验一致(移动端可优化为底部导航,桌面端为顶部 / 侧边导航)。 +7.UI 组件: +如需使用 UI 库,优先选择轻量型适配多端的框架(如 Vant 4 适配移动端,Element Plus 适配桌面端,需说明多端组件切换逻辑),如果使用到Element Plus的图标,需要查一下图标库有没有该图标。 +自定义组件需实现自适应尺寸(字体、间距、宽高随屏幕尺寸动态调整),避免固定像素值导致的适配问题。 +8.交互优化: +移动端需添加触摸反馈(如点击态、滑动动效),支持手势操作(如左右滑动切换页面)。 +桌面端优化鼠标悬停效果、键盘导航支持。 +平板端兼顾触摸与鼠标操作,优化横 / 竖屏切换体验。 +多端适配核心要求 +9.布局适配: +采用 “移动优先” 原则设计布局,通过媒体查询逐步扩展至平板和桌面端。 +关键区域(如头部、内容区、底部)需在不同设备上重排:移动端单列布局,平板双列 / 混合布局,桌面端多列布局。 +图片 / 视频使用object-fit和响应式 srcset,确保在不同分辨率下清晰显示且不拉伸。 +10.性能优化: +实现组件懒加载(基于defineAsyncComponent)和路由懒加载,减少首屏加载时间。 +移动端禁止不必要的动画和重绘,确保 60fps 流畅度;桌面端可适当增加过渡效果提升体验。 +监听窗口尺寸变化(resize事件),动态调整组件状态(避免频繁触发,需添加防抖处理)。 +11.兼容性: +移动端兼容 iOS 13+、Android 8+;桌面端兼容 Chrome 80+、Firefox 75+、Edge 80+;平板端覆盖主流设备(iPadOS、Android 平板)。 +避免使用 ES6 + 以上高级语法(或通过 Babel 转译),确保低版本浏览器兼容性。 +12.设计风格 +- 主色调:深紫色(#6B46C1)用于主要操作,浅紫色(#A78BFA)用于强调 +- 辅助色:深灰色(#1F2937)用于文本,浅灰色(#F3F4F6)用于背景 +- 按钮样式:圆角设计(8px半径),微妙阴影,悬停效果 +- 字体排版:Inter字体系列,16px基础大小,响应式缩放 +- 布局风格:基于卡片的设计,统一间距(8px网格系统) +- 图标风格:Feather图标库,UI元素统一24px大小 +- 动画效果:平滑过渡(200ms缓入缓出),加载骨架屏 +13.交付标准 +代码结构清晰,遵循 Vue3 最佳实践(如组件拆分粒度合理、逻辑与 UI 分离)。 +提供完整的多端测试报告(说明在不同设备 / 尺寸下的测试结果及适配方案)。 +附带 README,说明项目启动、打包命令,以及响应式布局的核心实现逻辑。 \ No newline at end of file diff --git a/apps/FrontendDesigner/src/assets/demo/suoluetu.png b/apps/FrontendDesigner/src/assets/demo/suoluetu.png new file mode 100644 index 0000000..350f238 Binary files /dev/null and b/apps/FrontendDesigner/src/assets/demo/suoluetu.png differ diff --git a/apps/FrontendDesigner/src/components/admin/AdminLayout.vue b/apps/FrontendDesigner/src/components/admin/AdminLayout.vue index 5b1c93e..d85ec41 100644 --- a/apps/FrontendDesigner/src/components/admin/AdminLayout.vue +++ b/apps/FrontendDesigner/src/components/admin/AdminLayout.vue @@ -62,31 +62,48 @@ - + - - - - - - - - - + + + + + + + + + + + + + + + + + + + + @@ -110,7 +127,7 @@ + + \ No newline at end of file diff --git a/apps/FrontendDesigner/src/views/admin/AdminDisassemblyOrders.vue b/apps/FrontendDesigner/src/views/admin/AdminDisassemblyOrders.vue new file mode 100644 index 0000000..f9afe2a --- /dev/null +++ b/apps/FrontendDesigner/src/views/admin/AdminDisassemblyOrders.vue @@ -0,0 +1,614 @@ + + + + + \ No newline at end of file diff --git a/apps/FrontendDesigner/src/views/admin/AdminOrders copy.vue b/apps/FrontendDesigner/src/views/admin/AdminOrders copy.vue new file mode 100644 index 0000000..f5ccbab --- /dev/null +++ b/apps/FrontendDesigner/src/views/admin/AdminOrders copy.vue @@ -0,0 +1,1000 @@ + + + + + \ No newline at end of file diff --git a/apps/FrontendDesigner/src/views/admin/AdminOrders.vue b/apps/FrontendDesigner/src/views/admin/AdminOrders.vue index dd9de0e..37fb73d 100644 --- a/apps/FrontendDesigner/src/views/admin/AdminOrders.vue +++ b/apps/FrontendDesigner/src/views/admin/AdminOrders.vue @@ -1,21 +1,5 @@ - + @@ -176,7 +199,7 @@ - {{ t(`admin.orders.status.${selectedOrder.status}`) }} + {{ t(`admin.orders.statusOptions.${selectedOrder.status}`) }} @@ -206,7 +229,7 @@ - {{ t(`admin.orders.status.${selectedOrderForStatus.status}`) }} + {{ t(`admin.orders.statusOptions.${selectedOrderForStatus.status}`) }} @@ -225,12 +248,168 @@ {{ t('common.confirm') }} + + + +
+ + + + + + + + + + + + + + + + + + + +
+ +
+ + + +
+ + + {{ selectedOrder.trackingNumber || 'SF1234567890' }} + + + {{ selectedOrder.carrier || '顺丰速运' }} + + + + {{ t('admin.orders.logisticsTimeline') }} + + + + {{ activity.content }} + + +
+ +
+ + + +
+ + + {{ selectedOrderForAction.orderNumber }} + + + {{ selectedOrderForAction.customerName }} + + + + {{ t(`admin.orders.statusOptions.${selectedOrderForAction.status}`) }} + + + +
{{ selectedOrderForAction.customerNote }}
+
+
+ + {{ t('admin.orders.availableActions') }} + +
+ + + {{ t('admin.orders.view') }} + + + + + {{ t('admin.orders.confirm') }} + + + + + {{ t('admin.orders.process') }} + + + + + {{ t('admin.orders.ship') }} + + + + + {{ t('admin.orders.viewLogistics') }} + +
+
+
\ No newline at end of file diff --git a/apps/frontend/.dockerignore b/apps/frontend/.dockerignore new file mode 100644 index 0000000..41501f9 --- /dev/null +++ b/apps/frontend/.dockerignore @@ -0,0 +1,15 @@ +node_modules +npm-debug.log +dist +.git +.gitignore +README.md +.env +.nyc_output +coverage +.nyc_output +.vscode +.idea +*.log +.DS_Store +Thumbs.db \ No newline at end of file diff --git a/apps/frontend/DEPLOYMENT_GUIDE.md b/apps/frontend/DEPLOYMENT_GUIDE.md new file mode 100644 index 0000000..3fec37e --- /dev/null +++ b/apps/frontend/DEPLOYMENT_GUIDE.md @@ -0,0 +1,349 @@ +# 🚀 前端 Docker 镜像部署到后端服务器完整指南 + +## 📋 部署流程概览 + +``` +本地构建 → 导出镜像 → 上传服务器 → 导入镜像 → 启动容器 + ↓ ↓ ↓ ↓ ↓ + 前端负责 前端负责 前端/后端 后端负责 后端负责 +``` + +--- + +## 👥 角色分工 + +### 🔧 前端开发者职责 +- ✅ 构建 Docker 镜像 +- ✅ 测试镜像本地运行 +- ✅ 导出镜像文件 +- ✅ 提供部署文档和配置文件 + +### 🖥️ 后端运维职责 +- ✅ 提供服务器访问权限 +- ✅ 接收镜像文件 +- ✅ 导入并运行容器 +- ✅ 配置域名和 SSL(如需要) + +--- + +## 📝 步骤详解 + +### 🎯 第一步:后端提供的信息 + +**后端需要向前端提供:** + +```bash +# 1. 服务器连接信息 +服务器IP: 192.168.1.100 +用户名: deploy +端口: 22 + +# 2. 部署目录 +部署路径: /app/frontend + +# 3. 端口信息 +应用端口: 3000 +域名: your-domain.com +``` + +### 🏗️ 第二步:前端本地构建镜像 + +#### 1. 确保代码可正常构建 +```bash +# 本地测试构建 +npm run build + +# 检查构建结果 +ls -la dist/ +``` + +#### 2. 构建 Docker 镜像 +```bash +# 在项目根目录执行 +cd d:\work\Aiproject\DeotalandAi\apps\frontend + +# 构建镜像(使用版本号标记) +docker build -t deotaland-frontend:v1.0.0 . + +# 验证镜像构建成功 +docker images | grep deotaland-frontend +``` + +#### 3. 本地测试镜像 +```bash +# 运行容器测试 +docker run -d -p 3001:3000 --name test-frontend deotaland-frontend:v1.0.0 + +# 检查容器状态 +docker ps + +# 测试访问(本地浏览器) +# 访问: http://localhost:3001 + +# 停止测试容器 +docker stop test-frontend +docker rm test-frontend +``` + +### 📦 第三步:导出镜像 + +#### 1. 保存镜像为文件 +```bash +# 导出镜像(文件会很大,这是正常的) +docker save -o deotaland-frontend-v1.0.0.tar deotaland-frontend:v1.0.0 + +# 检查文件大小 +ls -lh deotaland-frontend-v1.0.0.tar +``` + +#### 2. 压缩镜像文件(推荐) +```bash +# Windows 上压缩 +powershell Compress-Archive deotaland-frontend-v1.0.0.tar deotaland-frontend-v1.0.0.tar.zip + +# 或者使用 7zip +7z a deotaland-frontend-v1.0.0.tar.gz deotaland-frontend-v1.0.0.tar +``` + +### 🚀 第四步:上传到服务器 + +#### 方法 A:使用 SCP(推荐) +```bash +# 直接上传(需要服务器SSH权限) +scp deotaland-frontend-v1.0.0.tar.gz deploy@192.168.1.100:/app/frontend/ + +# 如果端口不是22 +scp -P 2222 deotaland-frontend-v1.0.0.tar.gz deploy@192.168.1.100:/app/frontend/ +``` + +#### 方法 B:使用 FTP/SFTP 工具 +- FileZilla +- WinSCP +- MobaXterm + +#### 方法 C:通过中间存储 +```bash +# 上传到云存储(如阿里云OSS、AWS S3) +# 后端再从云存储下载 +``` + +### 🔧 第五步:后端导入和运行 + +#### 1. 登录服务器 +```bash +# 后端操作 +ssh deploy@192.168.1.100 + +# 进入部署目录 +cd /app/frontend +``` + +#### 2. 解压文件(如果需要) +```bash +# 解压 tar.gz +gunzip deotaland-frontend-v1.0.0.tar.gz + +# 或者解压 zip +unzip deotaland-frontend-v1.0.0.tar.zip +``` + +#### 3. 导入镜像 +```bash +# 导入 Docker 镜像 +docker load -i deotaland-frontend-v1.0.0.tar + +# 验证导入成功 +docker images | grep deotaland-frontend +``` + +#### 4. 准备部署文件 +```bash +# 创建部署目录 +mkdir -p /app/frontend/configs + +# 上传 docker-compose 文件(前端提供) +# 保存为 docker-compose.yml +``` + +### 🎯 第六步:启动应用 + +#### 1. 使用 docker-compose 启动 +```bash +# 在包含 docker-compose.yml 的目录下执行 +cd /app/frontend + +# 启动服务 +docker-compose -f docker-compose.prod.yml up -d + +# 检查状态 +docker-compose ps + +# 查看日志 +docker-compose logs -f +``` + +#### 2. 验证部署成功 +```bash +# 检查容器运行状态 +docker ps + +# 测试本地访问 +curl http://localhost:3000 + +# 检查端口监听 +netstat -tlnp | grep 3000 +``` + +--- + +## 📁 需要提供的文件清单 + +### 📋 前端需要提供给后端的文件: + +1. **镜像文件**(必需) + ``` + deotaland-frontend-v1.0.0.tar + ``` + +2. **docker-compose 配置文件**(必需) + ``` + docker-compose.prod.yml + ``` + +3. **部署文档**(推荐) + ``` + DEPLOYMENT_GUIDE.md (本文档) + ``` + +4. **版本信息**(推荐) + ``` + version.txt - 包含版本号和构建时间 + ``` + +--- + +## 🔧 常用命令速查 + +### 前端构建命令 +```bash +# 构建镜像 +docker build -t deotaland-frontend:v1.0.0 . + +# 导出镜像 +docker save -o deotaland-frontend-v1.0.0.tar deotaland-frontend:v1.0.0 + +# 压缩文件 +gzip deotaland-frontend-v1.0.0.tar +``` + +### 后端部署命令 +```bash +# 导入镜像 +docker load -i deotaland-frontend-v1.0.0.tar + +# 启动服务 +docker-compose -f docker-compose.prod.yml up -d + +# 查看状态 +docker-compose ps + +# 查看日志 +docker-compose logs -f + +# 停止服务 +docker-compose down + +# 重启服务 +docker-compose restart +``` + +--- + +## 🚨 常见问题解决 + +### 问题 1:镜像文件太大 +**解决方案:** +- 使用 `.dockerignore` 文件排除不需要的文件 +- 使用多阶段构建优化镜像大小 +- 考虑使用镜像仓库代替文件传输 + +### 问题 2:上传速度慢 +**解决方案:** +- 使用压缩工具(gzip/7zip) +- 分批上传或使用云存储中转 +- 优化网络环境 + +### 问题 3:容器启动失败 +**排查步骤:** +```bash +# 1. 查看容器状态 +docker ps -a + +# 2. 查看错误日志 +docker logs + +# 3. 检查端口占用 +netstat -tlnp | grep 3000 + +# 4. 检查资源使用 +docker stats +``` + +### 问题 4:服务无法访问 +**排查步骤:** +```bash +# 1. 检查容器是否运行 +docker ps + +# 2. 测试容器内服务 +docker exec curl http://localhost:3000 + +# 3. 检查防火墙设置 +sudo ufw status # Ubuntu +sudo firewall-cmd --list-all # CentOS + +# 4. 检查云服务器安全组设置 +``` + +--- + +## 📊 性能优化建议 + +### 镜像优化 +- 使用 Alpine Linux 基础镜像 +- 实施多阶段构建 +- 清理构建缓存 + +### 部署优化 +- 使用镜像仓库(Docker Registry) +- 实施蓝绿部署 +- 配置健康检查 + +### 监控建议 +- 设置容器资源限制 +- 配置日志收集 +- 实施监控告警 + +--- + +## 🎯 下一步建议 + +1. **建立 CI/CD 流程**:自动化构建和部署 +2. **使用镜像仓库**:替代文件传输 +3. **配置域名和 SSL**:提供 HTTPS 访问 +4. **设置监控告警**:及时发现问题 +5. **实施自动扩容**:应对流量高峰 + +--- + +## 📞 支持联系方式 + +- **前端开发支持**:前端团队 +- **后端运维支持**:运维团队 +- **紧急问题**:电话/微信 XXX-XXXX-XXXX + +--- + +**最后更新时间**:2025年1月21日 +**文档版本**:v1.0 +**适用范围**:前端 Docker 镜像部署到后端服务器 \ No newline at end of file diff --git a/apps/frontend/DOCKER_BUILD_STEPS.md b/apps/frontend/DOCKER_BUILD_STEPS.md new file mode 100644 index 0000000..7cd55e8 --- /dev/null +++ b/apps/frontend/DOCKER_BUILD_STEPS.md @@ -0,0 +1,205 @@ +# Docker 本地镜像构建步骤指南 + +## 概述 +本文档详细记录了在本地构建前端应用Docker镜像的完整步骤,包括问题排查和解决方案。 + +## 环境要求 +- Docker Desktop 已安装并运行 +- 项目目录:`d:\work\Aiproject\DeotalandAi\apps\frontend` + +## 构建步骤 + +### 1. 初始构建尝试 + +#### 1.1 执行构建命令 +```bash +cd d:\work\Aiproject\DeotalandAi\apps\frontend +docker build -t deotaland-frontend . +``` + +#### 1.2 遇到的第一个问题 +**错误信息:** +``` +ERROR: pull access denied, repository does not exist or may require authorization +``` + +**问题原因:** 原Dockerfile使用了阿里云镜像源 `registry.cn-hangzhou.aliyuncs.com/library/node:18-alpine`,但该镜像源无法访问。 + +**解决方案:** 修改为使用官方Docker Hub镜像源。 + +### 2. Dockerfile修改 + +#### 2.1 修改基础镜像 +将: +```dockerfile +FROM registry.cn-hangzhou.aliyuncs.com/library/node:18-alpine +``` +修改为: +```dockerfile +FROM node:20-alpine +``` + +#### 2.2 调整依赖安装策略 +将: +```dockerfile +RUN npm ci --only=production +``` +修改为: +```dockerfile +RUN npm ci +``` + +**原因:** 需要安装开发依赖(如vite)来构建项目。 + +#### 2.3 升级Node.js版本 +从Node.js 18升级到20,解决Vite版本兼容性问题: +```dockerfile +FROM node:18-alpine # 旧版本 +FROM node:20-alpine # 新版本 +``` + +### 3. 最终Dockerfile配置 + +```dockerfile +# 使用官方Node.js镜像 +FROM node:20-alpine + +# 设置工作目录 +WORKDIR /app + +# 复制 package.json 和 package-lock.json +COPY package*.json ./ + +# 使用国内npm镜像源 +RUN npm config set registry https://registry.npmmirror.com/ + +# 复制项目文件 +COPY . . + +# 安装所有依赖(包括开发依赖) +RUN npm ci + +# 构建生产版本 +RUN npm run build + +# 安装 serve 来提供静态文件服务 +RUN npm install -g serve + +# 暴露端口 +EXPOSE 3000 + +# 启动命令 +CMD ["serve", "-s", "dist", "-l", "3000"] +``` + +### 4. 成功构建 + +#### 4.1 执行构建 +```bash +docker build -t deotaland-frontend . +``` + +#### 4.2 构建输出 +``` + => [internal] load build definition from Dockerfile + => [internal] load .dockerignore + => [internal] load metadata for docker.io/library/node:20-alpine + => [1/8] FROM docker.io/library/node:20-alpine + => [2/8] WORKDIR /app + => [3/8] COPY package*.json ./ + => [4/8] RUN npm config set registry https://registry.npmmirror.com/ + => [5/8] COPY . . + => [6/8] RUN npm ci + => [7/8] RUN npm run build + => [8/8] RUN npm install -g serve + => exporting to image + => => exporting layers + => => writing image sha256:... + => => naming to docker.io/library/deotaland-frontend:latest +``` + +### 5. 运行容器 + +#### 5.1 启动容器 +```bash +docker run -d -p 3001:3000 --name deotaland-frontend-container deotaland-frontend +``` + +#### 5.2 验证运行状态 +```bash +docker ps +``` + +#### 5.3 查看容器日志 +```bash +docker logs deotaland-frontend-container +``` + +**预期输出:** +``` +INFO Accepting connections at http://localhost:3000 +``` + +### 6. 访问应用 + +应用运行在:http://localhost:3001 + +## 常见问题及解决方案 + +### 6.1 端口冲突 +**问题:** 端口3000已被占用 +**解决方案:** 使用不同的主机端口映射,如3001:3000 + +### 6.2 容器名称冲突 +**问题:** 容器名称已存在 +**解决方案:** +```bash +docker rm deotaland-frontend-container +``` + +### 6.3 构建失败 +**问题:** vite命令未找到 +**解决方案:** 确保安装了所有依赖,不要使用`--only=production` + +### 6.4 Node.js版本不兼容 +**问题:** Vite需要Node.js 20.19+或22.12+ +**解决方案:** 升级到Node.js 20 + +## 最佳实践 + +### 7.1 镜像优化建议 +- 使用多阶段构建减少镜像大小 +- 合理利用缓存层 +- 使用`.dockerignore`文件排除不必要的文件 + +### 7.2 安全建议 +- 使用非root用户运行应用 +- 定期更新基础镜像 +- 扫描镜像漏洞 + +### 7.3 性能优化 +- 使用国内npm镜像源加速构建 +- 合理设置工作目录 +- 优化文件复制顺序 + +## 后续步骤 + +1. 配置CI/CD流水线自动构建 +2. 设置镜像仓库推送 +3. 配置生产环境部署 +4. 设置监控和日志收集 + +## 相关文件 + +- `Dockerfile` - Docker镜像构建配置 +- `.dockerignore` - Docker构建忽略文件 +- `package.json` - 项目依赖配置 +- `docker-compose.yml` - Docker Compose配置(如存在) + +--- + +**构建完成时间:** $(date) +**构建状态:** ✅ 成功 +**镜像名称:** deotaland-frontend +**容器名称:** deotaland-frontend-container +**访问地址:** http://localhost:3001 \ No newline at end of file diff --git a/apps/frontend/Dockerfile b/apps/frontend/Dockerfile new file mode 100644 index 0000000..c0fc700 --- /dev/null +++ b/apps/frontend/Dockerfile @@ -0,0 +1,29 @@ +# 使用官方Node.js镜像 +FROM node:20-alpine + +# 设置工作目录 +WORKDIR /app + +# 复制 package.json 和 package-lock.json +COPY package*.json ./ + +# 使用国内npm镜像源 +RUN npm config set registry https://registry.npmmirror.com/ + +# 复制项目文件 +COPY . . + +# 安装所有依赖(包括开发依赖) +RUN npm ci + +# 构建生产版本 +RUN npm run build + +# 安装 serve 来提供静态文件服务 +RUN npm install -g serve + +# 暴露端口 +EXPOSE 3000 + +# 启动命令 +CMD ["serve", "-s", "dist", "-l", "3000"] \ No newline at end of file diff --git a/apps/frontend/VERCEL-README.md b/apps/frontend/VERCEL-README.md deleted file mode 100644 index 7b650cf..0000000 --- a/apps/frontend/VERCEL-README.md +++ /dev/null @@ -1,55 +0,0 @@ -# Vercel 部署说明 🚀 - -## 快速开始 - -本项目已配置为可直接部署到 Vercel。以下是快速部署步骤: - -### 1. 推送代码到 Git 仓库 -```bash -git add . -git commit -m "准备部署到 Vercel" -git push origin main -``` - -### 2. 在 Vercel 中导入项目 -1. 访问 [vercel.com](https://vercel.com) -2. 点击 "New Project" -3. 选择你的 Git 仓库 -4. 选择 `frontend` 作为根目录 -5. 点击 "Deploy" - -### 3. 配置环境变量 -在 Vercel 项目设置中添加以下环境变量: - -``` -VITE_GOOGLE_API_KEY=你的_Google_AI_API_密钥 -VITE_APP_BASE_API=你的_API_地址 -VITE_STRIPE_PUBLISHABLE_KEY=你的_Stripe_公钥 -NODE_ENV=production -``` - -## 重要文件说明 - -- `vercel.json` - Vercel 部署配置文件 -- `vite.config.js` - 优化的 Vite 配置(包含 Vercel 特定设置) -- `.env.example` - 环境变量示例 -- `docs/vercel-deployment-guide.md` - 完整部署指南 -- `docs/environment-setup.md` - 环境变量详细说明 - -## 立即部署 - -想要现在就开始?运行以下命令: - -```bash -# 安装 Vercel CLI -npm i -g vercel - -# 登录并部署 -vercel login -cd frontend -vercel --prod -``` - -## 更多详情 - -查看 [完整部署指南](docs/vercel-deployment-guide.md) 获取详细的部署说明和故障排除指南。 \ No newline at end of file diff --git a/apps/frontend/build-package.sh b/apps/frontend/build-package.sh new file mode 100644 index 0000000..a920fc5 --- /dev/null +++ b/apps/frontend/build-package.sh @@ -0,0 +1,64 @@ +#!/bin/bash + +# 前端 Docker 构建打包脚本 +# 这个脚本用于在没有 Docker 环境的本地打包项目,然后上传到服务器构建 + +echo "🚀 开始打包前端项目..." + +# 1. 清理旧的构建文件 +echo "📦 清理旧文件..." +rm -rf dist-build.tar.gz docker-build.tar.gz + +# 2. 构建生产版本 +echo "🔨 构建生产版本..." +npm run build + +# 3. 创建构建目录 +echo "📁 创建构建包..." +mkdir -p build-package + +# 4. 复制必要文件 +echo "📋 复制文件..." +cp Dockerfile build-package/ +cp docker-compose.yml build-package/ +cp package.json build-package/ +cp package-lock.json build-package/ +cp -r dist build-package/ + +# 5. 复制其他必要文件(跳过 node_modules) +cp -r src build-package/ +cp -r public build-package/ +cp index.html build-package/ +cp vite.config.js build-package/ + +# 6. 创建部署脚本 +cat > build-package/deploy.sh << 'EOF' +#!/bin/bash + +# 服务器部署脚本 +echo "🚀 开始部署前端应用..." + +# 安装依赖 +echo "📦 安装依赖..." +npm ci --only=production + +# 构建镜像 +echo "🔨 构建 Docker 镜像..." +docker build -t deotaland-frontend . + +# 运行容器 +echo "🐳 运行容器..." +docker run -d -p 80:3000 --restart=always --name frontend deotaland-frontend + +echo "✅ 部署完成!访问 http://your-server-ip" +EOF + +chmod +x build-package/deploy.sh + +# 7. 打包 +echo "📦 创建压缩包..." +tar -czf docker-build.tar.gz build-package/ + +echo "✅ 打包完成!" +echo "📁 文件:docker-build.tar.gz" +echo "📤 下一步:上传到服务器并解压运行" \ No newline at end of file diff --git a/apps/frontend/deploy-checklist.md b/apps/frontend/deploy-checklist.md new file mode 100644 index 0000000..3528c51 --- /dev/null +++ b/apps/frontend/deploy-checklist.md @@ -0,0 +1,92 @@ +# ✅ 前端 Docker 部署检查清单 + +## 🔧 前端开发者检查项 + +### 构建前检查 +- [ ] 代码已提交到版本控制 +- [ ] 本地构建测试通过 (`npm run build`) +- [ ] 环境变量配置正确 +- [ ] Dockerfile 已更新到最新版本 + +### 构建过程 +- [ ] Docker 镜像构建成功 +- [ ] 本地容器测试通过 +- [ ] 镜像大小合理(< 1GB) +- [ ] 镜像版本号已标记 + +### 导出准备 +- [ ] 镜像导出为 tar 文件 +- [ ] 文件已压缩(节省传输时间) +- [ ] 生成了版本信息文件 +- [ ] 准备了部署文档 + +--- + +## 📋 需要提供给后端的文件 + +### 必需文件 +``` +📦 deotaland-frontend-v{版本号}.tar.gz # 压缩后的镜像文件 +📄 docker-compose.prod.yml # 生产环境配置 +📄 DEPLOYMENT_GUIDE.md # 部署指南 +``` + +### 可选文件 +``` +📄 version.txt # 版本信息 +📄 changelog.md # 更新日志 +📄 rollback-plan.md # 回滚方案 +``` + +--- + +## 🖥️ 后端运维检查项 + +### 环境准备 +- [ ] 服务器资源充足(CPU、内存、磁盘) +- [ ] Docker 和 Docker Compose 已安装 +- [ ] 端口 3000 未被占用 +- [ ] 防火墙配置正确 + +### 部署过程 +- [ ] 镜像文件成功上传到服务器 +- [ ] 镜像导入无错误 +- [ ] 容器启动成功 +- [ ] 健康检查通过 + +### 验证测试 +- [ ] 本地访问测试通过 (`curl localhost:3000`) +- [ ] 外部访问测试通过(如果开放) +- [ ] 日志无错误信息 +- [ ] 性能指标正常 + +--- + +## 🚨 紧急联系方式 + +| 角色 | 姓名 | 联系方式 | 负责内容 | +|------|------|----------|----------| +| 前端开发 | - | - | 构建问题、代码问题 | +| 后端运维 | - | - | 部署问题、服务器问题 | +| 项目负责人 | - | - | 整体协调 | + +--- + +## 📊 部署信息记录 + +### 本次部署信息 +- **部署版本**:v1.0.0 +- **部署时间**:2025-01-21 +- **前端开发者**: +- **后端运维**: +- **镜像大小**: +- **部署结果**:☐ 成功 ☐ 失败 + +### 回滚信息 +- **回滚版本**: +- **回滚原因**: +- **回滚时间**: + +--- + +**✅ 所有检查项完成后,请在相应方框内打勾** \ No newline at end of file diff --git a/apps/frontend/deploy-scripts/build-and-export.bat b/apps/frontend/deploy-scripts/build-and-export.bat new file mode 100644 index 0000000..94cc31d --- /dev/null +++ b/apps/frontend/deploy-scripts/build-and-export.bat @@ -0,0 +1,113 @@ +@echo off +echo 🚀 前端 Docker 镜像构建和导出脚本 +echo ======================================== + +:: 设置变量 +set VERSION=%1 +if "%VERSION%"=="" set VERSION=1.0.0 + +set IMAGE_NAME=deotaland-frontend +set IMAGE_TAG=%IMAGE_NAME%:v%VERSION% +set EXPORT_FILE=%IMAGE_NAME%-v%VERSION%.tar +set COMPRESSED_FILE=%EXPORT_FILE%.gz + +echo 📋 构建信息: +echo 镜像名称:%IMAGE_TAG% +echo 导出文件:%EXPORT_FILE% +echo 压缩文件:%COMPRESSED_FILE% +echo. + +:: 步骤1:构建镜像 +echo 🔨 步骤1:构建 Docker 镜像... +docker build -t %IMAGE_TAG% . + +if %errorlevel% neq 0 ( + echo ❌ 镜像构建失败! + pause + exit /b 1 +) +echo ✅ 镜像构建成功! +echo. + +:: 步骤2:本地测试 +echo 🧪 步骤2:本地测试容器... +docker run -d -p 3001:3000 --name test-frontend %IMAGE_TAG% + +:: 等待5秒让容器启动 +echo ⏳ 等待容器启动... +timeout /t 5 /nobreak > nul + +:: 检查容器状态 +docker ps | findstr test-frontend > nul +if %errorlevel% neq 0 ( + echo ❌ 容器启动失败! + docker logs test-frontend + docker rm -f test-frontend + pause + exit /b 1 +) + +echo ✅ 容器启动成功! +echo. + +:: 步骤3:停止测试容器 +echo 🛑 步骤3:清理测试容器... +docker stop test-frontend +docker rm test-frontend +echo ✅ 测试容器已清理 +echo. + +:: 步骤4:导出镜像 +echo 📦 步骤4:导出镜像... +docker save -o %EXPORT_FILE% %IMAGE_TAG% + +if %errorlevel% neq 0 ( + echo ❌ 镜像导出失败! + pause + exit /b 1 +) +echo ✅ 镜像导出成功! +echo. + +:: 步骤5:压缩文件 +echo 🗜️ 步骤5:压缩镜像文件... +powershell -Command "Compress-Archive -Path '%EXPORT_FILE%' -DestinationPath '%EXPORT_FILE%.zip' -Force" + +if %errorlevel% neq 0 ( + echo ⚠️ 压缩失败,但镜像文件可用 +) else ( + echo ✅ 镜像压缩成功! + + :: 删除原始tar文件 + del %EXPORT_FILE% + echo 🗑️ 已删除原始tar文件 +) +echo. + +:: 步骤6:生成版本信息 +echo 📝 步骤6:生成版本信息... +echo %date% %time% > version-v%VERSION%.txt +echo 镜像:%IMAGE_TAG% >> version-v%VERSION%.txt +echo 版本:v%VERSION% >> version-v%VERSION%.txt +echo ✅ 版本信息已生成 +echo. + +:: 步骤7:显示结果 +echo 🎉 构建完成! +echo ======================================== +echo 📁 输出文件: +if exist %EXPORT_FILE%.zip ( + echo - %EXPORT_FILE%.zip +) else ( + echo - %EXPORT_FILE% +) +echo - version-v%VERSION%.txt +echo. +echo 📊 镜像信息: +docker images %IMAGE_NAME% +echo. +echo 🚀 下一步: +echo 1. 将生成的文件提供给后端运维 +echo 2. 参考 DEPLOYMENT_GUIDE.md 进行部署 +echo. +pause \ No newline at end of file diff --git a/apps/frontend/deploy-scripts/deploy-to-server.sh b/apps/frontend/deploy-scripts/deploy-to-server.sh new file mode 100644 index 0000000..83d358a --- /dev/null +++ b/apps/frontend/deploy-scripts/deploy-to-server.sh @@ -0,0 +1,136 @@ +#!/bin/bash + +# 🚀 前端 Docker 镜像部署脚本(后端运维使用) +# ======================================== + +# 设置变量 +VERSION=${1:-"1.0.0"} +REMOTE_USER=${2:-"deploy"} +REMOTE_HOST=${3:-"192.168.1.100"} +REMOTE_PORT=${4:-"22"} + +LOCAL_IMAGE_FILE="deotaland-frontend-v${VERSION}.tar.gz" +LOCAL_COMPOSE_FILE="docker-compose.prod.yml" +LOCAL_CHECKLIST="deploy-checklist.md" + +REMOTE_DIR="/app/frontend" +IMAGE_NAME="deotaland-frontend:v${VERSION}" + +echo "🚀 前端 Docker 镜像部署脚本" +echo "=======================================" +echo "📋 部署信息:" +echo " 版本: v${VERSION}" +echo " 远程主机: ${REMOTE_USER}@${REMOTE_HOST}:${REMOTE_PORT}" +echo " 远程目录: ${REMOTE_DIR}" +echo " 镜像文件: ${LOCAL_IMAGE_FILE}" +echo "" + +# 检查本地文件 +if [ ! -f "${LOCAL_IMAGE_FILE}" ]; then + echo "❌ 镜像文件 ${LOCAL_IMAGE_FILE} 不存在!" + echo "请先运行 build-and-export.bat 构建镜像" + exit 1 +fi + +if [ ! -f "${LOCAL_COMPOSE_FILE}" ]; then + echo "❌ docker-compose 文件 ${LOCAL_COMPOSE_FILE} 不存在!" + exit 1 +fi + +echo "✅ 本地文件检查通过" +echo "" + +# 步骤1:创建远程目录 +echo "📁 步骤1:创建远程目录..." +ssh -p ${REMOTE_PORT} ${REMOTE_USER}@${REMOTE_HOST} "mkdir -p ${REMOTE_DIR}" + +if [ $? -ne 0 ]; then + echo "❌ 创建远程目录失败!" + exit 1 +fi +echo "✅ 远程目录创建成功" +echo "" + +# 步骤2:上传文件 +echo "📤 步骤2:上传文件到服务器..." +echo "正在上传镜像文件(这可能需要几分钟)..." + +scp -P ${REMOTE_PORT} ${LOCAL_IMAGE_FILE} ${REMOTE_USER}@${REMOTE_HOST}:${REMOTE_DIR}/ +if [ $? -ne 0 ]; then + echo "❌ 镜像文件上传失败!" + exit 1 +fi + +scp -P ${REMOTE_PORT} ${LOCAL_COMPOSE_FILE} ${REMOTE_USER}@${REMOTE_HOST}:${REMOTE_DIR}/docker-compose.yml +if [ $? -ne 0 ]; then + echo "❌ docker-compose 文件上传失败!" + exit 1 +fi + +if [ -f "${LOCAL_CHECKLIST}" ]; then + scp -P ${REMOTE_PORT} ${LOCAL_CHECKLIST} ${REMOTE_USER}@${REMOTE_HOST}:${REMOTE_DIR}/ +fi + +echo "✅ 文件上传成功" +echo "" + +# 步骤3:在服务器上执行部署命令 +echo "🔧 步骤3:在服务器上执行部署..." + +ssh -p ${REMOTE_PORT} ${REMOTE_USER}@${REMOTE_HOST} << EOF +cd ${REMOTE_DIR} + +echo "📦 正在解压镜像文件..." +gunzip -f ${LOCAL_IMAGE_FILE} + +echo "🐳 正在导入 Docker 镜像..." +docker load -i deotaland-frontend-v${VERSION}.tar + +echo "📊 镜像导入成功,当前镜像列表:" +docker images | grep deotaland-frontend + +echo "🛑 停止旧容器(如果存在)..." +docker-compose down || true + +echo "🚀 启动新容器..." +docker-compose up -d + +echo "⏳ 等待容器启动..." +sleep 10 + +echo "🔍 检查容器状态:" +docker-compose ps + +echo "🧪 健康检查:" +curl -f http://localhost:3000 > /dev/null 2>&1 +if [ \$? -eq 0 ]; then + echo "✅ 应用健康检查通过!" +else + echo "⚠️ 应用健康检查失败,请检查日志:" + docker-compose logs --tail=50 +fi + +echo "📊 容器资源使用情况:" +docker stats --no-stream \$(docker-compose ps -q) + +EOF + +if [ $? -ne 0 ]; then + echo "❌ 服务器部署失败!" + exit 1 +fi + +echo "" +echo "🎉 部署完成!" +echo "=======================================" +echo "📊 部署信息:" +echo " 版本: v${VERSION}" +echo " 远程主机: ${REMOTE_USER}@${REMOTE_HOST}" +echo " 访问地址: http://${REMOTE_HOST}:3000" +echo "" +echo "🔍 验证步骤:" +echo "1. 在浏览器访问: http://${REMOTE_HOST}:3000" +echo "2. 检查容器状态: docker-compose ps" +echo "3. 查看日志: docker-compose logs -f" +echo "" +echo "🚀 部署成功!🎉" \ No newline at end of file diff --git a/apps/frontend/docker-compose.prod.yml b/apps/frontend/docker-compose.prod.yml new file mode 100644 index 0000000..c15d76b --- /dev/null +++ b/apps/frontend/docker-compose.prod.yml @@ -0,0 +1,33 @@ +version: '3.8' + +services: + frontend: + image: deotaland-frontend:v1.0.0 # 使用预构建镜像 + ports: + - "3000:3000" + environment: + - NODE_ENV=production + restart: unless-stopped + container_name: deotaland-frontend-prod + + # 生产环境配置 + deploy: + resources: + limits: + memory: 512M + cpus: '0.5' + + # 健康检查 + healthcheck: + test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost:3000"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 40s + + # 日志配置 + logging: + driver: "json-file" + options: + max-size: "10m" + max-file: "3" \ No newline at end of file diff --git a/apps/frontend/docker-compose.yml b/apps/frontend/docker-compose.yml new file mode 100644 index 0000000..c02a2d5 --- /dev/null +++ b/apps/frontend/docker-compose.yml @@ -0,0 +1,9 @@ +services: + frontend: # 服务名称 + build: . # 基于当前目录构建镜像 + ports: # 端口映射 + - "3000:3000" # 主机端口:容器端口 + environment: # 环境变量 + - NODE_ENV=production # 设置Node.js环境为生产环境 + restart: unless-stopped # 自动重启策略 + container_name: deotaland-frontend-compose # 容器名称 \ No newline at end of file diff --git a/apps/frontend/ipconfig.js b/apps/frontend/ipconfig.js index 2c012fb..fe59b34 100644 --- a/apps/frontend/ipconfig.js +++ b/apps/frontend/ipconfig.js @@ -1,2 +1,2 @@ -export const API_BASE_URL = 'https://traebackendzo2n.vercel.app'; -// export const API_BASE_URL = 'http://localhost:3001'; \ No newline at end of file +// export const API_BASE_URL = 'https://traebackendzo2n.vercel.app'; +export const API_BASE_URL = 'http://localhost:3001'; \ No newline at end of file diff --git a/apps/frontend/src/App.vue b/apps/frontend/src/App.vue index 61dfb57..bd3ffed 100644 --- a/apps/frontend/src/App.vue +++ b/apps/frontend/src/App.vue @@ -4,12 +4,9 @@ import { useRouter, useRoute } from 'vue-router' import MainLayout from '@/components/layout/MainLayout.vue' import AppHeader from '@/components/layout/AppHeader.vue' import AppSidebar from '@/components/layout/AppSidebar.vue' - const route = useRoute() - // 判断当前是否为登录页面 const isLoginPage = computed(() => route.path === '/login') - // 判断当前是否为全屏页面 const isFullScreenPage = computed(() => route.meta.fullScreen) diff --git a/apps/frontend/src/assets/step/creatProject/step1.png b/apps/frontend/src/assets/step/creatProject/step1.png new file mode 100644 index 0000000..bac4618 Binary files /dev/null and b/apps/frontend/src/assets/step/creatProject/step1.png differ diff --git a/apps/frontend/src/assets/step/creatProject/step2.png b/apps/frontend/src/assets/step/creatProject/step2.png new file mode 100644 index 0000000..f641f9f Binary files /dev/null and b/apps/frontend/src/assets/step/creatProject/step2.png differ diff --git a/apps/frontend/src/assets/step/creatProject/step3.png b/apps/frontend/src/assets/step/creatProject/step3.png new file mode 100644 index 0000000..91a3921 Binary files /dev/null and b/apps/frontend/src/assets/step/creatProject/step3.png differ diff --git a/apps/frontend/src/assets/step/creatProject/step4.png b/apps/frontend/src/assets/step/creatProject/step4.png new file mode 100644 index 0000000..3b5f1e1 Binary files /dev/null and b/apps/frontend/src/assets/step/creatProject/step4.png differ diff --git a/apps/frontend/src/components/GuideModal/index.vue b/apps/frontend/src/components/GuideModal/index.vue new file mode 100644 index 0000000..2619516 --- /dev/null +++ b/apps/frontend/src/components/GuideModal/index.vue @@ -0,0 +1,469 @@ + + + + + \ No newline at end of file diff --git a/apps/frontend/src/components/HeaderComponent/HeaderComponent.vue b/apps/frontend/src/components/HeaderComponent/HeaderComponent.vue index d2e143c..faec841 100644 --- a/apps/frontend/src/components/HeaderComponent/HeaderComponent.vue +++ b/apps/frontend/src/components/HeaderComponent/HeaderComponent.vue @@ -57,6 +57,12 @@ position="top-right" /> + + - + + \ No newline at end of file diff --git a/apps/frontend/src/components/auth/GoogleOAuthButton.vue b/apps/frontend/src/components/auth/GoogleOAuthButton.vue index 1866878..ebe6d10 100644 --- a/apps/frontend/src/components/auth/GoogleOAuthButton.vue +++ b/apps/frontend/src/components/auth/GoogleOAuthButton.vue @@ -51,42 +51,45 @@ const props = defineProps({ } }) -const authStore = useAuthStore() const isProcessing = ref(false) - +// 动态加载 Google Identity Services 脚本 +const loadGoogleScript = () => { + return new Promise((resolve, reject) => { + if (window.google && window.google.accounts && window.google.accounts.id) { + return resolve() + } + const script = document.createElement('script') + script.src = 'https://accounts.google.com/gsi/client' + script.async = true + script.defer = true + script.onload = () => resolve() + script.onerror = (e) => reject(new Error('Google Identity Services 脚本加载失败')) + document.head.appendChild(script) + }) +} // 处理 Google 登录 const handleGoogleLogin = async () => { - if (isProcessing.value || props.loading) return - + if (isProcessing.value ) return isProcessing.value = true - - try { - // 模拟 Google OAuth 流程 - const mockGoogleUser = { - id: 'google_user_' + Date.now(), - email: 'creator@demo.com', - name: 'Demo Creator', - picture: 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNDAiIGhlaWdodD0iNDAiIHZpZXdCb3g9IjAgMCA0MCA0MCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPGNpcmNsZSBjeD0iMjAiIGN5PSIyMCIgcj0iMjAiIGZpbGw9IiNGMkY0RjgiLz4KPHN2ZyB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4PSI4IiB5PSI4Ij4KPHBhdGggZD0iTTEyIDJDNi40OCAyIDIgNi40OCAyIDEyUzYuNDggMjIgMTIgMjJTMjIgMTcuNTIgMjIgMTJTMTcuNTIgMiAxMiAyWk0xMiA3QzkuMjQgNyA3IDkuMjQgNyAxMlM5LjI0IDE3IDEyIDE3UzE3IDE0Ljc2IDE3IDEyUzE0Ljc2IDcgMTIgN1pNMTIgMTZDMTAuMzQgMTYgOSAxNC42NiA5IDEzUzEwLjM0IDEwIDEyIDEwUzE1IDExLjM0IDE1IDEzUzEzLjY2IDE2IDEyIDE2WiIgZmlsbD0iIzQyODVGNCIvPgo8L3N2Zz4KPC9zdmc+' + await loadGoogleScript() + const clientId = '680509991778-f5qgqbampabs1atblvm1jkoi4itl1nni.apps.googleusercontent.com' + const callback = async (response) => { + const idToken = response && response.credential + if (!idToken) { + errorMessage.value = '未获取到 Google 身份凭证' + return + } + console.log(idToken,'idTokenidToken'); } - - // 调用认证 store 的 Google 登录方法 - const result = await authStore.loginWithGoogle(mockGoogleUser) - - if (result.success) { - - emit('success', result.user) - } else { - - emit('error', result.error) - } - } catch (error) { - const errorMessage = error.message || t('login.google_login_processing_error') - emit('error', errorMessage) - } finally { - isProcessing.value = false - } + console.log('window.google'); + // 初始化并触发 One Tap 或弹出 + window.google.accounts.id.initialize({ client_id: clientId, callback }) + // 尝试弹出一键登录(如果浏览器允许) + window.google.accounts.id.prompt() } - +onMounted(() => { + loadGoogleScript() +}) // 注意:在实际项目中,这里需要集成真实的 Google OAuth SDK // 例如使用 @google-cloud/local-auth 或类似库 // 真实的实现需要: diff --git a/apps/frontend/src/components/auth/LoginForm.vue b/apps/frontend/src/components/auth/LoginForm.vue index 619bcb1..abb5b00 100644 --- a/apps/frontend/src/components/auth/LoginForm.vue +++ b/apps/frontend/src/components/auth/LoginForm.vue @@ -75,24 +75,18 @@ diff --git a/apps/frontend/src/components/auth/RegisterForm.vue b/apps/frontend/src/components/auth/RegisterForm.vue index 2dd5188..c0d69f3 100644 --- a/apps/frontend/src/components/auth/RegisterForm.vue +++ b/apps/frontend/src/components/auth/RegisterForm.vue @@ -51,7 +51,6 @@
{{ passwordError }}
-
diff --git a/apps/frontend/src/components/layout/AppHeader.vue b/apps/frontend/src/components/layout/AppHeader.vue index 175b3a4..d4a9bf1 100644 --- a/apps/frontend/src/components/layout/AppHeader.vue +++ b/apps/frontend/src/components/layout/AppHeader.vue @@ -470,7 +470,10 @@ export default { .brand-name { font-size: 20px; font-weight: 700; - color: var(--text-primary, #1f2937); + background: linear-gradient(135deg, #6B46C1 0%, #A78BFA 100%); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + background-clip: text; letter-spacing: -0.025em; } diff --git a/apps/frontend/src/components/layout/AppSidebar.vue b/apps/frontend/src/components/layout/AppSidebar.vue index 0b394d4..aa5d718 100644 --- a/apps/frontend/src/components/layout/AppSidebar.vue +++ b/apps/frontend/src/components/layout/AppSidebar.vue @@ -141,7 +141,7 @@ export default { { id: 'agent-management', path: '/agent-management', - label: t('sidebar.agentManagement'), + label: t('sidebar.agentManagement.title'), icon: 'BrainIcon', badge: null }, @@ -152,13 +152,13 @@ export default { icon: 'OrdersIcon', badge: null }, - { - id: 'device-settings', - path: '/device-settings', - label: t('sidebar.deviceSettings'), - icon: 'SettingsIcon', - badge: null - } + // { + // id: 'device-settings', + // path: '/device-settings', + // label: t('sidebar.deviceSettings'), + // icon: 'SettingsIcon', + // badge: null + // } ]) // 判断当前路由是否激活 diff --git a/apps/frontend/src/locales/index.js b/apps/frontend/src/locales/index.js index ede65a7..0ca798f 100644 --- a/apps/frontend/src/locales/index.js +++ b/apps/frontend/src/locales/index.js @@ -44,7 +44,122 @@ export default { creationWorkspace: '项目', projectGallery: '画廊', deviceSettings: '设置', - agentManagement: '智能体' + agentManagement: { + title: '智能体', + description: '管理和配置您的AI智能体', + createAgent: '创建智能体', + createTitle: '创建智能体', + name: '智能体名称', + namePlaceholder: '请输入智能体名称', + nameRequired: '请输入智能体名称', + modelPlaceholder: '请选择语言模型', + filters: { + status: '状态筛选', + search: '搜索智能体', + sort: '排序方式', + category: '分类筛选' + }, + searchPlaceholder: '搜索智能体名称、描述...', + stats: { + totalAgents: '智能体总数', + online: '在线', + offline: '离线', + totalConversations: '总对话数' + }, + agentsList: '智能体列表', + actions: { + view: '查看详情', + edit: '编辑', + delete: '删除', + configure: '配置', + more: '更多操作', + connect: '连接设备', + test: '测试对话' + }, + empty: { + title: '暂无智能体', + description: '您还没有创建任何智能体', + action: '创建智能体' + }, + status: { + all: '全部', + active: '活跃', + inactive: '未激活', + maintenance: '维护中' + }, + sort: { + name: '名称', + createdAt: '创建时间', + lastActive: '最后活跃', + status: '状态' + }, + category: { + all: '全部分类', + assistant: '助手', + customerService: '客服', + content: '内容', + education: '教育', + business: '商业' + }, + form: { + name: '智能体名称', + description: '描述', + category: '分类', + model: '模型', + prompt: '系统提示', + temperature: '温度', + maxTokens: '最大令牌数', + status: '状态', + active: '激活', + inactive: '未激活' + }, + dialog: { + createTitle: '创建智能体', + editTitle: '编辑智能体', + deviceBindTitle: '绑定设备' + } + } + }, + modelModal: { + customizeToHome: '定制到家' + }, + orderProcess: { + title: '定制到家流程', + subtitle: '了解您的订单从支付到发货的全过程', + note: '注意:以上时间为工作日计算,节假日可能会顺延。如有问题,请联系客服:13121765685', + acknowledge: '我已知晓', + steps: { + payment: { + title: '支付订单', + description: '选择支付方式完成订单支付,支付成功后订单将进入审核状态。', + time: '即时处理' + }, + review: { + title: '订单审核', + description: '后台将审核订单对应的模型是否可以制作,审核通过后进入排期生产,审核不通过将自动退款。', + time: '1-2个工作日' + }, + scheduling: { + title: '生产排期', + description: '审核通过后,订单将进入生产排期队列,等待生产开始。', + time: '1个工作日' + }, + production: { + title: '模型制作', + description: '专业团队使用高精度3D打印机制作您的定制模型,确保每个细节都完美呈现。', + time: '7-10个工作日' + }, + inspection: { + title: '产品检测包装', + description: '模型制作完成后,将进行产品质量检测和零件整理包装,确保产品完好无损。', + time: '1个工作日' + }, + shipping: { + title: '物流发货', + description: '包装完成后将通过顺丰速运发货,您将收到包含跟踪号码的邮件通知。', + time: '1-3个工作日' + } + } }, header: { searchPlaceholder: '搜索功能、内容或帮助...', @@ -69,7 +184,7 @@ export default { description: '统一设计、国际化与性能优化已集成。', floatingCards: { orders: '订单', - settings: '设置', + settings: '智能体', gallery: '画廊' }, welcome: { @@ -99,7 +214,23 @@ export default { analyticsDesc: '查看创作数据统计和趋势分析', templates: '模板库', templatesDesc: '使用专业模板快速开始创作', - tryNow: '立即体验' + tryNow: '立即体验', + create: { + title: '智能创作', + desc: 'AI驱动的创意内容生成平台' + }, + orders: { + title: '订单管理', + desc: '查看和管理您的所有订单' + }, + settings: { + title: '系统设置', + desc: '个性化配置您的创作环境' + }, + gallery: { + title: '作品画廊', + desc: '浏览和分享您的创意作品' + } }, recentActivity: { title: '最近活动', @@ -668,7 +799,9 @@ export default { no_account: '还没有账号?', register_now: '立即注册', theme_toggle_tooltip: '切换到深色主题', - language_toggle_tooltip: '切换到英文' + language_toggle_tooltip: '切换到英文', + email_label: '邮箱地址', + email_placeholder: '请输入邮箱地址', }, register: { title: '创建账号', @@ -676,8 +809,34 @@ export default { back_to_login: '返回登录', has_account: '已有账号?', login_now: '立即登录', + no_account: '还没有账号?', + register_now: '立即注册', theme_toggle_tooltip: '切换到深色主题', - language_toggle_tooltip: '切换到英文' + language_toggle_tooltip: '切换到英文', + email_label: '邮箱地址', + email_placeholder: '请输入邮箱地址', + password_label: '密码', + password_placeholder: '请输入密码', + confirm_password_label: '确认密码', + confirm_password_placeholder: '请确认密码', + username_label: '用户名', + username_placeholder: '请输入用户名', + register_button: '注册', + registering: '注册中...', + terms_agreement: '注册即表示您同意我们的', + terms_link: '服务条款', + and: '和', + privacy_link: '隐私政策', + email_empty_error: '请输入邮箱地址', + email_invalid_error: '请输入有效的邮箱地址', + password_empty_error: '请输入密码', + password_min_error: '密码至少需要6个字符', + password_strength_error: '密码必须包含字母和数字', + confirm_password_empty_error: '请确认密码', + password_mismatch_error: '两次输入的密码不一致', + username_min_error: '用户名至少需要3个字符', + username_invalid_error: '用户名只能包含字母、数字和下划线', + register_processing_error: '注册过程中发生错误' }, common: { close: '关闭', @@ -706,7 +865,41 @@ export default { login: 'Login', register: 'Register', forgotPassword: 'Forgot Password', - modelPurchase: 'Model Purchase' + modelPurchase: { + inputLabel: 'Please fill in the model link or ID', + inputPlaceholder: 'https://studio.tripo3d.ai/workspace/generate?project=... or Model ID', + timeline: { + title: 'Order Status', + orderPlaced: 'Order Placed', + orderShipped: 'Order Shipped', + delivered: 'Delivered', + hint: 'Shipping information will be sent via email, you can check order status anytime' + } + } + }, + forgotPassword: { + title: 'Reset Password', + subtitle: 'Enter your email address and we will send you a password reset link', + back_to_login: 'Back to Login', + remember_password: 'Remember your password?', + login_now: 'Login Now', + no_account: 'No account yet?', + register_now: 'Register Now', + theme_toggle_tooltip: 'Switch to dark theme', + language_toggle_tooltip: 'Switch to Chinese', + email_label: 'Email Address', + email_placeholder: 'Enter your email', + email_empty_error: 'Please enter email address', + email_invalid_error: 'Please enter a valid email address', + send_reset_email: 'Send Reset Email', + sending: 'Sending...', + email_sent_title: 'Email Sent Successfully', + email_sent_description: 'We have sent a password reset link to your email, please check your inbox', + email_not_received: "Haven't received the email?", + resend_after: 'Resend after', + resend_email: 'Resend Email', + reset_processing_error: 'An error occurred during password reset processing', + resend_processing_error: 'An error occurred during email resending processing' }, sidebar: { dashboard: 'Dashboard', @@ -735,6 +928,7 @@ export default { createAgent: 'Create Agent', createTitle: 'Create Agent', name: 'Agent Name', + namePlaceholder: 'Enter agent name', filters: { status: 'Status Filter', search: 'Search Agents', @@ -803,6 +997,47 @@ export default { }, deviceSettings: 'Settings' }, + modelModal: { + customizeToHome: 'Customize to Home' + }, + orderProcess: { + title: 'Customize to Home Process', + subtitle: 'Understand the complete process from payment to delivery', + note: 'Note: The above times are calculated in working days. Holidays may cause delays. If you have any questions, please contact customer service: 13121765685', + acknowledge: 'I Acknowledge', + steps: { + payment: { + title: 'Payment', + description: 'Select a payment method to complete your order. After successful payment, the order will enter the review status.', + time: 'Instant processing' + }, + review: { + title: 'Order Review', + description: 'Our team will review whether the model corresponding to your order can be produced. If approved, it will enter production scheduling; if rejected, the order will be automatically refunded.', + time: '1-2 business days' + }, + scheduling: { + title: 'Production Scheduling', + description: 'After approval, your order will enter the production queue and wait for production to begin.', + time: '1 business day' + }, + production: { + title: 'Model Creation', + description: 'Our professional team will use high-precision 3D printers to create your custom model, ensuring every detail is perfectly presented.', + time: '7-10 business days' + }, + inspection: { + title: 'Product Inspection & Packaging', + description: 'After the model is completed, we will conduct product quality inspection and parts packaging to ensure the product is intact.', + time: '1 business day' + }, + shipping: { + title: 'Shipping', + description: 'Once packaged, your order will be shipped via SF Express. You will receive an email notification with a tracking number.', + time: '1-3 business days' + } + } + }, header: { searchPlaceholder: 'Search features, content or help...', notifications: 'Notifications', @@ -826,7 +1061,7 @@ export default { description: 'Design system, i18n, and performance optimizations integrated.', floatingCards: { orders: 'Orders', - settings: 'Settings', + settings: 'Agent', gallery: 'Gallery' }, welcome: { @@ -856,7 +1091,23 @@ export default { analyticsDesc: 'View creation data statistics and trend analysis', templates: 'Templates', templatesDesc: 'Start creating quickly with professional templates', - tryNow: 'Try Now' + tryNow: 'Try Now', + create: { + title: 'Smart Creation', + desc: 'AI-powered creative content generation platform' + }, + orders: { + title: 'Order Management', + desc: 'View and manage all your orders' + }, + settings: { + title: 'System Settings', + desc: 'Personalize your creative environment' + }, + gallery: { + title: 'Gallery', + desc: 'Browse and share your creative works' + } }, recentActivity: { title: 'Recent Activity', @@ -1078,6 +1329,41 @@ export default { theme_toggle_light: 'Switch to light theme', theme_toggle_dark: 'Switch to dark theme', }, + register: { + title: 'Create Account', + subtitle: 'Join us and start your creative journey', + back_to_login: 'Back to Login', + has_account: 'Already have an account?', + login_now: 'Login Now', + no_account: 'No account yet?', + register_now: 'Register Now', + theme_toggle_tooltip: 'Switch to dark theme', + language_toggle_tooltip: 'Switch to Chinese', + email_label: 'Email Address', + email_placeholder: 'Enter your email', + password_label: 'Password', + password_placeholder: 'Enter your password', + confirm_password_label: 'Confirm Password', + confirm_password_placeholder: 'Confirm your password', + username_label: 'Username', + username_placeholder: 'Enter your username', + register_button: 'Register', + registering: 'Registering...', + terms_agreement: 'By registering, you agree to our ', + terms_link: 'Terms of Service', + and: ' and ', + privacy_link: 'Privacy Policy', + email_empty_error: 'Please enter email address', + email_invalid_error: 'Please enter a valid email address', + password_empty_error: 'Please enter password', + password_min_error: 'Password must be at least 6 characters', + password_strength_error: 'Password must contain letters and numbers', + confirm_password_empty_error: 'Please confirm your password', + password_mismatch_error: 'Passwords do not match', + username_min_error: 'Username must be at least 3 characters', + username_invalid_error: 'Username can only contain letters, numbers and underscores', + register_processing_error: 'An error occurred during registration processing' + }, payment: { title: 'Pay Order', orderId: 'Order ID', diff --git a/apps/frontend/src/router/index.js b/apps/frontend/src/router/index.js index 3f12a30..db831d0 100644 --- a/apps/frontend/src/router/index.js +++ b/apps/frontend/src/router/index.js @@ -3,7 +3,7 @@ import { useAuthStore } from '@/stores/auth' const ModernHome = () => import('../views/ModernHome.vue') const List = () => import('../views/List.vue') -const Login = () => import('../views/Login.vue') +const Login = () => import('../views/Login/Login.vue') const Register = () => import('../views/Register.vue') const ForgotPassword = () => import('../views/ForgotPassword.vue') const CreationWorkspace = () => import('../views/CreationWorkspace.vue') @@ -120,11 +120,10 @@ const router = createRouter({ // 路由守卫 router.beforeEach(async (to, from, next) => { + next() + return const authStore = useAuthStore() - // 获取当前用户状态 - authStore.initAuth() - const isAuthenticated = authStore.isAuthenticated const currentUser = authStore.user diff --git a/apps/frontend/src/stores/auth.js b/apps/frontend/src/stores/auth.js index 36aedb4..22a885e 100644 --- a/apps/frontend/src/stores/auth.js +++ b/apps/frontend/src/stores/auth.js @@ -1,248 +1,61 @@ import { defineStore } from 'pinia' import { ref, computed } from 'vue' -import { jwtVerify } from 'jose' - -// 用户角色标识定义 -export const USER_ROLES = { - CREATOR: 'creator', - ADMIN: 'admin', - VIEWER: 'viewer' -} - -// 角色标识显示名称 -export const ROLE_LABELS = { - [USER_ROLES.CREATOR]: '创作者', - [USER_ROLES.ADMIN]: '管理员', - [USER_ROLES.VIEWER]: '观察者' -} - +import { request } from '../utils/request' export const useAuthStore = defineStore('auth', () => { // 状态定义 const user = ref(null) const token = ref('') const loading = ref(false) - const error = ref(null) - - // 计算属性 - const isAuthenticated = computed(() => !!token.value && !!user.value) - - const userRole = computed(() => user.value?.role || null) - - const isCreator = computed(() => userRole.value === USER_ROLES.CREATOR) - const isAdmin = computed(() => userRole.value === USER_ROLES.ADMIN) - const isViewer = computed(() => userRole.value === USER_ROLES.VIEWER) - - const hasRole = computed(() => (role) => { - return userRole.value === role - }) - - // 角色权限检查(简化版本 - 仅检查角色标识) - const checkPermission = (requiredRole) => { - if (!isAuthenticated.value) return false - - const roleHierarchy = { - [USER_ROLES.CREATOR]: 3, - [USER_ROLES.ADMIN]: 2, - [USER_ROLES.VIEWER]: 1 - } - - const userLevel = roleHierarchy[userRole.value] || 0 - const requiredLevel = roleHierarchy[requiredRole] || 0 - - return userLevel >= requiredLevel - } - // 登录方法 - const login = async (credentials) => { + const login = async (data) => { loading.value = true - error.value = null - try { - // 模拟登录逻辑 - // 实际项目中这里会调用后端API - const response = await mockLogin(credentials) - - user.value = response.user - token.value = response.token - - // 保存到localStorage - localStorage.setItem('auth_user', JSON.stringify(response.user)) - localStorage.setItem('auth_token', response.token) - - return { success: true } - } catch (err) { - error.value = err.message || '登录失败' - return { success: false, error: error.value } - } finally { - loading.value = false - } - } - - // Google OAuth登录 - const loginWithGoogle = async (googleUser) => { - loading.value = true - error.value = null - - try { - // 验证Google token(实际项目中需要后端验证) - const response = await mockGoogleLogin(googleUser) - - user.value = response.user - token.value = response.token - - // 保存到localStorage - localStorage.setItem('auth_user', JSON.stringify(response.user)) - localStorage.setItem('auth_token', response.token) - - return { success: true } - } catch (err) { - error.value = err.message || 'Google登录失败' - return { success: false, error: error.value } - } finally { - loading.value = false - } - } - - // 登出方法 - const logout = () => { - user.value = null - token.value = '' - error.value = null - - // 清除localStorage - localStorage.removeItem('auth_user') - localStorage.removeItem('auth_token') - } - - // 初始化认证状态(从localStorage恢复) - const initAuth = () => { - const savedUser = localStorage.getItem('auth_user') - const savedToken = localStorage.getItem('auth_token') - - if (savedUser && savedToken) { - try { - user.value = JSON.parse(savedUser) - token.value = savedToken - - // 验证token有效性(简化版本) - // 实际项目中应该检查token是否过期 - } catch (err) { - // 清除无效的认证信息 - logout() + const res = await request.common(request.url.LOGIN, data) + if(res.code === 200){ + // 登录成功,保存token和用户信息 + token.value = res.data.token + user.value = res.data.user + localStorage.setItem('token', res.data.token) + return res } + return res + } catch (error) { + console.error('登录失败:', error) + throw error + } finally { + loading.value = false } } - - // 角色分配方法 - const assignRole = (role, userInfo = {}) => { - if (!Object.values(USER_ROLES).includes(role)) { - throw new Error('无效的用户角色') + // 登出方法 + const logout = async () => { + loading.value = true + try { + const res = await request.common(request.url.LOGOUT) + if(res.code === 200){ + // 登出成功,清除token和用户信息 + user.value = null + token.value = '' + localStorage.removeItem('token') + return res + } + return res + } catch (error) { + console.error('登出失败:', error) + throw error + } finally { + loading.value = false } - - const userData = { - ...userInfo, - role: role, - roleLabel: ROLE_LABELS[role] - } - - user.value = userData - - // 更新localStorage - localStorage.setItem('auth_user', JSON.stringify(userData)) - - return userData } - // 获取用户信息 const getUserInfo = () => { - if (!user.value) return null - - return { - ...user.value, - roleLabel: ROLE_LABELS[user.value.role] || '未知角色' - } + } - return { - // 状态 - user, - token, - loading, - error, - - // 计算属性 - isAuthenticated, - userRole, - isCreator, - isAdmin, - isViewer, - hasRole, - - // 方法 - login, - loginWithGoogle, - logout, - initAuth, - assignRole, - getUserInfo, - checkPermission + user, + token, + login, + logout, + getUserInfo, + loading } }) - -// 模拟登录函数 -async function mockLogin(credentials) { - // 模拟API延迟 - await new Promise(resolve => setTimeout(resolve, 1000)) - - // 简单验证 - if (!credentials.email || !credentials.password) { - throw new Error('请输入邮箱和密码') - } - - // 模拟用户角色分配(根据邮箱白名单) - let role = USER_ROLES.VIEWER - - if (credentials.email.includes('admin')) { - role = USER_ROLES.ADMIN - } else if (credentials.email.includes('creator')) { - role = USER_ROLES.CREATOR - } - - return { - user: { - id: Date.now(), - email: credentials.email, - name: credentials.email.split('@')[0], - role: role, - roleLabel: ROLE_LABELS[role], - avatar: null, - createdAt: new Date().toISOString() - }, - token: `mock_token_${Date.now()}_${role}`, - expiresAt: Date.now() + 24 * 60 * 60 * 1000 // 24小时后过期 - } -} - -// 模拟Google OAuth登录 -async function mockGoogleLogin(googleUser) { - // 模拟API延迟 - await new Promise(resolve => setTimeout(resolve, 800)) - - // Google OAuth 用户默认分配创作者角色 - const role = USER_ROLES.CREATOR - - return { - user: { - id: googleUser.id || Date.now(), - email: googleUser.email, - name: googleUser.name || googleUser.email.split('@')[0], - role: role, - roleLabel: ROLE_LABELS[role], - avatar: googleUser.picture, - provider: 'google', - createdAt: new Date().toISOString() - }, - token: `google_token_${Date.now()}_${role}`, - expiresAt: Date.now() + 24 * 60 * 60 * 1000 - } -} \ No newline at end of file diff --git a/apps/frontend/src/styles/theme.css b/apps/frontend/src/styles/theme.css index e90616e..4fdc28e 100644 --- a/apps/frontend/src/styles/theme.css +++ b/apps/frontend/src/styles/theme.css @@ -50,14 +50,43 @@ html, body { overflow-x: hidden; } -/* Hide scrollbars globally but keep functionality */ -* { - -ms-overflow-style: none; - scrollbar-width: none; +/* Custom scrollbar styles */ +::-webkit-scrollbar { + width: 8px; + height: 8px; } -*::-webkit-scrollbar { - display: none; +::-webkit-scrollbar-track { + background: transparent; +} + +::-webkit-scrollbar-thumb { + background: rgba(0, 0, 0, 0.2); + border-radius: 4px; + transition: background-color var(--t) var(--e); +} + +::-webkit-scrollbar-thumb:hover { + background: rgba(0, 0, 0, 0.3); +} + +/* Dark theme scrollbar */ +html.dark ::-webkit-scrollbar-thumb { + background: rgba(255, 255, 255, 0.2); +} + +html.dark ::-webkit-scrollbar-thumb:hover { + background: rgba(255, 255, 255, 0.3); +} + +/* Firefox scrollbar */ +* { + scrollbar-width: thin; + scrollbar-color: rgba(0, 0, 0, 0.2) transparent; +} + +html.dark * { + scrollbar-color: rgba(255, 255, 255, 0.2) transparent; } /* Subtle global transitions for key properties */ diff --git a/apps/frontend/src/utils/api/index.js b/apps/frontend/src/utils/api/index.js index e69de29..d9308b6 100644 --- a/apps/frontend/src/utils/api/index.js +++ b/apps/frontend/src/utils/api/index.js @@ -0,0 +1,4 @@ +import login from './login.js'; +export default { + ...login + }; \ No newline at end of file diff --git a/apps/frontend/src/utils/api/login.js b/apps/frontend/src/utils/api/login.js new file mode 100644 index 0000000..632ead6 --- /dev/null +++ b/apps/frontend/src/utils/api/login.js @@ -0,0 +1,9 @@ +const login = { + LOGIN:{url:'/user/login',method:'POST'},// 登录 + LOGOUT:{url:'/user/logout',method:'POST'},// 登出 + REGISTER:{url:'/user/register',method:'POST'},// 注册 + SEND_EMAIL_CODE:{url:'/user/send-email-code',method:'POST'},// 发送邮箱验证码 + OAUTH_GOOGLE:{url:'/user/oauth/google',method:'POST'},// google弹窗授权 + OAUTH_GOOGLE_CODE:{url:'/captcha/code',method:'GET'},// 后台验证码 +} +export default login; diff --git a/apps/frontend/src/utils/request.js b/apps/frontend/src/utils/request.js index f15b451..797cf33 100644 --- a/apps/frontend/src/utils/request.js +++ b/apps/frontend/src/utils/request.js @@ -1,8 +1,8 @@ import axios from 'axios'; - +import URL from './api/index'; // 创建axios实例 const service = axios.create({ - baseURL: import.meta.env.VITE_APP_BASE_API || '/api', // 使用环境变量配置基础URL + baseURL: import.meta.env.VITE_APP_BASE_API, // 使用环境变量配置基础URL timeout: 300000, // 请求超时时间 // 不设置默认的Content-Type,让axios根据数据类型自动设置 }); @@ -80,6 +80,7 @@ service.interceptors.response.use( // 封装请求方法 export const request = { + url:URL, // GET请求 get(url, params = {}) { return service({ @@ -117,12 +118,23 @@ export const request = { params }); }, - + common(plug,data={}){ + const config = { + url:plug.url, + method:plug.method, + params:data + }; + if (plug.method.toLowerCase() === 'get') { + config.params = data; + } else { + config.data = data; + } + return service(config); + }, // 上传文件 upload(url, file, onUploadProgress) { const formData = new FormData(); formData.append('file', file); - return service({ url, method: 'post', @@ -144,5 +156,4 @@ export const request = { }); } }; - export default service; \ No newline at end of file diff --git a/apps/frontend/src/views/CreateProject.vue b/apps/frontend/src/views/CreateProject.vue index 1bf2bf0..a6e9e24 100644 --- a/apps/frontend/src/views/CreateProject.vue +++ b/apps/frontend/src/views/CreateProject.vue @@ -2,7 +2,7 @@
- +
@@ -97,6 +97,14 @@ :url="importUrl" @close="closeImportModal" /> + + +
@@ -110,12 +118,14 @@ import ModelCard from '../components/modelCard/index.vue'; import ModelModal from '../components/ModelModal/index.vue'; import CharacterImportModal from '../components/CharacterImportModal/index.vue'; import HeaderComponent from '../components/HeaderComponent/HeaderComponent.vue'; +import GuideModal from '../components/GuideModal/index.vue'; // 弹窗相关状态 const showModelModal = ref(false); const selectedModel = ref(null); const showImportModal = ref(false); const importUrl = ref('https://xiaozhi.me/console/agents'); +const showGuideModal = ref(false); // 事件监听器清理函数存储 const cleanupFunctions = ref({}); @@ -148,6 +158,16 @@ const closeImportModal = () => { showImportModal.value = false; }; +// 关闭引导弹窗 +const closeGuideModal = () => { + showGuideModal.value = false; +}; + +// 完成引导 +const completeGuide = () => { + showGuideModal.value = false; +}; + // ==================== 层级管理器 ==================== /** * 卡片层级管理系统 @@ -855,6 +875,9 @@ import { addPassiveEventListener } from '@/utils/passiveEventListeners' // 组件挂载时添加事件监听器 onMounted(() => { + // 每次进入都显示引导弹窗 + showGuideModal.value = true; + // 使用优化的被动事件监听器 const removeWheelListener = addPassiveEventListener(document, 'wheel', preventZoom); const removeTouchStartListener = addPassiveEventListener(document, 'touchstart', preventPinchZoom); diff --git a/apps/frontend/src/views/ForgotPassword.vue b/apps/frontend/src/views/ForgotPassword.vue index aa1c310..e4c6842 100644 --- a/apps/frontend/src/views/ForgotPassword.vue +++ b/apps/frontend/src/views/ForgotPassword.vue @@ -118,7 +118,6 @@ const goToRegister = () => { // 页面挂载时初始化认证状态 onMounted(() => { - authStore.initAuth() // 如果已经登录,直接跳转 if (authStore.isAuthenticated) { diff --git a/apps/frontend/src/views/Login.vue b/apps/frontend/src/views/Login/Login.vue similarity index 97% rename from apps/frontend/src/views/Login.vue rename to apps/frontend/src/views/Login/Login.vue index e922b68..38f26a1 100644 --- a/apps/frontend/src/views/Login.vue +++ b/apps/frontend/src/views/Login/Login.vue @@ -16,16 +16,13 @@ />
-