(function () {
|
var config = Object.assign({
|
apiBaseUrl: "http://localhost:9098"
|
}, window.VISITOR_LOGIN_CONFIG || {});
|
|
var DEFAULT_PRINT_OPTIONS = [
|
{ fieldCode: "visitorName", fieldName: "访客姓名" },
|
{ fieldCode: "idCard", fieldName: "身份证号" },
|
{ fieldCode: "appointmentTimeRange", fieldName: "预约时间范围" },
|
{ fieldCode: "interviewee", fieldName: "被访者" },
|
{ fieldCode: "visitorFaceImage", fieldName: "访客人脸图片" },
|
{ fieldCode: "registerNo", fieldName: "登记编号" },
|
{ fieldCode: "plateNo", fieldName: "车牌号" },
|
{ fieldCode: "visitReason", fieldName: "来访事由" },
|
{ fieldCode: "visitArea", fieldName: "访问区域" }
|
];
|
|
var SAMPLE_VALUES = {
|
visitorName: { label: "访客", value: "王丽" },
|
idCard: { label: "身份证号码", value: "5109021548416116" },
|
appointmentTimeRange: { label: "访问时间", value: "2026-05-15 上午" },
|
interviewee: { label: "被访人", value: "李明" },
|
visitorFaceImage: { label: "人像", value: "" },
|
registerNo: { label: "登记编号", value: "DJ202605150001" },
|
plateNo: { label: "车牌号", value: "川A·156165" },
|
visitReason: { label: "来访事由", value: "业务拜访" },
|
visitArea: { label: "访问区域", value: "物业部" }
|
};
|
|
var state = {
|
printOptions: DEFAULT_PRINT_OPTIONS.slice(),
|
selectedPrintFields: ["visitorName", "idCard", "appointmentTimeRange", "interviewee"],
|
logoUrl: "",
|
logoFile: null,
|
draggingCode: ""
|
};
|
|
init();
|
|
function init() {
|
if (!getToken()) {
|
redirectToLogin();
|
return;
|
}
|
bindLayoutActions();
|
bindConfigTabs();
|
bindFormActions();
|
applyUserInfo(readLoginUser());
|
loadProfileName();
|
loadConfig();
|
}
|
|
function bindLayoutActions() {
|
var userMenuButton = document.getElementById("userMenuButton");
|
var userDropdown = document.getElementById("userDropdown");
|
var fullscreenButton = document.querySelector(".icon-button");
|
|
userMenuButton.addEventListener("click", function (event) {
|
event.stopPropagation();
|
var hidden = userDropdown.hidden;
|
userDropdown.hidden = !hidden;
|
userMenuButton.setAttribute("aria-expanded", String(hidden));
|
});
|
|
userDropdown.addEventListener("click", function (event) {
|
var action = event.target.getAttribute("data-action");
|
if (!action) {
|
return;
|
}
|
userDropdown.hidden = true;
|
userMenuButton.setAttribute("aria-expanded", "false");
|
if (action === "home") {
|
window.location.href = "./dashboard.html";
|
} else if (action === "logout") {
|
logout();
|
}
|
});
|
|
document.addEventListener("click", function () {
|
userDropdown.hidden = true;
|
userMenuButton.setAttribute("aria-expanded", "false");
|
});
|
|
fullscreenButton.addEventListener("click", function () {
|
if (!document.fullscreenElement && document.documentElement.requestFullscreen) {
|
document.documentElement.requestFullscreen();
|
} else if (document.exitFullscreen) {
|
document.exitFullscreen();
|
}
|
});
|
}
|
|
function bindConfigTabs() {
|
document.querySelectorAll("[data-config-tab]").forEach(function (button) {
|
button.addEventListener("click", function () {
|
var tab = button.getAttribute("data-config-tab");
|
document.querySelectorAll("[data-config-tab]").forEach(function (item) {
|
item.classList.toggle("active", item === button);
|
});
|
document.querySelectorAll("[data-tab-panel]").forEach(function (panel) {
|
panel.classList.toggle("active", panel.getAttribute("data-tab-panel") === tab);
|
});
|
});
|
});
|
}
|
|
function bindFormActions() {
|
document.getElementById("configForm").addEventListener("submit", function (event) {
|
event.preventDefault();
|
saveConfig();
|
});
|
|
document.getElementById("logoFile").addEventListener("change", function (event) {
|
var file = event.target.files && event.target.files[0];
|
if (!file) {
|
state.logoFile = null;
|
updateLogoFileName();
|
return;
|
}
|
if (!/^image\//.test(file.type)) {
|
state.logoFile = null;
|
event.target.value = "";
|
updateLogoFileName();
|
AppMessage.error("操作失败:请选择图片文件");
|
return;
|
}
|
state.logoFile = file;
|
updateLogoFileName(file.name);
|
});
|
|
document.getElementById("refreshPreview").addEventListener("click", function () {
|
renderTicketPreview();
|
AppMessage.success("操作成功");
|
});
|
}
|
|
function loadProfileName() {
|
apiRequest("/system/user/profile", { method: "GET" }).then(function (result) {
|
applyUserInfo(result.data || {});
|
}).catch(function () {
|
applyUserInfo(readLoginUser());
|
});
|
}
|
|
function loadConfig() {
|
apiRequest("/system/visitor/config/detail", { method: "POST" }).then(function (result) {
|
applyConfig(result.data || {});
|
}).catch(function (error) {
|
applyConfig({});
|
AppMessage.error("操作失败:" + (error.message || "系统配置加载失败"));
|
});
|
}
|
|
function applyConfig(data) {
|
setChecked("onsiteRegistrationEnabled", data.onsiteRegistrationEnabled, true);
|
setChecked("appointmentRegistrationEnabled", data.appointmentRegistrationEnabled, true);
|
setChecked("registerReceiverConfirmEnabled", data.registerReceiverConfirmEnabled, true);
|
setChecked("signReceiverConfirmEnabled", data.signReceiverConfirmEnabled, true);
|
setChecked("faceCompareEnabled", data.faceCompareEnabled, true);
|
setChecked("faceCaptureEnabled", data.faceCaptureEnabled, true);
|
setChecked("manualIdCardEnabled", data.manualIdCardEnabled, true);
|
setChecked("visitorMachineEntryEnabled", data.visitorMachineEntryEnabled, true);
|
|
document.getElementById("systemName").value = data.systemName || "自主访客登记管理平台";
|
document.getElementById("serviceProvider").value = data.serviceProvider || "XXX";
|
document.getElementById("supportPhone").value = data.supportPhone || "XXX";
|
|
state.logoUrl = data.logoUrl || "";
|
state.logoFile = null;
|
document.getElementById("logoFile").value = "";
|
updateLogoFileName();
|
|
state.printOptions = normalizePrintOptions(data.printFieldOptions);
|
state.selectedPrintFields = normalizeSelectedFields(data.printFields);
|
renderPrintFields();
|
renderTicketPreview();
|
}
|
|
function normalizePrintOptions(options) {
|
var labelMap = DEFAULT_PRINT_OPTIONS.reduce(function (map, item) {
|
map[item.fieldCode] = item.fieldName;
|
return map;
|
}, {});
|
var source = Array.isArray(options) && options.length ? options : DEFAULT_PRINT_OPTIONS;
|
var result = [];
|
source.forEach(function (item) {
|
var code = item.fieldCode || item.code || "";
|
if (!code) {
|
return;
|
}
|
result.push({
|
fieldCode: code,
|
fieldName: labelMap[code] || item.fieldName || item.label || code
|
});
|
});
|
return result.length ? result : DEFAULT_PRINT_OPTIONS.slice();
|
}
|
|
function normalizeSelectedFields(fields) {
|
var validCodes = state.printOptions.map(function (item) {
|
return item.fieldCode;
|
});
|
var selected = Array.isArray(fields) ? fields.filter(function (code, index) {
|
return validCodes.indexOf(code) !== -1 && fields.indexOf(code) === index;
|
}) : [];
|
if (selected.length) {
|
return selected;
|
}
|
return ["visitorName", "idCard", "appointmentTimeRange", "interviewee"].filter(function (code) {
|
return validCodes.indexOf(code) !== -1;
|
});
|
}
|
|
function renderPrintFields() {
|
var root = document.getElementById("printFieldList");
|
var selectedSet = state.selectedPrintFields.reduce(function (map, code) {
|
map[code] = true;
|
return map;
|
}, {});
|
var orderedOptions = state.selectedPrintFields.map(findPrintOption).filter(Boolean);
|
state.printOptions.forEach(function (option) {
|
if (!selectedSet[option.fieldCode]) {
|
orderedOptions.push(option);
|
}
|
});
|
|
root.innerHTML = orderedOptions.map(function (option) {
|
var checked = selectedSet[option.fieldCode];
|
return [
|
'<label class="print-field-item' + (checked ? " draggable" : "") + '" draggable="' + String(checked) + '" data-code="' + escapeHtml(option.fieldCode) + '">',
|
' <input type="checkbox" value="' + escapeHtml(option.fieldCode) + '"' + (checked ? " checked" : "") + '>',
|
' <span>' + escapeHtml(option.fieldName) + '</span>',
|
'</label>'
|
].join("");
|
}).join("");
|
|
root.querySelectorAll("input[type='checkbox']").forEach(function (checkbox) {
|
checkbox.addEventListener("change", function () {
|
togglePrintField(checkbox.value, checkbox.checked);
|
});
|
});
|
|
root.querySelectorAll(".print-field-item").forEach(function (item) {
|
item.addEventListener("dragstart", handleDragStart);
|
item.addEventListener("dragover", handleDragOver);
|
item.addEventListener("drop", handleDrop);
|
item.addEventListener("dragend", handleDragEnd);
|
});
|
}
|
|
function togglePrintField(code, checked) {
|
var index = state.selectedPrintFields.indexOf(code);
|
if (checked && index === -1) {
|
state.selectedPrintFields.push(code);
|
} else if (!checked && index !== -1) {
|
state.selectedPrintFields.splice(index, 1);
|
}
|
renderPrintFields();
|
renderTicketPreview();
|
}
|
|
function handleDragStart(event) {
|
var code = event.currentTarget.getAttribute("data-code");
|
if (state.selectedPrintFields.indexOf(code) === -1) {
|
event.preventDefault();
|
return;
|
}
|
state.draggingCode = code;
|
event.currentTarget.classList.add("dragging");
|
event.dataTransfer.effectAllowed = "move";
|
}
|
|
function handleDragOver(event) {
|
var targetCode = event.currentTarget.getAttribute("data-code");
|
if (state.selectedPrintFields.indexOf(targetCode) === -1) {
|
return;
|
}
|
event.preventDefault();
|
event.dataTransfer.dropEffect = "move";
|
}
|
|
function handleDrop(event) {
|
event.preventDefault();
|
var targetCode = event.currentTarget.getAttribute("data-code");
|
moveSelectedField(state.draggingCode, targetCode);
|
}
|
|
function handleDragEnd(event) {
|
event.currentTarget.classList.remove("dragging");
|
state.draggingCode = "";
|
}
|
|
function moveSelectedField(sourceCode, targetCode) {
|
if (!sourceCode || !targetCode || sourceCode === targetCode) {
|
return;
|
}
|
var sourceIndex = state.selectedPrintFields.indexOf(sourceCode);
|
var targetIndex = state.selectedPrintFields.indexOf(targetCode);
|
if (sourceIndex === -1 || targetIndex === -1) {
|
return;
|
}
|
state.selectedPrintFields.splice(sourceIndex, 1);
|
state.selectedPrintFields.splice(targetIndex, 0, sourceCode);
|
renderPrintFields();
|
renderTicketPreview();
|
}
|
|
function renderTicketPreview() {
|
var root = document.getElementById("ticketRows");
|
var rows = [
|
{ label: "登记时间", value: "2026-05-15 12:25" }
|
];
|
state.selectedPrintFields.forEach(function (code) {
|
if (SAMPLE_VALUES[code]) {
|
rows.push(SAMPLE_VALUES[code]);
|
}
|
});
|
rows.push({ label: "接待人", value: "张三" });
|
|
root.innerHTML = rows.map(function (row) {
|
if (row.label === "人像") {
|
return [
|
'<div class="ticket-row">',
|
' <strong>人像</strong>',
|
' <span class="ticket-face">⌂</span>',
|
'</div>'
|
].join("");
|
}
|
return [
|
'<div class="ticket-row">',
|
' <strong>' + escapeHtml(row.label) + '</strong>',
|
' <span>' + escapeHtml(row.value) + '</span>',
|
'</div>'
|
].join("");
|
}).join("");
|
}
|
|
function saveConfig() {
|
var saveButton = document.getElementById("saveConfigButton");
|
var payload = collectPayload();
|
if (!payload) {
|
return;
|
}
|
|
saveButton.disabled = true;
|
uploadLogoIfNeeded().then(function (logoUrl) {
|
if (logoUrl) {
|
payload.logoUrl = logoUrl;
|
}
|
return apiRequest("/system/visitor/config/save", {
|
method: "POST",
|
body: JSON.stringify(payload)
|
});
|
}).then(function (result) {
|
applyConfig(result.data || payload);
|
AppMessage.success("操作成功");
|
}).catch(function (error) {
|
AppMessage.error("操作失败:" + (error.message || "系统配置保存失败"));
|
}).then(function () {
|
saveButton.disabled = false;
|
});
|
}
|
|
function collectPayload() {
|
if (!state.selectedPrintFields.length) {
|
AppMessage.error("操作失败:打印凭条至少选择一个字段");
|
return null;
|
}
|
var systemName = valueOf("systemName");
|
if (!systemName) {
|
AppMessage.error("操作失败:系统名称不能为空");
|
return null;
|
}
|
return {
|
onsiteRegistrationEnabled: checkedOf("onsiteRegistrationEnabled"),
|
appointmentRegistrationEnabled: checkedOf("appointmentRegistrationEnabled"),
|
registerReceiverConfirmEnabled: checkedOf("registerReceiverConfirmEnabled"),
|
signReceiverConfirmEnabled: checkedOf("signReceiverConfirmEnabled"),
|
faceCompareEnabled: checkedOf("faceCompareEnabled"),
|
faceCaptureEnabled: checkedOf("faceCaptureEnabled"),
|
manualIdCardEnabled: checkedOf("manualIdCardEnabled"),
|
printFields: state.selectedPrintFields.slice(),
|
systemName: systemName,
|
logoUrl: state.logoUrl,
|
serviceProvider: valueOf("serviceProvider"),
|
supportPhone: valueOf("supportPhone"),
|
visitorMachineEntryEnabled: checkedOf("visitorMachineEntryEnabled")
|
};
|
}
|
|
function uploadLogoIfNeeded() {
|
if (!state.logoFile) {
|
return Promise.resolve("");
|
}
|
var formData = new FormData();
|
formData.append("file", state.logoFile);
|
return apiRequest("/common/upload", {
|
method: "POST",
|
body: formData,
|
skipJson: true
|
}).then(function (result) {
|
state.logoUrl = result.url || result.fileName || "";
|
state.logoFile = null;
|
document.getElementById("logoFile").value = "";
|
updateLogoFileName();
|
return state.logoUrl;
|
});
|
}
|
|
function apiRequest(path, options) {
|
options = options || {};
|
var headers = options.headers || {};
|
var token = getToken();
|
if (token) {
|
headers.Authorization = "Bearer " + token;
|
}
|
if (!options.skipJson) {
|
headers["Content-Type"] = "application/json";
|
}
|
|
return fetch(getApiBaseUrl() + normalizePath(path), {
|
method: options.method || "GET",
|
headers: headers,
|
body: options.body
|
}).then(function (response) {
|
return response.json().catch(function () {
|
return { code: response.ok ? 200 : response.status, msg: response.statusText };
|
});
|
}).then(function (result) {
|
if (result.code === 401) {
|
clearLoginState();
|
redirectToLogin();
|
throw new Error(result.msg || "登录状态已过期");
|
}
|
if (result.code !== 200) {
|
throw new Error(result.msg || "请求失败");
|
}
|
return result;
|
});
|
}
|
|
function logout() {
|
apiRequest("/logout", {
|
method: "POST",
|
skipJson: true
|
}).catch(function () {
|
return null;
|
}).then(function () {
|
clearLoginState();
|
redirectToLogin();
|
});
|
}
|
|
function applyUserInfo(user) {
|
user = user || {};
|
var displayName = user.nickName || user.userName || user.username || "用户";
|
document.getElementById("userDisplayName").textContent = displayName;
|
document.querySelector(".user-avatar").textContent = displayName.substring(0, 1);
|
}
|
|
function readLoginUser() {
|
try {
|
var loginResult = JSON.parse(localStorage.getItem("visitor_admin_login_result") || "{}");
|
return (loginResult.userInfo && loginResult.userInfo.user) || loginResult.user || {};
|
} catch (error) {
|
return {};
|
}
|
}
|
|
function updateLogoFileName(fileName) {
|
var text = fileName || (state.logoUrl ? getFileName(state.logoUrl) : "未选择任何文件");
|
document.getElementById("logoFileName").textContent = text;
|
}
|
|
function getFileName(path) {
|
var value = String(path || "");
|
return value.substring(value.lastIndexOf("/") + 1) || "已配置Logo";
|
}
|
|
function findPrintOption(code) {
|
for (var index = 0; index < state.printOptions.length; index++) {
|
if (state.printOptions[index].fieldCode === code) {
|
return state.printOptions[index];
|
}
|
}
|
return null;
|
}
|
|
function setChecked(id, value, fallback) {
|
document.getElementById(id).checked = typeof value === "boolean" ? value : fallback;
|
}
|
|
function checkedOf(id) {
|
return document.getElementById(id).checked;
|
}
|
|
function valueOf(id) {
|
return document.getElementById(id).value.trim();
|
}
|
|
function getApiBaseUrl() {
|
return trimRightSlash(localStorage.getItem("visitor_admin_api_base") || config.apiBaseUrl || window.location.origin);
|
}
|
|
function getToken() {
|
return localStorage.getItem("visitor_admin_token") || "";
|
}
|
|
function clearLoginState() {
|
localStorage.removeItem("visitor_admin_token");
|
localStorage.removeItem("visitor_admin_login_result");
|
localStorage.removeItem("visitor_admin_api_base");
|
}
|
|
function redirectToLogin() {
|
window.location.href = "../index.html";
|
}
|
|
function normalizePath(path) {
|
return "/" + String(path || "").replace(/^\/+/, "");
|
}
|
|
function trimRightSlash(value) {
|
return String(value || "").replace(/\/+$/, "");
|
}
|
|
function escapeHtml(value) {
|
return String(value == null ? "" : value).replace(/[&<>"']/g, function (char) {
|
return {
|
"&": "&",
|
"<": "<",
|
">": ">",
|
'"': """,
|
"'": "'"
|
}[char];
|
});
|
}
|
})();
|