fix license check

This commit is contained in:
2026-08-03 15:18:28 +08:00
parent 2090597858
commit bae71f3253
11 changed files with 469 additions and 20 deletions
+13
View File
@@ -246,6 +246,14 @@ function registerHandlers() {
callServer({ type: "createCompany", name: request.name, code: request.code }, request.credentials));
ipcMain.handle("organization:create-line", (_event, request) =>
callServer({ type: "createProductionLine", companyId: request.companyId, name: request.name, code: request.code }, request.credentials));
ipcMain.handle("organization:delete-company", (_event, request) =>
callServer({ type: "deleteCompany", companyId: request.companyId }, request.credentials));
ipcMain.handle("organization:delete-line", (_event, request) =>
callServer({
type: "deleteProductionLine",
companyId: request.companyId,
productionLineId: request.productionLineId
}, request.credentials));
ipcMain.handle("license:issue", async (_event, request) => {
const keySelection = await dialog.showOpenDialog({
@@ -295,6 +303,11 @@ function registerHandlers() {
{ type: "revokeLicense", licenseId: request.licenseId, reason: request.reason },
resolveCredentials(request.credentials)
));
ipcMain.handle("license:delete", (_event, request) =>
callServer(
{ type: "deleteLicense", licenseId: request.licenseId },
resolveCredentials(request.credentials)
));
ipcMain.handle("license:download", async (_event, request) => {
const resolvedCredentials = resolveCredentials(request.credentials);
const result = await callServer(
+3
View File
@@ -15,7 +15,10 @@ contextBridge.exposeInMainWorld("reinloop", {
listLicenses: (credentials) => ipcRenderer.invoke("license:list", credentials),
getLicense: (request) => ipcRenderer.invoke("license:get", request),
revokeLicense: (request) => ipcRenderer.invoke("license:revoke", request),
deleteLicense: (request) => ipcRenderer.invoke("license:delete", request),
downloadLicense: (request) => ipcRenderer.invoke("license:download", request),
deleteCompany: (request) => ipcRenderer.invoke("organization:delete-company", request),
deleteProductionLine: (request) => ipcRenderer.invoke("organization:delete-line", request),
submitReview: (request) => ipcRenderer.invoke("review:submit", request),
listModels: (request) => ipcRenderer.invoke("model:list", request),
chooseModelUploadFile: () => ipcRenderer.invoke("model:choose-upload-file"),
+2
View File
@@ -211,6 +211,7 @@
<label><span>公司名称</span><input id="company-name" required></label>
<label><span>公司编码</span><input id="company-code" pattern="[a-z0-9][a-z0-9_-]{1,63}" required></label>
<button class="button primary" type="submit">添加公司</button>
<button id="delete-company" class="button danger" type="button">删除当前公司</button>
</form>
<form id="line-form" class="form-surface">
<h3>添加产线</h3>
@@ -218,6 +219,7 @@
<label><span>产线名称</span><input id="line-name" required></label>
<label><span>产线编码</span><input id="line-code" pattern="[a-z0-9][a-z0-9_-]{1,63}" required></label>
<button class="button primary" type="submit">添加产线</button>
<button id="delete-line" class="button danger" type="button">删除当前产线</button>
</form>
</div>
</section>
+79 -1
View File
@@ -275,7 +275,7 @@ async function refreshLicenses() {
elements.licenseList.innerHTML = result.licenses.map((license) => `
<tr><td>${escapeHtml(license.companyName)} / ${escapeHtml(license.productionLineName)}</td>
<td>${escapeHtml(license.expiry)}</td><td>${license.status === "active" ? "有效" : "已撤销"}</td>
<td><button class="table-action" data-license-detail="${escapeHtml(license.licenseId)}">详情</button><button class="table-action" data-license-download="${escapeHtml(license.licenseId)}">下载</button>${license.status === "active" ? `<button class="table-action danger" data-license-revoke="${escapeHtml(license.licenseId)}">撤销</button>` : ""}</td></tr>
<td><button class="table-action" data-license-detail="${escapeHtml(license.licenseId)}">详情</button><button class="table-action" data-license-download="${escapeHtml(license.licenseId)}">下载</button>${license.status === "active" ? `<button class="table-action danger" data-license-revoke="${escapeHtml(license.licenseId)}">撤销</button>` : `<button class="table-action danger" data-license-delete="${escapeHtml(license.licenseId)}">删除</button>`}</td></tr>
`).join("");
elements.licenseEmpty.hidden = result.licenses.length > 0;
setStatus("许可证已刷新", "success");
@@ -688,6 +688,56 @@ document.querySelector("#line-form").addEventListener("submit", async (event) =>
await refreshOrganizations();
});
document.querySelector("#delete-line").addEventListener("click", async () => {
const company = selectedCompany();
const line = selectedLine();
if (!company || !line) return showError(new Error("请先选择公司和产线"));
const confirmation = await requestModelName({
title: "确认删除产线",
message: `删除产线 ${line.name} 后将清理关联业务数据。请输入完整 deviceId 以确认。`,
value: "",
confirmLabel: "删除产线",
danger: true,
expectedValue: line.deviceId
});
if (confirmation === null) return;
const result = await runBusy("正在删除产线", () => window.reinloop.deleteProductionLine({
companyId: company.id,
productionLineId: line.id,
credentials: credentials()
}));
if (!result) return;
elements.licenseDetail.hidden = true;
elements.licenseDetail.textContent = "";
await refreshOrganizations();
await refreshLicenses();
setStatus("产线已删除", "success");
});
document.querySelector("#delete-company").addEventListener("click", async () => {
const company = selectedCompany();
if (!company) return showError(new Error("请先选择公司"));
const confirmation = await requestModelName({
title: "确认删除公司",
message: `删除公司 ${company.name} 前必须先删除其产线与许可证。请输入公司编码以确认。`,
value: "",
confirmLabel: "删除公司",
danger: true,
expectedValue: company.code
});
if (confirmation === null) return;
const result = await runBusy("正在删除公司", () => window.reinloop.deleteCompany({
companyId: company.id,
credentials: credentials()
}));
if (!result) return;
elements.licenseDetail.hidden = true;
elements.licenseDetail.textContent = "";
await refreshOrganizations();
await refreshLicenses();
setStatus("公司已删除", "success");
});
document.querySelector("#license-form").addEventListener("submit", async (event) => {
event.preventDefault();
const company = selectedCompany();
@@ -712,6 +762,7 @@ elements.licenseList.addEventListener("click", async (event) => {
const detailId = button.dataset.licenseDetail;
const downloadId = button.dataset.licenseDownload;
const revokeId = button.dataset.licenseRevoke;
const deleteId = button.dataset.licenseDelete;
if (detailId) {
const result = await runBusy("正在读取许可证详情", () => window.reinloop.getLicense({ licenseId: detailId, credentials: credentials() }));
if (result) {
@@ -732,6 +783,33 @@ elements.licenseList.addEventListener("click", async (event) => {
}
return;
}
if (deleteId) {
const confirmation = await requestModelName({
title: "确认删除许可证",
message: "已撤销许可证才能删除。请输入许可证 ID 以确认永久删除。",
value: "",
confirmLabel: "永久删除",
danger: true,
expectedValue: deleteId
});
if (confirmation === null) return;
button.disabled = true;
try {
const result = await runBusy("正在删除许可证", () => window.reinloop.deleteLicense({
licenseId: deleteId,
credentials: credentials()
}));
if (result) {
await refreshLicenses();
elements.licenseDetail.hidden = true;
elements.licenseDetail.textContent = "";
setStatus("许可证已删除", "success");
}
} finally {
button.disabled = false;
}
return;
}
if (revokeId) {
const reason = await requestModelName({
title: "确认撤销许可证",