新增质量模块(工艺执行书 / 样茧试缫)与报表中心
质量模块: - 11 张工艺执行书表:封面、试产、选剥茧(含混茧明细)、试缫与大样、煮茧(含分车间配温、副煮车间)、自动缫(含大样)、后缫 - 10 张样茧试缫表:原料小样/综合样主表 + 选茧、解舒、茧幅、切剖、清洁洁净、茧丝百回纤度 - 服务与接口、主控指针回写(列表 √ 标记)、封面编号自增、报表数据包 - 前端 8 张报表打印版式、7 类工艺单据与 6 类调查录入弹窗、字段驱动表单/表格组件 - 菜单种子新增「质量」目录,样茧子表增加 YjssType 判别列,避免原料小样与综合样自增 Id 重号串数据 报表中心: - 报表模板管理、锐浪 grhtml5 加载与预览、全屏设计面板、数据源 Provider(落丝记录、职工花名册) 其他:同步工作进度 1-11 文档、开发数据库快照、.gitignore 忽略运行日志目录
This commit is contained in:
+207
@@ -0,0 +1,207 @@
|
||||
# 工作进度-3:部门管理补齐管理/职责类型绑定 + 角色授权「勾了不生效」根治
|
||||
|
||||
> 时间:2026-10-20(承接工作进度-2)
|
||||
> 环境:后端 .NET 8 + FreeSql + MediatR(Windows),前端 Vue3 + Element Plus + Vite
|
||||
> 范围:①部门管理页支持绑定 `ManageType` / `DutyType`;②定位并修复角色管理「分配权限保存后不生效、该角色登录看不到菜单」
|
||||
|
||||
---
|
||||
|
||||
## 一、本轮目标
|
||||
|
||||
1. 部门管理页面支持给部门绑定 `Department_ManageType_Enum` 与 `Department_DutyType_Enum`
|
||||
2. 修复「角色管理 → 分配权限 → 勾选菜单 → 确认保存 → 重新打开仍是未勾选、该角色账号也加载不到菜单」
|
||||
3. 补齐工作进度-2 遗留第 1 条:部门增删改后刷新部门缓存
|
||||
4. 顺手修掉部门编辑会把「禁用」状态改回「启用」的连带问题
|
||||
|
||||
---
|
||||
|
||||
## 二、部门管理(ManageType / DutyType 绑定)
|
||||
|
||||
### 2.1 定位
|
||||
|
||||
后端**原本就支持**两个字段:
|
||||
|
||||
| 层 | 文件 | 说明 |
|
||||
|---|---|---|
|
||||
| 实体 | `Domain/Entities/SYS/Departments/Department.cs` | `manage_type` / `duty_type` 私有 set |
|
||||
| 命令 | `CQRS/SYS/Departments/Commands/Department_CreateCommand.cs` / `_UpdateCommand.cs` | 均带两个枚举参数 |
|
||||
| 读模型 | `Dtos/SYS/Departments/DepartmentReadDto_View.cs` | 已返回 `ManageType` / `DutyType` |
|
||||
|
||||
问题全在前端 `web/src/views/sys/department/index.vue`:
|
||||
|
||||
| 项 | 原状态 |
|
||||
|---|---|
|
||||
| 表单 | 只有「类型」= `ManageType`;`DutyType` 藏在 `form` 里固定为 5,**没有任何控件** |
|
||||
| 列表 | 只有管理类型列,看不到职责类型 |
|
||||
| 上级部门 | 平铺下拉,看不出层级;`clearable` 还会把值置空,与 `long ParentId` 不匹配 |
|
||||
| 缓存 | 保存后不刷新 `utils/departments.js` 的部门缓存 |
|
||||
|
||||
> 注:菜单里生效的是 `/sys/department` → `sys/department/index`;`/system/department` → `system/department/index` 是死代码(它调用的 `/api/department` 已被下线,菜单也被 seeder 清掉)。
|
||||
|
||||
### 2.2 改动
|
||||
|
||||
**`web/src/views/sys/department/index.vue`(重写)**
|
||||
|
||||
- 表单新增「职责类型」下拉;「管理类型」改用共享枚举,删除本地硬编码的 `manageTypeMap`
|
||||
- 列表改**树形表格**(`row-key` + `tree-props`),新增「管理类型」「职责类型」两个标签列,新增「添加子部门」
|
||||
- 上级部门改 `el-tree-select`,编辑时排除自身及子孙(防成环)
|
||||
- 保存 / 删除 / 启停后调用 `clearDepCache()`,报表部门控件立即生效
|
||||
- `parentId` 按**字符串**回传(部门 Id 是雪花 Id,`Number()` 会丢精度)
|
||||
|
||||
**`web/src/utils/departments.js`**
|
||||
|
||||
- `DUTY` 补上缺失的 `后缫整理: 115`
|
||||
- 新增 `enumOptions(map)`(枚举 → 下拉选项,按数值升序)与 `enumLabel(map, value)`(值 → 中文名)
|
||||
|
||||
**`Infrastructure/FreeSqls/Repositories/SYS/Departments/DepartmentWriteRepository.cs`**
|
||||
|
||||
- `UpdateAsync` 增加 `.IgnoreColumns(x => new { x.IsActive, x.IsDeleted, x.CreatedAt, x.CreatedBy })`
|
||||
- 原因:`Department_UpdateCommand` 用 `new Department(...)` 重建对象,构造函数里 `IsActive = true`,`SetSource` 会把「禁用」的部门一编辑就改回「启用」;启用状态本应由独立的 `/active` 命令维护
|
||||
|
||||
### 2.3 实测
|
||||
|
||||
```
|
||||
POST /api/sys/department {manageType:15(车间), dutyType:25(前缫)} → 创建成功
|
||||
PUT /api/sys/department/{id} {dutyType:115(后缫整理)} → 修改成功
|
||||
读回 => manageType=15 dutyType=115 isActive=False ✅
|
||||
```
|
||||
|
||||
运行时(无头 Edge,`/sys/department`):
|
||||
|
||||
```
|
||||
TABLE_ROWS=38
|
||||
ROW0=123 / 安泰茧丝绸 / 部门 / 其他 / 0 / 启用 / 添加子部门 编辑 禁用 删除
|
||||
FORM_ITEMS=编码|部门名称|上级部门|管理类型|职责类型|排序|描述
|
||||
SELECT_1(管理类型)=公司,部门,车间,科室,岗位,虚拟
|
||||
SELECT_2(职责类型)=其他,仓储,选剥茧,煮茧,前缫,后缫,设备办,副产品,质检,丝绵,人力资源,丝业中心,前缫管理,后缫检验,后缫整理
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 三、角色授权「勾了不生效」根治(本轮重点)
|
||||
|
||||
### 3.1 现象
|
||||
|
||||
```
|
||||
角色管理 → 分配权限 → 勾选菜单 → 确认保存(提示"权限保存成功")
|
||||
→ 再次点分配权限:之前勾的菜单仍是未勾选
|
||||
→ 用该角色的账号登录:菜单也加载不出来
|
||||
```
|
||||
|
||||
### 3.2 根因:雪花 Id 被前端 `Number()` 转成 double 后精度丢失
|
||||
|
||||
```
|
||||
真实菜单 id : 134905585693888512
|
||||
Number() 后 : 134905585693888510 ← 少 2
|
||||
Number.isSafeInteger(...) = false
|
||||
```
|
||||
|
||||
`web/src/views/sys/role/index.vue` 的 `savePermType()` 里写的是 `resourceId: Number(key)`。后端本来已经用 `LongToStringJsonConverter` 把 `long` 序列化成字符串(避免 JS 精度问题),前端又把它转回数字,等于白折腾。
|
||||
|
||||
| 环节 | 表现 |
|
||||
|---|---|
|
||||
| 保存 | `sys_rbac_permissions.resource_id` 写成 `...510`,菜单表里不存在这个 id |
|
||||
| 重新打开 | `setCheckedKeys(['...510'])` 在树里找不到节点 → 勾不上 → 显示未勾选 |
|
||||
| 登录 | `GetUserMenusAsync` 拿 `...510` 查菜单表 → 查不到 → 菜单不出现 |
|
||||
| 再点确认 | 回显是空的 → 删除逻辑把这些权限彻底删掉 |
|
||||
|
||||
**只有 id 很小的老数据(11/12/13…)不暴露此问题**。第一轮用「普通用户」角色验证时,恰好勾的都是小 id 菜单,所以误判成"功能正常"——这是本次排查的教训。
|
||||
|
||||
### 3.3 修复(4 处)
|
||||
|
||||
| # | 文件 | 改动 |
|
||||
|---|---|---|
|
||||
| 1 | `web/src/views/sys/role/index.vue` | `resourceId: Number(key)` → `resourceId: key`(字符串原样回传)。菜单 / 部门 / 报表三类授权共用此函数,一并修好 |
|
||||
| 2 | `Application/CQRS/SYS/RBAC/Roles/Commands/RolePermission_AssignCommand.cs` | 新建菜单/操作类权限单元时,用菜单自己声明的 `Permission`(如 `base:worktype:list`)作为 `Code`;原来只有消息订阅会补 `Code`,其余会退化成 `menu:{id}:visble`,导致 `v-permission` 永远匹配不上。为此注入 `IRepository<Menu>` |
|
||||
| 3 | `Infrastructure/Data/DbSeeder.cs`(`FixMenuPermissions`) | 增加**自愈**:启动时删除 `ResourceId` 不对应任何菜单的失效权限单元及其 `role_permission` 关联,修复历史脏数据 |
|
||||
| 4 | `web/src/views/sys/department/index.vue` | `parentId` 同样改为字符串回传(同类隐患) |
|
||||
|
||||
> 后端 `LongToStringJsonConverter` 的 `Read` 已兼容字符串,所以前端传字符串可以直接绑定 `long`(实测 `parentId:"1"`、`resourceId:"134905585693888512"` 均正常)。
|
||||
|
||||
### 3.4 验证
|
||||
|
||||
修复前(前缫主任,勾「工种管理」):
|
||||
|
||||
```
|
||||
API_AFTER(18)=...,42,134905585693888510 ← 尾数错
|
||||
REOPEN_CHECKED=17 MISSING_ON_REOPEN=工种管理
|
||||
```
|
||||
|
||||
修复后:
|
||||
|
||||
```
|
||||
TICKED=工种管理 now=18
|
||||
API_AFTER(18)=11,12,17,13,14,18,15,16,19,20,21,22,23,24,30,31,42,134905585693888512
|
||||
REOPEN_CHECKED=18
|
||||
PERSISTED=YES(工种管理) ✅
|
||||
```
|
||||
|
||||
用该角色真实账号(余华 / 13547542219)登录:
|
||||
|
||||
```
|
||||
LOGIN code=200 roles=1000
|
||||
MENU_TREE:
|
||||
- 考勤管理 [/attendance] → 考勤打卡 / 我的考勤 / 请假申请 / 考勤记录 / 请假审批
|
||||
- 基础数据 [/base] → 工艺庄口 / 生丝规格 / 生丝定级指标 / 机组车台 / 工种管理 ← 新加的已生效
|
||||
- 生产-前缫 [/prod/qianxian] → 落丝记录
|
||||
- 消息中心 [/notification] → 我的消息 / 消息订阅
|
||||
PERMS 含 base:worktype:list
|
||||
```
|
||||
|
||||
重启后端时的自愈日志侧证:`前缫主任` 菜单权限中「不在菜单树内」的资源 Id 由 1 条降为 **0**;`后缫检验员` / `后缫主任` 的菜单权限数由 10 → 8(清掉 2 条无效单元)。
|
||||
|
||||
---
|
||||
|
||||
## 四、验证手段(沿用工作进度-2)
|
||||
|
||||
无 Node/npm 全局环境,前端用项目内置 node:
|
||||
|
||||
```batch
|
||||
:: .run-logs\start-web.bat 内部就是这两步
|
||||
set PATH=C:\Users\32453\.workbuddy\binaries\node\versions\22.22.2-6;%PATH%
|
||||
cd /d d:\f9webaitest\f9-web-ai-test\web
|
||||
node node_modules\vite\bin\vite.js
|
||||
```
|
||||
|
||||
后端:`dotnet run --project backend\F9WebAiTest.Api\F9WebAiTest.Api.csproj`
|
||||
|
||||
SPA 运行时验证(无头 Edge):
|
||||
|
||||
```powershell
|
||||
# 1) 诊断页放 web/public/__diag_xxx.html:login 写 localStorage → history.replaceState 改路由
|
||||
# → 等 el-table 出现 → 模拟点击 → 把断言写进 <div class="L">,用完即删
|
||||
msedge --headless=new --user-data-dir=$prof --virtual-time-budget=150000 --disable-gpu --dump-dom "http://localhost:5173/__diag_xxx.html"
|
||||
```
|
||||
|
||||
要点:
|
||||
- `--virtual-time-budget` 会让 `setTimeout` 与 `fetch` 都按虚拟时钟推进,可放心写 `await sleep()`
|
||||
- 想直接渲染某路由,在**模块脚本之前**插一段 `history.replaceState({}, '', '/sys/role')`(本项目是 `createWebHistory`,不是 hash 路由)
|
||||
- 诊断页里的内联 `<script>` 必须语法正确——本轮曾因多一个 `catch` 导致整段不执行、表现为"页面没反应",排查成本很高
|
||||
- 统计勾选状态要用 `:scope > .el-tree-node__content .el-checkbox`,否则父节点会把子节点的 `is-checked` 也算进来
|
||||
|
||||
---
|
||||
|
||||
## 五、当前状态
|
||||
|
||||
| 项 | 状态 |
|
||||
|---|---|
|
||||
| 部门新增/编辑绑定管理类型、职责类型 | 正常,列表以标签展示 ✅ |
|
||||
| 部门树形列表 / 添加子部门 / 上级树选择(排除自身子孙) | 正常 ✅ |
|
||||
| 部门编辑不再覆盖启用状态 | 已修 ✅ |
|
||||
| 部门缓存(报表部门控件)随部门增删改刷新 | 已接入 `clearDepCache()` ✅(工作进度-2 遗留 1 关闭) |
|
||||
| 角色授权:勾选 → 保存 → 回显 → 该角色登录加载菜单 | 全链路打通(含雪花 Id 菜单)✅ |
|
||||
|
||||
---
|
||||
|
||||
## 六、遗留与后续建议
|
||||
|
||||
1. **同类 `Number()` 隐患**(新数据 id 变大后会踩同一个坑,尚未动)
|
||||
- `web/src/views/base/chejianbanci/index.vue`(`depId`)
|
||||
- `web/src/views/base/jizuchetai/index.vue`(`departmentId`)
|
||||
- `web/src/views/base/employee/index.vue`(`depId` / `worktypeId`,含 `depIds.map(Number)`)
|
||||
- `web/src/views/prod/lsjl/index.vue`(`depOptions` 的 `id: Number(o.key)`)
|
||||
2. **超级管理员 `RolePermission` 重复**:`sys_rbac_role_permissions` 中 admin 有 481 条、只对应 49 个不同资源(历史 seeding 重复插入)。不影响鉴权(admin 直接放行),但角色列表「菜单权限」数字虚高,可去重。
|
||||
3. **部门权限无消费方**:授权会写 `department:{id}:visble`,但前后端没有任何地方按此做数据/可见性过滤,勾选当前无实际效果——要么接上数据范围,要么先从 UI 移除。
|
||||
4. **「操作」权限维度未启用**:`Resource_Type_Enum.操作 = 2` 与 `Permission_Type_Enum.Enable = 2` 已定义但未使用;保存时 `permissionType` 硬编码为 1(Visble)。按钮类节点混在「菜单权限」树里,无法单独授予「可操作」。
|
||||
5. **新菜单的权限单元**:现由 `FixMenuPermissions` 在启动时补建,`AssignRolePermission` 兜底时也会按菜单的 `Permission` 补 `Code`;建议后续把「建 Permission」直接并入菜单 CRUD,避免依赖启动时机。
|
||||
6. **死代码**:`web/src/views/system/{department,role,menu,employee}` 与路由表里的 `system/*/index` 已无菜单指向(`/system%` 菜单被 seeder 删除,对应后端接口也已下线),可整批删掉。
|
||||
Reference in New Issue
Block a user