Commit 48dc0d0a authored by David Yang's avatar David Yang

fix: bugs

parent 527e29e5
......@@ -102,10 +102,6 @@ AI 在编写 API 调用或数据转换逻辑时,必须遵守:
- 流程文档更新内容至少应包含:功能入口、关键交互步骤、状态变化、核心字段/筛选条件、异常处理或限制条件。
- 提交结果时,除了说明改动代码,也要简要说明同步更新了哪个流程文档、补充了哪部分逻辑。
## 业务文档索引
- 项目管理模块 - 请阅读 `/src/pages/project_manager_xy/project-management.business-flow.md`
## 获取当前登录用户信息
可使用 src/hooks/user.jsx 中的 hook useUserInfo 数据结构如下 { "username": "yang_admin", "password_changed": true, "token_expires_at": null, "\_id": "69b12a47e92b1de77c94a9f5", "display_name": "杨康", "type": "admin", "avatar": null, "profile": {}, "groups": [ { "\_id": "649e5a55ad1c1038911baabd", "name": "default", "display_name": "默认用户组", "users": [ { "_id": "649e5a55ad1c1038911baac0", "username": "system", "display_name": "系统" } ], "settings": {} } ], "applications": [ { "name": "fund_audit", "title": "数智报告平台", "groups": [ "default" ], "roles": [ "成员" ], "permissions": [] }, { "name": "aml_tables", "title": "反洗钱数据表", "groups": [ "default" ], "roles": [ "管理" ], "permissions": [] } ] }
......@@ -9,7 +9,7 @@
"@ant-design/icons": "^6.3.2",
"@headlessui/react": "^2.2.10",
"@heroicons/react": "^2.2.0",
"@heroui-pro/react": "file:../project_manager_new/node_modules/@heroui-pro/react",
"@heroui-pro/react": "1.0.0-beta.7",
"@heroui/react": "^3.2.2",
"@heroui/styles": "^3.2.2",
"@internationalized/date": "^3.12.2",
......
allowBuilds:
core-js: false
core-js-pure: false
es5-ext: false
esbuild: false
......@@ -88,6 +88,7 @@ import {
loadProblemRectificationListData,
loadProblemRectificationListResources,
loadProblemRectificationViewCountMap,
mergeDepartmentRectificationItems,
normalizeDelayRequest,
normalizeDelayRequestItems,
normalizeDepartmentRectificationItems,
......@@ -1418,8 +1419,13 @@ export default function ProblemRectificationListPage() {
const progressIdEditor = [];
if (isDepartmentFlow) {
const sourceRecord = await loadRecord(selectedRecords[0].id);
if (sourceRecord?.metadata?.is_locked === true) {
throw new Error('当前问题整改记录已锁定,不允许推送,请先解锁。');
}
const departmentItems = buildDepartmentRectificationItems(
selectedRecords[0].raw || selectedRecords[0],
sourceRecord,
departmentAssignments,
currentUserInfo,
);
......@@ -1442,19 +1448,34 @@ export default function ProblemRectificationListPage() {
progressIdEditor.push(item.progress_id_editor);
}
const nextDepartmentItems = mergeDepartmentRectificationItems(
sourceRecord,
departmentItems,
);
await batchUpdateRecords({
subject: PROBLEM_RECTIFICATION_SUBJECT,
filter: {
_id: selectedRecords[0].id,
},
data: buildDepartmentParentBatchUpdateData(departmentItems),
data: buildDepartmentParentBatchUpdateData(nextDepartmentItems),
});
const savedRecord = await loadRecord(selectedRecords[0].id);
const savedItems = normalizeDepartmentRectificationItems(savedRecord);
if (savedItems.length !== departmentItems.length) {
if (
savedItems.length !== nextDepartmentItems.length ||
departmentItems.some(
(item) =>
!savedItems.some(
(savedItem) =>
savedItem.item_id === item.item_id &&
savedItem.progress_id_editor === item.progress_id_editor,
),
)
) {
throw new Error(
`部门整改明细写入失败:预期 ${departmentItems.length} 条,后台实际返回 ${savedItems.length} 条。`,
`部门整改明细写入失败:预期保留 ${nextDepartmentItems.length} 条,后台实际返回 ${savedItems.length} 条。`,
);
}
} else {
......
......@@ -423,27 +423,78 @@ export function buildDepartmentAssignmentsFromRecord(record) {
export function buildDepartmentRectificationItems(record, assignments = [], currentUser = null) {
const now = dayjs().toISOString();
const currentUserId = normalizeUserId(currentUser);
const existingItems = normalizeDepartmentRectificationItems(record);
const existingByItemId = new Map(
existingItems
.filter((item) => item.item_id)
.map((item) => [item.item_id, item]),
);
const existingByDepartment = new Map(
existingItems
.filter((item) => normalizeText(item.responsible_department))
.map((item) => [normalizeText(item.responsible_department), item]),
);
return assignments.map((assignment, index) => ({
item_id: assignment.item_id || makeDepartmentItemId(record?.raw || record, assignment.responsible_department, index),
responsible_department: normalizeText(assignment.responsible_department) || '未指定责任部门',
editor: normalizeUserId(assignment.editor),
auditor: normalizeUserId(assignment.auditor),
rectification_progress: '',
rectification_situation: '',
the_time_of_rectification: null,
rectification_proof_materials: null,
editor_status: EDITOR_STATUS_PENDING,
audit_status: AUDIT_STATUS_PENDING,
final_audit_status: AUDIT_STATUS_PENDING,
progress_id_editor: '',
progress_id_auditor: '',
progress_id_sender: '',
created_by: currentUserId,
created_at: now,
updated_by: currentUserId,
updated_at: now,
}));
return assignments.map((assignment, index) => {
const department = normalizeText(assignment.responsible_department) || '未指定责任部门';
const itemId =
assignment.item_id ||
makeDepartmentItemId(record?.raw || record, department, index);
const existingItem = existingByItemId.get(itemId) || existingByDepartment.get(department) || {};
return {
...existingItem,
item_id: existingItem.item_id || itemId,
responsible_department: department,
editor: normalizeUserId(assignment.editor),
auditor: normalizeUserId(assignment.auditor),
rectification_progress: existingItem.rectification_progress || '',
rectification_situation: existingItem.rectification_situation || '',
the_time_of_rectification: existingItem.the_time_of_rectification || null,
rectification_proof_materials: existingItem.rectification_proof_materials || null,
editor_status: EDITOR_STATUS_PENDING,
audit_status: AUDIT_STATUS_PENDING,
final_audit_status: AUDIT_STATUS_PENDING,
progress_id_editor: '',
progress_id_auditor: '',
progress_id_sender: '',
created_by: existingItem.created_by || currentUserId,
created_at: existingItem.created_at || now,
updated_by: currentUserId,
updated_at: now,
};
});
}
export function mergeDepartmentRectificationItems(record, updatedItems = []) {
const existingItems = normalizeDepartmentRectificationItems(record);
if (existingItems.length === 0) {
return updatedItems.filter(Boolean);
}
const updatedByItemId = new Map(
updatedItems
.filter((item) => item?.item_id)
.map((item) => [item.item_id, item]),
);
const mergedItemIds = new Set();
const nextItems = existingItems.map((item) => {
const updatedItem = updatedByItemId.get(item.item_id);
if (!updatedItem) {
return item;
}
mergedItemIds.add(item.item_id);
return updatedItem;
});
updatedItems.forEach((item) => {
if (item?.item_id && !mergedItemIds.has(item.item_id)) {
nextItems.push(item);
}
});
return nextItems;
}
export function buildDepartmentDelayRequestItems({
......
......@@ -187,7 +187,7 @@ type Record = {
- 新增驾驶舱扩展字段当前在线上 Subject 中大多仍为 `text` 类型,前端工作台按标准值引导录入,用于支持后续严重程度、问题分类、问题原因和整改质效分析
- 其余 `select` 类型的可选值必须以线上 Subject 配置中的 `settings.options` 为准,禁止在页面内硬编码
- `problem_discovery_situation` 曾在历史文档和归档对象中出现,但本次主对象字段定义未包含;新页面只应在 Subject View 或线上字段配置存在时展示,不能作为 `problem_rectification` 固定字段依赖
- `department_rectification_items` 用于新转发流程的部门级整改明细。无论单条还是多条推送,每个问题都按责任部门生成明细;单条问题即使只有 1 个责任部门,也生成 1 条明细。转发后 `rectification_progress`、`rectification_situation`、`the_time_of_rectification`、`rectification_proof_materials`、`audit_status`、`final_audit_status` 以明细为事实来源,父字段仅做兼容汇总展示;整改进度、审批状态和最终审批状态按部门明细中最落后的状态汇总,例如“整改中”优先于“已整改”,“未审批”优先于“已审批”
- `department_rectification_items` 用于新转发流程的部门级整改明细。无论单条还是多条推送,每个问题都按责任部门生成明细;单条问题即使只有 1 个责任部门,也生成 1 条明细。已推送过的问题再次推送时,必须保留原部门明细记录和 `item_id`,只在本次参与推送的原明细行上更新填写人、审批人、流程状态和待办 ID;未参与本次推送的原明细行保持不变,不因弹窗删除部门配置而从父记录移除。转发后 `rectification_progress`、`rectification_situation`、`the_time_of_rectification`、`rectification_proof_materials`、`audit_status`、`final_audit_status` 以明细为事实来源,父字段仅做兼容汇总展示;整改进度、审批状态和最终审批状态按部门明细中最落后的状态汇总,例如“整改中”优先于“已整改”,“未审批”优先于“已审批”
- `problem_rectification_delay_request` 为历史问题级单次延期申请嵌套对象,与 `department_rectification_items` 平级;新发起延期默认按部门写入 `problem_rectification_delay_request_items`
- `problem_rectification_delay_request_items` 为部门级延期申请明细数组;每个责任部门 1 条延期申请,独立保存填写人、一级审批人、最终审批人、申请完成时间、延期事由、状态和待办 ID
- `is_locked` 为问题整改主记录的状态锁定标记;仅整改进度汇总值为 `已整改` 的记录允许写入 `true`,锁定后所有业务字段和流程状态均不可修改,只有解锁操作可以将其写回 `false`
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment