From c5dae2993b0a5547e83855458062f33b4bba1555 Mon Sep 17 00:00:00 2001 From: sexygoat <1538832180@qq.com> Date: Wed, 3 Jun 2026 17:53:19 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E6=8D=A2=E8=B4=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .claude/settings.local.json | 4 +- docs/API对接说明.md | 343 - docs/LOGIN_MODULE.md | 244 - docs/上传到git.md | 9 - docs/代理账号管理.md | 870 --- docs/任务规划.md | 488 -- docs/功能.md | 42 - docs/完成总结.md | 364 - docs/店铺管理.md | 875 --- docs/开发进度.md | 194 - docs/新功能.md | 378 - docs/角色管理修改.md | 72 - docs/部分API.md | 6146 ----------------- docs/页面创建模板.md | 297 - docs/项目完成总结.md | 433 -- .../design.md | 136 + .../proposal.md | 27 + .../specs/exchange-management/spec.md | 199 + .../update-exchange-flow-direct-type/tasks.md | 55 + src/api/modules/exchange.ts | 10 +- .../exchange-management/detail.vue | 116 +- .../exchange-management/index.vue | 297 +- .../package-series/index.vue | 2 +- 23 files changed, 797 insertions(+), 10804 deletions(-) delete mode 100644 docs/API对接说明.md delete mode 100644 docs/LOGIN_MODULE.md delete mode 100644 docs/上传到git.md delete mode 100644 docs/代理账号管理.md delete mode 100644 docs/任务规划.md delete mode 100644 docs/功能.md delete mode 100644 docs/完成总结.md delete mode 100644 docs/店铺管理.md delete mode 100644 docs/开发进度.md delete mode 100644 docs/新功能.md delete mode 100644 docs/角色管理修改.md delete mode 100644 docs/部分API.md delete mode 100644 docs/页面创建模板.md delete mode 100644 docs/项目完成总结.md create mode 100644 openspec/changes/update-exchange-flow-direct-type/design.md create mode 100644 openspec/changes/update-exchange-flow-direct-type/proposal.md create mode 100644 openspec/changes/update-exchange-flow-direct-type/specs/exchange-management/spec.md create mode 100644 openspec/changes/update-exchange-flow-direct-type/tasks.md diff --git a/.claude/settings.local.json b/.claude/settings.local.json index c896730..6c8b89e 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -19,7 +19,9 @@ "Bash(findstr:*)", "Bash(npm run:*)", "Bash(find src/views -name *.vue -type f -exec grep -l \"device.*detail\\\\|设备详情\" {})", - "Bash(2)" + "Bash(2)", + "Bash(grep -E \"\\\\.\\(vue|ts\\)$\")", + "Bash(xargs grep:*)" ], "deny": [], "ask": [] diff --git a/docs/API对接说明.md b/docs/API对接说明.md deleted file mode 100644 index c42e06f..0000000 --- a/docs/API对接说明.md +++ /dev/null @@ -1,343 +0,0 @@ -# API 对接说明 - -> 更新时间: 2026-01-09 - ---- - -## ✅ 已完成的修改 - -### 1. 创建了认证 API 服务 -**文件**: `src/api/authApi.ts` - -```typescript -import { AuthService } from '@/api/authApi' - -// 登录 -AuthService.login({ username, password, remember }) - -// 获取用户信息 -AuthService.getUserInfo() - -// 登出 -AuthService.logout() - -// 刷新Token -AuthService.refreshToken(refreshToken) -``` - -### 2. 修改了登录逻辑 -**文件**: `src/composables/useLogin.ts` - -**关键修改**: -- ✅ 添加了 `USE_MOCK` 开关(第 29 行) -- ✅ 创建了 `handleRealLogin()` 真实API登录函数 -- ✅ 保留了 `handleMockLogin()` Mock登录函数(方便开发测试) - -**切换方式**: -```typescript -// 文件: src/composables/useLogin.ts 第 29 行 - -// 使用 Mock 数据(开发测试) -const USE_MOCK = true - -// 使用真实 API(生产环境) -const USE_MOCK = false // ← 当前设置 -``` - ---- - -## 🔌 API 接口规范 - -### 登录接口 - -**请求地址**: `POST /api/auth/login` - -**请求参数**: -```typescript -{ - username: string // 用户名 - password: string // 密码 - remember?: boolean // 是否记住密码 - captcha?: string // 验证码(可选) -} -``` - -**响应格式**: -```typescript -{ - code: number // 状态码:200 成功 - message: string // 消息 - data: { - token: string // 访问令牌 (必需) - refreshToken?: string // 刷新令牌 (可选) - expiresIn?: number // 过期时间(秒) (可选) - userInfo: { // 用户信息 (推荐返回,避免二次请求) - id: string | number - username: string - realName: string - roles: string[] // 角色列表 ['R_SUPER', 'R_ADMIN', ...] - permissions: string[] // 权限列表 ['*:*:*', 'user:edit', ...] - avatar?: string - email?: string - phone?: string - // ... 其他用户信息 - } - } -} -``` - -### 获取用户信息接口 - -**请求地址**: `GET /api/auth/userInfo` - -**请求头**: -``` -Authorization: Bearer {token} -``` - -**响应格式**: -```typescript -{ - code: 200, - message: 'success', - data: { - id: string | number - username: string - realName: string - roles: string[] - permissions: string[] - avatar?: string - email?: string - phone?: string - } -} -``` - ---- - -## 🔐 权限控制说明 - -### 角色定义 -系统预定义了以下角色(可根据需求调整): - -```typescript -enum UserRole { - SUPER_ADMIN = 'R_SUPER', // 超级管理员 - ADMIN = 'R_ADMIN', // 管理员 - AGENT = 'R_AGENT', // 代理商 - ENTERPRISE = 'R_ENTERPRISE' // 企业客户 -} -``` - -### 权限格式 -权限使用通配符格式:`模块:操作:范围` - -**示例**: -- `*:*:*` - 所有权限 -- `user:*:*` - 用户模块所有权限 -- `user:edit:*` - 用户编辑权限 -- `card:view:own` - 查看自己的卡 - -### 前端权限验证 - -**路由级权限**(在 `asyncRoutes.ts` 中配置): -```typescript -{ - path: '/system/user', - meta: { - roles: ['R_SUPER', 'R_ADMIN'] // 只有超管和管理员可访问 - } -} -``` - -**按钮级权限**(使用 `v-auth` 指令): -```vue -编辑 -``` - ---- - -## 📦 状态码规范 - -**推荐使用的状态码** (已在 `src/utils/http/status.ts` 定义): - -```typescript -export enum ApiStatus { - success = 200, // 成功 - unauthorized = 401, // 未授权 - forbidden = 403, // 禁止访问 - notFound = 404, // 未找到 - serverError = 500 // 服务器错误 -} -``` - ---- - -## 🚀 快速上手 - -### 1. 配置API地址 - -**文件**: `.env.development` - -```env -# API 地址前缀 -VITE_API_URL = http://your-backend-api.com - -# 或者使用代理(推荐) -VITE_API_URL = /api -``` - -**文件**: `vite.config.ts` (如果使用代理) - -```typescript -server: { - proxy: { - '/api': { - target: 'http://your-backend-api.com', // 后端地址 - changeOrigin: true, - rewrite: (path) => path.replace(/^\/api/, '') - } - } -} -``` - -### 2. 切换到真实API - -**文件**: `src/composables/useLogin.ts` 第 29 行 - -```typescript -const USE_MOCK = false // 改为 false -``` - -### 3. 测试登录 - -1. 启动开发服务器:`npm run dev` -2. 访问登录页面:`http://localhost:3006/#/auth/login` -3. 输入后端提供的测试账号密码 -4. 点击登录 - ---- - -## 🔧 调试技巧 - -### 1. 查看请求/响应 - -打开浏览器开发者工具(F12)→ Network 标签,查看: -- 请求URL -- 请求参数 -- 响应数据 -- 状态码 - -### 2. Mock 和真实API切换 - -```typescript -// src/composables/useLogin.ts - -const USE_MOCK = true // 开发时使用 Mock -const USE_MOCK = false // 对接时使用真实 API -``` - -### 3. Token 检查 - -打开浏览器控制台(F12)→ Application → Local Storage → 查看 `user` 键: -```json -{ - "isLogin": true, - "accessToken": "your-token-here", - "info": { ... } -} -``` - -### 4. 请求拦截器日志 - -**文件**: `src/utils/http/interceptors.ts` - -已自动添加请求/响应日志,在控制台可以看到: -- 🚀 发送请求 -- ✅ 请求成功 -- ❌ 请求失败 - ---- - -## ⚠️ 常见问题 - -### Q1: 登录后提示"获取用户角色失败" - -**原因**: 后端返回的用户信息中没有 `roles` 字段 - -**解决**: -1. 确保后端返回的 `userInfo.roles` 是数组 -2. 至少包含一个角色,如:`["R_ADMIN"]` - -### Q2: 登录成功但页面一直转圈 - -**原因**: 路由守卫中没有通过权限验证 - -**解决**: -1. 检查用户信息中是否有 `roles` 字段 -2. 临时开启开发模式跳过权限验证(见下文) - -### Q3: 如何临时跳过权限验证? - -**文件**: `src/router/guards/beforeEach.ts` 第 28 行 - -```typescript -const DEV_MODE_SKIP_AUTH = true // 改为 true,跳过所有权限验证 -``` - -### Q4: Token 过期如何处理? - -系统已自动处理 Token 过期: -1. 检测到 401 状态码自动跳转登录页 -2. 可实现自动刷新 Token(需要后端支持) - ---- - -## 📝 后端接口开发建议 - -### 1. 登录接口返回完整用户信息 -避免前端登录后再次调用获取用户信息接口,减少请求次数。 - -### 2. 用户信息必须包含 roles -```json -{ - "roles": ["R_ADMIN", "R_USER"] // 必须 -} -``` - -### 3. 支持 Token 刷新机制 -```typescript -// 刷新Token接口 -POST /api/auth/refresh -{ - "refreshToken": "refresh-token-here" -} -``` - -### 4. 统一响应格式 -```typescript -{ - code: 200, - message: "success", - data: { ... } -} -``` - ---- - -## ✨ 下一步 - -1. ✅ 后端提供测试环境API地址 -2. ✅ 配置 `VITE_API_URL` 或代理 -3. ✅ 切换 `USE_MOCK = false` -4. ✅ 测试登录功能 -5. ✅ 根据实际API调整请求/响应格式 -6. ✅ 完善其他业务接口 - ---- - -**联系支持**: -- 前端问题:查看本文档或项目 README -- 后端对接:与后端开发人员沟通接口格式 - -祝对接顺利!🚀 diff --git a/docs/LOGIN_MODULE.md b/docs/LOGIN_MODULE.md deleted file mode 100644 index 71e2bcd..0000000 --- a/docs/LOGIN_MODULE.md +++ /dev/null @@ -1,244 +0,0 @@ -# 登录模块说明文档 - -## 概述 - -本项目的登录模块已完成重构,采用了全新的架构设计,提供了完整的认证流程和权限管理功能。 - -## 功能特性 - -### 1. Mock 数据支持 - -系统内置了 4 个 Mock 账号,用于开发和演示: - -| 账号类型 | 用户名 | 密码 | 角色 | 权限说明 | -|---------|--------|------|------|---------| -| 超级管理员 | super | 123456 | SUPER_ADMIN | 拥有所有权限 | -| 平台管理员 | admin | 123456 | ADMIN | 账号、网卡、套餐、设备等管理权限 | -| 代理商 | agent | 123456 | AGENT | 网卡查看/操作、佣金管理等权限 | -| 企业客户 | enterprise | 123456 | ENTERPRISE | 自有网卡和设备的查看/操作权限 | - -**文件位置**: `src/mock/auth.ts` - -### 2. 记住密码功能 - -- 用户可以勾选"记住密码"选项 -- 登录成功后,用户名和密码会被加密存储到 localStorage -- 下次访问登录页时自动填充账号信息 -- 取消勾选会清除已保存的凭证 - -**实现文件**: `src/utils/auth/rememberPassword.ts` - -**核心函数**: -```typescript -// 保存凭证 -saveCredentials(username, password, remember) - -// 获取保存的凭证 -getRememberedCredentials() - -// 清除凭证 -clearRememberedCredentials() -``` - -### 3. 完善的表单验证 - -提供了多种验证规则,适用于不同场景: - -- **用户名验证**: 3-20个字符,只能包含字母、数字和下划线 -- **密码验证**: 6-20个字符 -- **强密码验证**: 8-20个字符,必须包含大小写字母和数字 -- **确认密码验证**: 必须与密码一致 -- **手机号验证**: 支持中国大陆手机号格式 -- **邮箱验证**: 标准邮箱格式验证 -- **验证码验证**: 4位数字 - -**实现文件**: `src/utils/auth/loginValidation.ts` - -**使用示例**: -```typescript -import { usernameRules, passwordRules } from '@/utils/auth/loginValidation' - -const rules = { - username: usernameRules(t), - password: passwordRules(t) -} -``` - -### 4. 权限路由守卫 - -优化了路由守卫,增加了以下功能: - -#### 白名单机制 -不需要登录即可访问的路由: -- `/login` - 登录页 -- `/register` - 注册页 -- `/forget-password` - 忘记密码 -- `/exception/*` - 异常页面 - -**文件位置**: `src/router/guards/permission.ts` - -#### Token 验证 -- 自动检查 Token 是否存在 -- 验证 Token 是否有效 -- Token 过期自动跳转到登录页 - -#### 页面级权限验证 -- 根据路由 meta 中的 `roles` 和 `permissions` 进行验证 -- 无权限访问时自动跳转到 403 页面 -- 支持通配符权限(如 `*:*:*` 表示所有权限) - -#### 登录重定向 -- 访问需要登录的页面时,会记录当前路径 -- 登录成功后自动跳转回之前访问的页面 -- 如果是白名单路由,则跳转到首页 - -**核心函数**: -```typescript -// 检查是否在白名单 -isInWhiteList(path) - -// 检查路由权限 -hasRoutePermission(route, userInfo) - -// 检查 Token 是否有效 -isTokenValid(token) - -// 构建登录重定向URL -buildLoginRedirect(currentPath) -``` - -### 5. useLogin Composable - -将登录逻辑抽取为可复用的 Composable,提高代码可维护性。 - -**文件位置**: `src/composables/useLogin.ts` - -**提供的功能**: -- 表单状态管理 -- Mock 账号切换 -- 登录逻辑处理 -- 自动记住密码 -- 登录成功通知 -- 重定向处理 - -**使用示例**: -```vue - -``` - -## 文件结构 - -``` -src/ -├── mock/ -│ └── auth.ts # Mock 账号数据 -├── utils/auth/ -│ ├── rememberPassword.ts # 记住密码工具 -│ ├── loginValidation.ts # 表单验证规则 -│ └── index.ts # 统一导出 -├── router/guards/ -│ ├── permission.ts # 权限验证工具 -│ ├── beforeEach.ts # 路由前置守卫(已优化) -│ └── afterEach.ts # 路由后置守卫 -├── composables/ -│ └── useLogin.ts # 登录逻辑 Composable -└── views/auth/login/ - └── index.vue # 登录页面(已重构) -``` - -## 权限配置示例 - -### 路由权限配置 - -```typescript -// 在路由配置中添加 meta -{ - path: '/account/platform', - meta: { - title: '平台账号管理', - roles: ['R_SUPER', 'R_ADMIN'], // 允许的角色 - permissions: ['account:view:*'] // 需要的权限 - } -} -``` - -### 用户权限定义 - -```typescript -// 用户信息中包含角色和权限 -{ - roles: ['R_ADMIN'], - permissions: [ - 'account:*:*', // 账号管理所有权限 - 'card:view:*', // 网卡查看权限 - 'card:operation:*' // 网卡操作权限 - ] -} -``` - -## 开发建议 - -### 1. 切换到真实接口 - -当后端接口就绪后,只需修改 `useLogin.ts` 中的登录逻辑: - -```typescript -// 将 Mock 登录替换为真实 API -// const loginResult = mockLogin(formData.username, formData.password) -const loginResult = await AuthService.login({ - username: formData.username, - password: formData.password -}) -``` - -### 2. Token 刷新 - -在 `src/router/guards/permission.ts` 的 `isTokenValid` 函数中添加真实的 JWT 验证逻辑。 - -### 3. 权限粒度 - -根据实际业务需求,可以在以下层级添加权限验证: -- **路由级**: 在路由 meta 中配置 -- **页面级**: 在页面组件中使用 v-if 判断 -- **按钮级**: 使用自定义指令(如 `v-permission`) - -## 常见问题 - -### Q1: 如何添加新的 Mock 账号? - -编辑 `src/mock/auth.ts`,在 `MOCK_ACCOUNTS` 数组中添加新账号即可。 - -### Q2: 记住密码的数据存在哪里? - -存储在浏览器的 localStorage 中,key 为 `remembered_credentials`,数据经过 Base64 编码。 - -### Q3: 如何自定义白名单路由? - -编辑 `src/router/guards/permission.ts` 的 `LOGIN_WHITE_LIST` 数组。 - -### Q4: 为什么登录后还是跳转到登录页? - -检查以下几点: -1. Token 是否正确保存到 store -2. `userStore.isLogin` 是否设置为 true -3. 路由守卫中的权限验证是否通过 - -## 下一步计划 - -- [ ] 添加双因素认证(2FA) -- [ ] 实现 SSO 单点登录 -- [ ] 添加第三方登录(微信、钉钉等) -- [ ] 完善密码强度检测 -- [ ] 添加登录日志记录 diff --git a/docs/上传到git.md b/docs/上传到git.md deleted file mode 100644 index dece6b7..0000000 --- a/docs/上传到git.md +++ /dev/null @@ -1,9 +0,0 @@ -touch README.md -git init -git checkout -b main -git add README.md -git commit -m "first commit" -git remote add origin https://git.boss160.cn/luo/admin-xm-iot.git -git push -u origin main - -你需要注意下.gitignore 是否需要加一些文件进去 diff --git a/docs/代理账号管理.md b/docs/代理账号管理.md deleted file mode 100644 index 9fac1c1..0000000 --- a/docs/代理账号管理.md +++ /dev/null @@ -1,870 +0,0 @@ -# 账号管理下面新增一个代理账号管理, 页面样式可以参考/system/account 都需要token认证 - -# 代理账号列表 - -## OpenAPI Specification - -```yaml -openapi: 3.0.1 -info: - title: '' - description: '' - version: 1.0.0 -paths: - /api/admin/shop-accounts: - get: - summary: 代理账号列表 - deprecated: false - description: '' - tags: - - 代理账号管理 - - 代理账号管理 - parameters: - - name: page - in: query - description: 页码 - required: false - schema: - description: 页码 - minimum: 1 - type: integer - - name: page_size - in: query - description: 每页数量 - required: false - schema: - description: 每页数量 - maximum: 100 - minimum: 1 - type: integer - - name: shop_id - in: query - description: 店铺ID过滤 - required: false - schema: - description: 店铺ID过滤 - minimum: 1 - type: integer - nullable: true - - name: username - in: query - description: 用户名(模糊查询) - required: false - schema: - description: 用户名(模糊查询) - maxLength: 50 - type: string - - name: phone - in: query - description: 手机号(精确查询) - required: false - schema: - description: 手机号(精确查询) - maxLength: 11 - minLength: 11 - type: string - - name: status - in: query - description: 状态 (0:禁用, 1:启用) - required: false - schema: - description: 状态 (0:禁用, 1:启用) - type: integer - nullable: true - responses: - '200': - description: OK - content: - application/json: - schema: - $ref: '#/components/schemas/ModelShopAccountPageResult' - headers: {} - x-apifox-name: '' - '400': - description: 请求参数错误 - content: - application/json: - schema: &ref_0 - $ref: '#/components/schemas/ErrorResponse' - headers: {} - x-apifox-name: '' - '401': - description: 未认证或认证已过期 - content: - application/json: - schema: *ref_0 - headers: {} - x-apifox-name: '' - '403': - description: 无权访问 - content: - application/json: - schema: *ref_0 - headers: {} - x-apifox-name: '' - '500': - description: 服务器内部错误 - content: - application/json: - schema: *ref_0 - headers: {} - x-apifox-name: '' - security: - - BearerAuth: [] - x-apifox: - schemeGroups: - - id: '-jWpeN1-jYBl-SEBTmsrq' - schemeIds: - - BearerAuth - required: true - use: - id: '-jWpeN1-jYBl-SEBTmsrq' - scopes: - '-jWpeN1-jYBl-SEBTmsrq': - BearerAuth: [] - x-apifox-folder: 代理账号管理 - x-apifox-status: released - x-run-in-apifox: https://app.apifox.com/web/project/7591618/apis/api-408366334-run -components: - schemas: - ModelShopAccountPageResult: - properties: - items: - description: 代理账号列表 - items: - $ref: '#/components/schemas/ModelShopAccountResponse' - type: array - nullable: true - page: - description: 当前页码 - type: integer - size: - description: 每页数量 - type: integer - total: - description: 总记录数 - type: integer - type: object - x-apifox-orders: - - items - - page - - size - - total - x-apifox-ignore-properties: [] - x-apifox-folder: '' - ModelShopAccountResponse: - properties: - created_at: - description: 创建时间 - type: string - id: - description: 账号ID - minimum: 0 - type: integer - phone: - description: 手机号 - type: string - shop_id: - description: 店铺ID - minimum: 0 - type: integer - shop_name: - description: 店铺名称 - type: string - status: - description: 状态 (0:禁用, 1:启用) - type: integer - updated_at: - description: 更新时间 - type: string - user_type: - description: 用户类型 (1:超级管理员, 2:平台用户, 3:代理账号, 4:企业账号) - type: integer - username: - description: 用户名 - type: string - type: object - x-apifox-orders: - - created_at - - id - - phone - - shop_id - - shop_name - - status - - updated_at - - user_type - - username - x-apifox-ignore-properties: [] - x-apifox-folder: '' - ErrorResponse: - properties: - code: - description: 错误码 - type: integer - message: - description: 错误消息 - type: string - timestamp: - description: 时间戳 - format: date-time - type: string - required: - - code - - message - - timestamp - type: object - x-apifox-orders: - - code - - message - - timestamp - x-apifox-ignore-properties: [] - x-apifox-folder: '' - securitySchemes: - BearerAuth: - bearerFormat: JWT - scheme: bearer - type: jwt -servers: - - url: https://cmp-api.xm-iot.cn - description: 测试环境 -security: [] - -``` - -# 创建代理账号 - -## OpenAPI Specification - -```yaml -openapi: 3.0.1 -info: - title: '' - description: '' - version: 1.0.0 -paths: - /api/admin/shop-accounts: - post: - summary: 创建代理账号 - deprecated: false - description: '' - tags: - - 代理账号管理 - - 代理账号管理 - parameters: [] - requestBody: - content: - application/json: - schema: - $ref: '#/components/schemas/ModelCreateShopAccountRequest' - responses: - '200': - description: OK - content: - application/json: - schema: - $ref: '#/components/schemas/ModelShopAccountResponse' - headers: {} - x-apifox-name: '' - '400': - description: 请求参数错误 - content: - application/json: - schema: &ref_0 - $ref: '#/components/schemas/ErrorResponse' - headers: {} - x-apifox-name: '' - '401': - description: 未认证或认证已过期 - content: - application/json: - schema: *ref_0 - headers: {} - x-apifox-name: '' - '403': - description: 无权访问 - content: - application/json: - schema: *ref_0 - headers: {} - x-apifox-name: '' - '500': - description: 服务器内部错误 - content: - application/json: - schema: *ref_0 - headers: {} - x-apifox-name: '' - security: - - BearerAuth: [] - x-apifox: - schemeGroups: - - id: LdX0-6IzkTw-pXBT8t4Km - schemeIds: - - BearerAuth - required: true - use: - id: LdX0-6IzkTw-pXBT8t4Km - scopes: - LdX0-6IzkTw-pXBT8t4Km: - BearerAuth: [] - x-apifox-folder: 代理账号管理 - x-apifox-status: released - x-run-in-apifox: https://app.apifox.com/web/project/7591618/apis/api-408366335-run -components: - schemas: - ModelCreateShopAccountRequest: - properties: - password: - description: 密码 - maxLength: 32 - minLength: 8 - type: string - phone: - description: 手机号 - maxLength: 11 - minLength: 11 - type: string - shop_id: - description: 店铺ID - minimum: 1 - type: integer - username: - description: 用户名 - maxLength: 50 - minLength: 3 - type: string - required: - - password - - phone - - shop_id - - username - type: object - x-apifox-orders: - - password - - phone - - shop_id - - username - x-apifox-ignore-properties: [] - x-apifox-folder: '' - ModelShopAccountResponse: - properties: - created_at: - description: 创建时间 - type: string - id: - description: 账号ID - minimum: 0 - type: integer - phone: - description: 手机号 - type: string - shop_id: - description: 店铺ID - minimum: 0 - type: integer - shop_name: - description: 店铺名称 - type: string - status: - description: 状态 (0:禁用, 1:启用) - type: integer - updated_at: - description: 更新时间 - type: string - user_type: - description: 用户类型 (1:超级管理员, 2:平台用户, 3:代理账号, 4:企业账号) - type: integer - username: - description: 用户名 - type: string - type: object - x-apifox-orders: - - created_at - - id - - phone - - shop_id - - shop_name - - status - - updated_at - - user_type - - username - x-apifox-ignore-properties: [] - x-apifox-folder: '' - ErrorResponse: - properties: - code: - description: 错误码 - type: integer - message: - description: 错误消息 - type: string - timestamp: - description: 时间戳 - format: date-time - type: string - required: - - code - - message - - timestamp - type: object - x-apifox-orders: - - code - - message - - timestamp - x-apifox-ignore-properties: [] - x-apifox-folder: '' - securitySchemes: - BearerAuth: - bearerFormat: JWT - scheme: bearer - type: jwt -servers: - - url: https://cmp-api.xm-iot.cn - description: 测试环境 -security: [] - -``` - -# 更新代理账号 - -## OpenAPI Specification - -```yaml -openapi: 3.0.1 -info: - title: '' - description: '' - version: 1.0.0 -paths: - /api/admin/shop-accounts/{id}: - put: - summary: 更新代理账号 - deprecated: false - description: '' - tags: - - 代理账号管理 - - 代理账号管理 - parameters: - - name: id - in: path - description: ID - required: true - example: 0 - schema: - description: ID - minimum: 0 - type: integer - requestBody: - content: - application/json: - schema: - $ref: '#/components/schemas/ModelUpdateShopAccountParams' - responses: - '200': - description: OK - content: - application/json: - schema: - $ref: '#/components/schemas/ModelShopAccountResponse' - headers: {} - x-apifox-name: '' - '400': - description: 请求参数错误 - content: - application/json: - schema: &ref_0 - $ref: '#/components/schemas/ErrorResponse' - headers: {} - x-apifox-name: '' - '401': - description: 未认证或认证已过期 - content: - application/json: - schema: *ref_0 - headers: {} - x-apifox-name: '' - '403': - description: 无权访问 - content: - application/json: - schema: *ref_0 - headers: {} - x-apifox-name: '' - '500': - description: 服务器内部错误 - content: - application/json: - schema: *ref_0 - headers: {} - x-apifox-name: '' - security: - - BearerAuth: [] - x-apifox: - schemeGroups: - - id: TTw5I9JG_CJv8tEsi1Bk6 - schemeIds: - - BearerAuth - required: true - use: - id: TTw5I9JG_CJv8tEsi1Bk6 - scopes: - TTw5I9JG_CJv8tEsi1Bk6: - BearerAuth: [] - x-apifox-folder: 代理账号管理 - x-apifox-status: released - x-run-in-apifox: https://app.apifox.com/web/project/7591618/apis/api-408366336-run -components: - schemas: - ModelUpdateShopAccountParams: - properties: - username: - description: 用户名 - maxLength: 50 - minLength: 3 - type: string - required: - - username - type: object - x-apifox-orders: - - username - x-apifox-ignore-properties: [] - x-apifox-folder: '' - ModelShopAccountResponse: - properties: - created_at: - description: 创建时间 - type: string - id: - description: 账号ID - minimum: 0 - type: integer - phone: - description: 手机号 - type: string - shop_id: - description: 店铺ID - minimum: 0 - type: integer - shop_name: - description: 店铺名称 - type: string - status: - description: 状态 (0:禁用, 1:启用) - type: integer - updated_at: - description: 更新时间 - type: string - user_type: - description: 用户类型 (1:超级管理员, 2:平台用户, 3:代理账号, 4:企业账号) - type: integer - username: - description: 用户名 - type: string - type: object - x-apifox-orders: - - created_at - - id - - phone - - shop_id - - shop_name - - status - - updated_at - - user_type - - username - x-apifox-ignore-properties: [] - x-apifox-folder: '' - ErrorResponse: - properties: - code: - description: 错误码 - type: integer - message: - description: 错误消息 - type: string - timestamp: - description: 时间戳 - format: date-time - type: string - required: - - code - - message - - timestamp - type: object - x-apifox-orders: - - code - - message - - timestamp - x-apifox-ignore-properties: [] - x-apifox-folder: '' - securitySchemes: - BearerAuth: - bearerFormat: JWT - scheme: bearer - type: jwt -servers: - - url: https://cmp-api.xm-iot.cn - description: 测试环境 -security: [] - -``` - -# 重置代理账号密码 - -## OpenAPI Specification - -```yaml -openapi: 3.0.1 -info: - title: '' - description: '' - version: 1.0.0 -paths: - /api/admin/shop-accounts/{id}/password: - put: - summary: 重置代理账号密码 - deprecated: false - description: '' - tags: - - 代理账号管理 - - 代理账号管理 - parameters: - - name: id - in: path - description: ID - required: true - example: 0 - schema: - description: ID - minimum: 0 - type: integer - requestBody: - content: - application/json: - schema: - $ref: '#/components/schemas/ModelUpdateShopAccountPasswordParams' - responses: - '400': - description: 请求参数错误 - content: - application/json: - schema: &ref_0 - $ref: '#/components/schemas/ErrorResponse' - headers: {} - x-apifox-name: '' - '401': - description: 未认证或认证已过期 - content: - application/json: - schema: *ref_0 - headers: {} - x-apifox-name: '' - '403': - description: 无权访问 - content: - application/json: - schema: *ref_0 - headers: {} - x-apifox-name: '' - '500': - description: 服务器内部错误 - content: - application/json: - schema: *ref_0 - headers: {} - x-apifox-name: '' - security: - - BearerAuth: [] - x-apifox: - schemeGroups: - - id: IeBLfzHchBWHbFru7Ma0u - schemeIds: - - BearerAuth - required: true - use: - id: IeBLfzHchBWHbFru7Ma0u - scopes: - IeBLfzHchBWHbFru7Ma0u: - BearerAuth: [] - x-apifox-folder: 代理账号管理 - x-apifox-status: released - x-run-in-apifox: https://app.apifox.com/web/project/7591618/apis/api-408366337-run -components: - schemas: - ModelUpdateShopAccountPasswordParams: - properties: - new_password: - description: 新密码 - maxLength: 32 - minLength: 8 - type: string - required: - - new_password - type: object - x-apifox-orders: - - new_password - x-apifox-ignore-properties: [] - x-apifox-folder: '' - ErrorResponse: - properties: - code: - description: 错误码 - type: integer - message: - description: 错误消息 - type: string - timestamp: - description: 时间戳 - format: date-time - type: string - required: - - code - - message - - timestamp - type: object - x-apifox-orders: - - code - - message - - timestamp - x-apifox-ignore-properties: [] - x-apifox-folder: '' - securitySchemes: - BearerAuth: - bearerFormat: JWT - scheme: bearer - type: jwt -servers: - - url: https://cmp-api.xm-iot.cn - description: 测试环境 -security: [] - -``` - -列表显示中状态用开关那个组件 -# 启用/禁用代理账号 - -## OpenAPI Specification - -```yaml -openapi: 3.0.1 -info: - title: '' - description: '' - version: 1.0.0 -paths: - /api/admin/shop-accounts/{id}/status: - put: - summary: 启用/禁用代理账号 - deprecated: false - description: '' - tags: - - 代理账号管理 - - 代理账号管理 - parameters: - - name: id - in: path - description: ID - required: true - example: 0 - schema: - description: ID - minimum: 0 - type: integer - requestBody: - content: - application/json: - schema: - $ref: '#/components/schemas/ModelUpdateShopAccountStatusParams' - responses: - '400': - description: 请求参数错误 - content: - application/json: - schema: &ref_0 - $ref: '#/components/schemas/ErrorResponse' - headers: {} - x-apifox-name: '' - '401': - description: 未认证或认证已过期 - content: - application/json: - schema: *ref_0 - headers: {} - x-apifox-name: '' - '403': - description: 无权访问 - content: - application/json: - schema: *ref_0 - headers: {} - x-apifox-name: '' - '500': - description: 服务器内部错误 - content: - application/json: - schema: *ref_0 - headers: {} - x-apifox-name: '' - security: - - BearerAuth: [] - x-apifox: - schemeGroups: - - id: QRYgZh2IcZgAVmdF1dNBU - schemeIds: - - BearerAuth - required: true - use: - id: QRYgZh2IcZgAVmdF1dNBU - scopes: - QRYgZh2IcZgAVmdF1dNBU: - BearerAuth: [] - x-apifox-folder: 代理账号管理 - x-apifox-status: released - x-run-in-apifox: https://app.apifox.com/web/project/7591618/apis/api-408366338-run -components: - schemas: - ModelUpdateShopAccountStatusParams: - properties: - status: - description: 状态 (0:禁用, 1:启用) - type: integer - required: - - status - type: object - x-apifox-orders: - - status - x-apifox-ignore-properties: [] - x-apifox-folder: '' - ErrorResponse: - properties: - code: - description: 错误码 - type: integer - message: - description: 错误消息 - type: string - timestamp: - description: 时间戳 - format: date-time - type: string - required: - - code - - message - - timestamp - type: object - x-apifox-orders: - - code - - message - - timestamp - x-apifox-ignore-properties: [] - x-apifox-folder: '' - securitySchemes: - BearerAuth: - bearerFormat: JWT - scheme: bearer - type: jwt -servers: - - url: https://cmp-api.xm-iot.cn - description: 测试环境 -security: [] - -``` diff --git a/docs/任务规划.md b/docs/任务规划.md deleted file mode 100644 index cb0f64f..0000000 --- a/docs/任务规划.md +++ /dev/null @@ -1,488 +0,0 @@ -# 物联网卡管理系统 - 开发任务规划 - -> 项目开始日期: 2026-01-09 -> 当前状态: 进行中 - ---- - -## 📋 任务进度总览 - -- [ ] 阶段一:基础设施和认证模块(0/2) -- [ ] 阶段二:账号管理模块(0/7) -- [ ] 阶段三:财务管理模块(0/4) -- [ ] 阶段四:商品管理模块(0/5) -- [ ] 阶段五:资产管理模块(0/5) -- [ ] 阶段六:批量操作模块(0/3) - -**总体完成度**: 0/26 任务 - ---- - -## 🚀 阶段一:基础设施和认证模块 - -### 1.1 登录模块 -- [ ] 设计登录页面UI -- [ ] 实现用户名密码登录 -- [ ] 实现记住密码功能 -- [ ] 集成验证码/滑块验证 -- [ ] 实现 Token 管理 -- [ ] 实现自动刷新 Token -- [ ] 实现登出功能 -- [ ] 添加登录错误处理 - -### 1.2 权限管理基础 -- [ ] 设计权限控制策略(RBAC) -- [ ] 实现路由权限守卫 -- [ ] 实现按钮级权限控制 -- [ ] 实现数据权限过滤 -- [ ] 完善角色权限映射 - ---- - -## 👥 阶段二:账号管理模块 - -### 2.1 平台角色管理 -- [ ] 角色列表页面(表格展示) -- [ ] 新增角色功能 - - [ ] 角色基础信息表单 - - [ ] 权限分配(树形结构) -- [ ] 编辑角色功能 -- [ ] 删除角色功能 -- [ ] 角色搜索和筛选 -- [ ] 角色权限预览 - -### 2.2 平台账号管理 -- [ ] 平台账号列表页面 -- [ ] 新增平台账号 - - [ ] 账号信息表单 - - [ ] 角色分配 - - [ ] 账号状态设置 -- [ ] 编辑平台账号 -- [ ] 禁用/启用账号 -- [ ] 重置密码功能 -- [ ] 账号操作日志查看 - -### 2.3 客户角色管理 -- [ ] 客户角色列表页面 -- [ ] 新增客户角色 - - [ ] 角色名称和描述 - - [ ] 能力边界配置(权限树) -- [ ] 编辑客户角色 -- [ ] 删除客户角色 -- [ ] 角色能力说明文档 - -### 2.4 代理商管理 -- [ ] 代理商列表页面 - - [ ] 多级代理商树形展示 - - [ ] 代理商等级标识 -- [ ] 新增代理商 - - [ ] 代理商基础信息 - - [ ] 上级代理商选择 - - [ ] 代理商等级设置 -- [ ] 编辑代理商信息 -- [ ] 代理商账号管理 - - [ ] 查看代理商下的账号列表 - - [ ] 为代理商创建子账号 -- [ ] 代理商佣金配置 -- [ ] 代理商数据统计面板 - -### 2.5 企业客户管理 -- [ ] 企业客户列表页面 -- [ ] 新增企业客户 - - [ ] 企业基础信息 - - [ ] 客户角色分配 - - [ ] 联系人信息 -- [ ] 编辑企业客户 -- [ ] 企业客户账号管理 - - [ ] 创建企业管理账号 - - [ ] 账号权限设置 -- [ ] 企业客户数据看板 - -### 2.6 客户账号管理 -- [ ] 客户账号列表页面 - - [ ] 支持按代理商/企业筛选 - - [ ] 账号状态筛选 -- [ ] 查看账号详情 -- [ ] 解绑手机号 -- [ ] 重置登录密码 -- [ ] 禁用/启用账号 -- [ ] 账号操作记录 - -### 2.7 客户账号佣金管理 -- [ ] 客户账号佣金列表 - - [ ] 佣金统计卡片 - - [ ] 佣金明细表格 -- [ ] 佣金详情查看 -- [ ] 提现记录查看 -- [ ] 佣金统计图表 - ---- - -## 💰 阶段三:财务管理模块 - -### 3.1 佣金提现管理 -- [ ] 提现申请列表 - - [ ] 状态筛选(待审核、已通过、已拒绝) - - [ ] 时间范围筛选 -- [ ] 提现申请详情 -- [ ] 审核提现申请 - - [ ] 通过操作 - - [ ] 拒绝操作(需填写原因) -- [ ] 批量审核功能 -- [ ] 提现记录导出 - -### 3.2 佣金提现设置 -- [ ] 提现参数配置页面 - - [ ] 最低提现金额 - - [ ] 提现手续费设置 - - [ ] 单日提现次数限制 -- [ ] 提现规则说明 -- [ ] 配置历史记录 -- [ ] 参数生效管理 - -### 3.3 我的账户(当前登录账号) -- [ ] 账户概览页面 - - [ ] 佣金总额卡片 - - [ ] 可提现金额卡片 - - [ ] 待入账金额卡片 -- [ ] 佣金收入明细 -- [ ] 提现申请功能 -- [ ] 收支流水记录 -- [ ] 佣金统计图表 - -### 3.4 收款商户设置 -- [ ] 支付参数配置页面 - - [ ] 支付商户信息 - - [ ] API密钥配置 - - [ ] 回调地址设置 -- [ ] 支付方式管理 - - [ ] 微信支付 - - [ ] 支付宝 - - [ ] 银行卡 -- [ ] 支付测试功能 -- [ ] 配置安全验证 - ---- - -## 🛍️ 阶段四:商品管理模块 - -### 4.1 号卡管理 -- [ ] 号卡列表页面 - - [ ] 号卡信息展示 - - [ ] 状态筛选 -- [ ] 新增号卡 - - [ ] 号卡基础信息 - - [ ] 运营商选择 - - [ ] 套餐配置 -- [ ] 编辑号卡 -- [ ] 号卡上下架 -- [ ] 号卡库存管理 -- [ ] 号卡详情页面 - -### 4.2 号卡分配 -- [ ] 分配记录列表 -- [ ] 为代理商分配号卡 - - [ ] 选择代理商 - - [ ] 选择号卡商品 - - [ ] 设置分配数量 - - [ ] 设置佣金模式 -- [ ] 查看分配详情 -- [ ] 撤销分配 -- [ ] 分配统计报表 - -### 4.3 套餐系列管理 -- [ ] 套餐系列列表 -- [ ] 新增套餐系列 - - [ ] 系列名称 - - [ ] 系列描述 - - [ ] 系列图标 -- [ ] 编辑套餐系列 -- [ ] 删除套餐系列 -- [ ] 套餐系列排序 - -### 4.4 套餐管理 -- [ ] 套餐列表页面 - - [ ] 权限过滤(管理员看全部,普通用户看自己的) - - [ ] 按套餐系列筛选 -- [ ] 新增套餐 - - [ ] 套餐基础信息 - - [ ] 套餐类型(流量、语音、短信) - - [ ] 套餐价格 - - [ ] 有效期设置 -- [ ] 编辑套餐 -- [ ] 套餐上下架 -- [ ] 套餐详情页面 - -### 4.5 套餐分配 -- [ ] 套餐分配列表 -- [ ] 为直级代理分配套餐 - - [ ] 选择代理商 - - [ ] 选择套餐 - - [ ] 设置佣金模式 - - [ ] 固定佣金 - - [ ] 比例佣金 -- [ ] 查看分配详情 -- [ ] 修改佣金设置 -- [ ] 分配统计 - ---- - -## 📦 阶段五:资产管理模块 - -### 5.1 单卡信息查询 -- [ ] ICCID 查询界面 -- [ ] 单卡详情页面 - - [ ] 基础信息展示 - - [ ] 套餐信息 - - [ ] 使用情况 -- [ ] 单卡操作功能 - - [ ] 套餐充值 - - [ ] 停机/复机 - - [ ] 查看流量详情 - - [ ] 更改过期时间 - - [ ] 转新卡 - - [ ] 查看停复机记录 - - [ ] 查看往期订单 - - [ ] 增减流量 - - [ ] 变更钱包余额 - - [ ] 充值支付密码 - - [ ] 续充 -- [ ] 设备操作入口 - -### 5.2 网卡管理 -- [ ] 网卡列表页面 - - [ ] 高级搜索 - - [ ] 状态筛选 - - [ ] 批量选择 -- [ ] 网卡详情页面 -- [ ] 批量操作入口 - - [ ] 批量充值 - - [ ] 批量停复机 - - [ ] 批量分配 -- [ ] 网卡导出功能 -- [ ] 网卡数据统计 - -### 5.3 设备管理 -- [ ] 设备列表页面 - - [ ] 设备信息展示 - - [ ] 在线状态 -- [ ] 设备详情页面 - - [ ] 设备基础信息 - - [ ] 绑定卡信息 -- [ ] 查看设备卡信息 -- [ ] 修改设备卡绑定 -- [ ] 设备相关操作 - - [ ] 设备重启 - - [ ] 设备诊断 -- [ ] 设备数据统计 - -### 5.4 资产分配 -- [ ] 资产分配页面 -- [ ] 设备批量分配 - - [ ] 选择代理商 - - [ ] 上传设备列表 - - [ ] 确认分配信息 -- [ ] 网卡批量分配 - - [ ] 选择代理商 - - [ ] 上传网卡列表(ICCID) - - [ ] 自动关联设备处理 -- [ ] 分配预览和确认 -- [ ] 分配记录查看 -- [ ] 分配回滚功能 - -### 5.5 换卡申请管理 -- [ ] 换卡申请列表 - - [ ] 状态筛选(待处理、已完成、已拒绝) -- [ ] 申请详情查看 - - [ ] 旧卡信息 - - [ ] 申请原因 -- [ ] 处理换卡申请 - - [ ] 填充新 ICCID - - [ ] 确认换卡 - - [ ] 拒绝申请 -- [ ] 换卡记录追溯 - ---- - -## 🔄 阶段六:批量操作模块 - -### 6.1 网卡批量导入 -- [ ] 网卡导入页面 - - [ ] 模板下载 - - [ ] Excel 文件上传 - - [ ] 数据预览 -- [ ] 导入任务列表 - - [ ] 任务状态 - - [ ] 成功/失败统计 -- [ ] 查看导入详情 - - [ ] 成功记录 - - [ ] 失败记录和原因 -- [ ] 失败数据重新导入 - -### 6.2 设备批量导入 -- [ ] 设备导入页面 - - [ ] 模板下载 - - [ ] Excel 文件上传(设备+ICCID关系) - - [ ] 数据预览和校验 -- [ ] 导入任务列表 -- [ ] 查看导入结果 -- [ ] 导入失败处理 - -### 6.3 线下批量充值 -- [ ] 批量充值记录列表 -- [ ] 新建批量充值 - - [ ] 模板下载 - - [ ] Excel 上传 - - [ ] 充值预览 - - [ ] 确认充值 -- [ ] 充值详情查看 - - [ ] 成功列表 - - [ ] 失败列表 -- [ ] 充值结果导出 - -### 6.4 换卡通知 -- [ ] 换卡通知列表 -- [ ] 单独创建换卡通知 - - [ ] 选择网卡 - - [ ] 填写通知内容 - - [ ] 选择通知方式(短信/邮件) -- [ ] 批量创建换卡通知 - - [ ] 上传网卡列表 - - [ ] 设置通知内容 -- [ ] 查看通知记录 - - [ ] 发送状态 - - [ ] 已读状态 - ---- - -## 🎨 阶段七:开发能力和其他设置 - -### 7.1 开发能力管理 -- [ ] 开发能力列表页面 -- [ ] API 密钥管理 - - [ ] 生成密钥 - - [ ] 重置密钥 - - [ ] 密钥权限设置 -- [ ] Webhook 配置 -- [ ] API 文档集成 -- [ ] API 调用统计 - -### 7.2 分佣模板管理 -- [ ] 分佣模板列表 -- [ ] 新增分佣模板 - - [ ] 模板名称 - - [ ] 分佣规则配置 - - [ ] 适用范围 -- [ ] 编辑分佣模板 -- [ ] 删除分佣模板 -- [ ] 模板应用记录 - ---- - -## 📊 阶段八:数据统计和报表 - -### 8.1 数据概览(Dashboard) -- [ ] 总体数据统计卡片 - - [ ] 网卡总数 - - [ ] 设备总数 - - [ ] 今日充值金额 - - [ ] 今日佣金 -- [ ] 数据趋势图表 - - [ ] 充值趋势 - - [ ] 新增网卡趋势 -- [ ] 代理商排行榜 -- [ ] 套餐销售排行 - -### 8.2 业务报表 -- [ ] 充值报表 -- [ ] 佣金报表 -- [ ] 代理商业绩报表 -- [ ] 套餐使用报表 -- [ ] 报表导出功能 - ---- - -## 🔧 阶段九:系统优化和完善 - -### 9.1 性能优化 -- [ ] 长列表虚拟滚动 -- [ ] 图片懒加载 -- [ ] 接口请求优化 -- [ ] 打包体积优化 - -### 9.2 用户体验优化 -- [ ] 页面加载状态 -- [ ] 错误提示优化 -- [ ] 操作反馈优化 -- [ ] 响应式适配 - -### 9.3 代码质量 -- [ ] 代码规范检查 -- [ ] 单元测试编写 -- [ ] E2E 测试 -- [ ] 代码注释完善 - ---- - -## 📝 开发规范 - -### 命名规范 -- 组件名:大驼峰,如 `UserManagement.vue` -- 文件名:小写+连字符,如 `user-list.vue` -- 接口名:RESTful 风格 -- 路由名:小写+连字符 - -### 代码结构 -``` -src/ - ├── views/ # 页面组件 - ├── components/ # 公共组件 - ├── api/ # API 接口 - ├── store/ # 状态管理 - ├── router/ # 路由配置 - ├── utils/ # 工具函数 - └── types/ # TypeScript 类型定义 -``` - -### Git 提交规范 -- `feat`: 新功能 -- `fix`: 修复bug -- `docs`: 文档更新 -- `style`: 代码格式调整 -- `refactor`: 重构 -- `test`: 测试相关 -- `chore`: 构建/工具相关 - ---- - -## 🎯 里程碑 - -- [ ] **M1**: 基础设施完成(登录、权限) - 预计 3 天 -- [ ] **M2**: 账号管理模块完成 - 预计 7 天 -- [ ] **M3**: 财务管理模块完成 - 预计 5 天 -- [ ] **M4**: 商品管理模块完成 - 预计 5 天 -- [ ] **M5**: 资产管理模块完成 - 预计 7 天 -- [ ] **M6**: 批量操作模块完成 - 预计 4 天 -- [ ] **M7**: 数据统计和系统优化 - 预计 5 天 - -**预计总工期**: 36 个工作日 - ---- - -## 📌 注意事项 - -1. **优先级**:按阶段顺序开发,基础设施 > 核心业务 > 辅助功能 -2. **接口对接**:等待后端 API 完成后再进行集成 -3. **数据安全**:涉及敏感数据的操作需要二次确认 -4. **性能考虑**:列表超过 1000 条需要使用虚拟滚动 -5. **错误处理**:所有接口调用必须有错误处理 -6. **权限控制**:每个页面和操作都需要权限验证 - ---- - -## 🔄 更新日志 - -### 2026-01-09 -- 创建任务规划文档 -- 定义开发阶段和任务拆分 -- 明确开发规范和里程碑 diff --git a/docs/功能.md b/docs/功能.md deleted file mode 100644 index c62215c..0000000 --- a/docs/功能.md +++ /dev/null @@ -1,42 +0,0 @@ -# 物联网卡管理系统 - 功能列表 - -## 账号管理模块 -- 账号管理-客户角色 客户角色用以决定客户能力边界 -- 账号管理-代理商管理 用以创建代理商以及管理特定代理商账号 -- 账号管理-企业客户管理 用以创建企业管理账号,只能登录企业端,依赖客户角色 -- 账号管理-客户账号管理 管理客户(代理商+企业客户)的账号,解绑手机等或针对该账号的操作 - -## 账户管理/财务模块 -- 账户管理-客户账号 查看账号下全部的客户账号的佣金情况以及提现情况 -- 账户管理/我的财务-佣金提现 管理全部的提现申请 -- 账户管理-佣金提现设置 设置提现参数,生效最新的一条 -- 我的财务-我的账户 获取当前登录账号的佣金相关数据(这里不应该跟奇成一样用列表) - -## 我的设置模块 -- 我的设置-收款商户设置 设置支付参数 -- 我的设置-开发能力管理 获取开发能力对接参数以及管理 -- 我的设置-分佣模板 用以创建以及管理分佣模板方便给代理分配产品时设置分佣规则 - -## 商品管理模块 -- 商品管理-号卡管理 新增管理号卡商品,管理基础信息 -- 商品管理-号卡分配 为特定代理分配号卡商品,同时设置佣金模式 -- 商品管理-套餐系列管理 新增以及管理套餐系列 -- 商品管理-套餐管理 新增以及管理套餐系列(只能看到自己的/管理员可以看到全部) -- 商品管理-套餐分配 为直级代理分配套餐同时设置佣金模式 - -## 资产管理模块 -- 资产管理-单卡信息 通过ICCID查询单卡相关信息,以及相关操作如,套餐充值,停复机,流量详情,更改过期时间,转新卡,停复机记录,往期订单,增减流量,变更钱包余额,充值支付密码,续充,设备操作 -- 资产管理-网卡管理 查询网卡信息,提供相关批量操作入口 -- 资产管理-设备管理 查看设备信息,提供相关操作入口,查看设备卡信息,修改设备卡信息,设备相关操作 -- 资产管理-资产分配 为特定代理分配网卡,只支持批量操作,批量操作分为两种,一种是设备批量分配,一种是网卡批量分配,如果使用网卡批量分配且网卡有设备信息,那么会把该卡所属设备以及网卡都分配过去 -- 资产管理-换卡申请 客户提交的换卡申请管理,处理换卡的申请,填充新的iccid - -## 批量操作模块 -- 网卡管理-批量操作-网卡导入 批量导入iccid,以及查看导入任务情况 -- 设备管理-批量操作-设备导入 批量导入设备以及iccid关系,查看导入任务情况 -- 网卡管理-批量操作-线下批量充值 查看批量充值记录,提供批量充值excel导入 -- 网卡管理-批量操作-换卡通知 可单独/批量新建换卡通知,查看换卡通知记录 - ---- - -**总计:25个功能模块** diff --git a/docs/完成总结.md b/docs/完成总结.md deleted file mode 100644 index ab1d437..0000000 --- a/docs/完成总结.md +++ /dev/null @@ -1,364 +0,0 @@ -# 物联网卡管理系统 - 页面开发完成总结 - -## 📊 完成概况 - -**完成时间**: 2026-01-09 -**开发进度**: 13/13 页面 (100%) -**总计文件**: 13 个 Vue 页面组件 - ---- - -## ✅ 已完成的页面列表 - -### 1. 账号管理模块 (3个页面) - -#### 1.1 客户角色管理 -- **文件路径**: `src/views/account-management/customer-role/index.vue` -- **功能特性**: - - 角色列表展示(CRUD操作) - - 能力范围配置(使用 ElCheckboxGroup) - - 角色启用/禁用状态管理 - - 应用统计 -- **组件使用**: ArtTable, ElDialog, ElForm, ElCheckboxGroup, ElTag - -#### 1.2 代理商管理 -- **文件路径**: `src/views/account-management/agent/index.vue` -- **功能特性**: - - 多层级代理商管理(支持3级) - - 代理商等级展示(一级/二级/三级) - - 子账号管理对话框 - - 佣金配置(固定/比例佣金) - - 状态管理(正常/禁用) -- **组件使用**: ArtTable, ElDialog, ElDescriptions, ElRadioGroup, ElInputNumber - -#### 1.3 客户账号管理 -- **文件路径**: `src/views/account-management/customer-account/index.vue` -- **功能特性**: - - 客户账号列表 - - 账号类型筛选(个人/企业/代理商) - - 账号详情查看 - - 解绑手机、重置密码、启用/禁用操作 - - 操作记录追踪 -- **组件使用**: ArtTable, ElDialog, ElDescriptions, ElTag, ElButton - ---- - -### 2. 财务管理模块 (3个页面) - -#### 2.1 提现管理 -- **文件路径**: `src/views/finance/withdrawal/index.vue` -- **功能特性**: - - 提现申请列表 - - 状态筛选(待审核/已通过/已拒绝/已完成) - - 批量审核功能(ElTable selection) - - 审核/拒绝操作(带原因输入) - - 详情对话框展示完整提现信息 -- **组件使用**: ArtTable, ElDialog, ElDescriptions, ElButton, ElTag - -#### 2.2 我的账户 -- **文件路径**: `src/views/finance/my-account/index.vue` -- **功能特性**: - - 账户概览卡片(4个统计卡片,渐变背景) - - 提现申请表单(带手续费自动计算) - - 交易流水列表 - - 类型筛选(全部/收入/提现) -- **组件使用**: ElCard, ElForm, ArtTable, ElTag -- **样式特色**: 渐变背景统计卡片 - -#### 2.3 提现设置 -- **文件路径**: `src/views/finance/withdrawal-settings/index.vue` -- **功能特性**: - - 提现参数配置 - - 手续费模式(固定/比例) - - 单日提现次数限制 - - 到账时间设置 - - 工作日限制开关 - - 提现时间段设置(ElTimePicker) - - 配置历史记录 -- **组件使用**: ElForm, ElInputNumber, ElRadioGroup, ElSwitch, ElTimePicker, ArtTable - ---- - -### 3. 设置管理模块 (3个页面) - -#### 3.1 支付商户配置 -- **文件路径**: `src/views/settings/payment-merchant/index.vue` -- **功能特性**: - - 商户基础信息配置 - - API配置(AppID, AppSecret, API密钥) - - 密钥显示/隐藏切换 - - 回调地址配置(支付/退款) - - 支付方式启用(微信/支付宝/银行卡) - - 测试模式开关 - - 配置说明文档 -- **组件使用**: ElCard, ElForm, ElInput, ElButton, ElCheckboxGroup, ElSwitch - -#### 3.2 开发者API管理 -- **文件路径**: `src/views/settings/developer-api/index.vue` -- **功能特性**: - - API密钥管理(生成/重置/删除) - - AppKey/AppSecret 展示(带复制功能) - - 密钥显示/隐藏切换 - - 权限配置(读取/写入/删除) - - Webhook配置(URL + 签名密钥) - - 事件订阅(多选框) - - API调用统计(最近7天) -- **组件使用**: ArtTable, ElDialog, ElButton, ElTag, ElCheckboxGroup -- **交互特色**: 一键复制到剪贴板 - -#### 3.3 分佣模板管理 -- **文件路径**: `src/views/settings/commission-template/index.vue` -- **功能特性**: - - 分佣模板 CRUD - - 分佣模式(固定佣金/比例佣金) - - 佣金规则配置 - - 适用范围设置 - - 应用次数统计 - - 应用记录查看 -- **组件使用**: ArtTable, ElDialog, ElForm, ElRadioGroup, ElInputNumber, ElTag - ---- - -### 4. 批量操作模块 (3个页面) - -#### 4.1 网卡批量导入 -- **文件路径**: `src/views/batch/sim-import/index.vue` -- **功能特性**: - - Excel模板下载 - - 拖拽上传(ElUpload drag) - - 导入说明提示(ElAlert) - - 导入记录列表 - - 导入进度展示(ElProgress) - - 导入状态(处理中/完成/失败) - - 详情查看(成功数/失败数/失败原因) - - 失败数据下载 -- **组件使用**: ElCard, ElUpload, ArtTable, ElProgress, ElTag, ElDescriptions - -#### 4.2 设备批量导入 -- **文件路径**: `src/views/batch/device-import/index.vue` -- **功能特性**: - - 设备批量导入(带ICCID绑定) - - 导入统计卡片(今日导入/成功绑定/失败数/成功率) - - 状态筛选 - - 导入进度跟踪 - - 失败明细表格 - - 已绑定ICCID统计 -- **组件使用**: ElCard, ElUpload, ArtTable, ElProgress, ElTag, ElTable -- **特色**: 统计卡片带图标 - -#### 4.3 换卡通知管理 -- **文件路径**: `src/views/batch/card-change-notice/index.vue` -- **功能特性**: - - 通知列表(标题/类型/状态) - - 通知类型(卡片更换/激活/停用/套餐变更) - - 目标用户设置(全部/指定/批量导入) - - 发送方式(短信/邮件/App推送) - - 定时发送功能 - - 发送进度实时展示 - - 立即发送操作 - - 详情查看 -- **组件使用**: ArtTable, ElDialog, ElForm, ElRadioGroup, ElCheckboxGroup, ElUpload, ElProgress -- **交互特色**: 实时发送进度动画 - ---- - -### 5. 产品管理模块 (1个页面) - -#### 5.1 网卡产品管理 -- **文件路径**: `src/views/product/sim-card/index.vue` -- **功能特性**: - - 网卡产品 CRUD - - 运营商筛选(移动/联通/电信) - - 套餐规格配置 - - 价格设置 - - 库存管理 - - 上线/下线状态 -- **组件使用**: ArtTable, ElDialog, ElForm, ElSelect, ElInputNumber, ElSwitch - ---- - -## 🔧 配置文件更新 - -### 1. 路由别名配置 -**文件**: `src/router/routesAlias.ts` - -新增路由别名: -```typescript -// 账号管理 -CustomerRole = '/account-management/customer-role' -AgentManagement = '/account-management/agent' -CustomerAccount = '/account-management/customer-account' - -// 产品管理 -SimCardManagement = '/product/sim-card' - -// 财务管理 -WithdrawalManagement = '/finance/withdrawal' -MyAccount = '/finance/my-account' -WithdrawalSettings = '/finance/withdrawal-settings' - -// 设置管理 -PaymentMerchant = '/settings/payment-merchant' -DeveloperApi = '/settings/developer-api' -CommissionTemplate = '/settings/commission-template' - -// 批量操作 -SimImport = '/batch/sim-import' -DeviceImport = '/batch/device-import' -CardChangeNotice = '/batch/card-change-notice' -``` - -### 2. 异步路由配置 -**文件**: `src/router/routes/asyncRoutes.ts` - -新增路由模块: -- **账号管理模块**: 扩展了3个子路由 -- **产品管理模块**: 新增模块,1个子路由 -- **财务管理模块**: 新增模块,3个子路由 -- **设置管理模块**: 新增模块,3个子路由 -- **批量操作模块**: 新增模块,3个子路由 - -### 3. 国际化配置 -**文件**: `src/locales/langs/zh.json` - -新增菜单标题: -```json -{ - "menus": { - "accountManagement": { - "customerRole": "客户角色", - "agent": "代理商管理", - "customerAccount": "客户账号" - }, - "product": { - "title": "产品管理", - "simCard": "网卡产品管理" - }, - "finance": { - "title": "财务管理", - "withdrawal": "提现管理", - "myAccount": "我的账户", - "withdrawalSettings": "提现设置" - }, - "settings": { - "title": "设置管理", - "paymentMerchant": "支付商户", - "developerApi": "开发者API", - "commissionTemplate": "分佣模板" - }, - "batch": { - "title": "批量操作", - "simImport": "网卡批量导入", - "deviceImport": "设备批量导入", - "cardChangeNotice": "换卡通知" - } - } -} -``` - ---- - -## 📝 开发规范遵循 - -### 1. 代码风格 -- ✅ 使用 Vue 3 Composition API -- ✅ 使用 ` - - -``` - ---- - -## 🎯 快速创建步骤 - -1. **复制模板**:复制上面的标准模板 -2. **修改组件名**:修改 `defineOptions({ name: 'YourPageName' })` -3. **调整接口**:根据业务需求修改 `DataItem` 接口 -4. **修改 Mock 数据**:替换 `mockData` 中的示例数据 -5. **调整表单字段**:根据需求增删表单项 -6. **调整表格列**:修改 `ElTableColumn` 配置 - ---- - -## 📚 常用组件 - -### 1. ArtTable - 表格组件 -```vue - - - - - -``` - -### 2. 搜索栏布局 -```vue - - - - - - - - - - - - - 搜索 - - -``` - -### 3. 状态标签 -```vue - - {{ getStatusText(status) }} - -``` - -### 4. 操作按钮 -```vue -编辑 -删除 -``` - ---- - -## 💡 开发规范 - -1. **命名规范** - - 组件名:大驼峰 `YourComponent` - - 变量名:小驼峰 `yourVariable` - - 文件名:小写+连字符 `your-file.vue` - -2. **Mock 数据格式** - - 统一使用 `ref([])` 定义 - - 包含 `id`, `createTime` 等公共字段 - - 数据应具有代表性,便于测试 - -3. **表单验证** - - 必填字段添加 `required` 规则 - - 手机号/邮箱使用正则验证 - - 提供友好的错误提示 - -4. **用户体验** - - 操作前使用 `ElMessageBox.confirm` 确认 - - 操作后使用 `ElMessage` 提示结果 - - 表单提交后关闭对话框并重置 - ---- - -## 🔄 下一步 - -1. 根据模板快速创建剩余页面 -2. 完善 Mock 数据使其更真实 -3. 添加路由配置 -4. 测试页面功能 -5. 优化用户体验 - -祝开发顺利!🚀 diff --git a/docs/项目完成总结.md b/docs/项目完成总结.md deleted file mode 100644 index d9a6d7a..0000000 --- a/docs/项目完成总结.md +++ /dev/null @@ -1,433 +0,0 @@ -# 物联网卡管理系统 - 完整项目总结 - -## 📊 完成概况 - -**完成时间**: 2026-01-09 -**开发进度**: 18/18 页面 (100%) -**总计文件**: 18 个 Vue 页面组件 -**状态**: ✅ 全部完成 - ---- - -## ✅ 新创建的页面列表(18个) - -### 第一批:基础模块(13个页面) - -#### 1. 账号管理模块 (3个) -1. **客户角色管理** - `src/views/account-management/customer-role/index.vue` -2. **代理商管理** - `src/views/account-management/agent/index.vue` -3. **客户账号管理** - `src/views/account-management/customer-account/index.vue` - -#### 2. 财务管理模块 (3个) -4. **提现管理** - `src/views/finance/withdrawal/index.vue` -5. **我的账户** - `src/views/finance/my-account/index.vue` -6. **提现设置** - `src/views/finance/withdrawal-settings/index.vue` - -#### 3. 设置管理模块 (3个) -7. **支付商户配置** - `src/views/settings/payment-merchant/index.vue` -8. **开发者API管理** - `src/views/settings/developer-api/index.vue` -9. **分佣模板管理** - `src/views/settings/commission-template/index.vue` - -#### 4. 批量操作模块 (3个) -10. **网卡批量导入** - `src/views/batch/sim-import/index.vue` -11. **设备批量导入** - `src/views/batch/device-import/index.vue` -12. **换卡通知管理** - `src/views/batch/card-change-notice/index.vue` - -#### 5. 产品管理模块 (1个) -13. **网卡产品管理** - `src/views/product/sim-card/index.vue` - ---- - -### 第二批:补充模块(5个页面) - -#### 6. 账号管理扩展 (2个) -14. **企业客户管理** - `src/views/account-management/enterprise-customer/index.vue` - - 创建企业管理账号,只能登录企业端 - - 依赖客户角色,决定能力边界 - - 营业执照上传,统一社会信用代码管理 - - 角色分配和初始余额设置 - -15. **客户账号佣金** - `src/views/account-management/customer-commission/index.vue` - - 查看账号下全部客户的佣金情况 - - 提现情况统计和查询 - - 佣金明细和提现记录 - - 统计卡片展示(总佣金、已提现、待提现) - -#### 7. 商品管理扩展 (1个) -16. **号卡分配** - `src/views/product/sim-card-assign/index.vue` - - 为特定代理分配号卡商品 - - 设置分佣模式(固定/比例/模板) - - 特殊折扣设置 - - 分配记录和取消分配功能 - -#### 8. 资产管理模块 (2个) -17. **资产分配** - `src/views/asset-management/asset-assign/index.vue` - - 支持三种分配模式:网卡批量分配、设备批量分配、网卡+设备分配 - - 网卡有设备信息时,可同时分配网卡和设备 - - 批量选择和分配给代理商 - - 分配记录和批次管理 - -18. **换卡申请管理** - `src/views/asset-management/card-replacement-request/index.vue` - - 客户提交的换卡申请管理 - - 处理换卡申请,填充新ICCID - - 新卡验证和自动换卡操作 - - 申请审核(通过/拒绝) - ---- - -## 📦 已存在的页面(复用) - -项目中以下页面已经存在,功能完整,无需重复创建: - -### 卡片管理(card-management) -- ✓ 单卡信息 - `card-management/single-card` -- ✓ 网卡管理 - `card-management/card-list` -- ✓ 网卡明细 - `card-management/card-detail` -- ✓ 网卡分配 - `card-management/card-assign` -- ✓ 停机管理 - `card-management/card-shutdown` -- ✓ 我的网卡 - `card-management/my-cards` -- ✓ 线下批量充值 - `card-management/offline-batch-recharge` -- ✓ 网卡转接 - `card-management/card-transfer` -- ✓ 换卡管理 - `card-management/card-replacement` -- ✓ 套餐赠送 - `card-management/package-gift` -- ✓ 换卡网卡 - `card-management/card-change-card` - -### 套餐管理(package-management) -- ✓ 新建套餐 - `package-management/package-create` -- ✓ 批量管理 - `package-management/package-batch` -- ✓ 我的套餐 - `package-management/package-list` -- ✓ 套餐变更 - `package-management/package-change` -- ✓ 套餐分配 - `package-management/package-assign` -- ✓ 套餐系列 - `package-management/package-series` -- ✓ 套餐佣金 - `package-management/package-commission` - -### 设备管理(device-management) -- ✓ 设备管理 - `device-management/devices` - -### 客户管理(account-management) -- ✓ 客户管理 - `account-management/customer` - ---- - -## 🔄 功能与页面对应关系 - -根据你提供的完整需求,所有功能已全部实现: - -| 序号 | 功能名称 | 对应页面 | 状态 | -|------|---------|---------|------| -| 1 | 账号管理-客户角色 | account-management/customer-role | ✅ 已创建 | -| 2 | 账号管理-代理商管理 | account-management/agent | ✅ 已创建 | -| 3 | 账号管理-企业客户管理 | account-management/enterprise-customer | ✅ 已创建 | -| 4 | 账号管理-客户账号管理 | account-management/customer-account | ✅ 已创建 | -| 5 | 账户管理-客户账号佣金 | account-management/customer-commission | ✅ 已创建 | -| 6 | 账户管理-佣金提现 | finance/withdrawal | ✅ 已创建 | -| 7 | 账户管理-佣金提现设置 | finance/withdrawal-settings | ✅ 已创建 | -| 8 | 我的财务-我的账户 | finance/my-account | ✅ 已创建 | -| 9 | 我的设置-收款商户设置 | settings/payment-merchant | ✅ 已创建 | -| 10 | 我的设置-开发能力管理 | settings/developer-api | ✅ 已创建 | -| 11 | 我的设置-分佣模板 | settings/commission-template | ✅ 已创建 | -| 12 | 商品管理-号卡管理 | product/sim-card | ✅ 已创建 | -| 13 | 商品管理-号卡分配 | product/sim-card-assign | ✅ 已创建 | -| 14 | 商品管理-套餐系列管理 | package-management/package-series | ✅ 已存在 | -| 15 | 商品管理-套餐管理 | package-management/package-list | ✅ 已存在 | -| 16 | 商品管理-套餐分配 | package-management/package-assign | ✅ 已存在 | -| 17 | 资产管理-单卡信息 | card-management/single-card | ✅ 已存在 | -| 18 | 资产管理-网卡管理 | card-management/card-list | ✅ 已存在 | -| 19 | 资产管理-设备管理 | device-management/devices | ✅ 已存在 | -| 20 | 资产管理-资产分配 | asset-management/asset-assign | ✅ 已创建 | -| 21 | 资产管理-换卡申请 | asset-management/card-replacement-request | ✅ 已创建 | -| 22 | 批量操作-网卡导入 | batch/sim-import | ✅ 已创建 | -| 23 | 批量操作-设备导入 | batch/device-import | ✅ 已创建 | -| 24 | 批量操作-线下批量充值 | card-management/offline-batch-recharge | ✅ 已存在 | -| 25 | 批量操作-换卡通知 | batch/card-change-notice | ✅ 已创建 | - -**总计:25个功能全部实现 ✅** - ---- - -## 🔧 配置文件更新 - -### 1. 路由别名配置 -**文件**: `src/router/routesAlias.ts` - -新增路由别名: -```typescript -// 账号管理(扩展) -EnterpriseCustomer = '/account-management/enterprise-customer' -CustomerCommission = '/account-management/customer-commission' - -// 产品管理(扩展) -SimCardAssign = '/product/sim-card-assign' - -// 资产管理(新增模块) -AssetAssign = '/asset-management/asset-assign' -CardReplacementRequest = '/asset-management/card-replacement-request' -``` - -### 2. 异步路由配置 -**文件**: `src/router/routes/asyncRoutes.ts` - -新增路由模块: -- 账号管理模块:扩展2个子路由(企业客户、客户佣金) -- 产品管理模块:扩展1个子路由(号卡分配) -- 资产管理模块:新增模块,2个子路由(资产分配、换卡申请) - -### 3. 国际化配置 -**文件**: `src/locales/langs/zh.json` - -新增菜单标题: -```json -{ - "menus": { - "accountManagement": { - "enterpriseCustomer": "企业客户管理", - "customerCommission": "客户账号佣金" - }, - "product": { - "simCardAssign": "号卡分配" - }, - "assetManagement": { - "title": "资产管理", - "assetAssign": "资产分配", - "cardReplacementRequest": "换卡申请" - } - } -} -``` - ---- - -## 📝 页面功能特性 - -### 🔑 核心功能亮点 - -#### 1. 企业客户管理(EnterpriseCustomer) -- ✨ 企业信息完整管理(企业名称、统一社会信用代码、地址) -- 📄 营业执照上传功能 -- 👤 联系人信息管理 -- 🔐 企业端独立登录账号(不能登录管理端) -- 🎭 角色分配,依赖客户角色决定能力边界 -- 💰 初始余额设置 -- 📊 卡片和设备数量统计 -- ✅ 状态管理(正常/禁用/待审核) - -#### 2. 客户账号佣金(CustomerCommission) -- 📈 统计卡片展示(客户总数、累计佣金、已提现、待提现) -- 🔍 多维度筛选(客户类型、佣金范围) -- 💵 佣金明细查看(来源、订单号、佣金金额、比例) -- 📜 提现记录追踪(提现单号、金额、手续费、状态) -- 📊 排序功能(按佣金、提现金额排序) -- 📤 数据导出功能 - -#### 3. 号卡分配(SimCardAssign) -- 🎯 为代理商分配号卡产品 -- 💰 三种分佣模式: - - 固定佣金(每张固定金额) - - 比例佣金(按百分比) - - 模板佣金(使用预设模板) -- 🎁 特殊折扣设置 -- 📊 库存管理和分配数量追踪 -- 📝 分配记录查询 -- ❌ 取消分配功能(恢复库存) - -#### 4. 资产分配(AssetAssign) -- 🔀 三种分配模式: - - 网卡批量分配(仅分配网卡) - - 设备批量分配(仅分配设备) - - 网卡+设备分配(网卡有绑定设备时同时分配) -- ✅ 批量选择功能 -- 🎯 分配给指定代理商 -- 📝 分配说明和备注 -- 📊 分配历史记录 -- ⚠️ 资产所有权转移警告 - -#### 5. 换卡申请管理(CardReplacementRequest) -- 📈 统计卡片(待处理、处理中、已完成、已拒绝) -- 🔄 状态流转:待处理 → 处理中 → 已完成 -- 🆕 填充新卡ICCID功能 -- ✅ ICCID验证(长度、是否已使用) -- ❌ 申请拒绝(需填写拒绝原因) -- 📊 申请详情查看 -- 🔍 多条件筛选(状态、日期范围) - ---- - -## 🎨 统一设计规范 - -### UI组件使用 -- ✅ ArtTable - 自定义表格组件 -- ✅ ElCard - 卡片容器 -- ✅ ElDialog - 对话框 -- ✅ ElForm - 表单 -- ✅ ElDescriptions - 描述列表 -- ✅ ElTag - 标签 -- ✅ ElProgress - 进度条 -- ✅ ElUpload - 文件上传 - -### 交互模式 -- ✅ 搜索 + 筛选 + 操作按钮布局 -- ✅ 列表 + 详情对话框模式 -- ✅ 确认对话框(删除、状态变更) -- ✅ 表单验证和错误提示 -- ✅ 加载状态和进度展示 - -### 数据展示 -- ✅ 统计卡片(带图标和渐变色) -- ✅ 状态标签(不同颜色区分) -- ✅ 金额格式化显示 -- ✅ 时间格式化显示 -- ✅ 空状态提示 - ---- - -## 🚀 如何访问新页面 - -开发服务器运行在 `http://localhost:3006` - -### 账号管理模块 -- `/account-management/customer-role` - 客户角色 -- `/account-management/agent` - 代理商管理 -- `/account-management/customer-account` - 客户账号管理 -- `/account-management/enterprise-customer` - 企业客户管理 ⭐ 新增 -- `/account-management/customer-commission` - 客户账号佣金 ⭐ 新增 - -### 财务管理模块 -- `/finance/withdrawal` - 提现管理 -- `/finance/my-account` - 我的账户 -- `/finance/withdrawal-settings` - 提现设置 - -### 设置管理模块 -- `/settings/payment-merchant` - 支付商户 -- `/settings/developer-api` - 开发者API -- `/settings/commission-template` - 分佣模板 - -### 商品管理模块 -- `/product/sim-card` - 网卡产品管理 -- `/product/sim-card-assign` - 号卡分配 ⭐ 新增 - -### 资产管理模块 -- `/asset-management/asset-assign` - 资产分配 ⭐ 新增 -- `/asset-management/card-replacement-request` - 换卡申请 ⭐ 新增 - -### 批量操作模块 -- `/batch/sim-import` - 网卡批量导入 -- `/batch/device-import` - 设备批量导入 -- `/batch/card-change-notice` - 换卡通知 - ---- - -## 📊 开发统计 - -### 代码规模 -- **Vue组件**: 18个 -- **总代码行数**: 约 6000+ 行 -- **TypeScript接口**: 50+ 个 -- **Mock数据**: 完整覆盖 - -### 开发时间 -- **第一批页面**: 13个(约2小时) -- **第二批页面**: 5个(约1小时) -- **配置更新**: 路由+国际化(约30分钟) -- **总计**: 约3.5小时 - -### 功能覆盖率 -- ✅ CRUD操作: 100% -- ✅ 搜索筛选: 100% -- ✅ 状态管理: 100% -- ✅ 表单验证: 100% -- ✅ 数据统计: 100% - ---- - -## 🎯 下一步工作建议 - -### 1. API 对接 🔌 -- [ ] 将所有 Mock 数据替换为真实 API 调用 -- [ ] 统一错误处理和提示 -- [ ] 添加请求拦截器和响应拦截器 -- [ ] 实现 Token 刷新机制 -- [ ] 处理接口超时和重试 - -### 2. 权限控制 🔐 -- [ ] 按钮级权限控制(v-permission 指令) -- [ ] 数据权限过滤(根据用户角色) -- [ ] 路由权限守卫(动态路由注册) -- [ ] 操作日志记录 - -### 3. 数据验证 ✅ -- [ ] 完善表单验证规则 -- [ ] 后端数据校验 -- [ ] 异常数据处理 -- [ ] 防重复提交 - -### 4. 性能优化 ⚡ -- [ ] 列表虚拟滚动(大数据量) -- [ ] 组件懒加载 -- [ ] 图片懒加载 -- [ ] 防抖节流 -- [ ] 缓存策略 - -### 5. 用户体验 ✨ -- [ ] 骨架屏loading -- [ ] 空状态优化 -- [ ] 错误页面优化 -- [ ] 操作引导(新手引导) -- [ ] 快捷键支持 - -### 6. 测试 🧪 -- [ ] 单元测试(Vitest) -- [ ] 集成测试 -- [ ] E2E 测试(Playwright) -- [ ] 性能测试 -- [ ] 兼容性测试 - ---- - -## 📚 相关文档 - -- [任务规划文档](./任务规划.md) -- [页面创建模板](./页面创建模板.md) -- [API对接说明](./API对接说明.md) -- [功能需求文档](./功能.md) - ---- - -## ✨ 项目亮点 - -### 1. 完整性 ✅ -- 25个功能需求全部实现 -- 页面布局统一美观 -- 交互流程完整合理 - -### 2. 规范性 📐 -- 代码风格统一 -- TypeScript 类型完整 -- 组件复用率高 -- 命名规范清晰 - -### 3. 可维护性 🔧 -- 模块化清晰 -- Mock数据结构完整 -- 注释清晰 -- 易于扩展 - -### 4. 用户体验 🎨 -- 界面美观大方 -- 操作流程顺畅 -- 反馈及时明确 -- 状态提示清晰 - ---- - -## 🎉 总结 - -本次开发共完成 **18 个新页面组件**,配合项目中已有的页面,完整实现了物联网卡管理系统的全部 **25 个功能模块**。 - -**开发完成度**: 100% ✅ -**代码质量**: 优秀 ⭐⭐⭐⭐⭐ -**可维护性**: 优秀 👍 -**用户体验**: 优秀 🎨 - -所有页面均遵循统一的代码规范,使用 Mock 数据进行开发,界面美观、交互流畅,为后续 API 对接和功能扩展打下了坚实基础。 - -项目已经具备完整的功能框架,可以直接对接后端API进行真实数据调试。恭喜项目顺利完成!🎊 diff --git a/openspec/changes/update-exchange-flow-direct-type/design.md b/openspec/changes/update-exchange-flow-direct-type/design.md new file mode 100644 index 0000000..d1f6a33 --- /dev/null +++ b/openspec/changes/update-exchange-flow-direct-type/design.md @@ -0,0 +1,136 @@ +## Context + +现有换货管理系统仅支持物流换货流程,包含:创建 → 待填写信息 → 待发货 → 已发货 → 已完成 五个阶段。部分场景下(如现场换货、远程换货等),不需要物流环节,直接完成换货即可。 + +后端已实现直接换货类型的数据库字段和 API 接口升级,前端需要适配新的接口规范和 UI 交互。 + +## Goals / Non-Goals + +### Goals + +- 支持创建直接换货单,自动完成换货流程 +- 适配后端新增的 flow_type、shipped_at、completed_at 字段 +- 根据流程类型动态控制 UI 展示和操作权限 +- 保持向后兼容,历史数据正常展示 + +### Non-Goals + +- 不涉及客户端换货接口改造 +- 不修改换货单状态定义 +- 不改变物流换货的原有流程逻辑 + +## Decisions + +### 1. 流程类型枚举定义 + +```typescript +export enum ExchangeFlowType { + SHIPPING = 'shipping', // 物流换货 + DIRECT = 'direct' // 直接换货 +} + +export const EXCHANGE_FLOW_TYPE_MAP = { + [ExchangeFlowType.SHIPPING]: '物流换货', + [ExchangeFlowType.DIRECT]: '直接换货' +} +``` + +**Rationale**: 使用枚举统一管理流程类型,避免硬编码字符串,方便维护和扩展。 + +### 2. 创建表单的条件渲染 + +使用 `v-if` 根据选中的 flow_type 动态显示字段: + +- flow_type = 'direct' 时,显示"新资产标识符"和"是否迁移数据" +- flow_type = 'shipping' 时,隐藏这些字段 + +**Rationale**: 符合 Element Plus 表单最佳实践,避免不必要的字段提交。 + +**Alternatives considered**: +- 使用 `v-show` 隐藏:会导致隐藏字段仍参与表单验证 +- 使用动态表单项:增加复杂度,不够直观 + +### 3. 详情页按钮权限控制 + +在详情页组件中定义计算属性: + +```typescript +const canShip = computed(() => + exchange.value.flow_type === 'shipping' && exchange.value.status === 2 +) + +const canComplete = computed(() => + exchange.value.flow_type === 'shipping' && exchange.value.status === 3 +) + +const canCancel = computed(() => + exchange.value.flow_type === 'shipping' && [1, 2].includes(exchange.value.status) +) +``` + +**Rationale**: 将权限逻辑集中在计算属性中,模板中直接使用 `v-if`,代码清晰且易于测试。 + +### 4. 信息区块隐藏策略 + +对于 direct 类型,收货信息和物流信息区块采用以下策略: + +- **选择方案**: 使用 `v-if="exchange.flow_type === 'shipping'"` 完全隐藏 +- **原因**: direct 类型这些字段为 null,显示空白区块或"不适用"会造成页面冗余 + +**Alternatives considered**: +- 显示"不适用"占位:增加不必要的视觉噪音 +- 显示空区块:用户体验不佳 + +### 5. API 错误处理 + +后端对不合法操作返回 400 错误,前端需要: + +1. 在操作按钮级别根据 flow_type 和 status 做前置检查(优先) +2. 对后端返回的错误消息直接展示(兜底) + +**Rationale**: 前置检查提供更好的用户体验,后端错误处理作为安全兜底。 + +## Risks / Trade-offs + +### Risk: 历史数据 flow_type 为空 + +**Mitigation**: 后端承诺 flow_type 为空时等同于 'shipping',前端在渲染时做兼容处理: + +```typescript +const flowType = exchange.flow_type || 'shipping' +``` + +### Trade-off: UI 复杂度增加 + +引入流程类型后,详情页的条件渲染逻辑增多。 + +**Mitigation**: +- 使用计算属性封装权限判断逻辑 +- 添加单元测试覆盖不同流程类型的渲染场景 + +## Migration Plan + +### 阶段 1: API 类型升级(无破坏性) + +- 更新 TypeScript 接口定义 +- 向后兼容,不影响现有调用 + +### 阶段 2: UI 适配(向后兼容) + +- 列表页新增流程类型列和筛选 +- 详情页新增时间戳展示 +- 历史数据按 shipping 处理,正常显示 + +### 阶段 3: 创建功能升级(新增能力) + +- 新增流程类型选择 +- 支持创建 direct 类型换货单 + +### 阶段 4: 测试与发布 + +- 功能测试、回归测试 +- 灰度发布,监控错误 + +## Open Questions + +无 diff --git a/openspec/changes/update-exchange-flow-direct-type/proposal.md b/openspec/changes/update-exchange-flow-direct-type/proposal.md new file mode 100644 index 0000000..10079ae --- /dev/null +++ b/openspec/changes/update-exchange-flow-direct-type/proposal.md @@ -0,0 +1,27 @@ +# Change: 换货流程升级 - 新增直接换货类型 + +## Why + +现有换货流程仅支持物流换货(shipping),需要填写收货信息、发货、确认完成等多个步骤,流程较长。部分场景下需要支持直接换货(direct),即创建后立即完成,无需物流环节,提升换货效率。 + +## What Changes + +- **新增** 换货流程类型(flow_type)字段,支持 `shipping`(物流换货)和 `direct`(直接换货)两种类型 +- **新增** 发货时间(shipped_at)和完成时间(completed_at)字段,用于记录换货流程关键时间节点 +- **修改** 创建换货单接口,支持选择流程类型和直接换货参数 +- **修改** 换货单列表接口,新增流程类型筛选和资产标识符模糊查询 +- **修改** 换货单详情接口,返回流程类型和时间戳信息 +- **修改** 发货、确认完成、取消换货接口,增加流程类型限制逻辑 +- **BREAKING** direct 类型换货单不支持发货、确认完成和取消操作 +- **BREAKING** 取消换货仅支持 shipping 流程且状态为待填写信息或待发货时 + +## Impact + +- **Affected specs**: exchange-management(新建) +- **Affected code**: + - `src/api/modules/exchange.ts` - API 类型定义和接口调用 + - 换货单列表页面 - 新增流程类型列和筛选项 + - 换货单详情页面 - 根据流程类型控制按钮和信息区块显示 + - 创建换货单弹窗 - 新增流程类型选择和相关字段 +- **Database**: `tb_exchange_order` 表新增 `flow_type`、`shipped_at`、`completed_at` 字段 +- **API compatibility**: 向后兼容,历史数据 flow_type 为空时视为 shipping diff --git a/openspec/changes/update-exchange-flow-direct-type/specs/exchange-management/spec.md b/openspec/changes/update-exchange-flow-direct-type/specs/exchange-management/spec.md new file mode 100644 index 0000000..b8f549f --- /dev/null +++ b/openspec/changes/update-exchange-flow-direct-type/specs/exchange-management/spec.md @@ -0,0 +1,199 @@ +## ADDED Requirements + +### Requirement: 换货流程类型支持 + +系统 SHALL 支持两种换货流程类型:物流换货(shipping)和直接换货(direct),用于满足不同场景下的换货需求。 + +#### Scenario: 创建物流换货单 + +- **WHEN** 用户选择"物流换货"类型创建换货单 +- **THEN** 换货单状态为"待填写信息"(status=1),flow_type 为 "shipping" +- **AND** 需要后续填写收货信息、发货、确认完成等步骤 + +#### Scenario: 创建直接换货单 + +- **WHEN** 用户选择"直接换货"类型并填写新资产标识符创建换货单 +- **THEN** 换货单状态为"已完成"(status=4),flow_type 为 "direct" +- **AND** completed_at 字段记录当前时间 +- **AND** 无需填写收货信息和发货流程 + +#### Scenario: 历史数据兼容 + +- **WHEN** 读取 flow_type 为空的历史换货单 +- **THEN** 系统应将其视为"物流换货"(shipping)类型 +- **AND** 按照物流换货流程展示和处理 + +### Requirement: 换货时间戳记录 + +系统 SHALL 记录换货流程中的关键时间节点,包括发货时间(shipped_at)和完成时间(completed_at)。 + +#### Scenario: 物流换货发货时间记录 + +- **WHEN** 物流换货单执行发货操作 +- **THEN** shipped_at 字段记录发货时间 +- **AND** 换货单状态变更为"已发货"(status=3) + +#### Scenario: 物流换货完成时间记录 + +- **WHEN** 物流换货单确认完成 +- **THEN** completed_at 字段记录完成时间 +- **AND** 换货单状态变更为"已完成"(status=4) + +#### Scenario: 直接换货完成时间记录 + +- **WHEN** 创建直接换货单 +- **THEN** completed_at 字段立即记录创建时间 +- **AND** shipped_at 字段为 null(无发货环节) + +### Requirement: 创建换货单流程类型选择 + +用户在创建换货单时 SHALL 能够选择换货流程类型,并根据选择的类型填写相应的必填字段。 + +#### Scenario: 选择直接换货时必填新资产标识符 + +- **WHEN** 用户选择"直接换货"类型 +- **THEN** 表单必须显示"新资产标识符"输入框(必填) +- **AND** 必须显示"是否迁移数据"开关(可选,默认 false) + +#### Scenario: 选择物流换货时隐藏直接换货字段 + +- **WHEN** 用户选择"物流换货"类型 +- **THEN** 表单不显示"新资产标识符"和"是否迁移数据"字段 +- **AND** 仅需填写换货原因、旧资产类型和旧资产标识符 + +#### Scenario: 提交直接换货单参数 + +- **WHEN** 用户提交直接换货单 +- **THEN** 请求参数 MUST 包含 flow_type="direct"、new_identifier 和 migrate_data +- **AND** 后端返回状态为"已完成"的换货单 + +### Requirement: 换货单列表流程类型筛选 + +用户在换货单列表页 SHALL 能够按流程类型筛选换货单,并查看流程类型信息。 + +#### Scenario: 显示流程类型列 + +- **WHEN** 用户查看换货单列表 +- **THEN** 列表 MUST 显示"流程类型"列 +- **AND** 该列显示"物流换货"或"直接换货" + +#### Scenario: 按流程类型筛选 + +- **WHEN** 用户在筛选区选择流程类型(全部/物流换货/直接换货) +- **THEN** 列表仅显示选中类型的换货单 +- **AND** 查询参数 flow_type 传递对应值(shipping/direct) + +#### Scenario: 资产标识符模糊查询 + +- **WHEN** 用户输入资产标识符进行搜索 +- **THEN** 系统同时匹配旧资产标识符和新资产标识符 +- **AND** 返回所有匹配的换货单 + +### Requirement: 换货单详情流程类型展示 + +换货单详情页 SHALL 根据流程类型动态展示相关信息和时间戳。 + +#### Scenario: 显示流程类型和时间戳 + +- **WHEN** 用户查看换货单详情 +- **THEN** 详情页 MUST 显示"流程类型"字段(物流换货/直接换货) +- **AND** 对于物流换货,显示"发货时间"(shipped_at,已发货后有值) +- **AND** 对于所有已完成的换货单,显示"完成时间"(completed_at) + +#### Scenario: 直接换货隐藏收货和物流信息 + +- **WHEN** 用户查看直接换货单详情 +- **THEN** 详情页不显示"收货信息"区块 +- **AND** 详情页不显示"物流信息"区块 + +#### Scenario: 物流换货正常显示所有信息 + +- **WHEN** 用户查看物流换货单详情 +- **THEN** 详情页显示"收货信息"区块(填写后有值) +- **AND** 详情页显示"物流信息"区块(发货后有值) + +## MODIFIED Requirements + +### Requirement: 换货单发货操作限制 + +系统 SHALL 仅允许物流换货单执行发货操作,直接换货单不支持发货。 + +**原有行为**: 所有状态为"待发货"的换货单均可执行发货操作。 + +**新行为**: 仅 flow_type="shipping" 且 status=2(待发货)的换货单可执行发货操作。 + +#### Scenario: 物流换货单可以发货 + +- **WHEN** 换货单 flow_type="shipping" 且 status=2 +- **THEN** 详情页显示"发货"按钮 +- **AND** 用户可以填写快递公司、快递单号等信息并提交 + +#### Scenario: 直接换货单不可发货 + +- **WHEN** 换货单 flow_type="direct" +- **THEN** 详情页不显示"发货"按钮 +- **AND** 如果前端误调用发货接口,后端返回 400 错误:"流程类型不支持该操作" + +#### Scenario: 前端阻止不合法发货操作 + +- **WHEN** 详情页加载换货单数据 +- **THEN** 前端根据 flow_type 和 status 判断是否显示"发货"按钮 +- **AND** 仅在 flow_type="shipping" 且 status=2 时显示 + +### Requirement: 换货单确认完成操作限制 + +系统 SHALL 仅允许物流换货单在已发货状态下执行确认完成操作,直接换货单自动完成。 + +**原有行为**: 状态为"已发货"的换货单可执行确认完成操作。 + +**新行为**: 仅 flow_type="shipping" 且 status=3(已发货)的换货单可执行确认完成操作。 + +#### Scenario: 物流换货单可以确认完成 + +- **WHEN** 换货单 flow_type="shipping" 且 status=3 +- **THEN** 详情页显示"确认完成"按钮 +- **AND** 用户点击后换货单状态变更为"已完成" + +#### Scenario: 直接换货单不可确认完成 + +- **WHEN** 换货单 flow_type="direct" +- **THEN** 详情页不显示"确认完成"按钮 +- **AND** 如果前端误调用完成接口,后端返回 400 错误 + +#### Scenario: 前端阻止不合法完成操作 + +- **WHEN** 详情页加载换货单数据 +- **THEN** 前端根据 flow_type 和 status 判断是否显示"确认完成"按钮 +- **AND** 仅在 flow_type="shipping" 且 status=3 时显示 + +### Requirement: 换货单取消操作限制 + +系统 SHALL 仅允许物流换货单在待填写信息或待发货状态下取消,直接换货单和已发货的物流换货单不可取消。 + +**原有行为**: 状态为"待填写信息"或"待发货"的换货单可取消。 + +**新行为**: 仅 flow_type="shipping" 且 status IN (1, 2) 的换货单可取消。 + +#### Scenario: 物流换货单待发货前可取消 + +- **WHEN** 换货单 flow_type="shipping" 且 status=1 或 status=2 +- **THEN** 详情页显示"取消"按钮 +- **AND** 用户可以取消换货单 + +#### Scenario: 物流换货单已发货后不可取消 + +- **WHEN** 换货单 flow_type="shipping" 且 status=3 +- **THEN** 详情页不显示"取消"按钮 +- **AND** 如果前端误调用取消接口,后端返回错误 + +#### Scenario: 直接换货单不可取消 + +- **WHEN** 换货单 flow_type="direct" +- **THEN** 详情页不显示"取消"按钮 +- **AND** 如果前端误调用取消接口,后端返回 400 错误:"流程类型不支持该操作" + +#### Scenario: 前端阻止不合法取消操作 + +- **WHEN** 详情页加载换货单数据 +- **THEN** 前端根据 flow_type 和 status 判断是否显示"取消"按钮 +- **AND** 仅在 flow_type="shipping" 且 status IN (1, 2) 时显示 diff --git a/openspec/changes/update-exchange-flow-direct-type/tasks.md b/openspec/changes/update-exchange-flow-direct-type/tasks.md new file mode 100644 index 0000000..f71139c --- /dev/null +++ b/openspec/changes/update-exchange-flow-direct-type/tasks.md @@ -0,0 +1,55 @@ +## 1. API 类型定义更新 + +- [x] 1.1 更新 `ExchangeQueryParams` 接口,新增 `flow_type` 和 `identifier` 查询参数 +- [x] 1.2 更新 `CreateExchangeRequest` 接口,新增 `flow_type`、`new_identifier`、`migrate_data` 字段 +- [x] 1.3 更新 `ExchangeResponse` 接口,新增 `flow_type`、`flow_type_name`、`shipped_at`、`completed_at` 字段 + +## 2. 创建换货单功能 + +- [x] 2.1 更新创建换货单弹窗,新增流程类型选择器(单选:物流换货/直接换货) +- [x] 2.2 实现流程类型切换逻辑,direct 时显示新资产标识符和数据迁移开关 +- [x] 2.3 更新表单验证规则,direct 时 new_identifier 必填 +- [x] 2.4 更新 API 调用,传递完整的创建参数 + +## 3. 换货单列表功能 + +- [x] 3.1 新增流程类型列,显示"物流换货"或"直接换货" +- [x] 3.2 新增流程类型筛选下拉框(全部/物流换货/直接换货) +- [x] 3.3 更新资产标识符搜索为模糊查询(同时匹配旧资产和新资产) +- [x] 3.4 更新列表查询参数,支持 flow_type 和 identifier 筛选 + +## 4. 换货单详情功能 + +- [x] 4.1 新增流程类型展示字段(flow_type_name) +- [x] 4.2 新增发货时间(shipped_at)和完成时间(completed_at)展示 +- [x] 4.3 根据 flow_type 控制操作按钮显示: + - direct 类型隐藏"发货"、"确认完成"、"取消"按钮 + - shipping + status=1 仅显示"取消" + - shipping + status=2 显示"发货"和"取消" + - shipping + status=3 仅显示"确认完成" +- [x] 4.4 根据 flow_type 控制信息区块显示: + - direct 类型隐藏或标记"不适用"收货信息和物流信息区块 + +## 5. 发货功能 + +- [x] 5.1 在发货前检查 flow_type,仅允许 shipping 类型 +- [x] 5.2 对 direct 类型返回的 400 错误进行友好提示 + +## 6. 确认完成功能 + +- [x] 6.1 在确认完成前检查 flow_type,仅允许 shipping 且 status=3 +- [x] 6.2 对 direct 类型返回的错误进行友好提示 + +## 7. 取消换货功能 + +- [x] 7.1 在取消前检查 flow_type 和 status,仅允许 shipping 且 status 为 1 或 2 +- [x] 7.2 对不符合条件的操作返回友好提示 + +## 8. 测试与验证 + +- [ ] 8.1 测试创建物流换货单,验证原有流程正常 +- [ ] 8.2 测试创建直接换货单,验证自动完成逻辑 +- [ ] 8.3 测试列表筛选,验证 flow_type 和 identifier 查询正确 +- [ ] 8.4 测试详情页按钮和区块显示,验证不同流程类型的 UI 差异 +- [ ] 8.5 测试操作限制,验证 direct 类型不可发货、完成、取消 +- [ ] 8.6 测试历史数据兼容性,验证 flow_type 为空时视为 shipping diff --git a/src/api/modules/exchange.ts b/src/api/modules/exchange.ts index cabe1e8..dc432e2 100644 --- a/src/api/modules/exchange.ts +++ b/src/api/modules/exchange.ts @@ -10,7 +10,8 @@ export interface ExchangeQueryParams { page?: number page_size?: number status?: number // 换货状态 - identifier?: string // 资产标识符(模糊匹配) + flow_type?: string // 流程类型(shipping/direct) + identifier?: string // 资产标识符(模糊匹配,同时匹配旧资产、新资产) created_at_start?: string // 创建时间起始 created_at_end?: string // 创建时间结束 } @@ -20,6 +21,9 @@ export interface CreateExchangeRequest { exchange_reason: string // 换货原因 old_asset_type: string // 旧资产类型 (iot_card 或 device) old_identifier: string // 旧资产标识符(ICCID/虚拟号/IMEI/SN) + flow_type?: string // 流程类型(shipping/direct),默认 shipping + new_identifier?: string // 新资产标识符(direct 时必填) + migrate_data?: boolean // 是否迁移数据(默认 false) remark?: string // 备注(可选) } @@ -34,6 +38,10 @@ export interface ExchangeResponse { new_asset_identifier: string status: number // 换货状态(1:待填写信息, 2:待发货, 3:已发货待确认, 4:已完成, 5:已取消) status_text: string + flow_type: string // 流程类型(shipping/direct) + flow_type_name: string // 流程类型名称 + shipped_at?: string | null // 发货时间(仅 shipping 发货后有值) + completed_at?: string | null // 换货完成时间 recipient_name?: string recipient_phone?: string recipient_address?: string diff --git a/src/views/asset-management/exchange-management/detail.vue b/src/views/asset-management/exchange-management/detail.vue index a41d1e4..26ea3c0 100644 --- a/src/views/asset-management/exchange-management/detail.vue +++ b/src/views/asset-management/exchange-management/detail.vue @@ -55,9 +55,15 @@ return types[status] || 'info' } - // 详情页配置 - const detailSections: DetailSection[] = [ - { + // 根据流程类型动态生成详情页配置 + const detailSections = computed(() => { + if (!exchangeDetail.value) return [] + + const flowType = exchangeDetail.value.flow_type || 'shipping' // 历史数据兼容 + const sections: DetailSection[] = [] + + // 基本信息 + sections.push({ title: '基本信息', fields: [ { label: '换货单号', prop: 'exchange_no' }, @@ -65,6 +71,10 @@ label: '状态', render: (data) => h(ElTag, { type: getStatusType(data.status) }, () => data.status_text) }, + { + label: '流程类型', + formatter: (_, data) => data.flow_type_name || (flowType === 'direct' ? '直接换货' : '物流换货') + }, { label: '换货原因', prop: 'exchange_reason', @@ -86,44 +96,57 @@ prop: 'new_asset_identifier' } ] - }, - { - title: '收货信息', - fields: [ - { - label: '收货人姓名', - formatter: (value) => value || '--', - prop: 'recipient_name' - }, - { - label: '收货人电话', - formatter: (value) => value || '--', - prop: 'recipient_phone' - }, - { - label: '收货地址', - formatter: (value) => value || '--', - prop: 'recipient_address', - fullWidth: true - } - ] - }, - { - title: '物流信息', - fields: [ - { - label: '快递公司', - formatter: (value) => value || '--', - prop: 'express_company' - }, - { - label: '快递单号', - formatter: (value) => value || '--', - prop: 'express_no' - } - ] - }, - { + }) + + // 收货信息(仅物流换货显示) + if (flowType === 'shipping') { + sections.push({ + title: '收货信息', + fields: [ + { + label: '收货人姓名', + formatter: (value) => value || '--', + prop: 'recipient_name' + }, + { + label: '收货人电话', + formatter: (value) => value || '--', + prop: 'recipient_phone' + }, + { + label: '收货地址', + formatter: (value) => value || '--', + prop: 'recipient_address', + fullWidth: true + } + ] + }) + + // 物流信息(仅物流换货显示) + sections.push({ + title: '物流信息', + fields: [ + { + label: '快递公司', + formatter: (value) => value || '--', + prop: 'express_company' + }, + { + label: '快递单号', + formatter: (value) => value || '--', + prop: 'express_no' + }, + { + label: '发货时间', + formatter: (value) => (value ? formatDateTime(value) : '--'), + prop: 'shipped_at' + } + ] + }) + } + + // 其他信息 + sections.push({ title: '其他信息', fields: [ { @@ -132,6 +155,11 @@ prop: 'remark', fullWidth: true }, + { + label: '完成时间', + formatter: (value) => (value ? formatDateTime(value) : '--'), + prop: 'completed_at' + }, { label: '创建时间', formatter: (value) => formatDateTime(value), @@ -143,8 +171,10 @@ prop: 'updated_at' } ] - } - ] + }) + + return sections + }) // 加载换货单详情 const loadExchangeDetail = async () => { diff --git a/src/views/asset-management/exchange-management/index.vue b/src/views/asset-management/exchange-management/index.vue index 6a795b5..c400998 100644 --- a/src/views/asset-management/exchange-management/index.vue +++ b/src/views/asset-management/exchange-management/index.vue @@ -50,6 +50,25 @@ @closed="handleCloseCreateDialog" > + + + + + + + + 物流换货:需要填写收货信息、发货等步骤 + + + 直接换货:创建后自动完成,无需物流环节 + + + + + + + + {{ card.iccid }} + + {{ card.msisdn || '无接入号' }} + + + + + + + + + + {{ device.virtual_no }} + + {{ device.device_name || device.imei }} + + + + + + + + + 开启后将迁移钱包余额、套餐记录到新资产 + + { + if (createForm.flow_type !== 'direct') { + callback() + return + } + + if (!value || !value.trim()) { + callback(new Error('请输入新资产标识符')) + return + } + + callback() + } + const createRules = reactive({ exchange_reason: [{ required: true, message: '请选择换货原因', trigger: 'change' }], exchange_reason_other: [{ validator: validateOtherExchangeReason, trigger: 'blur' }], old_asset_type: [{ required: true, message: '请选择旧资产类型', trigger: 'change' }], - old_identifier: [{ required: true, message: '请选择旧资产标识符', trigger: 'change' }] + old_identifier: [{ required: true, message: '请选择旧资产标识符', trigger: 'change' }], + flow_type: [{ required: true, message: '请选择流程类型', trigger: 'change' }], + new_identifier: [{ validator: validateNewIdentifier, trigger: 'blur' }] }) // 旧资产搜索相关 @@ -299,6 +406,12 @@ const oldDeviceOptions = ref([]) const oldDeviceSearchLoading = ref(false) + // 新资产搜索相关(直接换货使用) + const newIotCardOptions = ref([]) + const newCardSearchLoading = ref(false) + const newDeviceOptions = ref([]) + const newDeviceSearchLoading = ref(false) + // 发货表单 const shipForm = reactive({ new_identifier: '', @@ -338,6 +451,19 @@ { label: '已取消', value: 5 } ] }, + { + label: '流程类型', + prop: 'flow_type', + type: 'select', + config: { + clearable: true, + placeholder: '全部' + }, + options: () => [ + { label: '物流换货', value: 'shipping' }, + { label: '直接换货', value: 'direct' } + ] + }, { label: '资产标识符', prop: 'identifier', @@ -384,6 +510,12 @@ minWidth: 150, showOverflowTooltip: true }, + { + prop: 'flow_type', + label: '流程类型', + width: 120, + formatter: (row: any) => row.flow_type_name || (row.flow_type === 'direct' ? '直接换货' : '物流换货') + }, { prop: 'old_asset_type', label: '旧资产类型', @@ -474,6 +606,9 @@ if (searchForm.status !== undefined && searchForm.status !== null) { params.status = searchForm.status } + if (searchForm.flow_type) { + params.flow_type = searchForm.flow_type + } if (searchForm.identifier) { params.identifier = searchForm.identifier } @@ -547,6 +682,25 @@ } } + // 流程类型变更 + const handleFlowTypeChange = async () => { + // 清空新资产标识符和数据迁移选项 + createForm.new_identifier = '' + createForm.migrate_data = false + newIotCardOptions.value = [] + newDeviceOptions.value = [] + createFormRef.value?.clearValidate('new_identifier') + + // 如果选择直接换货且已选择旧资产类型,加载默认新资产列表 + if (createForm.flow_type === 'direct' && createForm.old_asset_type) { + if (createForm.old_asset_type === 'iot_card') { + await loadDefaultNewIotCards() + } else if (createForm.old_asset_type === 'device') { + await loadDefaultNewDevices() + } + } + } + // 旧资产类型变更 const handleOldAssetTypeChange = async () => { // 清空旧资产标识符 @@ -554,11 +708,26 @@ oldIotCardOptions.value = [] oldDeviceOptions.value = [] + // 清空新资产标识符(如果是直接换货) + if (createForm.flow_type === 'direct') { + createForm.new_identifier = '' + newIotCardOptions.value = [] + newDeviceOptions.value = [] + } + // 根据类型加载默认数据 if (createForm.old_asset_type === 'iot_card') { await loadDefaultIotCards() + // 如果是直接换货,也加载新资产列表 + if (createForm.flow_type === 'direct') { + await loadDefaultNewIotCards() + } } else if (createForm.old_asset_type === 'device') { await loadDefaultDevices() + // 如果是直接换货,也加载新资产列表 + if (createForm.flow_type === 'direct') { + await loadDefaultNewDevices() + } } } @@ -664,6 +833,102 @@ } } + // 搜索新IoT卡(直接换货使用) + const searchNewIotCards = async (query: string) => { + if (!query) { + // 清空搜索时加载默认列表 + await loadDefaultNewIotCards() + return + } + + newCardSearchLoading.value = true + try { + const res = await CardService.getStandaloneIotCards({ + iccid: query, + page: 1, + page_size: 20 + }) + if (res.code === 0 && res.data) { + newIotCardOptions.value = res.data.items || [] + if (newIotCardOptions.value.length === 0) { + ElMessage.info('未找到匹配的IoT卡') + } + } + } catch (error) { + console.error('搜索IoT卡失败:', error) + newIotCardOptions.value = [] + } finally { + newCardSearchLoading.value = false + } + } + + // 加载默认新IoT卡列表 + const loadDefaultNewIotCards = async () => { + newCardSearchLoading.value = true + try { + const res = await CardService.getStandaloneIotCards({ + page: 1, + page_size: 10 + }) + if (res.code === 0 && res.data) { + newIotCardOptions.value = res.data.items || [] + } + } catch (error) { + console.error('加载IoT卡列表失败:', error) + newIotCardOptions.value = [] + } finally { + newCardSearchLoading.value = false + } + } + + // 搜索新设备(直接换货使用) + const searchNewDevices = async (query: string) => { + if (!query) { + // 清空搜索时加载默认列表 + await loadDefaultNewDevices() + return + } + + newDeviceSearchLoading.value = true + try { + const res = await DeviceService.getDevices({ + keyword: query, + page: 1, + page_size: 20 + }) + if (res.code === 0 && res.data) { + newDeviceOptions.value = res.data.items || [] + if (newDeviceOptions.value.length === 0) { + ElMessage.info('未找到匹配的设备') + } + } + } catch (error) { + console.error('搜索设备失败:', error) + newDeviceOptions.value = [] + } finally { + newDeviceSearchLoading.value = false + } + } + + // 加载默认新设备列表 + const loadDefaultNewDevices = async () => { + newDeviceSearchLoading.value = true + try { + const res = await DeviceService.getDevices({ + page: 1, + page_size: 10 + }) + if (res.code === 0 && res.data) { + newDeviceOptions.value = res.data.items || [] + } + } catch (error) { + console.error('加载设备列表失败:', error) + newDeviceOptions.value = [] + } finally { + newDeviceSearchLoading.value = false + } + } + // 确认创建 const handleConfirmCreate = () => { createFormRef.value?.validate(async (valid) => { @@ -676,12 +941,21 @@ ? createForm.exchange_reason_other.trim() : createForm.exchange_reason - const res = await ExchangeService.createExchange({ + const requestData: any = { exchange_reason: exchangeReason, old_asset_type: createForm.old_asset_type, old_identifier: createForm.old_identifier, + flow_type: createForm.flow_type, remark: createForm.remark || undefined - }) + } + + // 直接换货时需要传递新资产标识符和数据迁移标志 + if (createForm.flow_type === 'direct') { + requestData.new_identifier = createForm.new_identifier + requestData.migrate_data = createForm.migrate_data + } + + const res = await ExchangeService.createExchange(requestData) if (res.code === 0) { ElMessage.success('换货单创建成功') createDialogVisible.value = false @@ -701,6 +975,8 @@ // 清空搜索选项 oldIotCardOptions.value = [] oldDeviceOptions.value = [] + newIotCardOptions.value = [] + newDeviceOptions.value = [] } // 查看详情 @@ -712,7 +988,22 @@ const getActions = (row: ExchangeResponse) => { const actions: any[] = [] const status = row.status + const flowType = row.flow_type || 'shipping' // 历史数据兼容 + // 直接换货不支持任何操作(发货、确认完成、取消) + if (flowType === 'direct') { + // 状态4(已完成):旧资产转新(direct 也支持) + if (status === 4 && hasAuth('exchange:renew')) { + actions.push({ + label: '旧资产转新', + handler: () => handleRenewExchange(row), + type: 'warning' + }) + } + return actions + } + + // 物流换货流程 // 状态1(待填写信息):取消换货 if (status === 1) { if (hasAuth('exchange:cancel')) { diff --git a/src/views/package-management/package-series/index.vue b/src/views/package-management/package-series/index.vue index 060472f..570015e 100644 --- a/src/views/package-management/package-series/index.vue +++ b/src/views/package-management/package-series/index.vue @@ -968,7 +968,7 @@ // 构建请求数据 const data: any = { series_name: form.series_name, - description: form.description || undefined, + description: form.description, enable_one_time_commission: form.one_time_commission_config.enable }