立项配置版本管理优化(回滚逻辑、UI、下载功能)
This commit is contained in:
@@ -107,6 +107,38 @@ const getArrayRowIdentity = (moduleKey: keyof SetupConfigDraft, value: unknown):
|
||||
return "";
|
||||
};
|
||||
|
||||
type ArrayRowEntry = {
|
||||
key: string;
|
||||
value: unknown;
|
||||
rowIdentity: string;
|
||||
};
|
||||
|
||||
const buildArrayRowEntry = (moduleKey: keyof SetupConfigDraft, value: unknown, index: number): ArrayRowEntry => {
|
||||
const rowIdentity = getArrayRowIdentity(moduleKey, value);
|
||||
if (value && typeof value === "object" && !Array.isArray(value)) {
|
||||
const id = String((value as Record<string, unknown>).id || "").trim();
|
||||
if (id) {
|
||||
return {
|
||||
key: `id:${id}`,
|
||||
value,
|
||||
rowIdentity,
|
||||
};
|
||||
}
|
||||
}
|
||||
if (rowIdentity) {
|
||||
return {
|
||||
key: `identity:${rowIdentity}`,
|
||||
value,
|
||||
rowIdentity,
|
||||
};
|
||||
}
|
||||
return {
|
||||
key: `index:${index}`,
|
||||
value,
|
||||
rowIdentity: "",
|
||||
};
|
||||
};
|
||||
|
||||
const formatReadablePath = (moduleKey: keyof SetupConfigDraft, path: string): string => {
|
||||
let normalized = path;
|
||||
if (path === moduleKey) {
|
||||
@@ -247,11 +279,47 @@ const collectDiffRows = (
|
||||
if (Array.isArray(localValue) || Array.isArray(serverValue)) {
|
||||
const localArr = Array.isArray(localValue) ? localValue : [];
|
||||
const serverArr = Array.isArray(serverValue) ? serverValue : [];
|
||||
const maxLen = Math.max(localArr.length, serverArr.length);
|
||||
for (let i = 0; i < maxLen; i += 1) {
|
||||
const rowIdentity = getArrayRowIdentity(moduleKey, localArr[i] ?? serverArr[i]);
|
||||
const indexLabel = rowIdentity ? `${i}|${rowIdentity}` : `${i}`;
|
||||
collectDiffRows(moduleKey, moduleLabel, localArr[i], serverArr[i], `${path}[${indexLabel}]`, rows);
|
||||
|
||||
const localEntryMap = new Map<string, ArrayRowEntry[]>();
|
||||
localArr.forEach((item, index) => {
|
||||
const entry = buildArrayRowEntry(moduleKey, item, index);
|
||||
const list = localEntryMap.get(entry.key);
|
||||
if (list) {
|
||||
list.push(entry);
|
||||
} else {
|
||||
localEntryMap.set(entry.key, [entry]);
|
||||
}
|
||||
});
|
||||
|
||||
const consumeLocalEntry = (key: string): ArrayRowEntry | null => {
|
||||
const list = localEntryMap.get(key);
|
||||
if (!list || list.length === 0) return null;
|
||||
const entry = list.shift() || null;
|
||||
if (list.length === 0) localEntryMap.delete(key);
|
||||
return entry;
|
||||
};
|
||||
|
||||
let pairIndex = 0;
|
||||
serverArr.forEach((item, index) => {
|
||||
const serverEntry = buildArrayRowEntry(moduleKey, item, index);
|
||||
const localEntry = consumeLocalEntry(serverEntry.key);
|
||||
const rowIdentity = (localEntry?.rowIdentity || serverEntry.rowIdentity || "").trim();
|
||||
const indexLabel = rowIdentity ? `${pairIndex}|${rowIdentity}` : `${pairIndex}`;
|
||||
collectDiffRows(moduleKey, moduleLabel, localEntry?.value, serverEntry.value, `${path}[${indexLabel}]`, rows);
|
||||
pairIndex += 1;
|
||||
});
|
||||
|
||||
localEntryMap.forEach((list) => {
|
||||
list.forEach((localEntry) => {
|
||||
const rowIdentity = localEntry.rowIdentity.trim();
|
||||
const indexLabel = rowIdentity ? `${pairIndex}|${rowIdentity}` : `${pairIndex}`;
|
||||
collectDiffRows(moduleKey, moduleLabel, localEntry.value, undefined, `${path}[${indexLabel}]`, rows);
|
||||
pairIndex += 1;
|
||||
});
|
||||
});
|
||||
if (localArr.length === 0 && serverArr.length === 0) {
|
||||
// Keep behavior explicit for empty array pair to avoid extra recursion.
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -6,8 +6,8 @@ export type SetupWorkflowStatus = "UNSAVED_DRAFT" | "SAVED_DRAFT" | "PUBLISHED";
|
||||
export type SetupWorkflowTagMeta = { label: string; type: "success" | "warning" | "info" };
|
||||
|
||||
export const SETUP_WORKFLOW_TAG_META: Record<SetupWorkflowStatus, SetupWorkflowTagMeta> = {
|
||||
UNSAVED_DRAFT: { label: "草稿未保存", type: "warning" },
|
||||
SAVED_DRAFT: { label: "草稿已保存(未发布)", type: "info" },
|
||||
UNSAVED_DRAFT: { label: "未保存", type: "warning" },
|
||||
SAVED_DRAFT: { label: "已保存", type: "info" },
|
||||
PUBLISHED: { label: "已发布", type: "success" },
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user