169 lines
6.9 KiB
JavaScript
169 lines
6.9 KiB
JavaScript
// 外部系统连接管理:凭据只提交、不回显;查询能力在下一轮 build_agent 时按用户动态挂载。
|
||
import { $ } from "./dom.js";
|
||
import { api } from "./api.js";
|
||
import { escapeHtml, fmtTime } from "./format.js";
|
||
import { dialogConfirm, message } from "./dialog.js";
|
||
|
||
let editingId = "";
|
||
let providerReady = false;
|
||
let definitions = [];
|
||
|
||
function resetForm() {
|
||
editingId = "";
|
||
$("ext-form-title").textContent = "连接 Factory MES";
|
||
$("ext-name").value = "Factory MES";
|
||
$("ext-name").disabled = false;
|
||
$("ext-definition").disabled = false;
|
||
$("ext-username").value = "";
|
||
$("ext-password").value = "";
|
||
$("ext-err").textContent = "";
|
||
$("ext-save").textContent = "连接并验证";
|
||
$("ext-form-cancel").hidden = true;
|
||
}
|
||
|
||
export function closeExternalSystemsModal() {
|
||
$("external-modal").classList.remove("show");
|
||
resetForm();
|
||
}
|
||
|
||
async function openExternalSystemsModal() {
|
||
$("external-modal").classList.add("show");
|
||
resetForm();
|
||
await loadExternalSystems();
|
||
}
|
||
|
||
function cardHtml(item) {
|
||
const good = item.status === "active";
|
||
const badge = good ? "已连接" : (item.status === "disabled" ? "系统已停用" : "需更新凭据");
|
||
const checked = item.last_verified_at ? fmtTime(item.last_verified_at) : "尚未验证";
|
||
return `<div class="ext-card" data-id="${escapeHtml(item.external_system_id)}">
|
||
<div class="ext-card-head"><span class="ext-card-name">${escapeHtml(item.name)}</span><span class="sk-badge">${badge}</span></div>
|
||
<div class="meta">${escapeHtml(item.system_name || "Factory MES")} · ${escapeHtml(item.username_masked || "***")} · 最近验证 ${escapeHtml(checked)}</div>
|
||
<div class="ext-actions">
|
||
<button type="button" class="small" data-ext-test>测试连接</button>
|
||
<button type="button" class="small" data-ext-edit>更新凭据</button>
|
||
<button type="button" class="small danger" data-ext-delete>断开</button>
|
||
</div>
|
||
</div>`;
|
||
}
|
||
|
||
async function loadExternalSystems() {
|
||
const provider = $("ext-provider");
|
||
const list = $("ext-list");
|
||
provider.textContent = "加载中…";
|
||
list.innerHTML = '<div class="muted">加载中…</div>';
|
||
try {
|
||
const [p, systems] = await Promise.all([
|
||
api("GET", "/v1/external-system-providers"),
|
||
api("GET", "/v1/external-systems"),
|
||
]);
|
||
const factory = (p.providers || []).find((x) => x.provider === "factory_mes");
|
||
definitions = (factory && factory.definitions) || [];
|
||
providerReady = !!(factory && factory.configured && definitions.length);
|
||
$("ext-definition").innerHTML = definitions.map(x =>
|
||
`<option value="${escapeHtml(x.definition_id)}">${escapeHtml(x.name)}${x.host ? " · " + escapeHtml(x.host) : ""}</option>`
|
||
).join("");
|
||
if (!editingId && definitions.length) $("ext-name").value = definitions[0].name;
|
||
provider.textContent = providerReady
|
||
? `管理员已配置 ${definitions.length} 个 MES 系统,请选择后使用自己的 MES 账号连接`
|
||
: `暂没有可连接的 MES 系统${factory && factory.reason ? ":" + factory.reason : ",请联系管理员配置"}`;
|
||
$("ext-save").disabled = !providerReady;
|
||
const rows = systems.results || [];
|
||
list.innerHTML = rows.length
|
||
? rows.map(cardHtml).join("")
|
||
: '<div class="sk-empty">还没有外部系统连接。填写下方 MES 账号后,助手即可按你的 MES 权限查询。</div>';
|
||
} catch (e) {
|
||
providerReady = false;
|
||
provider.textContent = "加载失败";
|
||
list.innerHTML = `<div class="err">${escapeHtml(e.message)}</div>`;
|
||
$("ext-save").disabled = true;
|
||
}
|
||
}
|
||
|
||
$("hd-external").onclick = openExternalSystemsModal;
|
||
$("ext-close").onclick = closeExternalSystemsModal;
|
||
$("external-modal").addEventListener("click", (e) => {
|
||
if (e.target.id === "external-modal") closeExternalSystemsModal();
|
||
});
|
||
$("ext-form-cancel").onclick = resetForm;
|
||
$("ext-definition").onchange = () => {
|
||
if (editingId) return;
|
||
const selected = definitions.find(x => x.definition_id === $("ext-definition").value);
|
||
if (selected) $("ext-name").value = selected.name;
|
||
};
|
||
|
||
$("ext-form").addEventListener("submit", async (e) => {
|
||
e.preventDefault();
|
||
if (!providerReady) return;
|
||
const username = $("ext-username").value.trim();
|
||
const password = $("ext-password").value;
|
||
const name = $("ext-name").value.trim();
|
||
const definitionId = $("ext-definition").value;
|
||
if (!username || !password || (!editingId && (!name || !definitionId))) {
|
||
$("ext-err").textContent = "请填写连接名称、MES 用户名和密码";
|
||
return;
|
||
}
|
||
const btn = $("ext-save");
|
||
btn.disabled = true;
|
||
btn.textContent = "正在验证…";
|
||
$("ext-err").textContent = "";
|
||
try {
|
||
if (editingId) {
|
||
await api("PUT", `/v1/external-systems/${editingId}/credentials`, { username, password });
|
||
message("Factory MES 凭据已更新", "success");
|
||
} else {
|
||
await api("POST", "/v1/external-systems", {
|
||
definition_id: definitionId, name, username, password,
|
||
});
|
||
message("Factory MES 已连接;下一轮对话即可使用", "success");
|
||
}
|
||
resetForm();
|
||
await loadExternalSystems();
|
||
} catch (err) {
|
||
$("ext-err").textContent = err.message;
|
||
} finally {
|
||
btn.disabled = !providerReady;
|
||
btn.textContent = editingId ? "验证并更新" : "连接并验证";
|
||
}
|
||
});
|
||
|
||
$("ext-list").addEventListener("click", async (e) => {
|
||
const card = e.target.closest(".ext-card");
|
||
if (!card) return;
|
||
const id = card.dataset.id;
|
||
if (e.target.closest("[data-ext-edit]")) {
|
||
editingId = id;
|
||
$("ext-form-title").textContent = "更新 Factory MES 凭据";
|
||
$("ext-name").value = card.querySelector(".ext-card-name").textContent;
|
||
$("ext-name").disabled = true;
|
||
$("ext-definition").disabled = true;
|
||
$("ext-username").value = "";
|
||
$("ext-password").value = "";
|
||
$("ext-save").textContent = "验证并更新";
|
||
$("ext-form-cancel").hidden = false;
|
||
$("ext-username").focus();
|
||
return;
|
||
}
|
||
if (e.target.closest("[data-ext-test]")) {
|
||
const btn = e.target.closest("button");
|
||
btn.disabled = true;
|
||
try {
|
||
const result = await api("POST", `/v1/external-systems/${id}/test`);
|
||
message(result.ok ? `连接正常,可用接口 ${result.operation_count || 0} 个` : `连接失败:${result.error}`, result.ok ? "success" : "error");
|
||
await loadExternalSystems();
|
||
} catch (err) { message("测试失败:" + err.message, "error"); }
|
||
finally { btn.disabled = false; }
|
||
return;
|
||
}
|
||
if (e.target.closest("[data-ext-delete]")) {
|
||
const name = card.querySelector(".ext-card-name").textContent;
|
||
if (!await dialogConfirm({ title:"断开外部系统", message:`断开「${name}」?保存的 MES 密文凭据和连接配置将被清除。`, okText:"断开", danger:true })) return;
|
||
try {
|
||
await api("DELETE", `/v1/external-systems/${id}`);
|
||
message("外部系统已断开", "success");
|
||
resetForm();
|
||
await loadExternalSystems();
|
||
} catch (err) { message("断开失败:" + err.message, "error"); }
|
||
}
|
||
});
|