slark WIP snapshot (fence 1789540747913)

This commit is contained in:
my_local_kimi_dev2
2026-09-16 14:39:11 +08:00
parent 12de320459
commit f51e41a189
@@ -0,0 +1,133 @@
# 装机工单 MCP 工具设计(install.order.list.query / install.order.detail.query)
> 状态:已评审(2026-09-16 王恒确认) | 对应老接口:`POST /installOrder/pageList`、`POST /installOrder/lookDetails`(xiaoqu-franchisee `InstallOrderController.java:2004` / `:229`)
> 只读工具,不改老系统数据;数据源 m2(业务库)为主,详情聚合 m1(商城订单/地址)。
## 1. 工具清单
| 工具名 | category | kind | 用途 |
|---|---|---|---|
| `install.order.list.query` | workorder | read | 分页查询装机工单列表 |
| `install.order.detail.query` | workorder | read | 按 id 或装机单号查询工单详情(主单+明细+人员+流程) |
## 2. install.order.list.query
### 2.1 入参
对齐老 pageList,命名转 camelCase,匹配方式保持老语义(String 模糊、数字精确、时间区间):
| 参数 | 类型 | 必填 | 匹配 | 说明 |
|---|---|---|---|---|
| installOrderNo | string | 否 | 模糊 | 装机单号 |
| mallOrderNo | string | 否 | 模糊 | 商城销售订单号 |
| deliveryOrderNo | string | 否 | 模糊 | 送货工单号 |
| pickupOrderNo | string | 否 | 模糊 | 取货工单号 |
| scheduleTransferOrder | string | 否 | 模糊 | 待办划转单号 |
| installType | int | 否 | 精确 | 0=正式装机 1=测试装机 |
| agentId | int | 否 | 精确 | 所属代理公司 id |
| districtName | string | 否 | 模糊 | 项目/站点名称 |
| applyUserName | string | 否 | 模糊 | 申请人 |
| maintenanceUserName | string | 否 | 模糊 | 运维人员 |
| cooperateUserName | string | 否 | 模糊 | 协同人员 |
| orderState | int | 否 | 精确 | 0待审核 1被驳回 2调度中 3待出库 4待送货 5作业中 6待取回 7已结束 8已取消 |
| applyTimeFrom / applyTimeTo | string | 否 | 区间 | 申请时间,yyyy-MM-dd(To 含当天,服务端补 23:59:59) |
| page | int | 否 | — | 默认 1 |
| rows | int | 否 | — | 默认 20,上限 100,超出截断并在 notice 提示 |
裁剪说明(已评审确认):老接口的 7 组时间区间(finish/audit/dispatch/allocation/signature/pickup/warehousing)使用频率低,首版**只保留申请时间一组**;如确有需要再扩展。老接口的 `sidx/sord` 自由排序存在 SQL 注入面,**不移植**,固定排序 `apply_time DESC, id DESC`。
### 2.2 返回
沿用 MCP 统一分页结构:
```json
{
"total": 123, "page": 1, "rows": 20,
"notice": "rows 超过上限已截断为 100(仅超限时出现)",
"records": [ { "id": 1, "installOrderNo": "...", "installType": 0, "installTypeText": "正式装机",
"orderState": 5, "orderStateText": "作业中",
"agentId": 1, "agentName": "...", "propertyId": 1, "propertyName": "...",
"districtId": 1, "districtName": "...", "projectAddress": "...",
"applyUserName": "...", "maintenanceUserName": "...", "cooperateUserName": "...",
"hopeInstallDate": "...", "trueInstallDate": "...",
"applyTime": "yyyy-MM-dd HH:mm:ss", "finishDate": "...",
"mallOrderNo": "...", "deliveryOrderNo": "...", "pickupOrderNo": "...",
"totalInstallCount": 3 } ]
}
```
`totalInstallCount` 同老接口:按 `install_order_details` 汇总 install_count(分页记录逐条汇总,与老行为一致)。`orderStateText/installTypeText` 为附带文案,免查字典。
### 2.3 行级权限(新增 `PermissionService.applyInstallOrderRowFilter`)
老逻辑在 `xiaoqu-franchisee utils/WrapperUtils.java:127-264`(`getWorkOrderAuth`,pageList 传 `propertyFlag=true, className=property_id, orderNoName=install_order_no, type=0`),1:1 移植:
1. **总部**(权限组 `isagent != 1`):不过滤,看全部。
2. **代理销售非负责人**(Redis 字典 authDeptId 含本部门且不含负责人岗位,复用现有 `isSalesNonLeader` 语义):`property_id IN(自己创建的物业 ∪ 被授权代管公司名下的物业)`,集合为空则 `IN (0)`;命中后互斥 return,不进规则 3。
3. **其他代理用户**:
- `ids = 自己 agentId ∪ warehouse_agent_auth(user_id=自己).manager_agent_id`(本人 + 授权代管公司,**不含下级代理**,与现有 `visibleAgentIds` 不同,不可复用);
- 参与者单号 `orderNos = install_order_process(user_id=自己) ∪ install_order_user(user_id=自己)`(让运维/协同人员在调度阶段即可见工单);
- 代管物业 `propertyIds = agent_manage_district_auth(manage_agent_id IN ids).property_id`;
- 最终:`AND (apply_agent_id IN ids OR agent_id IN ids OR property_id IN propertyIds[如有] OR install_order_no IN orderNos[如有])`。
4. 未配置权限组的用户按现有约定直接拒绝(同 `isAgentAuthority`)。
## 3. install.order.detail.query
对齐老 `/installOrder/lookDetails`(`InstallOrderController.java:229`),返回 `InstallOrderApplyLookOutput` 的 MCP 版。商城订单聚合已评审确认**首版即带**(跨 m1 库)。
### 3.1 入参
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| id | int | 二选一 | 工单主键,>0 优先 |
| installOrderNo | string | 二选一 | 装机单号,精确匹配 |
| includeProcess | bool | 否 | 是否返回流程记录,默认 true |
| processLimit | int | 否 | 流程记录上限,默认 100,最大 500 |
### 3.2 返回
- `record`:主单全字段(同列表字段 + `customerContact/contactMobile/projectMemo/auditTime/dispatchTime/...` 等完整时间链与经手人);
- `details`:`install_order_details` 明细(物料、数量、安装位置等);
- `maintenanceUsers` / `cooperateUsers`:`install_order_user`(userType 0/1);
- `addressInfo`:收货地址(m1 `mall_shipping_address`,addressId 非空时);
- `mallOrder`:商城订单+订单明细+物料(m1,mallOrderNo 非空时);
- `processes`:流程记录,`schedule_state=2`(已办)、排除抄送(operationTheme!=12),按 `operation_time` 升序;调度/配发节点附人员,配发节点附 SN(`install_distribute_details`),出入库节点附 `install_to_out_warehouse` 记录与图片凭证 OSS URL(m1 `mall_logistics_pic` / m2 `warehouse_in_out_pic`)。
### 3.3 权限与防枚举
与列表**复用同一 `applyInstallOrderRowFilter`**:先按 id/单号查出主单,再套上同一个行级过滤 wrapper 校验可见性;不可见与不存在统一返回 `record=null` + `notice="工单不存在或无权查看"`,防止枚举越权工单(与 warehouse.out.detail.query 同一约定)。
## 4. 实现范围(变更文件清单)
新增(xiaoqu-agent-service):
- `entity/m2/InstallOrder.java`、`InstallOrderDetails.java`、`InstallOrderProcess.java`、`InstallOrderUser.java`、`InstallDistributeDetails.java`、`InstallToOutWarehouse.java`(只保留查询需要的字段)
- `mapper/m2/InstallOrderMapper.java` 等对应 Mapper(m2 分包已被 `M2DataSourceConfig` 扫描)
- `mcp/tool/InstallOrderTools.java`(两个 `@XqTool(category="workorder", kind="read")` 方法)
- `permission/PermissionService.java` 新增 `applyInstallOrderRowFilter`
- m1 侧复用现有商城订单/地址/物流 Mapper(warehouse.out.detail 已引入则直接复用,缺则新增)
- codegen 表白名单 `CodeGenerator.java` 登记新表
- 测试:`InstallOrderToolsTest`(结构/分页/排序/schema 发布)+ `PermissionServiceInstallOrderRowFilterTest`(总部/销售/代理三角色)
- 文档:`doc/agent-mcp-tools-reference.md` 新增章节、README 工具表登记
不改:老系统任何代码与数据;svc 库表结构(tool 表由 ToolSyncService 启动自动同步)。
## 5. 边界与性能
- 列表 `selectCount + LIMIT` 手写分页;固定排序,无注入面。
- 不做无界聚合;装机统计(数量/状态分布)如有需要,后续独立设计 `install.order.summary.query`。
- 详情的子表均按主单单号/id 精确查询,processLimit 兜底;图片只回传 OSS URL,不内嵌内容。
- 时间统一 `yyyy-MM-dd HH:mm:ss`,Asia/Shanghai。
## 6. 测试与验收
1. 单测全量通过(现有 236 + 新增)。
2. 三角色权限用例:总部无过滤;代理只见 自己+代管公司+代管物业+本人参与 的工单;销售非负责人只见 自己创建物业+代管物业;越权查详情返回 record=null 且提示与不存在一致。
3. rows=500 截断为 100 且带 notice;installOrderNo 模糊、orderState 精确、applyTime 区间生效。
4. 发布:合并 main → `deploy/deploy.sh remote-deploy` → 健康检查 POST /mcp 401 → svc 库 tool 表出现两个新工具 → 给目标 scope 绑定 scope_tool → 线上 tools/list 可见性验证。
## 7. 评审结论(2026-09-16 王恒确认)
1. 时间区间只保留申请时间一组(applyTimeFrom/To),其余 7 组不移植。
2. 详情首版即带商城订单聚合(跨 m1 库)。
3. category 用 `workorder`(不新建 `install`,也不并入 `warehouse`)。