feat: 本地暂存一线医疗点细节补全

This commit is contained in:
fengpu
2026-09-08 17:21:57 +08:00
parent 55819e077a
commit 60b4e38166
3 changed files with 275 additions and 51 deletions
@@ -452,8 +452,8 @@
panel.innerHTML = html;
}
/* ---- 小标签共用模板:半长热敏纸,字段为 订单号/名称/包装规格/包装日期/保质期,二维码居右 ---- */
function smallLabelHtml(nameLabel, name, specObj, shelfLife, code) {
/* ---- 小标签共用模板:半长热敏纸,字段为 订单号/名称/包装规格/包装日期,二维码居右 ---- */
function smallLabelHtml(nameLabel, name, specObj, code) {
return ''
+ '<div class="label-sticker label-sticker--small">'
+ '<div class="label-sticker__body">'
@@ -462,7 +462,6 @@
+ '<div class="label-info__item"><span class="label-info__label">' + nameLabel + '</span><span class="label-info__value">' + name + '</span></div>'
+ '<div class="label-info__item"><span class="label-info__label">包装规格:</span><span class="label-info__value">' + formatSpec(specObj) + '</span></div>'
+ '<div class="label-info__item"><span class="label-info__label">包装日期:</span><span class="label-info__value">' + mockData.packDate + '</span></div>'
+ '<div class="label-info__item"><span class="label-info__label">保质期:</span><span class="label-info__value">' + shelfLife + '</span></div>'
+ '</div>'
+ '</div>'
+ qrSvg(code, 48)
@@ -477,7 +476,7 @@
var specObj = typeof v.packSpec === 'object' ? v.packSpec : parseLegacyPackSpec(v.packSpec);
for (var p = 0; p < v.packSize; p++) {
var code = mockData.orderNo + '-V' + v.name.charAt(0) + (p + 1);
html += smallLabelHtml('净菜名称', v.name, specObj, v.shelfLife, code);
html += smallLabelHtml('净菜名称', v.name, specObj, code);
}
});
panel.innerHTML = html;
@@ -491,7 +490,7 @@
var specObj = typeof m.packSpec === 'object' ? m.packSpec : parseLegacyPackSpec(m.packSpec);
for (var p = 0; p < m.packSize; p++) {
var code = mockData.orderNo + '-M' + (p + 1);
html += smallLabelHtml('餐品名称', m.name, specObj, m.shelfLife, code);
html += smallLabelHtml('餐品名称', m.name, specObj, code);
}
});
panel.innerHTML = html;
@@ -131,9 +131,21 @@ tbody tr:hover td:last-child{background:#F8FBFF;}
select.form-control{background:#fff url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6'%3E%3Cpath d='M0 0l5 6 5-6z' fill='%23999'/%3E%3C/svg%3E") no-repeat right 10px center;appearance:none;-webkit-appearance:none;padding-right:28px;cursor:pointer;}
.radio-group{display:flex;align-items:center;gap:16px;height:32px;font-size:var(--font-sm);}
.radio-group label{display:flex;align-items:center;gap:5px;cursor:pointer;}
.check-tags{display:flex;flex-wrap:wrap;gap:8px;padding:4px 0;}
.check-tag{border:1px solid var(--border);border-radius:var(--radius-sm);padding:4px 12px;font-size:var(--font-xs);cursor:pointer;color:var(--text-secondary);}
.check-tag.checked{border-color:var(--primary);color:var(--primary);background:var(--primary-light);}
/* 多选下拉 */
.multi-select{position:relative;}
.multi-select__control{display:flex;flex-wrap:wrap;align-items:center;gap:4px;min-height:32px;border:1px solid var(--border);border-radius:var(--radius-sm);padding:3px 30px 3px 8px;font-size:var(--font-sm);color:var(--text-primary);background:#fff;cursor:pointer;position:relative;}
.multi-select__control:hover{border-color:var(--primary);}
.multi-select.open .multi-select__control{border-color:var(--primary);}
.multi-select__arrow{position:absolute;right:10px;top:50%;transform:translateY(-50%);pointer-events:none;transition:transform .2s;}
.multi-select.open .multi-select__arrow{transform:translateY(-50%) rotate(180deg);}
.multi-select__tags{display:flex;flex-wrap:wrap;gap:4px;}
.multi-select__placeholder{color:var(--text-placeholder);}
.multi-select__tag{display:inline-flex;align-items:center;height:22px;padding:0 8px;background:var(--primary-light);color:var(--primary);border:1px solid #91D5FF;border-radius:var(--radius-sm);font-size:var(--font-xs);}
.multi-select__dropdown{display:none;position:absolute;top:calc(100% + 4px);left:0;right:0;background:#fff;border:1px solid var(--border);border-radius:var(--radius-sm);box-shadow:var(--shadow-md);padding:4px 0;max-height:240px;overflow-y:auto;z-index:30;}
.multi-select.open .multi-select__dropdown{display:block;}
.multi-select__option{display:flex;align-items:center;gap:8px;padding:7px 12px;font-size:var(--font-sm);color:var(--text-primary);cursor:pointer;}
.multi-select__option:hover{background:#F8FBFF;}
.multi-select__option input{width:14px;height:14px;margin:0;cursor:pointer;}
.upload-row{display:flex;gap:8px;align-items:center;}
.upload-box{width:80px;height:80px;border:1px dashed var(--border);border-radius:var(--radius-sm);display:flex;flex-direction:column;align-items:center;justify-content:center;color:var(--text-placeholder);font-size:var(--font-sm);cursor:pointer;gap:2px;}
.upload-box:hover{border-color:var(--primary);color:var(--primary);}
@@ -338,13 +350,20 @@ select.form-control{background:#fff url("data:image/svg+xml,%3Csvg xmlns='http:/
</div>
<div class="form-section__title">辐射范围</div>
<div class="form-item"><span class="form-label"><span class="req">*</span> 辐射单位(可多选)</span>
<div class="check-tags" id="fRadiate">
<span class="check-tag checked" onclick="toggleTag(this)">采油一厂 · 樊学作业区</span>
<span class="check-tag" onclick="toggleTag(this)">采油一厂 · 麻子山作业区</span>
<span class="check-tag" onclick="toggleTag(this)">采油二厂 · 姬圪台作业区</span>
<span class="check-tag checked" onclick="toggleTag(this)">采油二厂 · 桐园作业区</span>
<span class="check-tag" onclick="toggleTag(this)">第四采油厂 · 西谷峁作业区</span>
<span class="check-tag" onclick="toggleTag(this)">采气一厂 · 靖边气田</span>
<div class="multi-select" id="fRadiate">
<div class="multi-select__control" onclick="toggleMulti(this)">
<span class="multi-select__tags"></span>
<span class="multi-select__placeholder">请选择辐射单位</span>
<svg class="multi-select__arrow" width="10" height="6" viewBox="0 0 10 6"><path d="M0 0l5 6 5-6" fill="#999"/></svg>
</div>
<div class="multi-select__dropdown">
<label class="multi-select__option"><input type="checkbox" value="采油一厂 · 樊学作业区" onchange="updateMulti(document.getElementById('fRadiate'))"><span>采油一厂 · 樊学作业区</span></label>
<label class="multi-select__option"><input type="checkbox" value="采油一厂 · 麻子山作业区" onchange="updateMulti(document.getElementById('fRadiate'))"><span>采油一厂 · 麻子山作业区</span></label>
<label class="multi-select__option"><input type="checkbox" value="采油二厂 · 姬圪台作业区" onchange="updateMulti(document.getElementById('fRadiate'))"><span>采油二厂 · 姬圪台作业区</span></label>
<label class="multi-select__option"><input type="checkbox" value="采油二厂 · 桐园作业区" onchange="updateMulti(document.getElementById('fRadiate'))"><span>采油二厂 · 桐园作业区</span></label>
<label class="multi-select__option"><input type="checkbox" value="第四采油厂 · 西谷峁作业区" onchange="updateMulti(document.getElementById('fRadiate'))"><span>第四采油厂 · 西谷峁作业区</span></label>
<label class="multi-select__option"><input type="checkbox" value="采气一厂 · 靖边气田" onchange="updateMulti(document.getElementById('fRadiate'))"><span>采气一厂 · 靖边气田</span></label>
</div>
</div></div>
<div class="form-section__title">医疗点简介</div>
<div class="form-item form-item--full"><textarea class="form-control form-textarea" id="fIntro" placeholder="请输入医疗点简介"></textarea></div>
@@ -472,6 +491,7 @@ function openForm(title){
document.getElementById('formTitle').textContent=title;
editId=null;
['fName','fLeader','fPhone','fAmount','fFound','fAddr','fIntro'].forEach(function(id){document.getElementById(id).value='';});
resetMultiDefault();
document.getElementById('formMask').classList.add('open');
document.getElementById('formDrawer').classList.add('open');
}
@@ -487,6 +507,7 @@ function openEdit(id){
document.getElementById('fFound').value=p.found;
document.getElementById('fAddr').value=p.addr;
document.getElementById('fIntro').value=p.intro;
setMultiFromText(p.radiate);
}
function saveForm(){
var name=document.getElementById('fName').value.trim();
@@ -494,7 +515,39 @@ function saveForm(){
showToast(editId?('医疗点「'+name+'」已保存'):('医疗点「'+name+'」已创建'));
closeDrawer('form');
}
function toggleTag(el){el.classList.toggle('checked');}
/* ===== 多选下拉 ===== */
function toggleMulti(control){control.parentElement.classList.toggle('open');}
function updateMulti(wrap){
var control=wrap.querySelector('.multi-select__control');
var tagsBox=control.querySelector('.multi-select__tags');
var ph=control.querySelector('.multi-select__placeholder');
var checked=wrap.querySelectorAll('.multi-select__option input:checked');
var html='';
checked.forEach(function(cb){html+='<span class="multi-select__tag">'+cb.value+'</span>';});
tagsBox.innerHTML=html;
ph.style.display=checked.length?'none':'';
}
function resetMultiDefault(){
var wrap=document.getElementById('fRadiate');
wrap.querySelectorAll('.multi-select__option input').forEach(function(cb){
var v=cb.value;
cb.checked=(v==='采油一厂 · 樊学作业区'||v==='采油二厂 · 桐园作业区');
});
updateMulti(wrap);
}
function setMultiFromText(text){
var wrap=document.getElementById('fRadiate');
wrap.querySelectorAll('.multi-select__option input').forEach(function(cb){
var name=(cb.value.split(' · ')[1]||cb.value);
cb.checked=text.indexOf(name)!==-1;
});
updateMulti(wrap);
}
document.addEventListener('click',function(e){
document.querySelectorAll('.multi-select.open').forEach(function(ms){
if(!ms.contains(e.target))ms.classList.remove('open');
});
});
/* ===== 详情抽屉 ===== */
function openDetail(id){
@@ -49,6 +49,7 @@ body{font-family:-apple-system,BlinkMacSystemFont,'PingFang SC','Microsoft YaHei
.filter-bar{background:#fff;padding:16px 24px;display:flex;align-items:center;gap:16px;flex-wrap:wrap;border-radius:var(--radius-md);box-shadow:var(--shadow-sm);}
.filter-item{display:flex;align-items:center;gap:8px;}
.filter-item label{font-size:var(--font-sm);color:var(--text-secondary);white-space:nowrap;}
.action-bar{display:flex;align-items:center;gap:8px;padding:16px 24px;background:#fff;margin-top:16px;border-radius:var(--radius-md) var(--radius-md) 0 0;box-shadow:var(--shadow-sm);}
.filter-select{height:36px;min-width:140px;border:1px solid var(--border);border-radius:var(--radius-sm);padding:0 28px 0 12px;font-size:var(--font-sm);color:var(--text-primary);background:#fff url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6'%3E%3Cpath d='M0 0l5 6 5-6z' fill='%23999'/%3E%3C/svg%3E") no-repeat right 8px center;cursor:pointer;outline:none;appearance:none;-webkit-appearance:none;}
.filter-input{height:36px;border:1px solid var(--border);border-radius:var(--radius-sm);padding:0 12px;font-size:var(--font-sm);color:var(--text-primary);outline:none;min-width:140px;}
.filter-input:focus{border-color:var(--primary);}
@@ -206,6 +207,14 @@ select.form-control{background:#fff url("data:image/svg+xml,%3Csvg xmlns='http:/
<button class="btn btn-default" onclick="resetFilter()">重置</button>
</div>
<!-- [交互] 操作栏 -->
<div class="action-bar">
<button class="btn btn-primary" onclick="openHospital()">
<svg width="14" height="14" viewBox="0 0 14 14" fill="none"><path d="M7 2v10M2 7h10" stroke="#fff" stroke-width="1.6" stroke-linecap="round"/></svg>新增医院
</button>
<button class="btn btn-primary" onclick="showToast('合作医院列表已导出(演示)')"><svg width="14" height="14" viewBox="0 0 14 14" fill="none"><path d="M2 10v2h10v-2M7 2v7M4.5 6.5L7 9l2.5-2.5" stroke="currentColor" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round"/></svg>导出列表数据</button>
</div>
<!-- 表格 -->
<div class="table-card">
<div class="table-card__content">
@@ -272,31 +281,79 @@ select.form-control{background:#fff url("data:image/svg+xml,%3Csvg xmlns='http:/
<!-- [交互] 医院管理员抽屉 -->
<div class="drawer-mask" id="adminMask" onclick="closeDrawer('admin')"></div>
<div class="drawer" id="adminDrawer" style="width:640px;right:-680px;">
<div class="drawer__header"><span id="adminTitle">医院管理员</span><button class="drawer__close" onclick="closeDrawer('admin')">×</button></div>
<div class="drawer" id="adminDrawer" style="width:760px;">
<div class="drawer__header"><span>医院管理员</span><button class="drawer__close" onclick="closeDrawer('admin')">×</button></div>
<div class="drawer__body">
<div class="drawer__toolbar">
<button class="btn btn-primary" onclick="toggleAdminForm(true)">新增管理员</button>
<!-- 医院信息 -->
<div style="display:flex;gap:20px;font-weight:600;margin-bottom:14px;font-size:var(--font-base);">
<span id="adminHospName"></span><span id="adminHospLevel"></span>
</div>
<!-- [交互] 新增管理员表单(页内展开) -->
<div class="drawer__toolbar">
<button class="btn btn-primary" onclick="showAdminForm(null)">
<svg width="14" height="14" viewBox="0 0 14 14" fill="none"><path d="M7 2v10M2 7h10" stroke="#fff" stroke-width="1.6" stroke-linecap="round"/></svg>新增管理员
</button>
<button class="btn btn-default" onclick="batchRemoveAdmin()">批量删除</button>
</div>
<!-- [交互] 新增/编辑管理员表单(页内展开) -->
<div id="adminForm" style="display:none;border:1px solid var(--border);border-radius:var(--radius-sm);padding:16px;margin-bottom:14px;background:#FAFCFF;">
<div class="form-item"><span class="form-label"><span class="req">*</span> 账号(仅字母数字下划线)</span><input class="form-control" id="aUser" placeholder="如 hospital_admin01"></div>
<div class="form-item"><span class="form-label"><span class="req">*</span> 姓名</span><input class="form-control" id="aName" placeholder="请输入姓名"></div>
<div class="form-item"><span class="form-label"><span class="req">*</span> 初始密码</span><input class="form-control" id="aPwd" type="password" placeholder="不少于8位,含大小写字母与数字"></div>
<div class="form-item"><span class="form-label"><span class="req">*</span> 确认密码</span><input class="form-control" id="aPwd2" type="password" placeholder="请再次输入密码"></div>
<div id="aPwdGroup">
<div class="form-item"><span class="form-label"><span class="req">*</span> 初始密码</span><input class="form-control" id="aPwd" type="password" placeholder="不少于8位,含大小写字母与数字"></div>
<div class="form-item"><span class="form-label"><span class="req">*</span> 确认密码</span><input class="form-control" id="aPwd2" type="password" placeholder="请再次输入密码"></div>
</div>
<div style="display:flex;justify-content:flex-end;gap:8px;">
<button class="btn btn-default" onclick="toggleAdminForm(false)">取消</button>
<button class="btn btn-default" onclick="hideAdminForm()">取消</button>
<button class="btn btn-primary" onclick="saveAdmin()">保存</button>
</div>
</div>
<table class="mini-table" style="border-collapse:separate;">
<thead><tr><th>账号</th><th>姓名</th><th>创建时间</th><th>操作</th></tr></thead>
<thead><tr><th style="width:36px"><input type="checkbox" onchange="adminPickAll(this)"></th><th>账号</th><th>姓名</th><th>创建时间</th><th>操作</th></tr></thead>
<tbody id="adminBody"></tbody>
</table>
</div>
<div class="drawer__footer"><button class="btn btn-default" onclick="closeDrawer('admin')">关闭</button></div>
</div>
<!-- [交互] 新增/编辑合作医院抽屉 -->
<div class="drawer-mask" id="hpMask" onclick="closeDrawer('hp')"></div>
<div class="drawer" id="hpDrawer">
<div class="drawer__header"><span id="hpTitle">新增合作医院</span><button class="drawer__close" onclick="closeDrawer('hp')">×</button></div>
<div class="drawer__body">
<!-- 医院下拉选择(新增可选,编辑锁定) -->
<div class="form-item">
<span class="form-label"><span class="req">*</span> 医院名称</span>
<select class="form-control" id="hpSelect" onchange="onHpSelect()"></select>
</div>
<!-- 回显基本信息(不含管理员) -->
<div class="form-item"><span class="form-label">医院级别</span><input class="form-control" id="hpLevel" readonly></div>
<div class="form-item">
<span class="form-label">医院主图</span>
<div style="display:flex;align-items:center;gap:12px;"><span class="img-ph">🏥</span><span style="font-size:var(--font-xs);color:var(--text-placeholder);">由系统管理模块维护</span></div>
</div>
<div class="form-item"><span class="form-label">详细地址</span><input class="form-control" id="hpAddr" readonly></div>
<div class="form-item"><span class="form-label">医院简介</span><textarea class="form-control" id="hpIntro" rows="3" readonly style="resize:none;height:auto;padding:8px 10px;"></textarea></div>
</div>
<div class="drawer__footer">
<button class="btn btn-default" onclick="closeDrawer('hp')">取消</button>
<button class="btn btn-primary" id="hpOkBtn" onclick="saveHospital()">确定</button>
</div>
</div>
<!-- [交互] 重置密码弹窗 -->
<div class="modal-mask" id="resetPwdMask">
<div class="modal">
<div class="modal__title">重置密码</div>
<div style="font-size:var(--font-sm);color:var(--text-secondary);margin-bottom:14px;">账号:<span id="resetPwdUser" style="font-weight:600;color:var(--text-primary);"></span></div>
<div class="form-item"><span class="form-label"><span class="req">*</span> 新密码</span><input class="form-control" id="rpPwd" type="password" placeholder="不少于8位,含大小写字母与数字"></div>
<div class="form-item"><span class="form-label"><span class="req">*</span> 确认密码</span><input class="form-control" id="rpPwd2" type="password" placeholder="请再次输入密码"></div>
<div class="modal__footer">
<button class="btn btn-default" onclick="closeModal('resetPwdMask')">取消</button>
<button class="btn btn-primary" onclick="confirmResetPwd()">确定</button>
</div>
</div>
</div>
<!-- [交互] 移除确认弹窗 -->
<div class="modal-mask" id="delMask">
<div class="modal">
@@ -324,12 +381,17 @@ var points=[
{id:7,name:'姬塬作业区医疗点',addr:'采油三厂筹备组姬塬先导试验区板房区',unit:'采油一厂',leader:'杨慧敏',found:'2024-02-27',hospital:null},
{id:8,name:'乌审旗采气区医疗点',addr:'采气一厂苏里格南作业区营地',unit:'采气一厂',leader:'徐立成',found:'2020-12-11',hospital:'庆阳市人民医院'}
];
var hospitals=[
{id:1,name:'CQ油田总医院',level:'三级甲等',addr:'西峰区长庆北路1号',admins:[['hgt_admin','石维国'],['hgt_nurse01','李桂芳']]},
{id:2,name:'第四采油厂总医院',level:'级甲等',addr:'西峰区石油西路22号',admins:[['sgyy_admin','高建军']]},
{id:3,name:'环县油田医院',level:'二级甲等',addr:'环县环城镇新区大街8号',admins:[['hx_admin','赵万福']]},
{id:4,name:'吴起油田医院',level:'一级',addr:'吴起县红旗街西段',admins:[]},
{id:5,name:'庆阳市人民医院',level:'三级甲等',addr:'西峰区兰州路456号',admins:[['qyrm_admin','徐立成']]}
/* 系统管理模块配置的医院主数据池;partner=true 表示已标记为医疗点合作医院 */
var sysHospitals=[
{id:1,name:'CQ油田总医院',level:'级甲等',addr:'西峰区长庆北路1号',intro:'长庆油田职工医院,承担油田一线医疗保障与职业病防治任务。',admins:[['hgt_admin','石维国'],['hgt_nurse01','李桂芳']],partner:true},
{id:2,name:'第四采油厂总医院',level:'二级甲等',addr:'西峰区石油西路22号',intro:'面向第四采油厂职工及家属的二级综合医院。',admins:[['sgyy_admin','高建军']],partner:true},
{id:3,name:'环县油田医院',level:'二级甲等',addr:'环县环城镇新区大街8号',intro:'服务环县油区职工的二级综合医院。',admins:[['hx_admin','赵万福']],partner:true},
{id:4,name:'吴起油田医院',level:'一级',addr:'吴起县红旗街西段',intro:'吴起县油区基层医疗机构。',admins:[],partner:true},
{id:5,name:'庆阳市人民医院',level:'三级甲等',addr:'西峰区兰州路456号',intro:'庆阳市三级甲等综合医院,区域医疗中心。',admins:[['qyrm_admin','徐立成']],partner:true},
{id:6,name:'长庆石油总医院',level:'三级甲等',addr:'西安市未央区凤城四路58号',intro:'长庆油田总部综合性医院。',admins:[],partner:false},
{id:7,name:'延安大学附属医院',level:'三级甲等',addr:'延安市宝塔区北大街43号',intro:'延安地区三级甲等综合医院。',admins:[],partner:false},
{id:8,name:'定边县人民医院',level:'二级甲等',addr:'定边县定边镇鼓楼南大街',intro:'定边县二级甲等综合医院。',admins:[],partner:false},
{id:9,name:'榆林市第一医院',level:'三级甲等',addr:'榆林市榆阳区西沙柳营东路',intro:'榆林市区域医疗中心。',admins:[],partner:false}
];
var curHosp=null,pendingRemove=null;
@@ -338,7 +400,7 @@ function jurCount(h){return points.filter(function(p){return p.hospital===h;}).l
function renderTable(){
var name=document.getElementById('filterName').value.trim();
var level=document.getElementById('filterLevel').value;
var list=hospitals.filter(function(h){return (!name||h.name.indexOf(name)!==-1)&&(!level||h.level===level);});
var list=sysHospitals.filter(function(h){return h.partner&&(!name||h.name.indexOf(name)!==-1)&&(!level||h.level===level);});
var tbody=document.getElementById('tableBody');
if(!list.length){tbody.innerHTML='<tr><td colspan="8" class="td-empty">暂无匹配数据</td></tr>';return;}
var html='';
@@ -356,6 +418,7 @@ function renderTable(){
+'<td class="td-actions">'
+'<button class="btn btn-link" onclick="openJur('+h.id+')">管辖范围</button>'
+'<button class="btn btn-link" onclick="openAdmin('+h.id+')">管理员</button>'
+'<button class="btn btn-link btn-link--danger" onclick="askRemove(\'hospital\','+h.id+')">删除</button>'
+'</td></tr>';
});
tbody.innerHTML=html;
@@ -364,7 +427,7 @@ function applyFilter(){renderTable();}
function resetFilter(){document.getElementById('filterName').value='';document.getElementById('filterLevel').value='';renderTable();}
/* ===== 管辖范围抽屉 ===== */
function hospById(id){return hospitals.find(function(h){return h.id===id;});}
function hospById(id){return sysHospitals.find(function(h){return h.id===id;});}
function openJur(id){
curHosp=hospById(id);
document.getElementById('jurTitle').textContent='管辖范围 · '+curHosp.name;
@@ -405,50 +468,159 @@ function confirmPick(){
}
function askRemove(kind,val){
pendingRemove={kind:kind,val:val};
document.getElementById('delText').textContent=kind==='point'
?('确认将该医疗点从「'+curHosp.name+'」管辖范围移除?移除后该医疗点需重新指定归属医院。')
:('确认移除管理员账号「'+pendingRemove.val+'」?其历史操作记录保留。');
var text;
if(kind==='point'){
text='确认将该医疗点从「'+curHosp.name+'」管辖范围移除?移除后该医疗点需重新指定归属医院。';
}else if(kind==='admin'){
text='确认移除管理员账号「'+val+'」?其历史操作记录保留。';
}else if(kind==='hospital'){
var h=hospById(val);
text='确认取消「'+h.name+'」的合作医院标记?取消后该医院将从列表移除,其管辖的医疗点需重新指定归属。';
}else if(kind==='adminBatch'){
text='确认批量移除 '+val.length+' 个管理员账号?其历史操作记录保留。';
}
document.getElementById('delText').textContent=text;
document.getElementById('delMask').classList.add('open');
}
function confirmRemove(){
if(pendingRemove.kind==='point'){
points.find(function(p){return p.id===+pendingRemove.val;}).hospital=null;
renderJur();renderTable();showToast('医疗点已移除管辖');
}else{
}else if(pendingRemove.kind==='admin'){
curHosp.admins=curHosp.admins.filter(function(a){return a[0]!==pendingRemove.val;});
renderAdmin();renderTable();showToast('管理员已移除');
}else if(pendingRemove.kind==='adminBatch'){
var accounts=pendingRemove.val;
curHosp.admins=curHosp.admins.filter(function(a){return accounts.indexOf(a[0])===-1;});
renderAdmin();renderTable();showToast('已移除 '+accounts.length+' 个管理员');
}else if(pendingRemove.kind==='hospital'){
var h=hospById(pendingRemove.val);
points.forEach(function(p){if(p.hospital===h.name)p.hospital=null;});
h.partner=false;
closeDrawer('hp');
renderTable();showToast('已取消合作医院标记');
}
closeModal('delMask');
}
/* ===== 新增/编辑合作医院抽屉 ===== */
var hpSelected=null;
function openHospital(){
document.getElementById('hpTitle').textContent='新增合作医院';
var sel=document.getElementById('hpSelect');
var opts=sysHospitals.filter(function(x){return !x.partner;});
sel.innerHTML='<option value="">请选择医院</option>'+opts.map(function(x){return '<option value="'+x.id+'">'+x.name+'</option>';}).join('');
sel.disabled=false;
hpSelected=null;
clearHpEcho();
document.getElementById('hpMask').classList.add('open');
document.getElementById('hpDrawer').classList.add('open');
}
function onHpSelect(){
var id=+document.getElementById('hpSelect').value;
hpSelected=id?hospById(id):null;
if(hpSelected){echoHp(hpSelected);}else{clearHpEcho();}
}
function echoHp(h){
document.getElementById('hpLevel').value=h.level;
document.getElementById('hpAddr').value=h.addr;
document.getElementById('hpIntro').value=h.intro||'';
}
function clearHpEcho(){
document.getElementById('hpLevel').value='';
document.getElementById('hpAddr').value='';
document.getElementById('hpIntro').value='';
}
function saveHospital(){
if(!hpSelected){showToast('请先选择医院');return;}
hpSelected.partner=true;
closeDrawer('hp');
renderTable();
showToast('已将「'+hpSelected.name+'」标记为合作医院');
}
/* ===== 医院管理员抽屉 ===== */
function openAdmin(id){
curHosp=hospById(id);
document.getElementById('adminTitle').textContent='医院管理员 · '+curHosp.name;
toggleAdminForm(false);
document.getElementById('adminHospName').textContent='医院名称:'+curHosp.name;
document.getElementById('adminHospLevel').textContent='医院等级:'+curHosp.level;
hideAdminForm();
renderAdmin();
document.getElementById('adminMask').classList.add('open');
document.getElementById('adminDrawer').classList.add('open');
}
function renderAdmin(){
document.getElementById('adminBody').innerHTML=curHosp.admins.length?curHosp.admins.map(function(a){
return '<tr><td>'+a[0]+'</td><td>'+a[1]+'</td><td>2026-0'+((a[1].length%8)+1)+'-1'+(a[0].length%9)+'</td>'
+'<td><button class="btn btn-link btn-link--danger" onclick="askRemove(\'admin\',\''+a[0]+'\')">移除</button></td></tr>';
}).join(''):'<tr><td colspan="4" class="td-empty">暂未设置管理员</td></tr>';
var rows=curHosp.admins;
document.getElementById('adminBody').innerHTML=rows.length?rows.map(function(a){
var t='2026-0'+((a[1].length%8)+1)+'-1'+(a[0].length%9);
return '<tr>'
+'<td><input type="checkbox" class="admin-check" value="'+a[0]+'"></td>'
+'<td>'+a[0]+'</td><td>'+a[1]+'</td><td>'+t+'</td>'
+'<td class="td-actions">'
+'<button class="btn btn-link" onclick="openResetPwd(\''+a[0]+'\')">重置密码</button>'
+'<button class="btn btn-link" onclick="showAdminForm(\''+a[0]+'\')">编辑</button>'
+'<button class="btn btn-link btn-link--danger" onclick="askRemove(\'admin\',\''+a[0]+'\')">删除</button>'
+'</td></tr>';
}).join(''):'<tr><td colspan="5" class="td-empty">暂未设置管理员</td></tr>';
}
function toggleAdminForm(show){
document.getElementById('adminForm').style.display=show?'':'none';
if(show){['aUser','aName','aPwd','aPwd2'].forEach(function(id){document.getElementById(id).value='';});}
var adminEditUser=null;
function showAdminForm(account){
adminEditUser=account;
document.getElementById('adminForm').style.display='';
var u=document.getElementById('aUser');
if(account){
var a=curHosp.admins.find(function(x){return x[0]===account;});
u.value=a[0];u.disabled=true;
document.getElementById('aName').value=a[1];
document.getElementById('aPwdGroup').style.display='none';
}else{
u.value='';u.disabled=false;
document.getElementById('aName').value='';
document.getElementById('aPwd').value='';
document.getElementById('aPwd2').value='';
document.getElementById('aPwdGroup').style.display='';
}
}
function hideAdminForm(){
document.getElementById('adminForm').style.display='none';
document.getElementById('aUser').disabled=false;
}
function saveAdmin(){
var u=document.getElementById('aUser').value.trim(),n=document.getElementById('aName').value.trim();
var p1=document.getElementById('aPwd').value,p2=document.getElementById('aPwd2').value;
if(!u||!n){showToast('请填写账号与姓名');return;}
if(p1.length<8){showToast('初始密码不少于8位');return;}
if(adminEditUser){
var a=curHosp.admins.find(function(x){return x[0]===adminEditUser;});
a[1]=n;
hideAdminForm();renderAdmin();renderTable();
showToast('管理员「'+n+'」已更新');
}else{
var p1=document.getElementById('aPwd').value,p2=document.getElementById('aPwd2').value;
if(p1.length<8){showToast('初始密码不少于8位');return;}
if(p1!==p2){showToast('两次输入的密码不一致');return;}
curHosp.admins.push([u,n]);
hideAdminForm();renderAdmin();renderTable();
showToast('管理员「'+n+'」已创建');
}
}
function adminPickAll(el){
document.querySelectorAll('.admin-check').forEach(function(c){c.checked=el.checked;});
}
function batchRemoveAdmin(){
var accounts=[].slice.call(document.querySelectorAll('.admin-check:checked')).map(function(c){return c.value;});
if(!accounts.length){showToast('请先勾选管理员');return;}
askRemove('adminBatch',accounts);
}
function openResetPwd(account){
document.getElementById('resetPwdUser').textContent=account;
document.getElementById('rpPwd').value='';
document.getElementById('rpPwd2').value='';
document.getElementById('resetPwdMask').classList.add('open');
}
function confirmResetPwd(){
var p1=document.getElementById('rpPwd').value,p2=document.getElementById('rpPwd2').value;
if(p1.length<8){showToast('新密码不少于8位');return;}
if(p1!==p2){showToast('两次输入的密码不一致');return;}
curHosp.admins.push([u,n]);
toggleAdminForm(false);renderAdmin();renderTable();
showToast('管理员「'+n+'」已创建');
closeModal('resetPwdMask');
showToast('密码已重置');
}
/* ===== 通用 ===== */