Merge remote-tracking branch 'upstream/main' into reinlooptest
This commit is contained in:
@@ -374,7 +374,8 @@ function requestModelName({
|
||||
confirmLabel = "确认",
|
||||
danger = false,
|
||||
expectedValue = null,
|
||||
expectedLabel = "输入内容"
|
||||
expectedLabel = "输入内容",
|
||||
ignoreCase = false
|
||||
}) {
|
||||
if (actionDialogState) closeActionDialog(null);
|
||||
elements.actionDialogTitle.textContent = title;
|
||||
@@ -391,7 +392,13 @@ function requestModelName({
|
||||
elements.actionDialogInput.select();
|
||||
});
|
||||
return new Promise((resolve) => {
|
||||
actionDialogState = { resolve, previousFocus, expectedValue, expectedLabel };
|
||||
actionDialogState = {
|
||||
resolve,
|
||||
previousFocus,
|
||||
expectedValue,
|
||||
expectedLabel,
|
||||
ignoreCase
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
@@ -400,18 +407,25 @@ elements.actionDialogForm.addEventListener("submit", (event) => {
|
||||
const value = elements.actionDialogInput.value.trim();
|
||||
const expectedValue = actionDialogState?.expectedValue;
|
||||
const expectedLabel = actionDialogState?.expectedLabel || "输入内容";
|
||||
const ignoreCase = actionDialogState?.ignoreCase === true;
|
||||
if (!value) {
|
||||
elements.actionDialogError.textContent = `${expectedLabel}不能为空`;
|
||||
elements.actionDialogError.hidden = false;
|
||||
elements.actionDialogInput.focus();
|
||||
return;
|
||||
}
|
||||
if (expectedValue !== null && value !== expectedValue) {
|
||||
if (expectedValue !== null) {
|
||||
const expected = String(expectedValue).trim();
|
||||
const matched = ignoreCase
|
||||
? value.toLowerCase() === expected.toLowerCase()
|
||||
: value === expected;
|
||||
if (!matched) {
|
||||
elements.actionDialogError.textContent = `${expectedLabel}不匹配,请按提示完整输入`;
|
||||
elements.actionDialogError.hidden = false;
|
||||
elements.actionDialogInput.focus();
|
||||
return;
|
||||
}
|
||||
}
|
||||
closeActionDialog(value);
|
||||
});
|
||||
elements.actionDialogCancel.addEventListener("click", () => closeActionDialog(null));
|
||||
@@ -708,7 +722,8 @@ document.querySelector("#delete-line").addEventListener("click", async () => {
|
||||
confirmLabel: "删除产线",
|
||||
danger: true,
|
||||
expectedValue: line.deviceId,
|
||||
expectedLabel: "deviceId"
|
||||
expectedLabel: "deviceId",
|
||||
ignoreCase: true
|
||||
});
|
||||
if (confirmation === null) return;
|
||||
const result = await runBusy("正在删除产线", () => window.reinloop.deleteProductionLine({
|
||||
@@ -734,7 +749,8 @@ document.querySelector("#delete-company").addEventListener("click", async () =>
|
||||
confirmLabel: "删除公司",
|
||||
danger: true,
|
||||
expectedValue: company.code,
|
||||
expectedLabel: "公司编码"
|
||||
expectedLabel: "公司编码",
|
||||
ignoreCase: true
|
||||
});
|
||||
if (confirmation === null) return;
|
||||
const result = await runBusy("正在删除公司", () => window.reinloop.deleteCompany({
|
||||
@@ -797,12 +813,13 @@ elements.licenseList.addEventListener("click", async (event) => {
|
||||
if (deleteId) {
|
||||
const confirmation = await requestModelName({
|
||||
title: "确认删除许可证",
|
||||
message: "已撤销许可证才能删除。请输入许可证 ID 以确认永久删除。",
|
||||
message: `已撤销许可证才能删除。请输入许可证 ID 以确认永久删除。\n\n当前许可证 ID:${deleteId}`,
|
||||
value: "",
|
||||
confirmLabel: "永久删除",
|
||||
danger: true,
|
||||
expectedValue: deleteId,
|
||||
expectedLabel: "许可证ID"
|
||||
expectedLabel: "许可证ID",
|
||||
ignoreCase: true
|
||||
});
|
||||
if (confirmation === null) return;
|
||||
button.disabled = true;
|
||||
|
||||
@@ -371,6 +371,28 @@ function createApp({
|
||||
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) {
|
||||
for (const record of database.fileRecords) {
|
||||
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)
|
||||
);
|
||||
|
||||
const deletedDirectories = await removeDeviceDirectories(deviceId);
|
||||
database.productionLines = database.productionLines.filter((item) => item.id !== productionLineId);
|
||||
|
||||
return {
|
||||
success: true,
|
||||
deletedProductionLineId: productionLineId,
|
||||
deletedFiles: deletedFileCount,
|
||||
deletedDirectories,
|
||||
deletedLicenses: revokedLicenses,
|
||||
deletedFeedback,
|
||||
deletedVolumeRequests: deletedRequests,
|
||||
|
||||
@@ -877,6 +877,14 @@ test("deleteProductionLine blocks active licenses and removes revoked data", asy
|
||||
assert.equal(blocked.errCode, "ACTIVE_LICENSES_PRESENT");
|
||||
|
||||
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({
|
||||
type: "deleteProductionLine",
|
||||
companyId: company.company.id,
|
||||
@@ -886,6 +894,10 @@ test("deleteProductionLine blocks active licenses and removes revoked data", asy
|
||||
assert.equal(deleted.success, true);
|
||||
assert.ok(deleted.deletedFiles >= 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 listedCompany = organizations.companies.find((item) => item.id === company.company.id);
|
||||
|
||||
Reference in New Issue
Block a user