编辑页面

修改后将从当前时间重新计算过期时间

导入预览

识别字段
23
有效数据
486
需确认
14
`; } function permissionsView() { const grantRows = personPermissions.filter(item => permissionRules[item.permission]).map(item => [ item.person, people.find(p => p.name === item.person)?.role || '-', item.permission, permissionExpireText(item) ]); return `

角色权限包

${actionButton('newRole', '')}
${tablePanel(['角色', '默认说明', '人数'], roles.map(r => [r.name, r.desc, r.count]))}

个人权限覆盖

${actionButton('grantPermission', '')}
${tablePanel(['人员', '角色', '覆盖权限', '有效期'], grantRows)}
`; } function peopleView() { const rows = state.role === 'lead' ? people.filter(p => p.group === 'A组' && ['技术员', '技术负责人'].includes(p.role)) : people; const title = state.role === 'lead' ? '本组技术人员管理' : '人员管理'; const addButton = state.role === 'lead' ? '' : actionButton('newRole', ''); return `

${title}

${addButton}
${tablePanel(['姓名', '账号', '角色', '所属组', '个人授权', '状态', '操作'], rows.map(p => [ p.name, p.account, p.role, p.group, permissionSummary(p.name), statusBadge(p.status, p.status === '启用' ? 'green' : 'red'), state.role === 'lead' ? `` : ` ` ]), true)}
`; } function logsView() { return `

操作日志与版本追溯

${actionButton('restoreVersion', '')}
${tablePanel(['时间', '操作人', '模块', '动作', '对象', '操作前', '操作后'], logs.map(l => [l.time, l.user, l.module, l.action, l.object, logValue(l.before), logValue(l.after)]))}
`; } const views = { dashboard, customers: customersView, projects: projectsView, experiments: experimentsView, formulas: formulasView, samples: samplesView, experiment: experimentView, followDetail: projectFollowDetailView, quality: qualityView, import: importView, people: peopleView, permissions: permissionsView, logs: logsView }; function renderRoleSwitch() { const switcher = $('#roleSwitch'); switcher.innerHTML = Object.entries(roleProfiles).map(([key, item]) => ``).join(''); switcher.value = state.role; } function render() { try { ensureViewAllowed(); renderRoleSwitch(); renderNav(); setTitle(); content.innerHTML = roleTip() + views[state.view](); bindActions(); } catch (error) { console.error('页面渲染失败', error); content.innerHTML = `

页面渲染失败

当前演示数据有一处格式异常:${error.message || '未知错误'}。请返回上一步或刷新页面后重试。
`; } } function bindActions() { document.querySelectorAll('[data-jump]').forEach(btn => { btn.addEventListener('click', () => { goToView(btn.dataset.jump, { detailTab: btn.dataset.jump === 'projects' ? 'overview' : state.detailTab }); }); }); document.querySelectorAll('[data-project]').forEach(row => { row.addEventListener('click', (event) => { event.stopPropagation(); const project = findVisibleProject(row.dataset.project); if (!project) return; state.selectedProject = project; if (state.role === 'sales' && row.closest('[data-customer]')) { goToView('followDetail', { project, detailTab: 'follow' }); } else { goToView('projects', { project, detailTab: 'overview' }); } }); }); document.querySelectorAll('[data-experiments]').forEach(btn => { btn.addEventListener('click', (event) => { event.stopPropagation(); const project = findVisibleProject(btn.dataset.experiments); if (!project) return; goToView('experiment', { project }); }); }); document.querySelectorAll('[data-assign-project]').forEach(btn => { btn.addEventListener('click', (event) => { event.stopPropagation(); if (!can('assign')) return; const project = findVisibleProject(btn.dataset.assignProject); if (!project) return; state.selectedProject = project; openModal('assign'); }); }); document.querySelectorAll('[data-add-experiment]').forEach(btn => { btn.addEventListener('click', (event) => { event.stopPropagation(); const project = findVisibleProject(btn.dataset.addExperiment); if (!project) return; state.selectedProject = project; openModal('newExperiment'); }); }); document.querySelectorAll('[data-new-experiment-from-list]').forEach(btn => { btn.addEventListener('click', (event) => { event.stopPropagation(); const project = visibleProjects()[0] || projects[0]; if (project) state.selectedProject = project; openModal('newExperiment'); }); }); document.querySelectorAll('[data-tech-plan]').forEach(btn => { btn.addEventListener('click', (event) => { event.stopPropagation(); const project = findVisibleProject(btn.dataset.techPlan); if (!project) return; state.selectedProject = project; openModal('newTechPlan'); }); }); document.querySelectorAll('[data-add-follow]').forEach(btn => { btn.addEventListener('click', (event) => { event.stopPropagation(); const project = findVisibleProject(btn.dataset.addFollow); if (!project) return; state.selectedProject = project; state.detailTab = 'follow'; openModal('newFollow'); }); }); document.querySelectorAll('[data-view-follow]').forEach(btn => { btn.addEventListener('click', (event) => { event.stopPropagation(); const project = findVisibleProject(btn.dataset.viewFollow); if (!project) return; goToView('followDetail', { project, detailTab: 'follow' }); }); }); document.querySelectorAll('[data-exp-detail]').forEach(btn => { btn.addEventListener('click', (event) => { event.stopPropagation(); openModal('experimentDetail', btn.dataset.expDetail); }); }); document.querySelectorAll('[data-test-record]').forEach(btn => { btn.addEventListener('click', (event) => { event.stopPropagation(); const [projectId] = String(btn.dataset.testRecord || '').split('::'); const project = projects.find(p => p.id === projectId); if (project) state.selectedProject = project; openModal('newTest', btn.dataset.testRecord); }); }); document.querySelectorAll('[data-customer]').forEach(row => { row.addEventListener('click', () => { const project = findVisibleProject(row.dataset.project) || visibleProjects().find(p => p.customer === row.dataset.customer); if (!project) return; goToView('followDetail', { project, detailTab: 'follow' }); }); }); document.querySelectorAll('[data-tab]').forEach(tab => { tab.addEventListener('click', () => { state.detailTab = tab.dataset.tab; render(); }); }); document.querySelectorAll('[data-revoke-permission]').forEach(btn => { btn.addEventListener('click', (event) => { event.stopPropagation(); const [person, permission] = String(btn.dataset.revokePermission || '').split('::'); if (!person || !permission) return; revokePermission(person, permission); }); }); document.querySelectorAll('[data-open-modal]').forEach(btn => { btn.addEventListener('click', () => openModal(btn.dataset.openModal, btn.dataset.person || '')); }); document.querySelectorAll('[data-edit-contact]').forEach(btn => { btn.addEventListener('click', (event) => { event.stopPropagation(); openModal('editCustomerContact', btn.dataset.editContact); }); }); document.querySelectorAll('[data-export-projects]').forEach(btn => { btn.addEventListener('click', (event) => { event.stopPropagation(); exportProjectTable(); }); }); document.querySelectorAll('[data-export-experiments]').forEach(btn => { btn.addEventListener('click', (event) => { event.stopPropagation(); exportExperimentTable(); }); }); } function openModal(type, payload) { state.modalType = type; state.modalPayload = payload || ''; const titles = { newCustomer: '新增客户档案', newProject: '新增客户项目', importProject: 'Excel导入项目表', importExperimentExcel: 'Excel导入实验数据', assign: '项目分配', newExperiment: '新增实验记录', newTechPlan: '输出技术方案', newFormula: '新增配方版本', newFollow: '新增跟进记录', newShipment: '新增寄样记录', newTest: '新增检测记录', newRole: '新增角色', newPerson: '新增人员', editPerson: '编辑人员', editCustomerContact: '编辑客户信息', grantPermission: '授予个人权限', restoreVersion: '恢复历史版本', roleHelp: '当前角色权限说明', experimentDetail: '实验检测指标详情' }; $('#modalTitle').textContent = titles[type] || '新增记录'; $('#modalBody').innerHTML = modalForm(type); bindModalInteractions(type); $('#modalSave').style.display = type === 'experimentDetail' || type === 'roleHelp' ? 'none' : ''; $('#modal').classList.add('open'); } function bindModalInteractions(type) { if (type === 'newExperiment') { const projectSelect = document.querySelector('[data-experiment-project]'); const customerInput = document.querySelector('[data-experiment-customer]'); const syncCustomer = () => { const project = visibleProjects().find(item => item.id === projectSelect?.value); if (project && customerInput) customerInput.value = project.customer; }; projectSelect?.addEventListener('change', syncCustomer); syncCustomer(); } if (type === 'newShipment') { const customerSelect = document.querySelector('[data-shipment-customer]'); const projectSelect = document.querySelector('[data-shipment-project]'); const renderProjectOptions = () => { if (!customerSelect || !projectSelect) return; const selectedProjectId = projectSelect.value || state.selectedProject.id; const rows = visibleProjects().filter(item => item.customer === customerSelect.value); projectSelect.innerHTML = rows.map(item => ``).join(''); }; customerSelect?.addEventListener('change', renderProjectOptions); renderProjectOptions(); } if (type === 'assign') { const groupSelect = document.querySelector('[data-assign-group]'); const ownerSelect = document.querySelector('[data-assign-owner]'); const renderOwnerOptions = () => { if (!groupSelect || !ownerSelect) return; const group = state.role === 'lead' ? 'A组' : groupSelect.value; const rows = people.filter(person => person.role === '技术员' && person.group === group && person.status !== '停用'); const currentOwner = ownerSelect.value || state.selectedProject.owner; ownerSelect.innerHTML = rows.map(person => `${person.name}`).join(''); }; groupSelect?.addEventListener('change', renderOwnerOptions); renderOwnerOptions(); } } function modalForm(type) { if (type === 'assign') { const groupOptions = state.role === 'lead' ? '' : `A组B组`; const selectedGroup = state.role === 'lead' ? 'A组' : (state.selectedProject.group && state.selectedProject.group !== '-' ? state.selectedProject.group : 'A组'); const technicianPool = state.role === 'lead' ? people.filter(person => person.role === '技术员' && person.group === 'A组' && person.status !== '停用') : people.filter(person => person.role === '技术员' && person.group === selectedGroup && person.status !== '停用'); const ownerOptions = technicianPool.map(person => `${person.name}`).join(''); const customer = customers.find(item => item.name === state.selectedProject.customer) || {}; const salesPeople = people.filter(person => person.role === '业务员/销售' && person.status !== '停用'); const salesOptions = salesPeople.map(person => `${person.name}`).join(''); return `
${isAdmin() ? `` : ''}
`; } if (type === 'newExperiment') { const projectOptions = visibleProjects().map(p => ``).join(''); const ownerField = state.role === 'tech' ? `` : ``; return `
${ownerField}
物理指标
`; } if (type === 'newTechPlan') { return `
`; } if (type === 'newFormula') { return `
`; } if (type === 'newCustomer') { return `
`; } if (type === 'newProject') { const nextProjectNo = `P202607-${String(projects.length + 101).padStart(3, '0')}`; const selectedCustomer = state.selectedProject?.customer || visibleCustomers()[0]?.name || customers[0]?.name || '新客户'; const customerOptions = visibleCustomers().map(customer => ``).join(''); return `
`; } if (type === 'editCustomerContact') { const customer = customers.find(item => item.name === state.modalPayload) || {}; const selected = (value, target) => value === target ? ' selected' : ''; return `
`; } if (type === 'importProject') { return `
`; } if (type === 'importExperimentExcel') { return `
`; } if (type === 'newFollow') { return `
`; } if (type === 'newShipment') { const customerNames = [...new Set(visibleProjects().map(p => p.customer))]; const selectedCustomer = customerNames.includes(state.selectedProject.customer) ? state.selectedProject.customer : (customerNames[0] || state.selectedProject.customer); const customerOptions = customerNames.map(name => ``).join(''); const projectOptions = visibleProjects() .filter(p => p.customer === selectedCustomer) .map(p => ``) .join(''); return `
`; } if (type === 'newTest') { const [payloadProject, payloadNo] = String(state.modalPayload || '').split('::'); const record = visibleExperimentRecords().find(r => r.project === payloadProject && r.no === payloadNo); const project = projects.find(p => p.id === (record?.project || state.selectedProject.id)) || state.selectedProject; const batchNo = `Q${String(tests.length + 1).padStart(3, '0')}`; return `
`; } if (type === 'grantPermission') { const selectedPerson = normalizePersonName(state.modalPayload) || '张工'; const personOptions = ['张工', '王工', '陈工', '王负责人', '赵检', '小孙'].map(name => `${name}`).join(''); const permissionOptions = Object.keys(permissionRules).map(name => ``).join(''); return `
`; } if (type === 'newPerson' || type === 'editPerson') { const editingPerson = people.find(p => p.name === state.modalPayload) || people.find(p => p.account === state.modalPayload) || {}; const selected = (value, target) => value === target ? ' selected' : ''; if (state.role === 'lead') { return `
`; } return `
`; } if (type === 'roleHelp') { const p = profile(); const allowedNav = visibleNavItems().map(item => item.label).join('、'); const actions = effectiveActions(); const personalGrants = personalPermissionsForCurrentUser().map(item => `${item.permission}(${permissionExpireText(item)})`).join('、') || '无个人额外授权'; return `
${p.label}
${p.tip}
权限项当前配置
可访问模块${allowedNav}
项目详情页签${p.tabs.join('、')}
可执行操作${actions.length ? actions.join('、') : '仅查看/填写已分配内容'}
个人额外授权${personalGrants}
内部配方/失败实验${canSeeInternalData() ? '可查看' : '默认不可见,需总工授权'}
`; } if (type === 'experimentDetail') { const [payloadProject, payloadNo] = String(state.modalPayload || '').split('::'); const record = visibleExperimentRecords().find(r => r.project === payloadProject && r.no === payloadNo); const project = projects.find(p => p.id === record?.project) || {}; const metrics = experimentMetrics[record?.no] || []; return `
${record ? experimentDisplayNo(record) : ''} / ${project.name || project.product || ''}
项目编号:${record?.project || '-'} 客户:${project.customer || '-'} 实验人员:${record?.owner || '-'} 日期:${record?.date || '-'}
结论:${record?.conclusion || '-'}
${metrics.map(m => ``).join('')}
检测指标标准要求实测值判定
${m.name}${m.standard}${m.value}${m.result}
`; } return `
`; } function closeModal() { $('#modal').classList.remove('open'); } function showToast() { const toast = $('#toast'); toast.classList.add('show'); setTimeout(() => toast.classList.remove('show'), 2200); } $('#modalClose').addEventListener('click', closeModal); $('#modalCancel').addEventListener('click', closeModal); $('#modalSave').addEventListener('click', async () => { try { const modalInputs = Array.from(document.querySelectorAll('#modalBody input, #modalBody select, #modalBody textarea')).map(el => el.value); if (state.modalType === 'importProject') { try { const result = await importProjectFile(); const hint = result.added || result.updated ? '已刷新到项目管理列表。' : '未新增项目,请检查项目编号是否已存在或字段是否正确。'; alert(`导入完成:新增 ${result.added} 条,更新 ${result.updated} 条,跳过 ${result.skipped} 条。${hint}`); } catch (error) { alert(error.message || '导入失败,请检查项目表字段。'); return; } } if (state.modalType === 'importExperimentExcel') { try { const result = await importExperimentExcelFile(); const hint = result.added ? '已刷新到实验记录列表。' : '未新增数据,请检查项目编号是否存在,或实验编号是否已导入过。'; alert(`导入完成:新增 ${result.added} 条,跳过重复 ${result.skipped} 条,待确认 ${result.unmatched} 条,无权限 ${result.denied || 0} 条。${hint}`); } catch (error) { alert(error.message || '导入失败,请检查Excel字段。'); return; } } if (state.modalType === 'newCustomer') { const customerName = modalInputs[0] || '新客户名称'; const existing = customers.find(item => item.name === customerName); if (existing) { alert('客户名称已存在,请修改后再保存。'); return; } customers.unshift({ name: customerName, level: modalInputs[1] || '普通客户', contact: modalInputs[2] || '客户联系人', phone: modalInputs[3] || '待补充', owner: profile().user, industry: modalInputs[4] || '待补充', demand: modalInputs[4] || '记录客户行业、产品方向、初步指标和潜在项目机会。', projects: [] }); state.view = 'customers'; state.filter = ''; $('#globalSearch').value = ''; addLog('客户管理', '新增客户', customerName, '无', `${modalInputs[1] || '普通客户'} / ${profile().user} / ${modalInputs[2] || '客户联系人'}`); } if (state.modalType === 'editCustomerContact') { const customer = customers.find(item => item.name === state.modalPayload) || customers.find(item => item.name === modalInputs[0]); if (customer) { const before = `${customer.level || '普通客户'} / ${customer.contact || '待补充'} / ${customer.phone || '待补充'} / ${customer.industry || '待补充'}`; customer.level = modalInputs[1] || customer.level || '普通客户'; customer.contact = modalInputs[2] || '待补充'; customer.phone = modalInputs[3] || '待补充'; customer.industry = modalInputs[4] || customer.industry || customer.demand || '待补充'; state.view = 'customers'; state.filter = ''; $('#globalSearch').value = ''; addLog('客户管理', '编辑客户信息', customer.name, before, `${customer.level} / ${customer.contact} / ${customer.phone} / ${customer.industry}`); } } if (state.modalType === 'newFormula') { const code = modalInputs[0] || `F${String(formulas.length + 1).padStart(3, '0')}`; const existing = formulas.find(item => item.code === code); if (existing) { alert('配方版本已存在,请修改后再保存。'); return; } formulas.unshift({ code, name: modalInputs[1] || '新配方', ratio: `树脂 ${modalInputs[2] || '-'} / 固化剂 ${modalInputs[3] || '-'} / 助剂 ${modalInputs[4] || '-'} / 溶剂 ${modalInputs[5] || '-'}`, status: modalInputs[6] || '待验证', owner: modalInputs[7] || profile().user, date: currentFollowTime().split(' ')[0], note: modalInputs[8] || '该配方比例固定保存,后续项目实验可引用该版本。' }); state.view = 'formulas'; state.filter = ''; $('#globalSearch').value = ''; addLog('配方管理', '新增配方版本', code, '无', modalInputs[1] || '新配方'); } if (state.modalType === 'newProject') { const projectId = modalInputs[0] || `P202607-${String(projects.length + 101).padStart(3, '0')}`; if (projects.some(project => project.id === projectId)) { alert('项目编号已存在,请修改后再保存。'); return; } const status = '待分配'; const newProject = { id: projectId, name: modalInputs[1] || modalInputs[3] || '新项目', customer: modalInputs[2] || '新客户', product: modalInputs[3] || '水性涂层开发', status, statusClass: 'red', group: '-', owner: '未分配', priority: modalInputs[4] || '普通', progress: 0, experiments: 0, samples: 0, due: modalInputs[5] || '2026-08-20', note: modalInputs[6] || '记录客户需求、初始指标和项目背景。' }; projects.unshift(newProject); let customer = customers.find(item => item.name === newProject.customer); if (!customer) { customer = { name: newProject.customer, level: '普通客户', owner: '小孙', contact: '待补充', phone: '待补充', industry: newProject.product || '待补充', demand: newProject.product || '待补充', projects: [] }; customers.unshift(customer); } customer.owner = '小孙'; if (customer && !customer.projects.includes(newProject.id)) customer.projects.push(newProject.id); state.selectedProject = newProject; state.view = 'projects'; state.detailTab = 'overview'; state.filter = ''; $('#globalSearch').value = ''; state.lastImportProjectIds = [newProject.id]; addLog('项目管理', '新增项目', newProject.id, '-', `${newProject.customer} / ${newProject.product}`); } if (state.modalType === 'assign') { if (!can('assign')) { alert('当前角色无权分配项目。'); return; } const previousOwner = state.selectedProject.owner; const previousGroup = state.selectedProject.group; const customer = customers.find(item => item.name === state.selectedProject.customer); const previousSales = customer?.owner || '未分配'; if (state.role === 'lead' && state.selectedProject.group !== 'A组') { alert('技术负责人只能分配本组项目。'); return; } state.selectedProject.group = modalInputs[1] || state.selectedProject.group; state.selectedProject.owner = modalInputs[2] || state.selectedProject.owner; if (state.role === 'lead') { state.selectedProject.group = 'A组'; state.selectedProject.priority = modalInputs[3] || state.selectedProject.priority; } else { if (customer) customer.owner = modalInputs[3] || customer.owner || '小孙'; state.selectedProject.priority = modalInputs[4] || state.selectedProject.priority; } if (state.selectedProject.status === '待分配') { updateProjectStatus(state.selectedProject, '研发中'); } const beforeText = state.role === 'lead' ? `${previousGroup}/${previousOwner}` : `${previousGroup}/${previousOwner}/业务员:${previousSales}`; const afterText = state.role === 'lead' ? `${state.selectedProject.group}/${state.selectedProject.owner}` : `${state.selectedProject.group}/${state.selectedProject.owner}/业务员:${customer?.owner || modalInputs[3] || '小孙'}`; addLog('项目管理', '分配/修改项目人员', state.selectedProject.id, beforeText, afterText); } if (state.modalType === 'newExperiment') { const project = projects.find(p => p.id === modalInputs[0]) || state.selectedProject; if (!project || !canEditExperimentProject(project.id)) { alert('当前角色只能给自己权限范围内的项目添加实验数据。'); return; } const nextNo = `EXP-${project.id.replace(/\D/g, '').slice(-3)}-${String(experimentRecords.filter(r => r.project === project.id).length + 1).padStart(2, '0')}`; const metricRows = [ ['外观', '按项目要求', modalInputs[5], modalInputs[5] ? '已录入' : '待补充'], ['固含(%)', '按项目指标', modalInputs[6], modalInputs[6] ? '已录入' : '待补充'], ['粘度', '按项目指标', modalInputs[7], modalInputs[7] ? '已录入' : '待补充'], ['PH值', '按项目指标', modalInputs[8], modalInputs[8] ? '已录入' : '待补充'] ]; const newRecord = { project: project.id, no: nextNo, formula: 'F003', item: metricRows.filter(item => item[2]).map(item => item[0]).join('/') || '结构化实验数据', result: modalInputs[3] || '研发中', owner: state.role === 'tech' ? profile().user : (modalInputs[2] || project.owner), date: (modalInputs[4] || '2026/07/08').replace(/\//g, '-'), conclusion: modalInputs[9] || '已录入基础实验数据,等待后续检测指标补充。' }; experimentRecords.push(newRecord); experimentMetrics[nextNo] = metricRows.map(([name, standard, value, result]) => ({ name, standard, value: value || '-', result })); project.experiments += 1; if (project.status === '待分配') updateProjectStatus(project, '研发中'); state.lastImportExperimentKeys = [experimentKey(newRecord)]; state.view = 'experiments'; state.filter = ''; $('#globalSearch').value = ''; addLog('实验记录', '新增实验记录', project.id, '-', experimentDisplayNo(newRecord)); } if (state.modalType === 'newTechPlan') { const project = state.selectedProject; const previousStatus = project.status; updateProjectStatus(project, '方案已提交'); addLog('项目管理', '输出技术方案', project.id, previousStatus, `${modalInputs[4] || 'TS-001'} / ${modalInputs[5] || '待确认'}`); } if (state.modalType === 'newFollow') { followRecords.unshift({ project: state.selectedProject.id, customer: state.selectedProject.customer, time: currentFollowTime(), user: modalInputs[3] || profile().user, type: modalInputs[2] || '客户跟进', content: modalInputs[4] || '已记录客户最新反馈,并同步给技术部作为下一轮调整依据。' }); const followType = modalInputs[2] || '客户跟进'; if (followType.includes('反馈')) { updateProjectStatus(state.selectedProject, '反馈调整中'); } else if (state.selectedProject.status === '待分配') { updateProjectStatus(state.selectedProject, '研发中'); } addLog('项目跟进记录', '新增跟进记录', state.selectedProject.id, '-', `${modalInputs[2] || '客户跟进'} / ${modalInputs[4] || '已记录客户最新反馈'}`); } if (state.modalType === 'newShipment') { const projectId = modalInputs[1] || state.selectedProject.id; const project = projects.find(p => p.id === projectId) || state.selectedProject; const sampleNo = `S${String(samples.length + 1).padStart(3, '0')}`; const sampleVersion = modalInputs[2] || 'A019'; const count = modalInputs[3] || '2kg'; const express = modalInputs[4] || '顺丰 0000'; const sender = modalInputs[5] || profile().user; shipmentRecords.unshift({ project: project.id, customer: project.customer, sample: sampleVersion, time: currentFollowTime(), user: sender, count, express, status: '待签收' }); samples.unshift({ no: sampleNo, project: project.id, customer: project.customer, version: sampleVersion, status: '已寄样', count, express, }); project.samples += 1; updateProjectStatus(project, '客户试样中'); addLog('寄样管理', '新增寄样记录', project.id, '-', `${sampleNo} / ${sampleVersion} / ${express}`); } if (state.modalType === 'newTest') { tests.unshift({ batch: modalInputs[0] || `Q${String(tests.length + 1).padStart(3, '0')}`, object: modalInputs[3] || '实验样品', type: modalInputs[4] || '样品检测', project: modalInputs[1] || state.selectedProject.id, result: modalInputs[5] || '合格', value: modalInputs[7] || '检测指标已录入', inspector: modalInputs[6] || profile().user, date: '07-07' }); addLog('检测质检', '新增实验检测记录', `${modalInputs[1] || state.selectedProject.id} / ${modalInputs[2] || '-'}`, '-', modalInputs[5] || '合格'); } if (state.modalType === 'newPerson') { const personRole = state.role === 'lead' ? '技术员' : (modalInputs[2] || '技术员'); const personGroup = state.role === 'lead' ? 'A组' : (modalInputs[3] || 'A组'); people.unshift({ name: modalInputs[0] || '新员工', account: modalInputs[1] || 'newuser', role: personRole, group: personGroup, phone: modalInputs[4] || '138****0000', status: modalInputs[5] || '启用' }); addLog('人员管理', state.role === 'lead' ? '新增本组技术员' : '新增人员', modalInputs[0] || '新员工', '-', `${personRole} / ${personGroup}`); } if (state.modalType === 'editPerson') { const target = people.find(p => p.name === state.modalPayload) || people.find(p => p.account === state.modalPayload) || people.find(p => p.account === modalInputs[1]) || people.find(p => p.name === modalInputs[0]); if (target) { if (state.role === 'lead' && (target.group !== 'A组' || !['技术员', '技术负责人'].includes(target.role))) { alert('技术负责人只能维护本组技术人员。'); return; } const before = `${target.role}/${target.group}/${target.status}`; target.name = modalInputs[0] || target.name; target.account = modalInputs[1] || target.account; target.role = state.role === 'lead' ? '技术员' : (modalInputs[2] || target.role); target.group = state.role === 'lead' ? 'A组' : (modalInputs[3] || target.group); target.phone = modalInputs[4] || target.phone; target.status = modalInputs[5] || target.status; addLog('人员管理', '编辑人员', target.name, before, `${target.role}/${target.group}/${target.status}`); } } if (state.modalType === 'grantPermission') { const person = normalizePersonName(modalInputs[0] || '张工'); const permission = modalInputs[1] || '查看操作日志'; const expires = modalInputs[2] || '长期'; const reason = modalInputs[3] || '项目需要'; const existing = personPermissions.find(item => normalizePersonName(item.person) === person && item.permission === permission); const payload = { person, permission, expires, reason, grantedBy: profile().user, time: currentFollowTime() }; if (existing) { const before = permissionExpireText(existing); Object.assign(existing, payload); addLog('人员管理', '更新个人权限', person, before, `${permission} / ${expires}`); } else { personPermissions.unshift(payload); addLog('人员管理', '授予个人权限', person, '-', `${permission} / ${expires}`); } } persistSharedData(); closeModal(); showToast(); render(); } catch (error) { console.error('保存演示数据失败', error); alert(`保存失败:${error.message || '请检查填写内容后重试。'}`); } }); $('#modal').addEventListener('click', (event) => { if (event.target.id === 'modal') closeModal(); }); $('#globalSearch').addEventListener('input', (event) => { state.filter = event.target.value; if (state.view !== 'projects') { goToView('projects', { filter: state.filter }); } else { render(); } $('#globalSearch').value = state.filter; $('#globalSearch').focus(); }); $('#backBtn').addEventListener('click', goBack); $('#printBtn').addEventListener('click', () => window.print()); $('#roleSwitch').addEventListener('change', (event) => { loadSharedData(); state.selectedProject = projects.find(p => p.id === state.selectedProject?.id) || projects[0]; state.role = event.target.value; state.filter = ''; state.history = []; $('#globalSearch').value = ''; ensureViewAllowed(); render(); showToast(); }); render(); 取消
访问码: z3vs2az4