fix del api
This commit is contained in:
@@ -374,7 +374,8 @@ function requestModelName({
|
|||||||
confirmLabel = "确认",
|
confirmLabel = "确认",
|
||||||
danger = false,
|
danger = false,
|
||||||
expectedValue = null,
|
expectedValue = null,
|
||||||
expectedLabel = "输入内容"
|
expectedLabel = "输入内容",
|
||||||
|
ignoreCase = false
|
||||||
}) {
|
}) {
|
||||||
if (actionDialogState) closeActionDialog(null);
|
if (actionDialogState) closeActionDialog(null);
|
||||||
elements.actionDialogTitle.textContent = title;
|
elements.actionDialogTitle.textContent = title;
|
||||||
@@ -391,7 +392,13 @@ function requestModelName({
|
|||||||
elements.actionDialogInput.select();
|
elements.actionDialogInput.select();
|
||||||
});
|
});
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
actionDialogState = { resolve, previousFocus, expectedValue, expectedLabel };
|
actionDialogState = {
|
||||||
|
resolve,
|
||||||
|
previousFocus,
|
||||||
|
expectedValue,
|
||||||
|
expectedLabel,
|
||||||
|
ignoreCase
|
||||||
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -400,17 +407,24 @@ elements.actionDialogForm.addEventListener("submit", (event) => {
|
|||||||
const value = elements.actionDialogInput.value.trim();
|
const value = elements.actionDialogInput.value.trim();
|
||||||
const expectedValue = actionDialogState?.expectedValue;
|
const expectedValue = actionDialogState?.expectedValue;
|
||||||
const expectedLabel = actionDialogState?.expectedLabel || "输入内容";
|
const expectedLabel = actionDialogState?.expectedLabel || "输入内容";
|
||||||
|
const ignoreCase = actionDialogState?.ignoreCase === true;
|
||||||
if (!value) {
|
if (!value) {
|
||||||
elements.actionDialogError.textContent = `${expectedLabel}不能为空`;
|
elements.actionDialogError.textContent = `${expectedLabel}不能为空`;
|
||||||
elements.actionDialogError.hidden = false;
|
elements.actionDialogError.hidden = false;
|
||||||
elements.actionDialogInput.focus();
|
elements.actionDialogInput.focus();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (expectedValue !== null && value !== expectedValue) {
|
if (expectedValue !== null) {
|
||||||
elements.actionDialogError.textContent = `${expectedLabel}不匹配,请按提示完整输入`;
|
const expected = String(expectedValue).trim();
|
||||||
elements.actionDialogError.hidden = false;
|
const matched = ignoreCase
|
||||||
elements.actionDialogInput.focus();
|
? value.toLowerCase() === expected.toLowerCase()
|
||||||
return;
|
: value === expected;
|
||||||
|
if (!matched) {
|
||||||
|
elements.actionDialogError.textContent = `${expectedLabel}不匹配,请按提示完整输入`;
|
||||||
|
elements.actionDialogError.hidden = false;
|
||||||
|
elements.actionDialogInput.focus();
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
closeActionDialog(value);
|
closeActionDialog(value);
|
||||||
});
|
});
|
||||||
@@ -708,7 +722,8 @@ document.querySelector("#delete-line").addEventListener("click", async () => {
|
|||||||
confirmLabel: "删除产线",
|
confirmLabel: "删除产线",
|
||||||
danger: true,
|
danger: true,
|
||||||
expectedValue: line.deviceId,
|
expectedValue: line.deviceId,
|
||||||
expectedLabel: "deviceId"
|
expectedLabel: "deviceId",
|
||||||
|
ignoreCase: true
|
||||||
});
|
});
|
||||||
if (confirmation === null) return;
|
if (confirmation === null) return;
|
||||||
const result = await runBusy("正在删除产线", () => window.reinloop.deleteProductionLine({
|
const result = await runBusy("正在删除产线", () => window.reinloop.deleteProductionLine({
|
||||||
@@ -734,7 +749,8 @@ document.querySelector("#delete-company").addEventListener("click", async () =>
|
|||||||
confirmLabel: "删除公司",
|
confirmLabel: "删除公司",
|
||||||
danger: true,
|
danger: true,
|
||||||
expectedValue: company.code,
|
expectedValue: company.code,
|
||||||
expectedLabel: "公司编码"
|
expectedLabel: "公司编码",
|
||||||
|
ignoreCase: true
|
||||||
});
|
});
|
||||||
if (confirmation === null) return;
|
if (confirmation === null) return;
|
||||||
const result = await runBusy("正在删除公司", () => window.reinloop.deleteCompany({
|
const result = await runBusy("正在删除公司", () => window.reinloop.deleteCompany({
|
||||||
@@ -797,12 +813,13 @@ elements.licenseList.addEventListener("click", async (event) => {
|
|||||||
if (deleteId) {
|
if (deleteId) {
|
||||||
const confirmation = await requestModelName({
|
const confirmation = await requestModelName({
|
||||||
title: "确认删除许可证",
|
title: "确认删除许可证",
|
||||||
message: "已撤销许可证才能删除。请输入许可证 ID 以确认永久删除。",
|
message: `已撤销许可证才能删除。请输入许可证 ID 以确认永久删除。\n\n当前许可证 ID:${deleteId}`,
|
||||||
value: "",
|
value: "",
|
||||||
confirmLabel: "永久删除",
|
confirmLabel: "永久删除",
|
||||||
danger: true,
|
danger: true,
|
||||||
expectedValue: deleteId,
|
expectedValue: deleteId,
|
||||||
expectedLabel: "许可证ID"
|
expectedLabel: "许可证ID",
|
||||||
|
ignoreCase: true
|
||||||
});
|
});
|
||||||
if (confirmation === null) return;
|
if (confirmation === null) return;
|
||||||
button.disabled = true;
|
button.disabled = true;
|
||||||
|
|||||||
@@ -371,6 +371,28 @@ function createApp({
|
|||||||
return before - database.fileRecords.length;
|
return before - database.fileRecords.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function removeDeviceDirectories(deviceId) {
|
||||||
|
const segments = String(deviceId || "").split("/");
|
||||||
|
if (segments.length !== 2 || !segments[0] || !segments[1]) return 0;
|
||||||
|
const [companyCode, lineCode] = segments;
|
||||||
|
const targets = [
|
||||||
|
path.join(store.modelsDirectory, companyCode, lineCode),
|
||||||
|
path.join(store.filesDirectory, "ReinLoop_GUI", companyCode, lineCode)
|
||||||
|
];
|
||||||
|
let removed = 0;
|
||||||
|
for (const directory of targets) {
|
||||||
|
try {
|
||||||
|
const stat = await fs.promises.stat(directory);
|
||||||
|
if (!stat.isDirectory()) continue;
|
||||||
|
} catch (_error) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
await fs.promises.rm(directory, { recursive: true, force: true });
|
||||||
|
removed += 1;
|
||||||
|
}
|
||||||
|
return removed;
|
||||||
|
}
|
||||||
|
|
||||||
function backfillIdentificationFiles(database) {
|
function backfillIdentificationFiles(database) {
|
||||||
for (const record of database.fileRecords) {
|
for (const record of database.fileRecords) {
|
||||||
if (!record.folder.endsWith("/ind_data") || ![".csv", ".json"].includes(path.extname(record.fileName).toLowerCase())) continue;
|
if (!record.folder.endsWith("/ind_data") || ![".csv", ".json"].includes(path.extname(record.fileName).toLowerCase())) continue;
|
||||||
@@ -549,12 +571,14 @@ function createApp({
|
|||||||
!(item.companyId === companyId && item.productionLineId === productionLineId)
|
!(item.companyId === companyId && item.productionLineId === productionLineId)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const deletedDirectories = await removeDeviceDirectories(deviceId);
|
||||||
database.productionLines = database.productionLines.filter((item) => item.id !== productionLineId);
|
database.productionLines = database.productionLines.filter((item) => item.id !== productionLineId);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
success: true,
|
success: true,
|
||||||
deletedProductionLineId: productionLineId,
|
deletedProductionLineId: productionLineId,
|
||||||
deletedFiles: deletedFileCount,
|
deletedFiles: deletedFileCount,
|
||||||
|
deletedDirectories,
|
||||||
deletedLicenses: revokedLicenses,
|
deletedLicenses: revokedLicenses,
|
||||||
deletedFeedback,
|
deletedFeedback,
|
||||||
deletedVolumeRequests: deletedRequests,
|
deletedVolumeRequests: deletedRequests,
|
||||||
|
|||||||
@@ -877,6 +877,14 @@ test("deleteProductionLine blocks active licenses and removes revoked data", asy
|
|||||||
assert.equal(blocked.errCode, "ACTIVE_LICENSES_PRESENT");
|
assert.equal(blocked.errCode, "ACTIVE_LICENSES_PRESENT");
|
||||||
|
|
||||||
await post({ type: "revokeLicense", licenseId, reason: "产线删除", adminToken: "test-token" });
|
await post({ type: "revokeLicense", licenseId, reason: "产线删除", adminToken: "test-token" });
|
||||||
|
|
||||||
|
const orphanModelDir = path.join(dataDirectory, "models", line.productionLine.deviceId);
|
||||||
|
const orphanFileDir = path.join(dataDirectory, "files", "ReinLoop_GUI", line.productionLine.deviceId);
|
||||||
|
await fs.promises.mkdir(orphanModelDir, { recursive: true });
|
||||||
|
await fs.promises.mkdir(orphanFileDir, { recursive: true });
|
||||||
|
await fs.promises.writeFile(path.join(orphanModelDir, "orphan.bin"), "orphan-model");
|
||||||
|
await fs.promises.writeFile(path.join(orphanFileDir, "orphan.json"), "orphan-file");
|
||||||
|
|
||||||
const deleted = await post({
|
const deleted = await post({
|
||||||
type: "deleteProductionLine",
|
type: "deleteProductionLine",
|
||||||
companyId: company.company.id,
|
companyId: company.company.id,
|
||||||
@@ -886,6 +894,10 @@ test("deleteProductionLine blocks active licenses and removes revoked data", asy
|
|||||||
assert.equal(deleted.success, true);
|
assert.equal(deleted.success, true);
|
||||||
assert.ok(deleted.deletedFiles >= 1);
|
assert.ok(deleted.deletedFiles >= 1);
|
||||||
assert.ok(deleted.deletedLicenses >= 1);
|
assert.ok(deleted.deletedLicenses >= 1);
|
||||||
|
assert.ok(deleted.deletedDirectories >= 1);
|
||||||
|
|
||||||
|
await assert.rejects(fs.promises.access(orphanModelDir));
|
||||||
|
await assert.rejects(fs.promises.access(orphanFileDir));
|
||||||
|
|
||||||
const organizations = await post({ type: "listOrganizations", adminToken: "test-token" });
|
const organizations = await post({ type: "listOrganizations", adminToken: "test-token" });
|
||||||
const listedCompany = organizations.companies.find((item) => item.id === company.company.id);
|
const listedCompany = organizations.companies.find((item) => item.id === company.company.id);
|
||||||
|
|||||||
Reference in New Issue
Block a user