API 第一版定型

This commit is contained in:
Your Name
2026-01-31 00:01:19 +08:00
commit 588e3bb478
8 changed files with 2242 additions and 0 deletions
+410
View File
@@ -0,0 +1,410 @@
(function () {
'use strict';
// ---------- 状态 ----------
var isLoggedIn = false; // 页面1 登录态,静态演示默认未登录
var currentView = 'list'; // list | detail
var currentRole = 'market'; // market | admin | engineer
var currentProjectId = null; // 当前详情/编辑的项目 ID,null 表示新建
var projects = [];
var listFiltered = [];
// ---------- Mock 数据 ----------
function getMockProjects() {
return [
{
id: '1',
name: '城东 110kV 输变电工程',
contractCode: 'HT-2024-001',
progress: '进行中',
costStatus: '正常',
ownerUnit: '市供电公司',
},
{
id: '2',
name: '高新区配电改造项目',
contractCode: 'HT-2024-002',
progress: '已竣工',
costStatus: '正常',
ownerUnit: '高新区管委会',
},
{
id: '3',
name: '西区 35kV 线路迁改',
contractCode: 'HT-2024-003',
progress: '筹备中',
costStatus: '节余',
ownerUnit: '西区建设局',
},
];
}
function getMockLogs(projectId) {
return [
{ operator: '张三', time: '2025-01-28 14:30', summary: '修改合同信息' },
{ operator: '李四', time: '2025-01-27 10:00', summary: '修改成本控制' },
{ operator: '王五', time: '2025-01-26 16:45', summary: '修改应收款' },
];
}
// ---------- DOM ----------
var roleSelect = document.getElementById('roleSelect');
var btnNewProject = document.getElementById('btnNewProject');
var viewList = document.getElementById('view-list');
var viewDetail = document.getElementById('view-detail');
var searchType = document.getElementById('searchType');
var searchInput = document.getElementById('searchInput');
var btnSearch = document.getElementById('btnSearch');
var filterProgress = document.getElementById('filterProgress');
var filterCost = document.getElementById('filterCost');
var listLoading = document.getElementById('listLoading');
var listEmpty = document.getElementById('listEmpty');
var projectTable = document.getElementById('projectTable');
var projectTableBody = document.getElementById('projectTableBody');
var pagination = document.getElementById('pagination');
var btnBack = document.getElementById('btnBack');
var detailTitle = document.getElementById('detailTitle');
var detailLoading = document.getElementById('detailLoading');
var detailContent = document.getElementById('detailContent');
var btnViewLog = document.getElementById('btnViewLog');
var btnSave = document.getElementById('btnSave');
var logOverlay = document.getElementById('logOverlay');
var logDrawer = document.getElementById('logDrawer');
var logDrawerClose = document.getElementById('logDrawerClose');
var logLoading = document.getElementById('logLoading');
var logEmpty = document.getElementById('logEmpty');
var logList = document.getElementById('logList');
var toast = document.getElementById('toast');
var navList = document.getElementById('navList');
var viewLogin = document.getElementById('view-login');
var appMain = document.getElementById('appMain');
var loginForm = document.getElementById('loginForm');
var loginError = document.getElementById('loginError');
var btnLoginSubmit = document.getElementById('btnLoginSubmit');
var btnLogout = document.querySelector('.btn-logout');
// ---------- 页面1:登录 / 退出 ----------
function showLogin() {
isLoggedIn = false;
if (viewLogin) viewLogin.classList.remove('hidden');
if (appMain) appMain.style.display = 'none';
}
function showApp() {
isLoggedIn = true;
if (viewLogin) viewLogin.classList.add('hidden');
if (appMain) appMain.style.display = 'flex';
}
if (loginForm) {
loginForm.addEventListener('submit', function (e) {
e.preventDefault();
var account = document.getElementById('loginAccount');
var password = document.getElementById('loginPassword');
if (!account || !password) return;
if (loginError) loginError.style.display = 'none';
if (btnLoginSubmit) btnLoginSubmit.disabled = true;
// 静态演示:任意非空账号密码视为成功;可改为模拟失败(如 password === 'fail'
setTimeout(function () {
if (btnLoginSubmit) btnLoginSubmit.disabled = false;
if (password.value === 'fail') {
if (loginError) {
loginError.textContent = '账号或密码错误,请重试';
loginError.style.display = 'block';
}
return;
}
showApp();
renderList();
}, 400);
});
}
if (btnLogout) {
btnLogout.addEventListener('click', function () {
showLogin();
});
}
// ---------- 权限:是否市场部 ----------
function isMarketRole() {
return currentRole === 'market';
}
function updateRoleUI() {
if (btnNewProject) btnNewProject.style.display = isMarketRole() ? '' : 'none';
}
if (roleSelect) {
roleSelect.addEventListener('change', function () {
currentRole = roleSelect.value;
updateRoleUI();
});
}
// ---------- 视图切换 ----------
function showList() {
currentView = 'list';
if (viewList) viewList.classList.add('active');
if (viewDetail) viewDetail.classList.remove('active');
document.querySelectorAll('.nav-item').forEach(function (n) { n.classList.remove('active'); });
if (navList) navList.classList.add('active');
}
function showDetail(projectId) {
currentView = 'detail';
currentProjectId = projectId;
if (viewList) viewList.classList.remove('active');
if (viewDetail) viewDetail.classList.add('active');
document.querySelectorAll('.nav-item').forEach(function (n) { n.classList.remove('active'); });
if (detailTitle) detailTitle.textContent = projectId ? '项目详情' : '新建项目';
if (detailLoading) detailLoading.style.display = 'block';
if (detailContent) detailContent.style.display = 'none';
if (projectId) {
// 模拟加载详情
setTimeout(function () {
if (detailLoading) detailLoading.style.display = 'none';
if (detailContent) detailContent.style.display = 'block';
fillDetailForm(projectId);
}, 400);
} else {
if (detailLoading) detailLoading.style.display = 'none';
if (detailContent) detailContent.style.display = 'block';
clearDetailForm();
}
}
function fillDetailForm(projectId) {
var p = projects.find(function (x) { return x.id === projectId; });
if (!p) return;
var nameInput = detailContent.querySelector('input[name="projectName"]');
if (nameInput) nameInput.value = p.name || '';
var codeInput = detailContent.querySelector('input[name="contractCode"]');
if (codeInput) codeInput.value = p.contractCode || '';
var ownerInput = detailContent.querySelector('input[name="ownerUnit"]');
if (ownerInput) ownerInput.value = p.ownerUnit || '';
}
function clearDetailForm() {
var inputs = detailContent ? detailContent.querySelectorAll('input, select, textarea') : [];
inputs.forEach(function (el) {
if (el.type === 'checkbox' || el.type === 'radio') el.checked = false;
else el.value = '';
});
}
// ---------- Tab 切换 ----------
function bindTabs() {
var tabs = document.querySelectorAll('.tab');
var panels = document.querySelectorAll('.tab-panel');
tabs.forEach(function (tab) {
tab.addEventListener('click', function () {
var t = tab.getAttribute('data-tab');
tabs.forEach(function (x) { x.classList.remove('active'); });
panels.forEach(function (p) {
var pid = p.id;
if (pid === 'panel-' + t) p.classList.add('active');
else p.classList.remove('active');
});
tab.classList.add('active');
});
});
}
// ---------- 列表:渲染 ----------
function filterList() {
var type = searchType && searchType.value ? searchType.value : 'name';
var keyword = (searchInput && searchInput.value || '').trim().toLowerCase();
var progressVal = filterProgress && filterProgress.value ? filterProgress.value : '';
var costVal = filterCost && filterCost.value ? filterCost.value : '';
listFiltered = projects.filter(function (p) {
if (keyword) {
var name = (p.name || '').toLowerCase();
var code = (p.contractCode || '').toLowerCase();
if (type === 'name' && name.indexOf(keyword) === -1) return false;
if (type === 'code' && code.indexOf(keyword) === -1) return false;
}
if (progressVal) {
if ((p.progressKey || '').toLowerCase() !== progressVal.toLowerCase()) return false;
}
if (costVal) {
if ((p.costKey || '').toLowerCase() !== costVal.toLowerCase()) return false;
}
return true;
});
}
function mapProgressToKey(p) {
var map = { '筹备中': 'planning', '进行中': 'ongoing', '已竣工': 'completed', '已结算': 'settled' };
p.progressKey = map[p.progress] || p.progress;
return p;
}
function mapCostToKey(p) {
var map = { '正常': 'normal', '超支': 'over', '节余': 'under' };
p.costKey = map[p.costStatus] || p.costStatus;
return p;
}
function renderList() {
if (listLoading) listLoading.style.display = 'block';
if (listEmpty) listEmpty.style.display = 'none';
if (projectTable) projectTable.style.visibility = 'hidden';
setTimeout(function () {
filterList();
if (listLoading) listLoading.style.display = 'none';
if (listFiltered.length === 0) {
if (listEmpty) listEmpty.style.display = 'flex';
if (projectTable) projectTable.style.visibility = 'hidden';
} else {
if (listEmpty) listEmpty.style.display = 'none';
if (projectTable) projectTable.style.visibility = 'visible';
var html = listFiltered.map(function (p) {
return (
'<tr>' +
'<td>' + (p.name || '—') + '</td>' +
'<td>' + (p.contractCode || '—') + '</td>' +
'<td>' + (p.progress || '—') + '</td>' +
'<td>' + (p.costStatus || '—') + '</td>' +
'<td>' + (p.ownerUnit || '—') + '</td>' +
'<td class="cell-actions">' +
'<button type="button" class="link-action" data-id="' + p.id + '">查看</button> ' +
'<button type="button" class="link-action" data-id="' + p.id + '">编辑</button>' +
'</td>' +
'</tr>'
);
}).join('');
if (projectTableBody) projectTableBody.innerHTML = html;
projectTableBody.querySelectorAll('.link-action').forEach(function (btn) {
btn.addEventListener('click', function () {
var id = btn.getAttribute('data-id');
showDetail(id);
});
});
}
var totalEl = pagination && pagination.querySelector('.pagination-info');
if (totalEl) totalEl.textContent = '共 ' + listFiltered.length + ' 条';
}, 300);
}
// ---------- 搜索与筛选 ----------
if (btnSearch) btnSearch.addEventListener('click', renderList);
if (searchInput) searchInput.addEventListener('keydown', function (e) { if (e.key === 'Enter') renderList(); });
if (filterProgress) filterProgress.addEventListener('change', renderList);
if (filterCost) filterCost.addEventListener('change', renderList);
// ---------- 新建项目 ----------
if (btnNewProject) {
btnNewProject.addEventListener('click', function () {
showDetail(null);
});
}
// ---------- 返回列表 ----------
if (btnBack) {
btnBack.addEventListener('click', function () {
showList();
});
}
if (navList) {
navList.addEventListener('click', function (e) {
e.preventDefault();
showList();
});
}
// ---------- 保存 ----------
if (btnSave) {
btnSave.addEventListener('click', function () {
var textSpan = btnSave.querySelector('.btn-text');
var loadingSpan = btnSave.querySelector('.btn-loading');
if (loadingSpan && loadingSpan.style.display === 'inline') return;
if (textSpan) textSpan.style.display = 'none';
if (loadingSpan) loadingSpan.style.display = 'inline';
btnSave.disabled = true;
setTimeout(function () {
if (textSpan) textSpan.style.display = 'inline';
if (loadingSpan) loadingSpan.style.display = 'none';
btnSave.disabled = false;
showToast('保存成功', 'success');
}, 800);
});
}
// ---------- 操作日志抽屉 ----------
function openLogDrawer() {
if (logOverlay) logOverlay.classList.add('visible');
if (logDrawer) logDrawer.classList.add('visible');
if (logOverlay) logOverlay.setAttribute('aria-hidden', 'false');
if (logLoading) logLoading.style.display = 'block';
if (logEmpty) logEmpty.style.display = 'none';
if (logList) logList.innerHTML = '';
setTimeout(function () {
if (logLoading) logLoading.style.display = 'none';
var logs = getMockLogs(currentProjectId);
if (logs.length === 0) {
if (logEmpty) logEmpty.style.display = 'flex';
} else {
logList.innerHTML = logs.map(function (l) {
return (
'<li class="log-item">' +
'<div class="log-meta">' + l.operator + ' · ' + l.time + '</div>' +
'<div class="log-desc">' + l.summary + '</div>' +
'</li>'
);
}).join('');
}
}, 400);
}
function closeLogDrawer() {
if (logOverlay) logOverlay.classList.remove('visible');
if (logDrawer) logDrawer.classList.remove('visible');
if (logOverlay) logOverlay.setAttribute('aria-hidden', 'true');
}
if (btnViewLog) btnViewLog.addEventListener('click', openLogDrawer);
if (logDrawerClose) logDrawerClose.addEventListener('click', closeLogDrawer);
if (logOverlay) logOverlay.addEventListener('click', closeLogDrawer);
// ---------- Toast ----------
function showToast(message, type) {
if (!toast) return;
toast.textContent = message;
toast.className = 'toast visible' + (type ? ' ' + type : '');
clearTimeout(toast._tid);
toast._tid = setTimeout(function () {
toast.classList.remove('visible');
}, 2500);
}
// ---------- 初始化 ----------
projects = getMockProjects().map(function (p) {
mapProgressToKey(p);
mapCostToKey(p);
return p;
});
bindTabs();
updateRoleUI();
// 未登录时只显示登录页;已登录则显示主应用(可通过 hash 或 localStorage 模拟,此处默认显示登录页)
if (viewLogin && appMain) {
showLogin();
} else {
renderList();
}
})();