From dc6e423299dfccfbb97639da690e44e3309555db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=90=B4=E6=96=87=E5=B3=B0?= Date: Wed, 29 Apr 2026 11:55:56 +0800 Subject: [PATCH] up --- .workbuddy/memory/2026-04-29.md | 7 + .workbuddy/memory/MEMORY.md | 546 +++++---- backend/my_work/main.go | 1 + backend/my_work/routers/api.go | 1 + backend/my_work/routers/apiCustomer.go | 11 + .../routers/{api_Files.go => apiFiles.go} | 0 frontend/ops_vue_js/src/router/index.js | 2 +- frontend/ops_vue_js/src/views/AdminView.vue | 16 - .../ops_vue_js/src/views/SysAdminView.vue | 1088 ----------------- .../src/views/sysadmin/GroupsTab.vue | 436 +++++++ .../ops_vue_js/src/views/sysadmin/LogsTab.vue | 198 +++ .../src/views/sysadmin/SysAdminView.vue | 126 ++ .../src/views/sysadmin/UsersTab.vue | 364 ++++++ frontend/ops_vue_js/vite.config.js | 12 +- 14 files changed, 1428 insertions(+), 1380 deletions(-) create mode 100644 .workbuddy/memory/2026-04-29.md create mode 100644 backend/my_work/routers/apiCustomer.go rename backend/my_work/routers/{api_Files.go => apiFiles.go} (100%) delete mode 100644 frontend/ops_vue_js/src/views/AdminView.vue delete mode 100644 frontend/ops_vue_js/src/views/SysAdminView.vue create mode 100644 frontend/ops_vue_js/src/views/sysadmin/GroupsTab.vue create mode 100644 frontend/ops_vue_js/src/views/sysadmin/LogsTab.vue create mode 100644 frontend/ops_vue_js/src/views/sysadmin/SysAdminView.vue create mode 100644 frontend/ops_vue_js/src/views/sysadmin/UsersTab.vue diff --git a/.workbuddy/memory/2026-04-29.md b/.workbuddy/memory/2026-04-29.md new file mode 100644 index 0000000..656dfa5 --- /dev/null +++ b/.workbuddy/memory/2026-04-29.md @@ -0,0 +1,7 @@ +# 2026-04-29 工作日志 + +- 修复 SysAdminView.vue 第 849 行 `` 占位符 bug(上一轮 i18n 修改误删内容),恢复为 `avatar` +- 在 `en.json` 的 `message` 节点补充缺失的 `"sysadmin": "System Admin"` 翻译 +- 全面重新分析代码结构,更新并精简 MEMORY.md(整合后端 main.go 启动流程、apiSysAdmin 完整路由、前端路由守卫逻辑、stores/user.js isSysAdmin 机制等) +- 将 SysAdminView.vue 拆分为三个子组件:`src/views/sysadmin/UsersTab.vue`(用户管理+详情弹窗)、`GroupsTab.vue`(用户组+添加/移除成员)、`LogsTab.vue`(登录失败日志);父组件改用 v-show 保持子组件挂载,UsersTab 自身 onMounted 加载数据,Groups/Logs 由父组件 watch(activeTab) 懒加载 +- 将 SysAdminView.vue 整体移入 `src/views/sysadmin/` 目录,并更新 router/index.js 中的引用路径为 `@/views/sysadmin/SysAdminView.vue` diff --git a/.workbuddy/memory/MEMORY.md b/.workbuddy/memory/MEMORY.md index 796c11e..62fe6cb 100644 --- a/.workbuddy/memory/MEMORY.md +++ b/.workbuddy/memory/MEMORY.md @@ -1,182 +1,220 @@ # MEMORY.md - 长效记忆 -## 项目架构 +> 最后更新: 2026-04-29 + +--- + +## 项目概览 **项目名称**: OPS 运营管理系统 -**技术栈**: Vue 3 + TypeScript (前端) / Go + Gin + GORM (后端) +**技术栈**: Vue 3 + Vite (前端 Web) / uni-app (移动端) / Go + Gin + GORM (后端) -### 目录结构 ``` ops2/ -├── backend/my_work/ # Go 后端(端口 8080) +├── backend/my_work/ # Go 后端(端口由 config.yaml 决定,默认 8080) ├── frontend/ -│ ├── ops_vue_js/ # Vue 3 Web 前端 -│ └── ops2_uniapp/ # uni-app 移动端(待开发) +│ ├── ops_vue_js/ # Vue 3 Web 前端 +│ └── ops2_uniapp/ # uni-app 移动端 └── DOC/ ``` +--- + ## 后端架构 -### 入口: `backend/my_work/main.go` -- 配置读取: `data/config.yaml`,无则复制 `defConfig/configTemp.yaml` -- 支持 SQLite/MySQL/PostgreSQL -- 按顺序初始化路由:User → Files → Schedule → Purchase → WorkOrder → Warehouse +### 启动流程 (`main.go`) +1. 检查 `./data/config.yaml`,不存在则复制 `./defConfig/configTemp.yaml` +2. `configed` 必须为 `true` 才能启动 +3. 初始化顺序:`ReturnInit` → `ApiUserInit` → `ApiFilesInit` → `ApiScheduleInit` → `ApiPurchaseInit` → `ApiWorkOrderInit` → `ApiWarehouseInit` → `BindsInit` +4. 静态文件服务 `./dist`,所有非 `/api` 请求转发给前端 HTML +5. 支持 TLS(证书路径在 config 中配置) +6. 版本信息通过 `-ldflags -X` 编译注入(`GitVersion / GitCommit / BuildTime`) -### 核心模块 (`backend/my_work/routers/`) -| 文件 | 用途 | -|------|------| -| `apiUsers.go` | 用户认证(登录/注册/Cookie) | -| `apiFiles.go` | 文件上传/管理 | -| `apiSchedule.go` | 日程排班 | -| `apiPurchase.go` | 采购订单 | -| `apiWorkOrder.go` | 工单管理 | -| `apiWarehouse.go` | 仓库管理(容器+物品) | -| `apiStatic.go` | 静态资源 | +### 路由根 (`api.go`) +``` +/api +├── /static → ApiStatic +├── /users → ApiUser +├── /files → ApiFiles +├── /purchase → ApiPurchase +├── /schedule → ApiSchedule +├── /work_order → ApiWorkOrder +├── /warehouse → ApiWarehouse +└── /admin → ApiSysAdmin +``` + +### 请求/响应格式 +```json +// 请求体 +{ "userCookieValue": "xxx", "data": { ...业务参数 } } + +// 响应体 +{ "err_code": 0, "err_msg": "apiOK", "return": { ... } } +``` +错误码从 `./defConfig/errorCodes.json` 读取,常用:`apiOK`=0,`userNoLogin`=-44,`permission_denied`,`parameErr`,`dbErr` + +### 认证机制 +- 登录成功返回 Cookie 对象(存 `TabUserCookie` 表) +- 后续请求通过 JSON body 中 `userCookieValue` 传递 +- Cookie 过期后端返回 err_code=-44,前端拦截器自动处理 +- `AuthenticationAuthority(ctx)` → 分离 cookie 和 data,验证返回 `(isAuth bool, user TabUser, data map)` + +--- ## 用户认证模块 (`apiUsers.go`) -### 核心函数 -- `AuthenticationAuthorityFromCookie(c string)` - 验证 Cookie 并返回用户 -- `AuthenticationAuthority(ctx)` - 通用认证函数,分离 Cookie 和 data -- `GetUserInfoFromUserID(userID uint)` - 通过 ID 获取用户详情 +### 数据表 +| 表 | 说明 | +|---|---| +| `TabUser` | 用户(Name 唯一索引) | +| `TabUserGroups` | 用户组 | +| `TabUserGroupBinds` | 用户-组绑定 | +| `TabUserInfo` | 用户详情(头像/昵称/性别/生日/语言等) | +| `TabUserCookie` | 登录 Cookie(ExpiresAt,Remember 字段) | +| `TabUserLoginFailLog` | 登录失败日志(24小时内聚合,累计 Count) | -### 用户组 -- 自动创建 `admins` 组和 `admin` 用户(默认密码:adminpassword) -- 各功能模块独立创建管理员组:`purchase_admin`、`work_order_admin`、`schedule_admin`、`warehouse_admin` +### 初始化 +- 自动创建 `admins` 组 + `admin` 用户(默认密码 `adminpassword`) +- 密码:加盐哈希,支持 `text` / `md5` / `md5salt`(config 指定) + +### 权限缓存(内存) +各模块维护各自的管理员 ID 列表: +| 变量 | 所属模块 | 刷新函数 | +|---|---|---| +| `sysAdmins []uint` | apiUsers.go | `updateSysAdminsCash()` | +| `scheduleAdmins []uint` | apiSchedule.go | `ScheduleUpdateAdminsCash()` | +| `purchaseAdmins []uint` | apiPurchase.go | `PurchaseUpdateAdminsCash()` | +| `workOrderAdmins []uint` | apiWorkOrder.go | `WorkOrderUpdateAdminsCash()` | +| `warehouseAdmins []uint` | apiWarehouse.go | `WarehouseUpdateAdminsCash()` | + +**修改用户组时自动刷新缓存**(`apiSysAdmin.go` 的 `add_group_member` 和 `remove_group_member`): +```go +switch group.Name { +case "admins": updateSysAdminsCash() +case "schedule_admin": ScheduleUpdateAdminsCash() +case "purchase_admin": PurchaseUpdateAdminsCash() +case "work_order_admin": WorkOrderUpdateAdminsCash() +case "warehouse_admin": WarehouseUpdateAdminsCash() +} +``` ### API 路由 (`/api/users/*`) | 路由 | 用途 | |------|------| -| `POST /login` | 用户登录(返回 Cookie) | -| `POST /register` | 用户注册 | -| `POST /getinfo` | 获取当前用户信息 | -| `POST /changePassword` | 修改密码 | +| `POST /login` | 登录(返回 Cookie 对象,含 Remember) | +| `POST /register` | 注册 | +| `POST /getinfo` | 获取当前用户信息(含 isSysAdmin 字段) | +| `POST /changePassword` | 修改密码(oldpass/newpass) | | `POST /changeEmail` | 修改邮箱 | -| `POST /updateAvatar` | 更新头像(FormData 上传) | -| `POST /updateInfo` | 更新用户详情 | +| `POST /updateAvatar` | 更新头像(FormData) | +| `POST /updateInfo` | 更新详情(firstName/username/birthdate/gender/region/language) | | `GET /getuserinfo/:id` | 获取指定用户信息 | -| `GET/POST /test` | 测试接口 | -### 密码机制 -- 密码加盐哈希(Salt + Hash) -- 支持 `text` / `md5` / `md5salt` 三种哈希类型(配置指定) +--- -## 文件管理模块 (`apiFiles.go`) +## 系统管理模块 (`apiSysAdmin.go`) -### 数据表 -- `TabFileInfo_` - 文件元数据(SHA256 哈希为唯一标识) +**路由前缀**: `/api/admin/*`,全部要求 `SysAdminCheck` -| 字段 | 说明 | +| 路由 | 用途 | |------|------| -| `Sha256` | 文件哈希(主键/索引) | +| `POST /sysadmins` | 获取系统管理员 ID 列表 | +| `POST /users` | 用户列表(分页+搜索,返回含头像路径) | +| `POST /groups` | 用户组列表(含成员数 + 前5个成员ID) | +| `POST /group_members` | 指定组的成员列表(分页) | +| `POST /user_detail` | 用户详情(基本信息 + userinfo) | +| `POST /reset_user_password` | 重置密码(同时注销该用户所有 cookie) | +| `POST /add_group_member` | 添加用户到组(含缓存刷新) | +| `POST /remove_group_member` | 从组移除用户(含缓存刷新) | +| `POST /login_fail_logs` | 登录失败日志(分页+搜索 username/IP) | + +`SysAdminCheck(userID)` 直接查内存 `sysAdmins` 列表。 + +--- + +## 文件管理模块 (`api_Files.go`) + +### 数据表 `TabFileInfo` +| 字段 | 说明 | +|---|---| +| `Sha256` | 唯一标识,去重键 | | `Name` | 原始文件名 | | `Path` | 存储路径 | | `Mime` | MIME 类型 | -| `Type` | 文件类型(image/video/pdf 等) | -| `Const` | 引用计数(同文件多次上传只存一份) | - -### API 路由 (`/api/files/*`) -| 路由 | 用途 | -|------|------| -| `POST /upload/image` | 上传图片(FormData,含 SHA256 去重) | -| `GET /:mode/:hash` | 获取文件(mode=get 下载,mode=download 预览) | +| `Type` | image/video/pdf 等 | +| `Const` | 引用计数 | ### 存储结构 ``` data/ -├── static/avatar/ # 用户头像 +├── static/avatar/ # 用户头像(/api/static/avatar/:filename) └── upload/ - ├── image/ # 图片(以 SHA256 命名) + ├── image/ # 以 SHA256 命名 ├── video/ ├── music/ └── pdf/ ``` -## 日程排班模块 (`apiSchedule.go`) +### API (`/api/files/*`) +| 路由 | 用途 | +|---|---| +| `POST /upload/image` | 上传图片(FormData + SHA256 去重) | +| `GET /:mode/:hash` | `get`=下载(带文件名),`download`=预览 | + +--- + +## 日程模块 (`apiSchedule.go`) ### 数据表 -| 表 | 用途 | +- `TabSchedule`(软删除):Title / StartDate / EndDate / BgColor(默认#3788d9) / Remark +- `TabScheduleLog`:操作日志 + +### API (`/api/schedule/*`) +| 路由 | 用途 | |---|---| -| `TabSchedule` | 日程(软删除) | -| `TabScheduleLog` | 操作日志 | +| `POST /getevents` | 按日期范围查询(`start_date <= end AND end_date >= start`) | +| `POST /addevent` | 新增 | +| `POST /editevent` | 编辑 | +| `POST /deleevent` | 软删除 | -### 日程结构 -| 字段 | 说明 | -|------|------| -| `Title` | 日程标题 | -| `StartDate` | 开始日期(YYYY-MM-DD) | -| `EndDate` | 结束日期(YYYY-MM-DD) | -| `BgColor` | 背景颜色(默认 #3788d9) | -| `Remark` | 备注 | +--- -### API 路由 (`/api/schedule/*`) -| 路由 | 用途 | -|------|------| -| `POST /getevents` | 获取日程列表(按日期范围) | -| `POST /addevent` | 新增日程 | -| `POST `/editevent`` | 编辑日程 | -| `POST /deleevent` | 删除日程(软删除) | - -### 查询逻辑 -```sql -WHERE start_date <= :end AND end_date >= :start -``` - -## 静态资源模块 (`apiStatic.go`) - -| 路由 | 用途 | -|------|------| -| `GET /static/avatar/:filename` | 获取用户头像 | - -### 数据库模型 (`backend/my_work/models/sql.go`) -- `TabUser_` - 用户 -- `TabUserGroups_` - 用户组 -- `TabUserInfo_` - 用户详情 -- `TabCookie_` - 登录 Cookie(有效期 604800 秒) -- `APIRequestLog_` - API 日志 - -### 仓库模块核心表 (`apiWarehouse.go`) -- `TabWarehouseContainer` - 容器(树形,最多5层嵌套) -- `TabWarehouseItem` - 物品 -- `TabWarehouseItemCommit` - 物品移动记录 -- `TabWarehouseLog` - 操作日志 -- `TabWarehouseItemWorkOrderBind` - 物品-工单关联 - -## 采购模块 (`backend/my_work/routers/apiPurchase.go`) +## 采购模块 (`apiPurchase.go`) ### 数据表 | 表 | 用途 | |---|---| | `TabPurchaseOrder` | 采购订单(软删除) | -| `TabPurchaseCosts` | 费用明细(单价/运费,支持多币种) | +| `TabPurchaseCosts` | 费用明细(单价/运费,多币种) | | `TabPurchaseFileBind` | 图片关联 | | `TabPurchaseCommit` | 状态变更记录 | | `TabPurchaseLog` | 操作日志 | -### 订单状态流程 +### 状态流 ``` -pending(待处理) → ordered(已下单) → arrived(已到达) → received(已收件) - ↓ - lost(丢件) / returned(退件) +pending → ordered → arrived → received + ↓ + lost / returned ``` -### 货币类型 -`1-CNY` / `2-MOP` / `3-HKD` / `4-USD` +### 货币:`1-CNY / 2-MOP / 3-HKD / 4-USD` -### API 路由 (`/api/purchase/*`) +### API (`/api/purchase/*`) | 路由 | 用途 | -|------|------| -| `POST /getorder` | 获取订单详情(含费用、图片、状态记录、关联工单) | -| `POST /getorders` | 获取订单列表(支持搜索、分页、状态筛选) | -| `POST /addorder` | 新增订单 | -| `POST /updateorder` | 编辑订单(含费用、图片重建) | -| `POST /deleteorder` | 删除订单 | -| `POST /updatestatus` | 更新订单状态(可附评论/图片) | +|---|---| +| `POST /getorder` | 订单详情(含费用/图片/状态记录/关联工单) | +| `POST /getorders` | 列表(搜索/分页/状态筛选) | +| `POST /addorder` | 新增 | +| `POST /updateorder` | 编辑(费用/图片重建) | +| `POST /deleteorder` | 删除 | +| `POST /updatestatus` | 更新状态(可附评论/图片) | | `POST /delete_commit` | 删除状态记录 | -| `POST /getordercount` | 统计各状态数量 | +| `POST /getordercount` | 各状态数量统计 | | `POST /search_work_orders` | 搜索工单(用于关联) | -## 工单模块 (`backend/my_work/routers/apiWorkOrder.go`) +--- + +## 工单模块 (`apiWorkOrder.go`) ### 数据表 | 表 | 用途 | @@ -184,191 +222,161 @@ pending(待处理) → ordered(已下单) → arrived(已到达) → received( | `TabWorkOrder` | 工单(软删除) | | `TabWorkOrderFileBind` | 工单图片关联 | | `TabWorkOrderCommit` | 进度记录 | -| `TabWorkOrderLog` | 操作日志 | | `TabWorkOrderCommitFileBind` | 进度关联图片 | -| `TabWorkOrderPurchaseOrderBind` | 工单-采购订单关联 | +| `TabWorkOrderPurchaseOrderBind` | 工单-采购订单关联(含 CommitID) | +| `TabWorkOrderLog` | 操作日志 | -### 工单状态流程 +### 状态流 ``` -pending(待处理) → checked(已检查) → parts_ordered(已下单零件) → repaired(已维修) → returned(已送还) - ↓ - unrepairable(无法维修) +pending → checked → parts_ordered → repaired → returned + ↓ + unrepairable ``` -### 关联关系 -- 工单 ↔ 仓库物品 (`TabWarehouseItemWorkOrderBind`) -- 工单 ↔ 采购订单 (`TabWorkOrderPurchaseOrderBind`) -- 特殊逻辑:状态变更为 `returned` 时,自动移除物品的容器绑定 +### 特殊逻辑 +- 状态变为 `returned` 时,自动移除物品的容器绑定(`ContainerID = nil`) +- 工单 ↔ 物品:`TabWarehouseItemWorkOrderBind` +- 工单 ↔ 采购:`TabWorkOrderPurchaseOrderBind` -### API 路由 (`/api/work_order/*`) +### API (`/api/work_order/*`) | 路由 | 用途 | -|------|------| -| `POST /add` | 新增工单(可关联物品) | -| `POST /update` | 编辑工单 | -| `POST /list` | 获取工单列表 | -| `POST /get` | 获取工单详情(含图片、进度、关联物品/采购订单) | -| `POST /commit` | 提交进度(更新状态,可关联采购订单) | -| `POST /delete` | 删除工单 | +|---|---| +| `POST /add` | 新增(可关联物品) | +| `POST /update` | 编辑 | +| `POST /list` | 列表 | +| `POST /get` | 详情(含图片/进度/关联物品/采购) | +| `POST /commit` | 提交进度(更新状态,可关联采购) | +| `POST /delete` | 删除 | | `POST /delete_commit` | 删除进度 | -| `POST /count` | 统计各状态数量 | +| `POST /count` | 各状态统计 | | `POST /search_purchase_orders` | 搜索采购订单(用于关联) | -## 前端架构 +--- -### Web 前端 (`frontend/ops_vue_js/`) +## 仓库模块 (`apiWarehouse.go`) -**技术栈**: Vue 3 + Vite 7 + Pinia + Vue Router + Vue I18n +### 数据表 +| 表 | 用途 | +|---|---| +| `TabWarehouseContainer` | 容器(树形,最多5层,ParentID=nil为顶级) | +| `TabWarehouseItem` | 物品(ContainerID=nil表示未入库) | +| `TabWarehouseItemCommit` | 物品移动记录 | +| `TabWarehouseLog` | 操作日志 | -**项目结构**: +### 跨模块绑定表 (`binds.go`) +| 表 | 用途 | +|---|---| +| `TabWarehouseItemWorkOrderBind` | 物品-工单 | +| `TabWarehouseItemFileBind` | 物品-图片 | +| `TabWarehouseContainerFileBind` | 容器-图片 | +| `TabPurchaseFileBind` | 采购-图片 | +| `TabWorkOrderFileBind` | 工单-图片 | +| `TabWorkOrderCommitFileBind` | 工单进度-图片 | +| `TabWorkOrderPurchaseOrderBind` | 工单-采购 | + +--- + +## Web 前端架构 (`frontend/ops_vue_js/`) + +**技术栈**: Vue 3 + Vite 7 + Pinia + Vue Router (hash 模式) + Vue I18n + Tailwind CSS v4 + Tabler Icons + +### 目录结构 ``` src/ -├── api/ # API 封装层 -│ ├── index.js # Axios 实例 + 拦截器 + 统一调用接口 -│ ├── auth.js # 认证 API (登录/注册/用户信息/密码修改) -│ ├── purchase.js # 采购订单 API -│ ├── warehouse.js # 仓库管理 API -│ ├── work_order.js # 工单管理 API -│ ├── schedule.js # 日程管理 API -│ └── users.js # 其他用户信息 API -├── components/ # 公共组件 -├── composables/ # Vue 组合式函数 (Hooks) -├── i18n/ # 国际化 (en.json, zh-CN.json) -├── layouts/ # 页面布局 (AuthLayout, DefaultLayout) -├── router/ # 路由配置 -├── stores/ # Pinia 状态管理 -├── views/ # 页面视图 -└── main.js # 应用入口 +├── api/ +│ ├── index.js # Axios 实例,基础 URL /api,请求拦截注入 cookie,响应拦截处理 -44 +│ ├── auth.js # 认证 + sysadmin 管理 API +│ ├── purchase.js # 采购 API +│ ├── warehouse.js # 仓库 API +│ ├── work_order.js # 工单 API +│ ├── schedule.js # 日程 API +│ └── users.js # 其他用户信息 API(按需加载头像/用户名) +├── components/ +│ ├── AppHeader.vue # 导航栏(含系统管理入口,权限判断 isSysAdmin) +│ ├── AppFooter.vue +│ ├── AppToast.vue +│ ├── ConfirmDialog.vue +│ ├── PurchaseOrderForm.vue +│ ├── SettingNav.vue +│ ├── tagadder.vue +│ ├── useDropzone.vue # 文件拖拽上传 +│ ├── imageCropper.vue # 图片裁剪 +│ ├── datePicker.vue +│ ├── dateTimePicker.vue +│ └── datatimePickerForFullCalendar.vue +├── composables/ +├── i18n/ +│ ├── en.json # 英文翻译 +│ └── zh-CN.json # 中文翻译 +├── layouts/ +│ ├── DefaultLayout.vue # 需要登录的页面布局 +│ └── AuthLayout.vue # 认证页面全屏布局 +├── router/index.js +├── stores/ +│ ├── user.js # 当前用户(isLoggedIn / isSysAdmin / cookie / avatarUrl) +│ ├── users.js # 其他用户信息缓存(按需拉取,防重复请求) +│ └── toast.js # 全局 Toast +└── views/ + ├── HomeView.vue + ├── ScheduleView.vue # FullCalendar + ├── SysAdminView.vue # 系统管理(仅 sysAdmin 可访问,meta.requireSysAdmin) + ├── AdminView.vue + ├── purchase/ # PurchaseList / addorder / ShowOrder / editorder + ├── work_order/ # WorkOrderList / AddEditWorkOrder / ShowWorkOrder + ├── warehouse/ # WarehouseOverview / ContainerList / ContainerDetail / ItemList / ItemDetail / AddItem / ItemEdit + └── settings/ # AccountView / ContactView / SecurityView ``` -**API 封装** (`src/api/index.js`): -- 基于 Axios,基础 URL: `/api` -- 请求拦截器自动注入 `userCookieValue` -- 响应拦截器处理 Cookie 过期 (err_code: -44) -- 统一返回 `{ errCode, data, raw }` 格式 -- 支持文件上传 (FormData) +### 路由说明 +- 公开页:`/` `/login` `/register` `/forgot_password` `/schedule` `/404` +- `/sysadmin` 需要 `meta.requireSysAdmin`,不满足跳回首页 +- 未登录跳转 `/login?redirect=原路径` -**路由** (`src/router/index.js`): -- 使用 `createWebHashHistory`(hash 模式) -- 认证页面: `/login`, `/register`, `/forgot_password` -- 需要登录的页面在白名单外 +### 状态管理 (`stores/user.js`) +- Cookie 持久化:`Remember=true` 存 localStorage,否则只存 sessionStorage +- `isSysAdmin` 由 `/users/getinfo` 返回的 `isSysAdmin` 字段驱动 +- `fetchUserInfo()` 在 `login()` 后自动调用 -**页面视图** (`src/views/`): -| 模块 | 页面 | -|------|------| -| 首页 | `HomeView.vue` | -| 日程 | `ScheduleView.vue` (FullCalendar) | -| 采购 | `PurchaseList.vue`, `addorder.vue`, `ShowOrder.vue`, `editorder.vue` | -| 工单 | `WorkOrderList.vue`, `AddEditWorkOrder.vue`, `ShowWorkOrder.vue` | -| 仓库 | `WarehouseOverview.vue`, `WarehouseContainerList.vue`, `WarehouseContainerDetail.vue`, `WarehouseItemList.vue`, `WarehouseItemDetail.vue`, `WarehouseAddItem.vue`, `WarehouseItemEdit.vue` | -| 设置 | `AccountView.vue`, `ContactView.vue`, `SecurityView.vue` | +### i18n 翻译节点 +`week / errorpage / appname / tagadder / dropzone / cropper / purchase / work_order / warehouse / purchase_addorder / schedule / home / message / settings / button / footer / cost_type / order_status / sysadmin` -**状态管理** (`src/stores/`): -- `user.js`: 用户状态 (登录/登出/会话恢复/用户信息) -- `toast.js`: 全局 Toast 通知 -- `users.js`: 其他用户信息缓存 - -**样式方案**: -- Tailwind CSS v4 -- Tabler Icons -- 亮色/暗色模式支持 - -**国际化**: `src/i18n/en.json`, `zh-CN.json` -- 覆盖模块: week, errorpage, appname, tagadder, dropzone, cropper, purchase, work_order, warehouse, purchase_addorder, schedule, home, message, settings, button, footer, cost_type, order_status - -**构建配置** (`vite.config.js`): -- 输出目录: `../../backend/my_work/dist` +### 构建配置 +- 输出目录: `../../backend/my_work/dist`(后端直接 serve) - 开发代理: `/api` → `http://127.0.0.1:8080` - 路径别名: `@` → `./src` -### 移动端 (`frontend/ops2_uniapp/`) +--- -**技术栈**: uni-app + Vue 3 + Pinia + HBuilderX +## 移动端 (`frontend/ops2_uniapp/`) -**项目结构**: -``` -ops2_uniapp/ -├── api/ # API 接口封装 -│ ├── index.js # 基础请求工具(框架已有,方法待实现) -│ ├── request.js # 请求配置(待完善) -│ └── user.js # 用户接口 -├── components/ -│ └── my-toast/ # 自定义 Toast 组件 -├── pages/ # 页面 -│ ├── index/index.vue # 主页 TabBar(占位) -│ ├── order/order.vue # 订单 TabBar(占位) -│ ├── message/message.vue # 消息 TabBar(占位) -│ ├── user/user.vue # 用户 TabBar(基础框架) -│ ├── login/login.vue # 登录页(已完成 85%) -│ └── settings/settings.vue # 设置页(已完成 90%) -├── stores/ -│ ├── config.js # 配置 Store(完整) -│ └── user.js # 用户 Store(基础) -├── utils/ -│ └── index.js # 工具函数(isUrl) -├── pages.json # 路由配置 -├── manifest.json # 应用配置 -└── package.json # 依赖(pinia) -``` +**技术栈**: uni-app + Vue 3 + Pinia -**Stores 状态管理**: -- `useConfigStore`: apiBaseUrl / appName / version / theme - - `setApiBaseUrl()` / `getApiBaseUrl()` - API 地址持久化 -- `useUserStore`: username / token - - `setUser()` / `logout()` +**当前完成度**: ~40% -**API 封装状态**: -- `api/index.js`: 框架有,get/post/upload 方法空实现 -- 登录页直接使用 `uni.request()` 调用,绕过了封装层 -- 需要完善 Cookie 认证机制(参照 Web 前端) +| 页面 | 完成度 | +|---|---| +| login | 85%(表单/验证/请求/Toast) | +| settings | 90%(API 地址配置/连接测试) | +| index/order/message | 5%(占位) | +| user | 20%(登录入口) | -**页面完成度**: -| 页面 | 完成度 | 说明 | -|------|--------|------| -| index | 5% | 占位文本 | -| order | 5% | 占位文本 | -| message | 5% | 占位文本 | -| user | 20% | 登录按钮 + 设置入口 | -| login | **85%** | 表单 + 验证 + 请求 + Toast | -| settings | **90%** | API 地址编辑 + 连接测试 | +**待完成**: +- 完善 `api/index.js`(Cookie 认证,参照 Web 前端) +- 实现各功能页面(仓库/工单/采购等) -**当前总完成度**: ~35-40% - -**移动端待开发**: -1. 完善 API 封装层(Cookie 认证) -2. 实现各功能页面(主页仪表盘、订单列表、消息列表、用户中心) -3. 添加更多组件(Loading、确认对话框、空状态) -4. 对接后端各模块(仓库、工单、采购等) - -## 前后端交互协议 - -### 请求格式 (POST JSON) -```json -{ - "data": { - "userCookieValue": "xxx", - ...业务参数 - } -} -``` - -### 响应格式 -```json -{ - "err_code": 0, - "return": { ... } -} -``` - -### 认证机制 -- 登录成功后服务端返回 Cookie(存储在 `TabCookie_` 表) -- 后续请求通过 `userCookieValue` 字段传递 -- Cookie 过期码: -44 +--- ## 开发注意事项 -1. **移动端开发时**: 需要完善 `api/index.js` 的请求封装,参照 Web 前端实现 Cookie 认证 -2. **仓库模块**: 是当前开发重点,支持树形容器、物品管理、工单关联 -3. **同源部署**: 后端直接 serve `./dist` 静态文件,简化部署 +1. **后端 JSON 字段命名**: 结构体字段为 PascalCase(如 `UserID / AvatarPath`),前端需对应 +2. **头像**: `usersStore.getAvatarUrlFromUserID(id)` 返回 `/api/static/avatar/{path}` 或默认 `/ava.svg` +3. **i18n 修改**: 同时修改 `en.json` 和 `zh-CN.json` 两个文件 +4. **同源部署**: 后端 serve `./dist` 静态资源,前端 build 直接输出到后端目录 +5. **API 封装**: `api/index.js` 统一返回 `{ errCode, data, raw }` + +--- ## 更新记录 -- 2026-04-24: 首次梳理项目运行逻辑,保存长效记忆 +- 2026-04-24: 首次梳理 +- 2026-04-28: 修复 SysAdminView 中 `` 误删 bug;添加 message.sysadmin 英文翻译 +- 2026-04-29: 全面重新分析代码,更新并精简记忆文档 diff --git a/backend/my_work/main.go b/backend/my_work/main.go index cc61dd7..a8e0393 100644 --- a/backend/my_work/main.go +++ b/backend/my_work/main.go @@ -80,6 +80,7 @@ func main() { routers.ApiPurchaseInit() routers.ApiWorkOrderInit() routers.ApiWarehouseInit() + routers.ApiCustomerInit() routers.BindsInit() //最后初始化绑定数据表 diff --git a/backend/my_work/routers/api.go b/backend/my_work/routers/api.go index 4e4b3fc..4a202df 100644 --- a/backend/my_work/routers/api.go +++ b/backend/my_work/routers/api.go @@ -44,6 +44,7 @@ func ApiRoot(r *gin.RouterGroup) { ApiWorkOrder(r.Group("/work_order")) ApiWarehouse(r.Group("/warehouse")) ApiSysAdmin(r.Group("/admin")) + ApiCustomer(r.Group("/customer")) r.GET("/", func(ctx *gin.Context) { ReturnJson(ctx, "apiOK", gin.H{ "isOpsApiRoot": true, diff --git a/backend/my_work/routers/apiCustomer.go b/backend/my_work/routers/apiCustomer.go new file mode 100644 index 0000000..c7f3df6 --- /dev/null +++ b/backend/my_work/routers/apiCustomer.go @@ -0,0 +1,11 @@ +package routers + +import "github.com/gin-gonic/gin" + +func ApiCustomerInit() { + +} + +func ApiCustomer(r *gin.RouterGroup) { + +} diff --git a/backend/my_work/routers/api_Files.go b/backend/my_work/routers/apiFiles.go similarity index 100% rename from backend/my_work/routers/api_Files.go rename to backend/my_work/routers/apiFiles.go diff --git a/frontend/ops_vue_js/src/router/index.js b/frontend/ops_vue_js/src/router/index.js index cab747b..77ca1d6 100644 --- a/frontend/ops_vue_js/src/router/index.js +++ b/frontend/ops_vue_js/src/router/index.js @@ -111,7 +111,7 @@ const router = createRouter({ { path: 'sysadmin', name: 'sysadmin', - component: () => import('@/views/SysAdminView.vue'), + component: () => import('@/views/sysadmin/SysAdminView.vue'), meta: { requireSysAdmin: true }, }, ], diff --git a/frontend/ops_vue_js/src/views/AdminView.vue b/frontend/ops_vue_js/src/views/AdminView.vue deleted file mode 100644 index b27fc2c..0000000 --- a/frontend/ops_vue_js/src/views/AdminView.vue +++ /dev/null @@ -1,16 +0,0 @@ - - - diff --git a/frontend/ops_vue_js/src/views/SysAdminView.vue b/frontend/ops_vue_js/src/views/SysAdminView.vue deleted file mode 100644 index a6a4b2b..0000000 --- a/frontend/ops_vue_js/src/views/SysAdminView.vue +++ /dev/null @@ -1,1088 +0,0 @@ - - - diff --git a/frontend/ops_vue_js/src/views/sysadmin/GroupsTab.vue b/frontend/ops_vue_js/src/views/sysadmin/GroupsTab.vue new file mode 100644 index 0000000..34c5a11 --- /dev/null +++ b/frontend/ops_vue_js/src/views/sysadmin/GroupsTab.vue @@ -0,0 +1,436 @@ + + + diff --git a/frontend/ops_vue_js/src/views/sysadmin/LogsTab.vue b/frontend/ops_vue_js/src/views/sysadmin/LogsTab.vue new file mode 100644 index 0000000..5837c18 --- /dev/null +++ b/frontend/ops_vue_js/src/views/sysadmin/LogsTab.vue @@ -0,0 +1,198 @@ + + + diff --git a/frontend/ops_vue_js/src/views/sysadmin/SysAdminView.vue b/frontend/ops_vue_js/src/views/sysadmin/SysAdminView.vue new file mode 100644 index 0000000..72e14af --- /dev/null +++ b/frontend/ops_vue_js/src/views/sysadmin/SysAdminView.vue @@ -0,0 +1,126 @@ + + + diff --git a/frontend/ops_vue_js/src/views/sysadmin/UsersTab.vue b/frontend/ops_vue_js/src/views/sysadmin/UsersTab.vue new file mode 100644 index 0000000..4411ee1 --- /dev/null +++ b/frontend/ops_vue_js/src/views/sysadmin/UsersTab.vue @@ -0,0 +1,364 @@ + + + diff --git a/frontend/ops_vue_js/vite.config.js b/frontend/ops_vue_js/vite.config.js index 236a601..54682dc 100644 --- a/frontend/ops_vue_js/vite.config.js +++ b/frontend/ops_vue_js/vite.config.js @@ -15,12 +15,12 @@ let packageJson = JSON.parse(readFileSync(packageJsonPath, "utf-8")); // 每次 build 时自动递增 patch 版本 const isBuild = process.argv.includes("build"); if (isBuild) { - const parts = packageJson.version.split("."); - const patch = Math.max(0, parseInt(parts[2] || "0", 10)); - parts[2] = String(patch + 1); - packageJson.version = parts.join("."); - writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2) + "\n", "utf-8"); - console.log(`[bump] version → ${packageJson.version}`); + // const parts = packageJson.version.split("."); + // const patch = Math.max(0, parseInt(parts[2] || "0", 10)); + // parts[2] = String(patch + 1); + // packageJson.version = parts.join("."); + // writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2) + "\n", "utf-8"); + // console.log(`[bump] version → ${packageJson.version}`); } // https://vite.dev/config/