feat: Web管理端新增系统管理模块18页原型及全站脱敏修正
- 系统管理模块首版:用户管理5页、权限管理3页、机构管理2页、系统配置4页、通知管理4页,配套新建模块 CHANGELOG - 站点地图 SITE_MAP 新增系统管理模块条目(入口 user-admin.html) - 全站脱敏修正:健康长庆规划文档、一线医疗合作医院、应急大屏 CHANGELOG 中「长庆油田」统一为「CQ能源」 - 蓝牙秤小程序资料完善页按钮文案「完成并进入首页」改为「开始使用」 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.7
parent
17595d5fb2
commit
bf08a9614b
@@ -4,7 +4,7 @@
|
||||
|
||||
## 1\.1 改造背景
|
||||
|
||||
基于《健康长庆平台服务技术改造方案》的总体战略,长庆油田健康管理系统正处于从“分布式单体”向“准云原生微服务”架构转型的关键期。本项目旨在通过彻底的架构重构,解决系统长期存在的“技术栈滞后、数据孤岛严重、用户体验割裂”三大核心痛点,构建一个具备高并发支撑能力、信创全面适配、数据互联互通的新一代数字化健康管理平台。
|
||||
基于《健康长庆平台服务技术改造方案》的总体战略,CQ能源健康管理系统正处于从“分布式单体”向“准云原生微服务”架构转型的关键期。本项目旨在通过彻底的架构重构,解决系统长期存在的“技术栈滞后、数据孤岛严重、用户体验割裂”三大核心痛点,构建一个具备高并发支撑能力、信创全面适配、数据互联互通的新一代数字化健康管理平台。
|
||||
|
||||
## 1\.2 现状与痛点分析
|
||||
|
||||
@@ -2182,7 +2182,7 @@ AI项目生成多维度营养分析报告,包括各维度的营养摄入统计
|
||||
||主诉分类|\-|以应急方式为维度柱状图统计应急次数|
|
||||
||体检数据|\-|以年为维度网状图展示医院体检人数|
|
||||
||健康终端报警|\-|列表滚动展示最新穿戴设备监测告警数据|
|
||||
||长庆油田大病人数|\-|环形图展示大病员工危险程度占比|
|
||||
||CQ能源大病人数|\-|环形图展示大病员工危险程度占比|
|
||||
||基层医疗点远程会诊|\-|图文展示医疗点远程会诊信息|
|
||||
||多方视频通话|\-|各应急中心间视频通话|
|
||||
|银川应急就医服务中心大屏|应急资源地图|所有资源<br>油田医院<br>医疗点<br>救护车<br>合作医院<br>地方医院<br>急救路线|地图上标记各类资源的位置信息|
|
||||
|
||||
+20
-1
@@ -188,7 +188,26 @@ const ICONS = {
|
||||
|
||||
const SITE_MAP = [
|
||||
{ id:'web-admin', label:'Web 管理端', icon:'web', color:'#69b1ff', modules:[
|
||||
{ name:'系统管理', dir:'web-admin/system-management', pages:[] },
|
||||
{ name:'系统管理', dir:'web-admin/system-management', entry:'user-admin.html', pages:[
|
||||
{ file:'user-admin.html', label:'用户管理 · 管理员账号' },
|
||||
{ file:'user-all.html', label:'用户管理 · 全部用户' },
|
||||
{ file:'user-consult.html', label:'用户管理 · 咨询账号' },
|
||||
{ file:'user-emergency.html', label:'用户管理 · 应急中心账号' },
|
||||
{ file:'user-employee.html', label:'用户管理 · 员工账号' },
|
||||
{ file:'application.html', label:'权限管理 · 应用管理' },
|
||||
{ file:'menu.html', label:'权限管理 · 菜单管理' },
|
||||
{ file:'role.html', label:'权限管理 · 角色管理' },
|
||||
{ file:'hospital.html', label:'机构管理 · 医院管理' },
|
||||
{ file:'unit.html', label:'机构管理 · 单位管理' },
|
||||
{ file:'dict.html', label:'系统配置 · 数据字典' },
|
||||
{ file:'dict-category.html', label:'系统配置 · 字典分类' },
|
||||
{ file:'variable.html', label:'系统配置 · 变量配置' },
|
||||
{ file:'version.html', label:'系统配置 · 版本更新' },
|
||||
{ file:'announcement.html', label:'通知管理 · 公告' },
|
||||
{ file:'sms-send.html', label:'通知管理 · 发送短信' },
|
||||
{ file:'sms-history.html', label:'通知管理 · 短信发送历史' },
|
||||
{ file:'sms-template.html', label:'通知管理 · 短信模板' }
|
||||
]},
|
||||
{ name:'健康体检', dir:'web-admin/health-checkup', entry:'archive-personal.html', pages:[
|
||||
{ file:'archive-personal.html', label:'个人体检数据' },
|
||||
{ file:'archive-unit.html', label:'单位报表数据' },
|
||||
|
||||
@@ -161,7 +161,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button class="btn-primary" id="submitBtn" onclick="submitProfile()">完成并进入首页</button>
|
||||
<button class="btn-primary" id="submitBtn" onclick="submitProfile()">开始使用</button>
|
||||
</div>
|
||||
|
||||
<div class="home-indicator"></div>
|
||||
|
||||
@@ -75,7 +75,7 @@
|
||||
- 保留左侧 3px 色条 `::before`、数字+单位、标签、趋势小标记(↑12% / ↓8%)
|
||||
- **视频通话按钮弹窗化**:地图右下角"视频通话"按钮点击行为由 `alert` 升级为选择弹窗
|
||||
- 新增 `[弹窗] 视频通话 - 选择加入的应急中心`(`#videoCallModal`),复用 `.modal-overlay` + `.modal` 基础结构,宽度 560px
|
||||
- 弹窗内含 6 张应急中心卡片(救场/标准/长庆油田/延安/庆阳/榆林),2 列网格布局
|
||||
- 弹窗内含 6 张应急中心卡片(救场/标准/CQ能源/延安/庆阳/榆林),2 列网格布局
|
||||
- 每张卡片显示:中心名称、在线状态徽章(在线/忙碌/离线 三态,含发光小圆点)、值班负责人、在线人数
|
||||
- 卡片支持多选:点击切换 `.vc-card--selected` 选中态,右上角显示对勾角标;离线卡片不可选(半透明 + 锁图标 + `cursor:not-allowed`)
|
||||
- 默认预选「救场应急中心」「标准应急中心」两张在线卡片
|
||||
|
||||
@@ -405,12 +405,12 @@ var points=[
|
||||
];
|
||||
/* 系统管理模块配置的医院主数据池;partner=true 表示已标记为医疗点合作医院 */
|
||||
var sysHospitals=[
|
||||
{id:1,name:'CQ油田总医院',level:'三级甲等',addr:'西峰区长庆北路1号',intro:'长庆油田职工医院,承担油田一线医疗保障与职业病防治任务。',admins:[['hgt_admin','石维国'],['hgt_nurse01','李桂芳']],partner:true},
|
||||
{id:1,name:'CQ油田总医院',level:'三级甲等',addr:'西峰区长庆北路1号',intro:'CQ能源职工医院,承担油田一线医疗保障与职业病防治任务。',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:6,name:'长庆石油总医院',level:'三级甲等',addr:'西安市未央区凤城四路58号',intro:'CQ能源总部综合性医院。',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}
|
||||
|
||||
@@ -0,0 +1,199 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>公告 | 系统管理</title>
|
||||
<style>
|
||||
*{box-sizing:border-box;margin:0;padding:0;}
|
||||
body{font-family:-apple-system,BlinkMacSystemFont,'PingFang SC','Microsoft YaHei',sans-serif;font-size:var(--font-sm);background:#F5F7FA;color:#333;min-width:1280px;}
|
||||
:root{
|
||||
--primary:#1890FF;--primary-light:#E6F7FF;--success:#52C41A;--warning:#FAAD14;--danger:#FF4D4F;
|
||||
--text-primary:#333;--text-secondary:#666;--text-placeholder:#999;--border:#E8E8E8;--background:#F5F7FA;
|
||||
--font-xs:11px;--font-sm:13px;--font-base:15px;--font-lg:17px;
|
||||
--radius-sm:4px;--radius-md:8px;--radius-lg:12px;
|
||||
--shadow-sm:0 1px 4px rgba(0,0,0,0.08);--shadow-md:0 4px 12px rgba(0,0,0,0.10);
|
||||
}
|
||||
.top-bar{display:flex;align-items:center;height:56px;background:#001529;padding:0 24px;position:fixed;top:0;left:0;right:0;z-index:100;}
|
||||
.top-bar__logo{display:flex;align-items:center;gap:8px;color:#fff;font-size:var(--font-lg);font-weight:600;white-space:nowrap;width:200px;flex-shrink:0;}
|
||||
.top-bar__logo svg{width:28px;height:28px;}
|
||||
.top-bar__nav{display:flex;align-items:center;gap:4px;flex:1;}
|
||||
.top-bar__nav a{color:rgba(255,255,255,0.65);text-decoration:none;padding:6px 14px;border-radius:var(--radius-sm);font-size:var(--font-sm);transition:all .2s;}
|
||||
.top-bar__nav a:hover{color:#fff;background:rgba(255,255,255,0.08);}
|
||||
.top-bar__nav a.active{color:#fff;background:var(--primary);}
|
||||
.top-bar__right{display:flex;align-items:center;gap:16px;color:rgba(255,255,255,0.65);font-size:var(--font-sm);}
|
||||
.btn-back{color:rgba(255,255,255,0.65);cursor:pointer;display:flex;align-items:center;gap:4px;text-decoration:none;}
|
||||
.btn-back:hover{color:#fff;}
|
||||
.avatar{width:32px;height:32px;border-radius:50%;background:#1890FF;display:flex;align-items:center;justify-content:center;color:#fff;font-size:var(--font-sm);cursor:pointer;}
|
||||
.sidebar{position:fixed;top:56px;left:0;bottom:0;width:240px;background:#001529;overflow-y:auto;z-index:90;padding-top:8px;padding-bottom:24px;}
|
||||
.sidebar-menu__title{color:rgba(255,255,255,0.35);font-size:var(--font-xs);padding:16px 24px 8px;letter-spacing:.5px;}
|
||||
.sidebar-item{display:flex;align-items:center;gap:8px;padding:9px 24px;color:rgba(255,255,255,0.65);font-size:var(--font-sm);cursor:pointer;transition:all .15s;text-decoration:none;}
|
||||
.sidebar-item:hover{color:#fff;background:rgba(255,255,255,0.06);}
|
||||
.sidebar-item.active{color:#fff;background:var(--primary);}
|
||||
.main{margin-left:240px;margin-top:56px;padding:24px;min-height:calc(100vh - 56px);}
|
||||
.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;}
|
||||
.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);}
|
||||
.btn{height:36px;padding:0 16px;border-radius:var(--radius-sm);font-size:var(--font-sm);cursor:pointer;border:none;transition:all .2s;display:inline-flex;align-items:center;gap:6px;white-space:nowrap;}
|
||||
.btn-primary{background:var(--primary);color:#fff;}.btn-primary:hover{background:#40a9ff;}
|
||||
.btn-default{background:#fff;color:var(--text-primary);border:1px solid var(--border);}.btn-default:hover{color:var(--primary);border-color:var(--primary);}
|
||||
.btn-link{background:none;color:var(--primary);padding:0 4px;height:auto;}.btn-link:hover{color:#40a9ff;}
|
||||
.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);}
|
||||
.table-card{background:#fff;border-radius:0 0 var(--radius-md) var(--radius-md);box-shadow:var(--shadow-sm);overflow:hidden;}
|
||||
.table-card__content{overflow-x:auto;}
|
||||
table{width:100%;border-collapse:separate;border-spacing:0;min-width:1000px;}
|
||||
thead th{background:#FAFAFA;padding:10px 14px;text-align:center;font-size:var(--font-sm);color:var(--text-secondary);font-weight:500;border-bottom:1px solid var(--border);white-space:nowrap;}
|
||||
tbody td{padding:12px 14px;text-align:center;font-size:var(--font-sm);color:var(--text-primary);border-bottom:1px solid #F0F0F0;white-space:nowrap;}
|
||||
tbody tr:last-child td{border-bottom:none;}
|
||||
tbody tr:hover{background:#F8FBFF;}
|
||||
thead tr th:last-child,tbody td:last-child{position:sticky;right:0;z-index:5;background:#fff;box-shadow:-4px 0 8px rgba(0,0,0,0.04);}
|
||||
thead tr th:last-child{z-index:8;background:#FAFAFA;}
|
||||
tbody tr:hover td:last-child{background:#F8FBFF;}
|
||||
.td-empty{text-align:center;padding:48px 0;color:var(--text-placeholder);}
|
||||
.badge{display:inline-block;padding:2px 10px;border-radius:10px;font-size:var(--font-xs);}
|
||||
.badge--success{background:#F6FFED;color:#389E0D;border:1px solid #B7EB8F;}
|
||||
.badge--muted{background:#F5F5F5;color:var(--text-secondary);border:1px solid var(--border);}
|
||||
.pagination{display:flex;align-items:center;justify-content:flex-end;padding:16px 24px;gap:8px;border-top:1px solid var(--border);}
|
||||
.pagination span{font-size:var(--font-sm);color:var(--text-secondary);}
|
||||
.page-btn{min-width:32px;height:32px;border:1px solid var(--border);border-radius:var(--radius-sm);background:#fff;cursor:pointer;font-size:var(--font-sm);display:inline-flex;align-items:center;justify-content:center;padding:0 6px;transition:all .2s;}
|
||||
.page-btn:hover,.page-btn.active{background:var(--primary);color:#fff;border-color:var(--primary);}
|
||||
.modal-mask{display:none;position:fixed;inset:0;background:rgba(0,0,0,.45);z-index:950;align-items:center;justify-content:center;}
|
||||
.modal-mask.open{display:flex;}
|
||||
.modal{width:600px;background:#fff;border-radius:var(--radius-md);box-shadow:var(--shadow-md);}
|
||||
.modal__head{display:flex;align-items:center;justify-content:space-between;padding:16px 24px;border-bottom:1px solid var(--border);font-size:var(--font-base);font-weight:600;}
|
||||
.modal__close{cursor:pointer;color:var(--text-placeholder);font-size:20px;line-height:1;border:none;background:none;}
|
||||
.modal__body{padding:24px;max-height:60vh;overflow-y:auto;}
|
||||
.modal__footer{display:flex;justify-content:flex-end;gap:8px;padding:12px 24px;border-top:1px solid var(--border);}
|
||||
.form-item{display:flex;align-items:flex-start;margin-bottom:18px;}
|
||||
.form-item label{width:88px;min-width:88px;text-align:right;padding-right:12px;font-size:var(--font-sm);color:var(--text-secondary);line-height:36px;}
|
||||
.form-item label .req{color:var(--danger);margin-right:2px;}
|
||||
.form-item .control{flex:1;}
|
||||
.form-input{width:100%;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;}
|
||||
.form-input:focus{border-color:var(--primary);box-shadow:0 0 0 2px rgba(24,144,255,0.1);}
|
||||
.form-textarea{width:100%;border:1px solid var(--border);border-radius:var(--radius-sm);padding:8px 12px;font-size:var(--font-sm);color:var(--text-primary);outline:none;resize:vertical;min-height:100px;line-height:1.6;}
|
||||
.form-textarea:focus{border-color:var(--primary);box-shadow:0 0 0 2px rgba(24,144,255,0.1);}
|
||||
.radio-row{display:flex;gap:20px;line-height:36px;}
|
||||
.radio-row label{display:inline-flex;align-items:center;gap:6px;cursor:pointer;font-size:var(--font-sm);color:var(--text-primary);}
|
||||
.radio-row input{accent-color:var(--primary);width:15px;height:15px;cursor:pointer;}
|
||||
.detail-block{background:#F5F7FA;border-radius:var(--radius-sm);padding:16px;font-size:var(--font-sm);line-height:1.8;color:var(--text-primary);}
|
||||
.toast{position:fixed;top:80px;left:50%;transform:translateX(-50%);background:#333;color:#fff;padding:10px 24px;border-radius:var(--radius-sm);font-size:var(--font-sm);z-index:9999;opacity:0;transition:opacity .2s;pointer-events:none;}
|
||||
.toast.show{opacity:1;}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="top-bar">
|
||||
<div class="top-bar__logo"><svg viewBox="0 0 28 28" fill="none"><rect width="28" height="28" rx="6" fill="#1890FF"/><path d="M14 6.5l7 3.5v4.5c0 4.2-2.9 6.8-7 7.5-4.1-.7-7-3.3-7-7.5V10l7-3.5z" stroke="#fff" stroke-width="1.8" fill="none"/><path d="M11 13.5h6M14 10.5v6" stroke="#fff" stroke-width="1.8" stroke-linecap="round"/></svg> 系统管理</div>
|
||||
<nav class="top-bar__nav">
|
||||
<a href="user-admin.html">用户管理</a>
|
||||
<a href="application.html">权限管理</a>
|
||||
<a href="hospital.html">机构管理</a>
|
||||
<a href="dict.html">系统配置</a>
|
||||
<a href="announcement.html" class="active">通知管理</a>
|
||||
</nav>
|
||||
<div class="top-bar__right">
|
||||
<a class="btn-back" href="../../index.html"><svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M10 3L5 8l5 5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg> 返回首页</a>
|
||||
<div class="avatar">管</div>
|
||||
<span style="color:rgba(255,255,255,0.65);">系统管理员 ▾</span>
|
||||
</div>
|
||||
</div>
|
||||
<aside class="sidebar">
|
||||
<div class="sidebar-menu__title">通知管理</div>
|
||||
<a href="announcement.html" class="sidebar-item active">公告</a>
|
||||
<a href="sms-send.html" class="sidebar-item">发送短信</a>
|
||||
<a href="sms-history.html" class="sidebar-item">短信发送历史</a>
|
||||
<a href="sms-template.html" class="sidebar-item">短信模板</a>
|
||||
</aside>
|
||||
|
||||
<main class="main">
|
||||
<div class="filter-bar">
|
||||
<div class="filter-item"><label>标题</label><input class="filter-input" id="filterTitle" placeholder="请输入"></div>
|
||||
<div class="filter-item"><label>发布日期</label><input class="filter-input" type="date" id="filterFrom"><span style="color:var(--text-placeholder);">至</span><input class="filter-input" type="date" id="filterTo"></div>
|
||||
<button class="btn btn-primary" onclick="searchQuery()"><svg width="14" height="14" viewBox="0 0 14 14" fill="none"><circle cx="6" cy="6" r="4.5" stroke="#fff" stroke-width="1.3"/><path d="M9.5 9.5L13 13" stroke="#fff" stroke-width="1.3" stroke-linecap="round"/></svg>查询</button>
|
||||
<button class="btn btn-default" onclick="resetQuery()">重置</button>
|
||||
</div>
|
||||
<div class="action-bar">
|
||||
<button class="btn btn-primary" onclick="openAdd()"><svg width="14" height="14" viewBox="0 0 14 14" fill="none"><path d="M7 2v10M2 7h10" stroke="currentColor" stroke-width="1.4" stroke-linecap="round"/></svg>新增公告</button>
|
||||
<button class="btn btn-default" onclick="showToast('导出列表数据')">导出列表数据</button>
|
||||
<button class="btn btn-default" onclick="showToast('查看导出任务')">查看导出任务</button>
|
||||
</div>
|
||||
<div class="table-card">
|
||||
<div class="table-card__content">
|
||||
<table>
|
||||
<thead><tr><th style="width:60px">序号</th><th>通知标题</th><th style="width:160px">通知范围</th><th style="width:170px">发布时间</th><th style="width:100px">发布状态</th><th style="width:110px">操作人</th><th style="width:150px">操作</th></tr></thead>
|
||||
<tbody id="tableBody"></tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="pagination"><span>共 <b id="totalCount">0</b> 条</span><button class="page-btn" onclick="showToast('演示数据仅一页')">上一页</button><button class="page-btn active">1</button><button class="page-btn" onclick="showToast('演示数据仅一页')">下一页</button></div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<div class="modal-mask" id="annMask">
|
||||
<div class="modal">
|
||||
<div class="modal__head"><span id="annTitle">新增公告</span><button class="modal__close" onclick="closeModal()">×</button></div>
|
||||
<div class="modal__body">
|
||||
<div class="form-item"><label><span class="req">*</span>通知标题</label><div class="control"><input class="form-input" id="fTitle" placeholder="请输入通知标题"></div></div>
|
||||
<div class="form-item"><label><span class="req">*</span>通知范围</label><div class="control">
|
||||
<div class="radio-row">
|
||||
<label><input type="radio" name="scope" value="全部" checked onchange="onScopeChange()">全部</label>
|
||||
<label><input type="radio" name="scope" value="指定机构" onchange="onScopeChange()">指定机构</label>
|
||||
<label><input type="radio" name="scope" value="指定员工" onchange="onScopeChange()">指定员工</label>
|
||||
</div>
|
||||
</div></div>
|
||||
<div class="form-item" id="scopeTargetRow" style="display:none;"><label>选择对象</label><div class="control"><input class="form-input" id="fTarget" readonly placeholder="点击选择" onclick="showToast('打开选择弹窗')"></div></div>
|
||||
<div class="form-item"><label><span class="req">*</span>通知内容</label><div class="control"><textarea class="form-textarea" id="fContent" placeholder="请输入通知内容"></textarea></div></div>
|
||||
</div>
|
||||
<div class="modal__footer"><button class="btn btn-default" onclick="closeModal()">取消</button><button class="btn btn-primary" onclick="submitForm()">确定</button></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal-mask" id="detailMask">
|
||||
<div class="modal">
|
||||
<div class="modal__head"><span id="detailTitle">公告详情</span><button class="modal__close" onclick="closeDetail()">×</button></div>
|
||||
<div class="modal__body"><div class="detail-block" id="detailContent"></div></div>
|
||||
<div class="modal__footer"><button class="btn btn-default" onclick="closeDetail()">关闭</button></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="toast" id="toast"></div>
|
||||
|
||||
<script>
|
||||
var announcements=[
|
||||
{id:'1',title:'关于开展2026年度健康体检的通知',scope:'全员',time:'2026-09-01 10:00',status:'已发布',operator:'系统管理员',content:'根据年度健康管理工作安排,2026年度员工健康体检将于9月15日起陆续开展,请各单位组织员工按时参加。'},
|
||||
{id:'2',title:'中秋假期健康提示',scope:'全员',time:'2026-09-08 09:30',status:'已发布',operator:'运营管理员',content:'中秋假期将至,请合理安排作息,注意饮食健康,外出注意安全。'},
|
||||
{id:'3',title:'系统升级维护公告',scope:'全员',time:'2026-09-10 18:00',status:'草稿',operator:'系统管理员',content:'平台将于本周六凌晨进行系统升级维护,期间部分功能暂停使用。'}
|
||||
];
|
||||
function renderTable(){
|
||||
var list=announcements;
|
||||
document.getElementById('totalCount').textContent=list.length;
|
||||
document.getElementById('tableBody').innerHTML=list.map(function(a,i){
|
||||
return '<tr><td>'+(i+1)+'</td><td style="text-align:left;">'+a.title+'</td><td>'+a.scope+'</td><td>'+a.time+'</td><td><span class="badge '+(a.status==='已发布'?'badge--success':'badge--muted')+'">'+a.status+'</span></td><td>'+a.operator+'</td>'+
|
||||
'<td><button class="btn btn-link" onclick="openDetail('+a.id+')">详情</button><span style="color:var(--border);margin:0 4px;">|</span><button class="btn btn-link" onclick="showToast(\'发布成功\')">发布</button><span style="color:var(--border);margin:0 4px;">|</span><button class="btn btn-link" style="color:var(--danger);" onclick="delAnn('+a.id+')">删除</button></td></tr>';
|
||||
}).join('');
|
||||
}
|
||||
function searchQuery(){renderTable();showToast('查询完成');}
|
||||
function resetQuery(){document.getElementById('filterTitle').value='';document.getElementById('filterFrom').value='';document.getElementById('filterTo').value='';renderTable();}
|
||||
function delAnn(id){if(!confirm('确定删除该公告吗?'))return;announcements=announcements.filter(function(a){return a.id!==id;});renderTable();showToast('删除成功');}
|
||||
function openDetail(id){var a=announcements.find(function(x){return x.id===id;});document.getElementById('detailTitle').textContent=a?a.title:'公告详情';document.getElementById('detailContent').textContent=a?a.content:'';document.getElementById('detailMask').classList.add('open');}
|
||||
function closeDetail(){document.getElementById('detailMask').classList.remove('open');}
|
||||
function onScopeChange(){var v=document.querySelector('input[name="scope"]:checked').value;document.getElementById('scopeTargetRow').style.display=v==='全部'?'none':'flex';}
|
||||
function openAdd(){
|
||||
document.getElementById('annTitle').textContent='新增公告';
|
||||
document.getElementById('fTitle').value='';document.getElementById('fContent').value='';document.getElementById('fTarget').value='';
|
||||
document.querySelector('input[name="scope"][value="全部"]').checked=true;onScopeChange();
|
||||
document.getElementById('annMask').classList.add('open');
|
||||
}
|
||||
function closeModal(){document.getElementById('annMask').classList.remove('open');}
|
||||
function submitForm(){
|
||||
var title=document.getElementById('fTitle').value.trim();if(!title){showToast('请输入通知标题');return;}
|
||||
var content=document.getElementById('fContent').value.trim();if(!content){showToast('请输入通知内容');return;}
|
||||
var scope=document.querySelector('input[name="scope"]:checked').value;
|
||||
announcements.push({id:String(announcements.length+1),title:title,scope:scope,time:'2026-09-11 10:00',status:'草稿',operator:'系统管理员',content:content});
|
||||
closeModal();renderTable();showToast('新增成功');
|
||||
}
|
||||
function showToast(msg){var t=document.getElementById('toast');t.textContent=msg;t.classList.add('show');setTimeout(function(){t.classList.remove('show');},1500);}
|
||||
document.addEventListener('click',function(e){if(e.target.id==='annMask')closeModal();if(e.target.id==='detailMask')closeDetail();});
|
||||
renderTable();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,346 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>应用管理 | 系统管理</title>
|
||||
<style>
|
||||
*{box-sizing:border-box;margin:0;padding:0;}
|
||||
body{font-family:-apple-system,BlinkMacSystemFont,'PingFang SC','Microsoft YaHei',sans-serif;font-size:var(--font-sm);background:#F5F7FA;color:#333;min-width:1280px;}
|
||||
:root{
|
||||
--primary:#1890FF;--primary-light:#E6F7FF;--success:#52C41A;--warning:#FAAD14;--danger:#FF4D4F;
|
||||
--text-primary:#333;--text-secondary:#666;--text-placeholder:#999;--border:#E8E8E8;--background:#F5F7FA;
|
||||
--font-xs:11px;--font-sm:13px;--font-base:15px;--font-lg:17px;
|
||||
--radius-sm:4px;--radius-md:8px;--radius-lg:12px;
|
||||
--shadow-sm:0 1px 4px rgba(0,0,0,0.08);--shadow-md:0 4px 12px rgba(0,0,0,0.10);
|
||||
}
|
||||
.top-bar{display:flex;align-items:center;height:56px;background:#001529;padding:0 24px;position:fixed;top:0;left:0;right:0;z-index:100;}
|
||||
.top-bar__logo{display:flex;align-items:center;gap:8px;color:#fff;font-size:var(--font-lg);font-weight:600;white-space:nowrap;width:200px;flex-shrink:0;}
|
||||
.top-bar__logo svg{width:28px;height:28px;}
|
||||
.top-bar__nav{display:flex;align-items:center;gap:4px;flex:1;}
|
||||
.top-bar__nav a{color:rgba(255,255,255,0.65);text-decoration:none;padding:6px 14px;border-radius:var(--radius-sm);font-size:var(--font-sm);transition:all .2s;}
|
||||
.top-bar__nav a:hover{color:#fff;background:rgba(255,255,255,0.08);}
|
||||
.top-bar__nav a.active{color:#fff;background:var(--primary);}
|
||||
.top-bar__right{display:flex;align-items:center;gap:16px;color:rgba(255,255,255,0.65);font-size:var(--font-sm);}
|
||||
.btn-back{color:rgba(255,255,255,0.65);cursor:pointer;display:flex;align-items:center;gap:4px;text-decoration:none;}
|
||||
.btn-back:hover{color:#fff;}
|
||||
.avatar{width:32px;height:32px;border-radius:50%;background:#1890FF;display:flex;align-items:center;justify-content:center;color:#fff;font-size:var(--font-sm);cursor:pointer;}
|
||||
.sidebar{position:fixed;top:56px;left:0;bottom:0;width:240px;background:#001529;overflow-y:auto;z-index:90;padding-top:8px;padding-bottom:24px;}
|
||||
.sidebar-menu__title{color:rgba(255,255,255,0.35);font-size:var(--font-xs);padding:16px 24px 8px;letter-spacing:.5px;}
|
||||
.sidebar-item{display:flex;align-items:center;gap:8px;padding:9px 24px;color:rgba(255,255,255,0.65);font-size:var(--font-sm);cursor:pointer;transition:all .15s;text-decoration:none;}
|
||||
.sidebar-item:hover{color:#fff;background:rgba(255,255,255,0.06);}
|
||||
.sidebar-item.active{color:#fff;background:var(--primary);}
|
||||
.main{margin-left:240px;margin-top:56px;padding:24px;min-height:calc(100vh - 56px);}
|
||||
.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;}
|
||||
.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:160px;}
|
||||
.filter-input:focus{border-color:var(--primary);}
|
||||
.btn{height:36px;padding:0 16px;border-radius:var(--radius-sm);font-size:var(--font-sm);cursor:pointer;border:none;transition:all .2s;display:inline-flex;align-items:center;gap:6px;white-space:nowrap;}
|
||||
.btn-primary{background:var(--primary);color:#fff;}.btn-primary:hover{background:#40a9ff;}
|
||||
.btn-default{background:#fff;color:var(--text-primary);border:1px solid var(--border);}.btn-default:hover{color:var(--primary);border-color:var(--primary);}
|
||||
.btn-link{background:none;color:var(--primary);padding:0 4px;height:auto;}.btn-link:hover{color:#40a9ff;}
|
||||
.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);}
|
||||
.table-card{background:#fff;border-radius:0 0 var(--radius-md) var(--radius-md);box-shadow:var(--shadow-sm);overflow:hidden;}
|
||||
.table-card__content{overflow-x:auto;-webkit-overflow-scrolling:touch;}
|
||||
table{width:100%;border-collapse:separate;border-spacing:0;min-width:1400px;}
|
||||
thead th{background:#FAFAFA;padding:10px 14px;text-align:center;font-size:var(--font-sm);color:var(--text-secondary);font-weight:500;border-bottom:1px solid var(--border);white-space:nowrap;}
|
||||
tbody td{padding:12px 14px;text-align:center;font-size:var(--font-sm);color:var(--text-primary);border-bottom:1px solid #F0F0F0;white-space:nowrap;}
|
||||
tbody tr:last-child td{border-bottom:none;}
|
||||
tbody tr:hover{background:#F8FBFF;}
|
||||
thead tr th:last-child,tbody td:last-child{position:sticky;right:0;z-index:5;background:#fff;box-shadow:-4px 0 8px rgba(0,0,0,0.04);}
|
||||
thead tr th:last-child{z-index:8;background:#FAFAFA;}
|
||||
tbody tr:hover td:last-child{background:#F8FBFF;}
|
||||
.td-empty{text-align:center;padding:48px 0;color:var(--text-placeholder);}
|
||||
.badge{display:inline-block;padding:2px 10px;border-radius:10px;font-size:var(--font-xs);}
|
||||
.badge--info{background:#E6F7FF;color:#096DD9;border:1px solid #91D5FF;}
|
||||
.badge--muted{background:#F5F5F5;color:var(--text-secondary);border:1px solid var(--border);}
|
||||
.pagination{display:flex;align-items:center;justify-content:flex-end;padding:16px 24px;gap:8px;border-top:1px solid var(--border);}
|
||||
.pagination span{font-size:var(--font-sm);color:var(--text-secondary);}
|
||||
.page-btn{min-width:32px;height:32px;border:1px solid var(--border);border-radius:var(--radius-sm);background:#fff;cursor:pointer;font-size:var(--font-sm);display:inline-flex;align-items:center;justify-content:center;padding:0 6px;transition:all .2s;}
|
||||
.page-btn:hover,.page-btn.active{background:var(--primary);color:#fff;border-color:var(--primary);}
|
||||
.page-btn:disabled{opacity:.4;cursor:not-allowed;background:#fff;color:var(--text-placeholder);border-color:var(--border);}
|
||||
.switch{position:relative;display:inline-block;width:44px;height:22px;cursor:pointer;vertical-align:middle;}
|
||||
.switch input{display:none;}
|
||||
.switch .track{position:absolute;inset:0;border-radius:11px;background:rgba(0,0,0,0.25);transition:all .2s;}
|
||||
.switch .thumb{position:absolute;top:2px;left:2px;width:18px;height:18px;border-radius:50%;background:#fff;transition:all .2s;box-shadow:0 1px 3px rgba(0,0,0,0.2);}
|
||||
.switch.on .track{background:var(--primary);}
|
||||
.switch.on .thumb{left:24px;}
|
||||
.modal-mask{display:none;position:fixed;inset:0;background:rgba(0,0,0,.45);z-index:950;align-items:center;justify-content:center;}
|
||||
.modal-mask.open{display:flex;}
|
||||
.modal{width:600px;background:#fff;border-radius:var(--radius-md);box-shadow:var(--shadow-md);}
|
||||
.modal__head{display:flex;align-items:center;justify-content:space-between;padding:16px 24px;border-bottom:1px solid var(--border);font-size:var(--font-base);font-weight:600;}
|
||||
.modal__close{cursor:pointer;color:var(--text-placeholder);font-size:20px;line-height:1;border:none;background:none;}
|
||||
.modal__close:hover{color:var(--text-primary);}
|
||||
.modal__body{padding:24px;max-height:60vh;overflow-y:auto;}
|
||||
.modal__footer{display:flex;justify-content:flex-end;gap:8px;padding:12px 24px;border-top:1px solid var(--border);}
|
||||
.form-item{display:flex;align-items:flex-start;margin-bottom:18px;}
|
||||
.form-item:last-child{margin-bottom:0;}
|
||||
.form-item label{width:90px;min-width:90px;text-align:right;padding-right:12px;font-size:var(--font-sm);color:var(--text-secondary);line-height:36px;}
|
||||
.form-item label .req{color:var(--danger);margin-right:2px;}
|
||||
.form-item .control{flex:1;}
|
||||
.form-input{width:100%;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;}
|
||||
.form-input:focus{border-color:var(--primary);box-shadow:0 0 0 2px rgba(24,144,255,0.1);}
|
||||
.form-textarea{width:100%;border:1px solid var(--border);border-radius:var(--radius-sm);padding:8px 12px;font-size:var(--font-sm);color:var(--text-primary);outline:none;resize:vertical;min-height:72px;line-height:1.6;}
|
||||
.form-textarea:focus{border-color:var(--primary);box-shadow:0 0 0 2px rgba(24,144,255,0.1);}
|
||||
.icon-upload{width:72px;height:72px;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);cursor:pointer;gap:4px;background:#FAFAFA;}
|
||||
.icon-upload:hover{border-color:var(--primary);color:var(--primary);}
|
||||
.icon-upload svg{width:24px;height:24px;}
|
||||
.toast{position:fixed;top:80px;left:50%;transform:translateX(-50%);background:#333;color:#fff;padding:10px 24px;border-radius:var(--radius-sm);font-size:var(--font-sm);z-index:9999;opacity:0;transition:opacity .2s;pointer-events:none;}
|
||||
.toast.show{opacity:1;}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<!-- 顶部导航栏 -->
|
||||
<div class="top-bar">
|
||||
<div class="top-bar__logo"><svg viewBox="0 0 28 28" fill="none"><rect width="28" height="28" rx="6" fill="#1890FF"/><path d="M14 6.5l7 3.5v4.5c0 4.2-2.9 6.8-7 7.5-4.1-.7-7-3.3-7-7.5V10l7-3.5z" stroke="#fff" stroke-width="1.8" fill="none"/><path d="M11 13.5h6M14 10.5v6" stroke="#fff" stroke-width="1.8" stroke-linecap="round"/></svg> 系统管理</div>
|
||||
<nav class="top-bar__nav">
|
||||
<a href="user-admin.html">用户管理</a>
|
||||
<a href="application.html" class="active">权限管理</a>
|
||||
<a href="hospital.html">机构管理</a>
|
||||
<a href="dict.html">系统配置</a>
|
||||
<a href="announcement.html">通知管理</a>
|
||||
</nav>
|
||||
<div class="top-bar__right">
|
||||
<a class="btn-back" href="../../index.html"><svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M10 3L5 8l5 5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg> 返回首页</a>
|
||||
<div class="avatar">管</div>
|
||||
<span style="color:rgba(255,255,255,0.65);">系统管理员 ▾</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 侧边栏(当前一级分组「权限管理」的二级菜单) -->
|
||||
<aside class="sidebar">
|
||||
<div class="sidebar-menu__title">权限管理</div>
|
||||
<a href="application.html" class="sidebar-item active">应用管理</a>
|
||||
<a href="menu.html" class="sidebar-item">菜单管理</a>
|
||||
<a href="role.html" class="sidebar-item">角色管理</a>
|
||||
</aside>
|
||||
|
||||
<!-- 主内容 -->
|
||||
<main class="main">
|
||||
<!-- [交互] 筛选栏 -->
|
||||
<div class="filter-bar">
|
||||
<div class="filter-item">
|
||||
<label>应用名称</label>
|
||||
<input class="filter-input" id="filterName" placeholder="请输入应用名称">
|
||||
</div>
|
||||
<button class="btn btn-primary" onclick="searchQuery()">
|
||||
<svg width="14" height="14" viewBox="0 0 14 14" fill="none"><circle cx="6" cy="6" r="4.5" stroke="#fff" stroke-width="1.3"/><path d="M9.5 9.5L13 13" stroke="#fff" stroke-width="1.3" stroke-linecap="round"/></svg>查询
|
||||
</button>
|
||||
<button class="btn btn-default" onclick="resetQuery()">重置</button>
|
||||
</div>
|
||||
|
||||
<!-- [交互] 操作栏 -->
|
||||
<div class="action-bar">
|
||||
<button class="btn btn-primary" onclick="openModal('add',null)">
|
||||
<svg width="14" height="14" viewBox="0 0 14 14" fill="none"><path d="M7 2v10M2 7h10" stroke="currentColor" stroke-width="1.4" stroke-linecap="round"/></svg>新增应用
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- 表格 -->
|
||||
<div class="table-card">
|
||||
<div class="table-card__content">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width:70px">序号</th>
|
||||
<th style="width:160px">应用名称</th>
|
||||
<th style="width:150px">APPID</th>
|
||||
<th style="width:120px">应用类型</th>
|
||||
<th style="width:110px">应用分类</th>
|
||||
<th style="width:180px">应用编码</th>
|
||||
<th style="width:80px">排序</th>
|
||||
<th style="width:220px">应用描述</th>
|
||||
<th style="width:100px">状态</th>
|
||||
<th style="width:190px">操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="tableBody"></tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="pagination">
|
||||
<span>共 <b id="totalCount">0</b> 条</span>
|
||||
<button class="page-btn" id="prevBtn" onclick="turnPage(-1)">上一页</button>
|
||||
<span id="pageNum">1</span>
|
||||
<button class="page-btn" id="nextBtn" onclick="turnPage(1)">下一页</button>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<!-- [交互] 新增/编辑应用弹窗 -->
|
||||
<div class="modal-mask" id="appMask">
|
||||
<div class="modal">
|
||||
<div class="modal__head"><span id="appTitle">新增应用</span><button class="modal__close" onclick="closeModal()">×</button></div>
|
||||
<div class="modal__body">
|
||||
<div class="form-item">
|
||||
<label>应用图标</label>
|
||||
<div class="control"><div class="icon-upload" onclick="showToast('上传应用图标')"><svg viewBox="0 0 24 24" fill="none"><path d="M12 16V4M8 8l4-4 4 4" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"/><path d="M4 16v3a1 1 0 001 1h14a1 1 0 001-1v-3" stroke="currentColor" stroke-width="1.6" stroke-linecap="round"/></svg><span style="font-size:var(--font-xs)">上传</span></div></div>
|
||||
</div>
|
||||
<div class="form-item">
|
||||
<label><span class="req">*</span>应用名称</label>
|
||||
<div class="control"><input class="form-input" id="fName" maxlength="30" placeholder="请输入应用名称"></div>
|
||||
</div>
|
||||
<div class="form-item">
|
||||
<label><span class="req">*</span>应用包名</label>
|
||||
<div class="control"><input class="form-input" id="fRedirect" placeholder="请输入应用包名"></div>
|
||||
</div>
|
||||
<div class="form-item">
|
||||
<label><span class="req">*</span>应用类型</label>
|
||||
<div class="control"><select class="form-input" id="fAppType"><option value="">请选择应用类型</option><option value="预防">预防</option><option value="救治">救治</option><option value="数据">数据</option><option value="系统管理">系统管理</option></select></div>
|
||||
</div>
|
||||
<div class="form-item">
|
||||
<label><span class="req">*</span>应用分类</label>
|
||||
<div class="control"><select class="form-input" id="fCustomType"><option value="">请选择应用分类</option><option value="通用">通用</option><option value="定制">定制</option></select></div>
|
||||
</div>
|
||||
<div class="form-item">
|
||||
<label><span class="req">*</span>应用排序</label>
|
||||
<div class="control"><input class="form-input" id="fSort" type="number" min="1" placeholder="请输入排序值"></div>
|
||||
</div>
|
||||
<div class="form-item">
|
||||
<label><span class="req">*</span>应用编码</label>
|
||||
<div class="control"><input class="form-input" id="fCode" maxlength="30" placeholder="请输入应用编码"></div>
|
||||
</div>
|
||||
<div class="form-item">
|
||||
<label>应用描述</label>
|
||||
<div class="control"><textarea class="form-textarea" id="fDesc" maxlength="200" placeholder="请输入应用描述"></textarea></div>
|
||||
</div>
|
||||
<div class="form-item">
|
||||
<label>应用状态</label>
|
||||
<div class="control"><div style="display:flex;align-items:center;height:36px;gap:8px;"><label class="switch on" id="fStatusSwitch" onclick="toggleStatus()"><input type="checkbox" checked><span class="track"></span><span class="thumb"></span></label><span id="fStatusText" style="color:var(--text-secondary);">启用</span></div></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal__footer">
|
||||
<button class="btn btn-default" onclick="closeModal()">取消</button>
|
||||
<button class="btn btn-primary" onclick="submitForm()">确定</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="toast" id="toast"></div>
|
||||
|
||||
<script>
|
||||
/* ===== 演示数据 ===== */
|
||||
var APPTYPE_BADGE={'预防':'badge--info','救治':'badge--info','数据':'badge--info','系统管理':'badge--muted'};
|
||||
var apps=[
|
||||
{id:'1001',name:'员工健康APP',appType:'预防',customType:'通用',code:'employee-health',sort:1,desc:'员工端健康管理应用',status:1},
|
||||
{id:'1002',name:'应急救治APP',appType:'救治',customType:'通用',code:'emergency-medical',sort:2,desc:'应急就医与救治调度应用',status:1},
|
||||
{id:'1003',name:'健康数据中心',appType:'数据',customType:'通用',code:'health-data',sort:3,desc:'健康数据可视化与统计分析',status:1},
|
||||
{id:'1004',name:'系统管理',appType:'系统管理',customType:'通用',code:'system-management',sort:4,desc:'平台系统管理与权限配置',status:1},
|
||||
{id:'1005',name:'一线医疗',appType:'预防',customType:'定制',code:'frontline-medical',sort:5,desc:'一线医疗点服务与管理',status:1},
|
||||
{id:'1006',name:'健康小屋',appType:'预防',customType:'定制',code:'health-hut',sort:6,desc:'健康小屋自助检测服务',status:0}
|
||||
];
|
||||
var editingId=null;
|
||||
|
||||
function renderTable(){
|
||||
var kw=document.getElementById('filterName').value.trim();
|
||||
var list=apps.filter(function(a){return !kw||a.name.indexOf(kw)>=0;});
|
||||
document.getElementById('totalCount').textContent=list.length;
|
||||
var body=document.getElementById('tableBody');
|
||||
if(list.length===0){
|
||||
body.innerHTML='<tr><td colspan="10" class="td-empty">暂无数据</td></tr>';
|
||||
return;
|
||||
}
|
||||
body.innerHTML=list.map(function(a,i){
|
||||
var statusHtml=a.status===1
|
||||
?'<label class="switch on" onclick="toggleStatus('+a.id+')"><input type="checkbox" checked><span class="track"></span><span class="thumb"></span></label>'
|
||||
:'<label class="switch" onclick="toggleStatus('+a.id+')"><input type="checkbox"><span class="track"></span><span class="thumb"></span></label>';
|
||||
return '<tr>'+
|
||||
'<td>'+(i+1)+'</td>'+
|
||||
'<td>'+a.name+'</td>'+
|
||||
'<td>'+a.id+'</td>'+
|
||||
'<td><span class="badge '+(APPTYPE_BADGE[a.appType]||'badge--muted')+'">'+a.appType+'</span></td>'+
|
||||
'<td>'+a.customType+'</td>'+
|
||||
'<td>'+a.code+'</td>'+
|
||||
'<td>'+a.sort+'</td>'+
|
||||
'<td style="text-align:left;">'+a.desc+'</td>'+
|
||||
'<td>'+statusHtml+'</td>'+
|
||||
'<td>'+
|
||||
'<button class="btn btn-link" onclick="openModal(\'edit\','+a.id+')">编辑</button>'+
|
||||
'<span style="color:var(--border);margin:0 4px;">|</span>'+
|
||||
'<button class="btn btn-link" onclick="goMenu('+a.id+')">菜单</button>'+
|
||||
'<span style="color:var(--border);margin:0 4px;">|</span>'+
|
||||
'<button class="btn btn-link" style="color:var(--danger);" onclick="delApp('+a.id+')">删除</button>'+
|
||||
'</td>'+
|
||||
'</tr>';
|
||||
}).join('');
|
||||
}
|
||||
function searchQuery(){renderTable();showToast('查询完成');}
|
||||
function resetQuery(){document.getElementById('filterName').value='';renderTable();}
|
||||
function turnPage(d){showToast('演示数据仅一页');}
|
||||
function toggleStatus(id){
|
||||
if(id===undefined||id===null){ // 弹窗内的状态开关
|
||||
var sw=document.getElementById('fStatusSwitch');
|
||||
var on=sw.classList.toggle('on');
|
||||
sw.querySelector('input').checked=on;
|
||||
document.getElementById('fStatusText').textContent=on?'启用':'停用';
|
||||
return;
|
||||
}
|
||||
var a=apps.find(function(x){return x.id===id;});
|
||||
if(a){a.status=a.status===1?0:1;renderTable();showToast(a.status===1?'已启用':'已停用');}
|
||||
}
|
||||
function goMenu(id){showToast('跳转至菜单管理(appId='+id+')');setTimeout(function(){location.href='menu.html?appId='+id;},300);}
|
||||
function delApp(id){
|
||||
if(!confirm('确定要删除该条数据吗?此操作不可恢复。'))return;
|
||||
apps=apps.filter(function(x){return x.id!==id;});
|
||||
renderTable();showToast('删除成功');
|
||||
}
|
||||
/* ===== 弹窗 ===== */
|
||||
function openModal(type,id){
|
||||
editingId=id;
|
||||
document.getElementById('appTitle').textContent=type==='add'?'新增应用':'编辑应用';
|
||||
document.getElementById('fName').value='';
|
||||
document.getElementById('fRedirect').value='';
|
||||
document.getElementById('fAppType').value='';
|
||||
document.getElementById('fCustomType').value='';
|
||||
document.getElementById('fSort').value='';
|
||||
document.getElementById('fCode').value='';
|
||||
document.getElementById('fDesc').value='';
|
||||
var sw=document.getElementById('fStatusSwitch');
|
||||
sw.classList.add('on');sw.querySelector('input').checked=true;
|
||||
document.getElementById('fStatusText').textContent='启用';
|
||||
if(type==='edit'&&id){
|
||||
var a=apps.find(function(x){return x.id===id;});
|
||||
if(a){
|
||||
document.getElementById('fName').value=a.name;
|
||||
document.getElementById('fRedirect').value=a.code;
|
||||
document.getElementById('fAppType').value=a.appType;
|
||||
document.getElementById('fCustomType').value=a.customType;
|
||||
document.getElementById('fSort').value=a.sort;
|
||||
document.getElementById('fCode').value=a.code;
|
||||
document.getElementById('fDesc').value=a.desc;
|
||||
if(a.status!==1){sw.classList.remove('on');sw.querySelector('input').checked=false;document.getElementById('fStatusText').textContent='停用';}
|
||||
}
|
||||
}
|
||||
document.getElementById('appMask').classList.add('open');
|
||||
}
|
||||
function closeModal(){document.getElementById('appMask').classList.remove('open');}
|
||||
function submitForm(){
|
||||
var name=document.getElementById('fName').value.trim();
|
||||
if(!name){showToast('请输入应用名称');return;}
|
||||
var appType=document.getElementById('fAppType').value;
|
||||
if(!appType){showToast('请选择应用类型');return;}
|
||||
var customType=document.getElementById('fCustomType').value;
|
||||
if(!customType){showToast('请选择应用分类');return;}
|
||||
var code=document.getElementById('fCode').value.trim();
|
||||
if(!code){showToast('请输入应用编码');return;}
|
||||
var sort=parseInt(document.getElementById('fSort').value)||1;
|
||||
var desc=document.getElementById('fDesc').value.trim();
|
||||
var status=document.getElementById('fStatusSwitch').classList.contains('on')?1:0;
|
||||
if(editingId){
|
||||
var a=apps.find(function(x){return x.id===editingId;});
|
||||
if(a){a.name=name;a.appType=appType;a.customType=customType;a.code=code;a.sort=sort;a.desc=desc;a.status=status;}
|
||||
}else{
|
||||
apps.push({id:String(1000+apps.length+1),name:name,appType:appType,customType:customType,code:code,sort:sort,desc:desc,status:status});
|
||||
}
|
||||
closeModal();renderTable();showToast(editingId?'编辑成功':'新增成功');
|
||||
}
|
||||
function showToast(msg){
|
||||
var t=document.getElementById('toast');t.textContent=msg;t.classList.add('show');
|
||||
setTimeout(function(){t.classList.remove('show');},1500);
|
||||
}
|
||||
document.addEventListener('click',function(e){if(e.target===document.getElementById('appMask'))closeModal();});
|
||||
renderTable();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,173 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>字典分类 | 系统管理</title>
|
||||
<style>
|
||||
*{box-sizing:border-box;margin:0;padding:0;}
|
||||
body{font-family:-apple-system,BlinkMacSystemFont,'PingFang SC','Microsoft YaHei',sans-serif;font-size:var(--font-sm);background:#F5F7FA;color:#333;min-width:1280px;}
|
||||
:root{
|
||||
--primary:#1890FF;--primary-light:#E6F7FF;--success:#52C41A;--warning:#FAAD14;--danger:#FF4D4F;
|
||||
--text-primary:#333;--text-secondary:#666;--text-placeholder:#999;--border:#E8E8E8;--background:#F5F7FA;
|
||||
--font-xs:11px;--font-sm:13px;--font-base:15px;--font-lg:17px;
|
||||
--radius-sm:4px;--radius-md:8px;--radius-lg:12px;
|
||||
--shadow-sm:0 1px 4px rgba(0,0,0,0.08);--shadow-md:0 4px 12px rgba(0,0,0,0.10);
|
||||
}
|
||||
.top-bar{display:flex;align-items:center;height:56px;background:#001529;padding:0 24px;position:fixed;top:0;left:0;right:0;z-index:100;}
|
||||
.top-bar__logo{display:flex;align-items:center;gap:8px;color:#fff;font-size:var(--font-lg);font-weight:600;white-space:nowrap;width:200px;flex-shrink:0;}
|
||||
.top-bar__logo svg{width:28px;height:28px;}
|
||||
.top-bar__nav{display:flex;align-items:center;gap:4px;flex:1;}
|
||||
.top-bar__nav a{color:rgba(255,255,255,0.65);text-decoration:none;padding:6px 14px;border-radius:var(--radius-sm);font-size:var(--font-sm);transition:all .2s;}
|
||||
.top-bar__nav a:hover{color:#fff;background:rgba(255,255,255,0.08);}
|
||||
.top-bar__nav a.active{color:#fff;background:var(--primary);}
|
||||
.top-bar__right{display:flex;align-items:center;gap:16px;color:rgba(255,255,255,0.65);font-size:var(--font-sm);}
|
||||
.btn-back{color:rgba(255,255,255,0.65);cursor:pointer;display:flex;align-items:center;gap:4px;text-decoration:none;}
|
||||
.btn-back:hover{color:#fff;}
|
||||
.avatar{width:32px;height:32px;border-radius:50%;background:#1890FF;display:flex;align-items:center;justify-content:center;color:#fff;font-size:var(--font-sm);cursor:pointer;}
|
||||
.sidebar{position:fixed;top:56px;left:0;bottom:0;width:240px;background:#001529;overflow-y:auto;z-index:90;padding-top:8px;padding-bottom:24px;}
|
||||
.sidebar-menu__title{color:rgba(255,255,255,0.35);font-size:var(--font-xs);padding:16px 24px 8px;letter-spacing:.5px;}
|
||||
.sidebar-item{display:flex;align-items:center;gap:8px;padding:9px 24px;color:rgba(255,255,255,0.65);font-size:var(--font-sm);cursor:pointer;transition:all .15s;text-decoration:none;}
|
||||
.sidebar-item:hover{color:#fff;background:rgba(255,255,255,0.06);}
|
||||
.sidebar-item.active{color:#fff;background:var(--primary);}
|
||||
.main{margin-left:240px;margin-top:56px;padding:24px;min-height:calc(100vh - 56px);}
|
||||
.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;}
|
||||
.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:180px;}
|
||||
.filter-input:focus{border-color:var(--primary);}
|
||||
.btn{height:36px;padding:0 16px;border-radius:var(--radius-sm);font-size:var(--font-sm);cursor:pointer;border:none;transition:all .2s;display:inline-flex;align-items:center;gap:6px;white-space:nowrap;}
|
||||
.btn-primary{background:var(--primary);color:#fff;}.btn-primary:hover{background:#40a9ff;}
|
||||
.btn-default{background:#fff;color:var(--text-primary);border:1px solid var(--border);}.btn-default:hover{color:var(--primary);border-color:var(--primary);}
|
||||
.btn-link{background:none;color:var(--primary);padding:0 4px;height:auto;}.btn-link:hover{color:#40a9ff;}
|
||||
.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);}
|
||||
.table-card{background:#fff;border-radius:0 0 var(--radius-md) var(--radius-md);box-shadow:var(--shadow-sm);overflow:hidden;}
|
||||
.table-card__content{overflow-x:auto;}
|
||||
table{width:100%;border-collapse:separate;border-spacing:0;min-width:800px;}
|
||||
thead th{background:#FAFAFA;padding:10px 14px;text-align:center;font-size:var(--font-sm);color:var(--text-secondary);font-weight:500;border-bottom:1px solid var(--border);white-space:nowrap;}
|
||||
tbody td{padding:12px 14px;text-align:center;font-size:var(--font-sm);color:var(--text-primary);border-bottom:1px solid #F0F0F0;white-space:nowrap;}
|
||||
tbody tr:last-child td{border-bottom:none;}
|
||||
tbody tr:hover{background:#F8FBFF;}
|
||||
thead tr th:last-child,tbody td:last-child{position:sticky;right:0;z-index:5;background:#fff;box-shadow:-4px 0 8px rgba(0,0,0,0.04);}
|
||||
thead tr th:last-child{z-index:8;background:#FAFAFA;}
|
||||
tbody tr:hover td:last-child{background:#F8FBFF;}
|
||||
.td-empty{text-align:center;padding:48px 0;color:var(--text-placeholder);}
|
||||
.pagination{display:flex;align-items:center;justify-content:flex-end;padding:16px 24px;gap:8px;border-top:1px solid var(--border);}
|
||||
.pagination span{font-size:var(--font-sm);color:var(--text-secondary);}
|
||||
.page-btn{min-width:32px;height:32px;border:1px solid var(--border);border-radius:var(--radius-sm);background:#fff;cursor:pointer;font-size:var(--font-sm);display:inline-flex;align-items:center;justify-content:center;padding:0 6px;transition:all .2s;}
|
||||
.page-btn:hover,.page-btn.active{background:var(--primary);color:#fff;border-color:var(--primary);}
|
||||
.modal-mask{display:none;position:fixed;inset:0;background:rgba(0,0,0,.45);z-index:950;align-items:center;justify-content:center;}
|
||||
.modal-mask.open{display:flex;}
|
||||
.modal{width:520px;background:#fff;border-radius:var(--radius-md);box-shadow:var(--shadow-md);}
|
||||
.modal__head{display:flex;align-items:center;justify-content:space-between;padding:16px 24px;border-bottom:1px solid var(--border);font-size:var(--font-base);font-weight:600;}
|
||||
.modal__close{cursor:pointer;color:var(--text-placeholder);font-size:20px;line-height:1;border:none;background:none;}
|
||||
.modal__body{padding:24px;max-height:60vh;overflow-y:auto;}
|
||||
.modal__footer{display:flex;justify-content:flex-end;gap:8px;padding:12px 24px;border-top:1px solid var(--border);}
|
||||
.form-item{display:flex;align-items:flex-start;margin-bottom:18px;}
|
||||
.form-item label{width:88px;min-width:88px;text-align:right;padding-right:12px;font-size:var(--font-sm);color:var(--text-secondary);line-height:36px;}
|
||||
.form-item label .req{color:var(--danger);margin-right:2px;}
|
||||
.form-item .control{flex:1;}
|
||||
.form-input{width:100%;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;}
|
||||
.form-input:focus{border-color:var(--primary);box-shadow:0 0 0 2px rgba(24,144,255,0.1);}
|
||||
.form-textarea{width:100%;border:1px solid var(--border);border-radius:var(--radius-sm);padding:8px 12px;font-size:var(--font-sm);color:var(--text-primary);outline:none;resize:vertical;min-height:68px;line-height:1.6;}
|
||||
.form-textarea:focus{border-color:var(--primary);box-shadow:0 0 0 2px rgba(24,144,255,0.1);}
|
||||
.toast{position:fixed;top:80px;left:50%;transform:translateX(-50%);background:#333;color:#fff;padding:10px 24px;border-radius:var(--radius-sm);font-size:var(--font-sm);z-index:9999;opacity:0;transition:opacity .2s;pointer-events:none;}
|
||||
.toast.show{opacity:1;}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="top-bar">
|
||||
<div class="top-bar__logo"><svg viewBox="0 0 28 28" fill="none"><rect width="28" height="28" rx="6" fill="#1890FF"/><path d="M14 6.5l7 3.5v4.5c0 4.2-2.9 6.8-7 7.5-4.1-.7-7-3.3-7-7.5V10l7-3.5z" stroke="#fff" stroke-width="1.8" fill="none"/><path d="M11 13.5h6M14 10.5v6" stroke="#fff" stroke-width="1.8" stroke-linecap="round"/></svg> 系统管理</div>
|
||||
<nav class="top-bar__nav">
|
||||
<a href="user-admin.html">用户管理</a>
|
||||
<a href="application.html">权限管理</a>
|
||||
<a href="hospital.html">机构管理</a>
|
||||
<a href="dict.html" class="active">系统配置</a>
|
||||
<a href="announcement.html">通知管理</a>
|
||||
</nav>
|
||||
<div class="top-bar__right">
|
||||
<a class="btn-back" href="../../index.html"><svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M10 3L5 8l5 5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg> 返回首页</a>
|
||||
<div class="avatar">管</div>
|
||||
<span style="color:rgba(255,255,255,0.65);">系统管理员 ▾</span>
|
||||
</div>
|
||||
</div>
|
||||
<aside class="sidebar">
|
||||
<div class="sidebar-menu__title">系统配置</div>
|
||||
<a href="dict.html" class="sidebar-item">数据字典</a>
|
||||
<a href="dict-category.html" class="sidebar-item active">字典分类</a>
|
||||
<a href="variable.html" class="sidebar-item">变量配置</a>
|
||||
<a href="version.html" class="sidebar-item">版本更新</a>
|
||||
</aside>
|
||||
|
||||
<main class="main">
|
||||
<div class="filter-bar">
|
||||
<div class="filter-item"><label>分类名称</label><input class="filter-input" id="filterName" placeholder="请输入分类名称"></div>
|
||||
<button class="btn btn-primary" onclick="searchQuery()"><svg width="14" height="14" viewBox="0 0 14 14" fill="none"><circle cx="6" cy="6" r="4.5" stroke="#fff" stroke-width="1.3"/><path d="M9.5 9.5L13 13" stroke="#fff" stroke-width="1.3" stroke-linecap="round"/></svg>查询</button>
|
||||
<button class="btn btn-default" onclick="resetQuery()">重置</button>
|
||||
</div>
|
||||
<div class="action-bar">
|
||||
<button class="btn btn-primary" onclick="openModal('add',null)"><svg width="14" height="14" viewBox="0 0 14 14" fill="none"><path d="M7 2v10M2 7h10" stroke="currentColor" stroke-width="1.4" stroke-linecap="round"/></svg>新增分类</button>
|
||||
</div>
|
||||
<div class="table-card">
|
||||
<div class="table-card__content">
|
||||
<table>
|
||||
<thead><tr><th style="width:70px">序号</th><th style="width:200px">分类名称</th><th>分类描述</th><th style="width:200px">创建时间</th><th style="width:130px">操作</th></tr></thead>
|
||||
<tbody id="tableBody"></tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="pagination"><span>共 <b id="totalCount">0</b> 条</span><button class="page-btn" onclick="showToast('演示数据仅一页')">上一页</button><button class="page-btn active">1</button><button class="page-btn" onclick="showToast('演示数据仅一页')">下一页</button></div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<div class="modal-mask" id="catMask">
|
||||
<div class="modal">
|
||||
<div class="modal__head"><span id="catTitle">新增分类</span><button class="modal__close" onclick="closeModal()">×</button></div>
|
||||
<div class="modal__body">
|
||||
<div class="form-item"><label><span class="req">*</span>分类名称</label><div class="control"><input class="form-input" id="fName" maxlength="30" placeholder="请输入分类名称"></div></div>
|
||||
<div class="form-item"><label>分类描述</label><div class="control"><textarea class="form-textarea" id="fDesc" maxlength="200" placeholder="请输入分类描述"></textarea></div></div>
|
||||
</div>
|
||||
<div class="modal__footer"><button class="btn btn-default" onclick="closeModal()">取消</button><button class="btn btn-primary" onclick="submitForm()">确定</button></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="toast" id="toast"></div>
|
||||
|
||||
<script>
|
||||
var categories=[
|
||||
{id:'1',name:'用户管理',desc:'用户相关字典',time:'2026-08-01 10:00'},
|
||||
{id:'2',name:'机构管理',desc:'机构相关字典',time:'2026-08-01 10:00'},
|
||||
{id:'3',name:'权限管理',desc:'权限相关字典',time:'2026-08-01 10:00'},
|
||||
{id:'4',name:'系统配置',desc:'系统配置相关字典',time:'2026-08-02 09:30'}
|
||||
];
|
||||
var editingId=null;
|
||||
function renderTable(){
|
||||
var kw=document.getElementById('filterName').value.trim();
|
||||
var list=categories.filter(function(c){return !kw||c.name.indexOf(kw)>=0;});
|
||||
document.getElementById('totalCount').textContent=list.length;
|
||||
document.getElementById('tableBody').innerHTML=list.length===0?'<tr><td colspan="5" class="td-empty">暂无数据</td></tr>':list.map(function(c,i){
|
||||
return '<tr><td>'+(i+1)+'</td><td>'+c.name+'</td><td style="text-align:left;">'+c.desc+'</td><td>'+c.time+'</td><td><button class="btn btn-link" onclick="openModal(\'edit\','+c.id+')">编辑</button><span style="color:var(--border);margin:0 4px;">|</span><button class="btn btn-link" style="color:var(--danger);" onclick="delCat('+c.id+')">删除</button></td></tr>';
|
||||
}).join('');
|
||||
}
|
||||
function searchQuery(){renderTable();showToast('查询完成');}
|
||||
function resetQuery(){document.getElementById('filterName').value='';renderTable();}
|
||||
function delCat(id){if(!confirm('确定删除该分类吗?'))return;categories=categories.filter(function(c){return c.id!==id;});renderTable();showToast('删除成功');}
|
||||
function openModal(type,id){
|
||||
editingId=id;
|
||||
document.getElementById('catTitle').textContent=type==='add'?'新增分类':'编辑分类';
|
||||
document.getElementById('fName').value='';document.getElementById('fDesc').value='';
|
||||
if(type==='edit'&&id){var c=categories.find(function(x){return x.id===id;});if(c){document.getElementById('fName').value=c.name;document.getElementById('fDesc').value=c.desc;}}
|
||||
document.getElementById('catMask').classList.add('open');
|
||||
}
|
||||
function closeModal(){document.getElementById('catMask').classList.remove('open');}
|
||||
function submitForm(){
|
||||
var name=document.getElementById('fName').value.trim();if(!name){showToast('请输入分类名称');return;}
|
||||
var desc=document.getElementById('fDesc').value.trim();
|
||||
if(editingId){var c=categories.find(function(x){return x.id===editingId;});if(c){c.name=name;c.desc=desc;}}
|
||||
else categories.push({id:String(categories.length+1),name:name,desc:desc,time:'2026-09-11 10:00'});
|
||||
closeModal();renderTable();showToast(editingId?'编辑成功':'新增成功');
|
||||
}
|
||||
function showToast(msg){var t=document.getElementById('toast');t.textContent=msg;t.classList.add('show');setTimeout(function(){t.classList.remove('show');},1500);}
|
||||
document.addEventListener('click',function(e){if(e.target===document.getElementById('catMask'))closeModal();});
|
||||
renderTable();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,340 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>数据字典 | 系统管理</title>
|
||||
<style>
|
||||
*{box-sizing:border-box;margin:0;padding:0;}
|
||||
body{font-family:-apple-system,BlinkMacSystemFont,'PingFang SC','Microsoft YaHei',sans-serif;font-size:var(--font-sm);background:#F5F7FA;color:#333;min-width:1280px;}
|
||||
:root{
|
||||
--primary:#1890FF;--primary-light:#E6F7FF;--success:#52C41A;--warning:#FAAD14;--danger:#FF4D4F;
|
||||
--text-primary:#333;--text-secondary:#666;--text-placeholder:#999;--border:#E8E8E8;--background:#F5F7FA;
|
||||
--font-xs:11px;--font-sm:13px;--font-base:15px;--font-lg:17px;
|
||||
--radius-sm:4px;--radius-md:8px;--radius-lg:12px;
|
||||
--shadow-sm:0 1px 4px rgba(0,0,0,0.08);--shadow-md:0 4px 12px rgba(0,0,0,0.10);
|
||||
}
|
||||
.top-bar{display:flex;align-items:center;height:56px;background:#001529;padding:0 24px;position:fixed;top:0;left:0;right:0;z-index:100;}
|
||||
.top-bar__logo{display:flex;align-items:center;gap:8px;color:#fff;font-size:var(--font-lg);font-weight:600;white-space:nowrap;width:200px;flex-shrink:0;}
|
||||
.top-bar__logo svg{width:28px;height:28px;}
|
||||
.top-bar__nav{display:flex;align-items:center;gap:4px;flex:1;}
|
||||
.top-bar__nav a{color:rgba(255,255,255,0.65);text-decoration:none;padding:6px 14px;border-radius:var(--radius-sm);font-size:var(--font-sm);transition:all .2s;}
|
||||
.top-bar__nav a:hover{color:#fff;background:rgba(255,255,255,0.08);}
|
||||
.top-bar__nav a.active{color:#fff;background:var(--primary);}
|
||||
.top-bar__right{display:flex;align-items:center;gap:16px;color:rgba(255,255,255,0.65);font-size:var(--font-sm);}
|
||||
.btn-back{color:rgba(255,255,255,0.65);cursor:pointer;display:flex;align-items:center;gap:4px;text-decoration:none;}
|
||||
.btn-back:hover{color:#fff;}
|
||||
.avatar{width:32px;height:32px;border-radius:50%;background:#1890FF;display:flex;align-items:center;justify-content:center;color:#fff;font-size:var(--font-sm);cursor:pointer;}
|
||||
.sidebar{position:fixed;top:56px;left:0;bottom:0;width:240px;background:#001529;overflow-y:auto;z-index:90;padding-top:8px;padding-bottom:24px;}
|
||||
.sidebar-menu__title{color:rgba(255,255,255,0.35);font-size:var(--font-xs);padding:16px 24px 8px;letter-spacing:.5px;}
|
||||
.sidebar-item{display:flex;align-items:center;gap:8px;padding:9px 24px;color:rgba(255,255,255,0.65);font-size:var(--font-sm);cursor:pointer;transition:all .15s;text-decoration:none;}
|
||||
.sidebar-item:hover{color:#fff;background:rgba(255,255,255,0.06);}
|
||||
.sidebar-item.active{color:#fff;background:var(--primary);}
|
||||
.main{margin-left:240px;margin-top:56px;padding:24px;min-height:calc(100vh - 56px);}
|
||||
.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;}
|
||||
.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);}
|
||||
.btn{height:36px;padding:0 16px;border-radius:var(--radius-sm);font-size:var(--font-sm);cursor:pointer;border:none;transition:all .2s;display:inline-flex;align-items:center;gap:6px;white-space:nowrap;}
|
||||
.btn-primary{background:var(--primary);color:#fff;}.btn-primary:hover{background:#40a9ff;}
|
||||
.btn-default{background:#fff;color:var(--text-primary);border:1px solid var(--border);}.btn-default:hover{color:var(--primary);border-color:var(--primary);}
|
||||
.btn-link{background:none;color:var(--primary);padding:0 4px;height:auto;}.btn-link:hover{color:#40a9ff;}
|
||||
.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);}
|
||||
.table-card{background:#fff;border-radius:0 0 var(--radius-md) var(--radius-md);box-shadow:var(--shadow-sm);overflow:hidden;}
|
||||
.table-card__content{overflow-x:auto;-webkit-overflow-scrolling:touch;}
|
||||
table{width:100%;border-collapse:separate;border-spacing:0;min-width:1200px;}
|
||||
thead th{background:#FAFAFA;padding:10px 14px;text-align:center;font-size:var(--font-sm);color:var(--text-secondary);font-weight:500;border-bottom:1px solid var(--border);white-space:nowrap;}
|
||||
tbody td{padding:12px 14px;text-align:center;font-size:var(--font-sm);color:var(--text-primary);border-bottom:1px solid #F0F0F0;white-space:nowrap;}
|
||||
tbody tr:last-child td{border-bottom:none;}
|
||||
tbody tr:hover{background:#F8FBFF;}
|
||||
thead tr th:last-child,tbody td:last-child{position:sticky;right:0;z-index:5;background:#fff;box-shadow:-4px 0 8px rgba(0,0,0,0.04);}
|
||||
thead tr th:last-child{z-index:8;background:#FAFAFA;}
|
||||
tbody tr:hover td:last-child{background:#F8FBFF;}
|
||||
.td-empty{text-align:center;padding:48px 0;color:var(--text-placeholder);}
|
||||
.badge{display:inline-block;padding:2px 10px;border-radius:10px;font-size:var(--font-xs);}
|
||||
.badge--success{background:#F6FFED;color:#389E0D;border:1px solid #B7EB8F;}
|
||||
.badge--muted{background:#F5F5F5;color:var(--text-secondary);border:1px solid var(--border);}
|
||||
.pagination{display:flex;align-items:center;justify-content:flex-end;padding:16px 24px;gap:8px;border-top:1px solid var(--border);}
|
||||
.pagination span{font-size:var(--font-sm);color:var(--text-secondary);}
|
||||
.page-btn{min-width:32px;height:32px;border:1px solid var(--border);border-radius:var(--radius-sm);background:#fff;cursor:pointer;font-size:var(--font-sm);display:inline-flex;align-items:center;justify-content:center;padding:0 6px;transition:all .2s;}
|
||||
.page-btn:hover,.page-btn.active{background:var(--primary);color:#fff;border-color:var(--primary);}
|
||||
/* 详情页返回 */
|
||||
.page-header{display:flex;align-items:center;gap:12px;background:#fff;padding:16px 24px;border-radius:var(--radius-md);box-shadow:var(--shadow-sm);margin-bottom:16px;}
|
||||
.page-header .back{cursor:pointer;color:var(--text-secondary);display:flex;align-items:center;gap:4px;font-size:var(--font-sm);}
|
||||
.page-header .back:hover{color:var(--primary);}
|
||||
.page-header .title{font-size:var(--font-base);font-weight:600;}
|
||||
.page-header .sub{color:var(--text-placeholder);font-size:var(--font-sm);}
|
||||
/* 弹窗/抽屉 */
|
||||
.modal-mask{display:none;position:fixed;inset:0;background:rgba(0,0,0,.45);z-index:950;align-items:center;justify-content:center;}
|
||||
.modal-mask.open{display:flex;}
|
||||
.modal{width:560px;background:#fff;border-radius:var(--radius-md);box-shadow:var(--shadow-md);}
|
||||
.modal__head{display:flex;align-items:center;justify-content:space-between;padding:16px 24px;border-bottom:1px solid var(--border);font-size:var(--font-base);font-weight:600;}
|
||||
.modal__close{cursor:pointer;color:var(--text-placeholder);font-size:20px;line-height:1;border:none;background:none;}
|
||||
.modal__close:hover{color:var(--text-primary);}
|
||||
.modal__body{padding:24px;max-height:60vh;overflow-y:auto;}
|
||||
.modal__footer{display:flex;justify-content:flex-end;gap:8px;padding:12px 24px;border-top:1px solid var(--border);}
|
||||
.form-item{display:flex;align-items:flex-start;margin-bottom:18px;}
|
||||
.form-item label{width:88px;min-width:88px;text-align:right;padding-right:12px;font-size:var(--font-sm);color:var(--text-secondary);line-height:36px;}
|
||||
.form-item label .req{color:var(--danger);margin-right:2px;}
|
||||
.form-item .control{flex:1;}
|
||||
.form-input{width:100%;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;}
|
||||
.form-input:focus{border-color:var(--primary);box-shadow:0 0 0 2px rgba(24,144,255,0.1);}
|
||||
.form-textarea{width:100%;border:1px solid var(--border);border-radius:var(--radius-sm);padding:8px 12px;font-size:var(--font-sm);color:var(--text-primary);outline:none;resize:vertical;min-height:68px;line-height:1.6;}
|
||||
.form-textarea:focus{border-color:var(--primary);box-shadow:0 0 0 2px rgba(24,144,255,0.1);}
|
||||
.drawer-mask{display:none;position:fixed;inset:0;background:rgba(0,0,0,.45);z-index:900;}
|
||||
.drawer-mask.open{display:block;}
|
||||
.drawer{position:fixed;top:0;right:-640px;bottom:0;width:600px;background:#fff;z-index:910;box-shadow:-8px 0 24px rgba(0,0,0,.12);transition:right .25s ease;display:flex;flex-direction:column;}
|
||||
.drawer.open{right:0;}
|
||||
.drawer__header{display:flex;align-items:center;justify-content:space-between;padding:16px 24px;border-bottom:1px solid var(--border);font-size:var(--font-base);font-weight:600;flex-shrink:0;}
|
||||
.drawer__close{cursor:pointer;color:var(--text-placeholder);font-size:20px;line-height:1;border:none;background:none;}
|
||||
.drawer__body{flex:1;overflow-y:auto;padding:24px;}
|
||||
.drawer__footer{display:flex;justify-content:flex-end;gap:8px;padding:12px 24px;border-top:1px solid var(--border);flex-shrink:0;}
|
||||
.toast{position:fixed;top:80px;left:50%;transform:translateX(-50%);background:#333;color:#fff;padding:10px 24px;border-radius:var(--radius-sm);font-size:var(--font-sm);z-index:9999;opacity:0;transition:opacity .2s;pointer-events:none;}
|
||||
.toast.show{opacity:1;}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="top-bar">
|
||||
<div class="top-bar__logo"><svg viewBox="0 0 28 28" fill="none"><rect width="28" height="28" rx="6" fill="#1890FF"/><path d="M14 6.5l7 3.5v4.5c0 4.2-2.9 6.8-7 7.5-4.1-.7-7-3.3-7-7.5V10l7-3.5z" stroke="#fff" stroke-width="1.8" fill="none"/><path d="M11 13.5h6M14 10.5v6" stroke="#fff" stroke-width="1.8" stroke-linecap="round"/></svg> 系统管理</div>
|
||||
<nav class="top-bar__nav">
|
||||
<a href="user-admin.html">用户管理</a>
|
||||
<a href="application.html">权限管理</a>
|
||||
<a href="hospital.html">机构管理</a>
|
||||
<a href="dict.html" class="active">系统配置</a>
|
||||
<a href="announcement.html">通知管理</a>
|
||||
</nav>
|
||||
<div class="top-bar__right">
|
||||
<a class="btn-back" href="../../index.html"><svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M10 3L5 8l5 5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg> 返回首页</a>
|
||||
<div class="avatar">管</div>
|
||||
<span style="color:rgba(255,255,255,0.65);">系统管理员 ▾</span>
|
||||
</div>
|
||||
</div>
|
||||
<aside class="sidebar">
|
||||
<div class="sidebar-menu__title">系统配置</div>
|
||||
<a href="dict.html" class="sidebar-item active">数据字典</a>
|
||||
<a href="dict-category.html" class="sidebar-item">字典分类</a>
|
||||
<a href="variable.html" class="sidebar-item">变量配置</a>
|
||||
<a href="version.html" class="sidebar-item">版本更新</a>
|
||||
</aside>
|
||||
|
||||
<main class="main">
|
||||
<!-- 字典列表视图 -->
|
||||
<div id="listView">
|
||||
<div class="filter-bar">
|
||||
<div class="filter-item"><label>字典名称</label><input class="filter-input" id="filterName" placeholder="请输入"></div>
|
||||
<div class="filter-item"><label>字典编码</label><input class="filter-input" id="filterCode" placeholder="请输入"></div>
|
||||
<div class="filter-item"><label>字典分类</label><select class="filter-select" id="filterType"><option value="">请选择</option><option>用户管理</option><option>机构管理</option><option>权限管理</option></select></div>
|
||||
<button class="btn btn-primary" onclick="searchQuery()"><svg width="14" height="14" viewBox="0 0 14 14" fill="none"><circle cx="6" cy="6" r="4.5" stroke="#fff" stroke-width="1.3"/><path d="M9.5 9.5L13 13" stroke="#fff" stroke-width="1.3" stroke-linecap="round"/></svg>查询</button>
|
||||
<button class="btn btn-default" onclick="resetQuery()">重置</button>
|
||||
</div>
|
||||
<div class="action-bar">
|
||||
<button class="btn btn-primary" onclick="openDictModal('add',null)"><svg width="14" height="14" viewBox="0 0 14 14" fill="none"><path d="M7 2v10M2 7h10" stroke="currentColor" stroke-width="1.4" stroke-linecap="round"/></svg>新增</button>
|
||||
<button class="btn btn-primary" onclick="openCategoryDrawer()"><svg width="14" height="14" viewBox="0 0 14 14" fill="none"><path d="M7 2v10M2 7h10" stroke="currentColor" stroke-width="1.4" stroke-linecap="round"/></svg>新增字典分类</button>
|
||||
</div>
|
||||
<div class="table-card">
|
||||
<div class="table-card__content">
|
||||
<table>
|
||||
<thead><tr><th style="width:70px">序号</th><th style="width:160px">字典名称</th><th style="width:220px">字典编码</th><th style="width:140px">字典分类</th><th style="width:200px">描述</th><th style="width:200px">创建时间</th><th style="width:220px">操作</th></tr></thead>
|
||||
<tbody id="dictBody"></tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="pagination"><span>共 <b id="dictTotal">0</b> 条</span><button class="page-btn" onclick="showToast('演示数据仅一页')">上一页</button><button class="page-btn active">1</button><button class="page-btn" onclick="showToast('演示数据仅一页')">下一页</button></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 字典配置详情视图 -->
|
||||
<div id="detailView" style="display:none;">
|
||||
<div class="page-header">
|
||||
<span class="back" onclick="backToList()"><svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M10 3L5 8l5 5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg>返回</span>
|
||||
<span class="title">字典列表</span>
|
||||
<span class="sub" id="detailSub"></span>
|
||||
</div>
|
||||
<div class="filter-bar">
|
||||
<div class="filter-item"><label>名称</label><input class="filter-input" id="diName" placeholder="请输入名称"></div>
|
||||
<div class="filter-item"><label>状态</label><select class="filter-select" id="diStatus"><option value="">请选择状态</option><option>启用</option><option>停用</option></select></div>
|
||||
<button class="btn btn-primary" onclick="renderDictItems()">查询</button>
|
||||
<button class="btn btn-default" onclick="resetItemSearch()">重置</button>
|
||||
</div>
|
||||
<div class="action-bar">
|
||||
<button class="btn btn-primary" onclick="openItemModal('add',null)"><svg width="14" height="14" viewBox="0 0 14 14" fill="none"><path d="M7 2v10M2 7h10" stroke="currentColor" stroke-width="1.4" stroke-linecap="round"/></svg>新增</button>
|
||||
</div>
|
||||
<div class="table-card">
|
||||
<div class="table-card__content">
|
||||
<table style="min-width:900px;">
|
||||
<thead><tr><th style="width:70px">序号</th><th>名称</th><th style="width:160px">数据值</th><th style="width:100px">状态</th><th style="width:160px">描述</th><th style="width:200px">创建时间</th><th style="width:130px">操作</th></tr></thead>
|
||||
<tbody id="dictItemBody"></tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<!-- 新增/编辑字典弹窗 -->
|
||||
<div class="modal-mask" id="dictMask">
|
||||
<div class="modal">
|
||||
<div class="modal__head"><span id="dictTitle">新增字典</span><button class="modal__close" onclick="closeModal('dictMask')">×</button></div>
|
||||
<div class="modal__body">
|
||||
<div class="form-item"><label><span class="req">*</span>字典名称</label><div class="control"><input class="form-input" id="dName" placeholder="请输入字典名称"></div></div>
|
||||
<div class="form-item"><label><span class="req">*</span>字典编码</label><div class="control"><input class="form-input" id="dCode" placeholder="请输入字典编码"></div></div>
|
||||
<div class="form-item"><label>字典分类</label><div class="control"><select class="form-input" id="dType"><option value="">请选择</option><option>用户管理</option><option>机构管理</option><option>权限管理</option></select></div></div>
|
||||
<div class="form-item"><label>描述</label><div class="control"><textarea class="form-textarea" id="dDesc" placeholder="请输入描述"></textarea></div></div>
|
||||
</div>
|
||||
<div class="modal__footer"><button class="btn btn-default" onclick="closeModal('dictMask')">取消</button><button class="btn btn-primary" onclick="submitDict()">确定</button></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 字典项弹窗 -->
|
||||
<div class="modal-mask" id="itemMask">
|
||||
<div class="modal">
|
||||
<div class="modal__head"><span id="itemTitle">新增字典项</span><button class="modal__close" onclick="closeModal('itemMask')">×</button></div>
|
||||
<div class="modal__body">
|
||||
<div class="form-item"><label><span class="req">*</span>名称</label><div class="control"><input class="form-input" id="iName" placeholder="请输入名称"></div></div>
|
||||
<div class="form-item"><label><span class="req">*</span>数据值</label><div class="control"><input class="form-input" id="iValue" placeholder="请输入数据值"></div></div>
|
||||
<div class="form-item"><label>描述</label><div class="control"><input class="form-input" id="iDesc" placeholder="请输入描述"></div></div>
|
||||
<div class="form-item"><label>排序值</label><div class="control"><input class="form-input" id="iSort" type="number" placeholder="请输入排序值"></div></div>
|
||||
<div class="form-item"><label>状态</label><div class="control"><select class="form-input" id="iStatus"><option>启用</option><option>停用</option></select></div></div>
|
||||
</div>
|
||||
<div class="modal__footer"><button class="btn btn-default" onclick="closeModal('itemMask')">取消</button><button class="btn btn-primary" onclick="submitItem()">确定</button></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 字典分类抽屉 -->
|
||||
<div class="drawer-mask" id="catMask" onclick="closeDrawer()"></div>
|
||||
<div class="drawer" id="catDrawer">
|
||||
<div class="drawer__header"><span>字典分类</span><button class="drawer__close" onclick="closeDrawer()">×</button></div>
|
||||
<div class="drawer__body">
|
||||
<button class="btn btn-primary" style="margin-bottom:16px;" onclick="openCatModal('add',null)"><svg width="14" height="14" viewBox="0 0 14 14" fill="none"><path d="M7 2v10M2 7h10" stroke="currentColor" stroke-width="1.4" stroke-linecap="round"/></svg>新增分类</button>
|
||||
<table style="min-width:0;">
|
||||
<thead><tr><th style="width:60px">序号</th><th style="width:160px">分类名称</th><th>分类描述</th><th style="width:120px">操作</th></tr></thead>
|
||||
<tbody id="catBody"></tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 字典分类增改弹窗 -->
|
||||
<div class="modal-mask" id="catModalMask">
|
||||
<div class="modal">
|
||||
<div class="modal__head"><span id="catModalTitle">新增分类</span><button class="modal__close" onclick="closeModal('catModalMask')">×</button></div>
|
||||
<div class="modal__body">
|
||||
<div class="form-item"><label><span class="req">*</span>分类名称</label><div class="control"><input class="form-input" id="cName" placeholder="请输入分类名称"></div></div>
|
||||
<div class="form-item"><label>分类描述</label><div class="control"><textarea class="form-textarea" id="cDesc" placeholder="请输入分类描述"></textarea></div></div>
|
||||
</div>
|
||||
<div class="modal__footer"><button class="btn btn-default" onclick="closeModal('catModalMask')">取消</button><button class="btn btn-primary" onclick="submitCat()">确定</button></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="toast" id="toast"></div>
|
||||
|
||||
<script>
|
||||
var dicts=[
|
||||
{id:'1',name:'性别',code:'gender',type:'用户管理',desc:'人员性别',time:'2026-08-01 10:00'},
|
||||
{id:'2',name:'用户类型',code:'user_type',type:'用户管理',desc:'平台用户类型',time:'2026-08-01 10:00'},
|
||||
{id:'3',name:'医院等级',code:'hospital_level',type:'机构管理',desc:'医院等级',time:'2026-08-02 09:30'},
|
||||
{id:'4',name:'应用类型',code:'app_type',type:'权限管理',desc:'应用归属类型',time:'2026-08-03 14:20'}
|
||||
];
|
||||
var categories=[
|
||||
{id:'1',name:'用户管理',desc:'用户相关字典'},
|
||||
{id:'2',name:'机构管理',desc:'机构相关字典'},
|
||||
{id:'3',name:'权限管理',desc:'权限相关字典'}
|
||||
];
|
||||
var dictItems=[
|
||||
{id:'1',name:'男',value:'1',status:'启用',desc:'男性',time:'2026-08-01 10:00'},
|
||||
{id:'2',name:'女',value:'2',status:'启用',desc:'女性',time:'2026-08-01 10:00'},
|
||||
{id:'3',name:'未知',value:'0',status:'停用',desc:'未知性别',time:'2026-08-01 10:00'}
|
||||
];
|
||||
var editingDictId=null, editingItemId=null, editingCatId=null;
|
||||
|
||||
function renderDicts(){
|
||||
var list=dicts;
|
||||
document.getElementById('dictTotal').textContent=list.length;
|
||||
document.getElementById('dictBody').innerHTML=list.map(function(d,i){
|
||||
return '<tr><td>'+(i+1)+'</td><td>'+d.name+'</td><td>'+d.code+'</td><td>'+d.type+'</td><td style="text-align:left;">'+d.desc+'</td><td>'+d.time+'</td>'+
|
||||
'<td><button class="btn btn-link" onclick="openDetail(\''+d.id+'\')">字典配置</button><span style="color:var(--border);margin:0 4px;">|</span><button class="btn btn-link" onclick="openDictModal(\'edit\','+d.id+')">编辑</button><span style="color:var(--border);margin:0 4px;">|</span><button class="btn btn-link" style="color:var(--danger);" onclick="delDict('+d.id+')">删除</button></td></tr>';
|
||||
}).join('');
|
||||
}
|
||||
function searchQuery(){renderDicts();showToast('查询完成');}
|
||||
function resetQuery(){document.getElementById('filterName').value='';document.getElementById('filterCode').value='';document.getElementById('filterType').value='';renderDicts();}
|
||||
function delDict(id){if(!confirm('确定删除该字典吗?'))return;dicts=dicts.filter(function(d){return d.id!==id;});renderDicts();showToast('删除成功');}
|
||||
|
||||
function openDictModal(type,id){
|
||||
editingDictId=id;
|
||||
document.getElementById('dictTitle').textContent=type==='add'?'新增字典':'编辑字典';
|
||||
document.getElementById('dName').value='';document.getElementById('dCode').value='';document.getElementById('dType').value='';document.getElementById('dDesc').value='';
|
||||
if(type==='edit'&&id){var d=dicts.find(function(x){return x.id===id;});if(d){document.getElementById('dName').value=d.name;document.getElementById('dCode').value=d.code;document.getElementById('dType').value=d.type;document.getElementById('dDesc').value=d.desc;}}
|
||||
document.getElementById('dictMask').classList.add('open');
|
||||
}
|
||||
function submitDict(){
|
||||
var name=document.getElementById('dName').value.trim();if(!name){showToast('请输入字典名称');return;}
|
||||
var code=document.getElementById('dCode').value.trim();if(!code){showToast('请输入字典编码');return;}
|
||||
var type=document.getElementById('dType').value;var desc=document.getElementById('dDesc').value.trim();
|
||||
if(editingDictId){var d=dicts.find(function(x){return x.id===editingDictId;});if(d){d.name=name;d.code=code;d.type=type;d.desc=desc;}}
|
||||
else dicts.push({id:String(dicts.length+1),name:name,code:code,type:type,desc:desc,time:'2026-09-11 10:00'});
|
||||
closeModal('dictMask');renderDicts();showToast(editingDictId?'编辑成功':'新增成功');
|
||||
}
|
||||
|
||||
/* 字典配置详情 */
|
||||
function openDetail(id){
|
||||
var d=dicts.find(function(x){return x.id===id;});
|
||||
document.getElementById('detailSub').textContent=d?d.name:'';
|
||||
document.getElementById('listView').style.display='none';
|
||||
document.getElementById('detailView').style.display='block';
|
||||
renderDictItems();
|
||||
}
|
||||
function backToList(){document.getElementById('detailView').style.display='none';document.getElementById('listView').style.display='block';}
|
||||
function renderDictItems(){
|
||||
document.getElementById('dictItemBody').innerHTML=dictItems.map(function(it,i){
|
||||
return '<tr><td>'+(i+1)+'</td><td>'+it.name+'</td><td>'+it.value+'</td><td><span class="badge '+(it.status==='启用'?'badge--success':'badge--muted')+'">'+it.status+'</span></td><td style="text-align:left;">'+it.desc+'</td><td>'+it.time+'</td>'+
|
||||
'<td><button class="btn btn-link" onclick="openItemModal(\'edit\','+it.id+')">编辑</button><span style="color:var(--border);margin:0 4px;">|</span><button class="btn btn-link" style="color:var(--danger);" onclick="delItem('+it.id+')">删除</button></td></tr>';
|
||||
}).join('');
|
||||
}
|
||||
function resetItemSearch(){document.getElementById('diName').value='';document.getElementById('diStatus').value='';renderDictItems();}
|
||||
function delItem(id){if(!confirm('确定删除该字典项吗?'))return;dictItems=dictItems.filter(function(x){return x.id!==id;});renderDictItems();showToast('删除成功');}
|
||||
function openItemModal(type,id){
|
||||
editingItemId=id;
|
||||
document.getElementById('itemTitle').textContent=type==='add'?'新增字典项':'编辑字典项';
|
||||
document.getElementById('iName').value='';document.getElementById('iValue').value='';document.getElementById('iDesc').value='';document.getElementById('iSort').value='';document.getElementById('iStatus').value='启用';
|
||||
if(type==='edit'&&id){var it=dictItems.find(function(x){return x.id===id;});if(it){document.getElementById('iName').value=it.name;document.getElementById('iValue').value=it.value;document.getElementById('iDesc').value=it.desc;document.getElementById('iStatus').value=it.status;}}
|
||||
document.getElementById('itemMask').classList.add('open');
|
||||
}
|
||||
function submitItem(){
|
||||
var name=document.getElementById('iName').value.trim();if(!name){showToast('请输入名称');return;}
|
||||
var value=document.getElementById('iValue').value.trim();if(!value){showToast('请输入数据值');return;}
|
||||
var desc=document.getElementById('iDesc').value.trim();var status=document.getElementById('iStatus').value;
|
||||
if(editingItemId){var it=dictItems.find(function(x){return x.id===editingItemId;});if(it){it.name=name;it.value=value;it.desc=desc;it.status=status;}}
|
||||
else dictItems.push({id:String(dictItems.length+1),name:name,value:value,status:status,desc:desc,time:'2026-09-11 10:00'});
|
||||
closeModal('itemMask');renderDictItems();showToast(editingItemId?'编辑成功':'新增成功');
|
||||
}
|
||||
|
||||
/* 字典分类抽屉 */
|
||||
function openCategoryDrawer(){renderCats();document.getElementById('catMask').classList.add('open');document.getElementById('catDrawer').classList.add('open');}
|
||||
function closeDrawer(){document.getElementById('catMask').classList.remove('open');document.getElementById('catDrawer').classList.remove('open');}
|
||||
function renderCats(){
|
||||
document.getElementById('catBody').innerHTML=categories.map(function(c,i){
|
||||
return '<tr><td>'+(i+1)+'</td><td>'+c.name+'</td><td style="text-align:left;">'+c.desc+'</td><td><button class="btn btn-link" onclick="openCatModal(\'edit\','+c.id+')">编辑</button><span style="color:var(--border);margin:0 4px;">|</span><button class="btn btn-link" style="color:var(--danger);" onclick="delCat('+c.id+')">删除</button></td></tr>';
|
||||
}).join('');
|
||||
}
|
||||
function delCat(id){if(!confirm('确定删除该分类吗?'))return;categories=categories.filter(function(c){return c.id!==id;});renderCats();showToast('删除成功');}
|
||||
function openCatModal(type,id){
|
||||
editingCatId=id;
|
||||
document.getElementById('catModalTitle').textContent=type==='add'?'新增分类':'编辑分类';
|
||||
document.getElementById('cName').value='';document.getElementById('cDesc').value='';
|
||||
if(type==='edit'&&id){var c=categories.find(function(x){return x.id===id;});if(c){document.getElementById('cName').value=c.name;document.getElementById('cDesc').value=c.desc;}}
|
||||
document.getElementById('catModalMask').classList.add('open');
|
||||
}
|
||||
function submitCat(){
|
||||
var name=document.getElementById('cName').value.trim();if(!name){showToast('请输入分类名称');return;}
|
||||
var desc=document.getElementById('cDesc').value.trim();
|
||||
if(editingCatId){var c=categories.find(function(x){return x.id===editingCatId;});if(c){c.name=name;c.desc=desc;}}
|
||||
else categories.push({id:String(categories.length+1),name:name,desc:desc});
|
||||
closeModal('catModalMask');renderCats();showToast(editingCatId?'编辑成功':'新增成功');
|
||||
}
|
||||
|
||||
function closeModal(id){document.getElementById(id).classList.remove('open');}
|
||||
function showToast(msg){var t=document.getElementById('toast');t.textContent=msg;t.classList.add('show');setTimeout(function(){t.classList.remove('show');},1500);}
|
||||
document.addEventListener('click',function(e){if(e.target.id==='dictMask')closeModal('dictMask');if(e.target.id==='itemMask')closeModal('itemMask');if(e.target.id==='catModalMask')closeModal('catModalMask');});
|
||||
renderDicts();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,27 @@
|
||||
# 系统管理 变更记录
|
||||
|
||||
## [2026-09-11] feat: 系统管理模块启动 · 全模块 18 页首版
|
||||
|
||||
启动 Web 管理端「系统管理」模块原型建设,按《健康长庆系统升级改造详细规划V8》系统管理域规划,交付 5 个一级分组共 18 页。模块壳层遵循管理端统一规范(顶栏 = 一级分组、侧栏 = 当前分组二级菜单、页头不放面包屑),各页采用「筛选栏 + 操作栏 + 表格 + 弹窗」通用结构,页面间通过侧栏菜单跳转。
|
||||
|
||||
**涉及文件:**
|
||||
|
||||
- `user-admin.html` — 用户管理 · 管理员账号(账号/姓名/角色/状态筛选、新增/编辑/详情、导出列表数据与导出任务)
|
||||
- `user-all.html` — 用户管理 · 全部用户(全量用户汇总视图、编辑/详情)
|
||||
- `user-consult.html` — 用户管理 · 咨询账号(新增/编辑/详情)
|
||||
- `user-emergency.html` — 用户管理 · 应急中心账号(新增/编辑/详情)
|
||||
- `user-employee.html` — 用户管理 · 员工账号(新增/编辑/详情、导出列表数据)
|
||||
- `application.html` — 权限管理 · 应用管理(编辑/删除、菜单查看)
|
||||
- `menu.html` — 权限管理 · 菜单管理(树形菜单、添加下级/编辑/删除)
|
||||
- `role.html` — 权限管理 · 角色管理(角色-用户关联、选择用户/批量移除/删除角色)
|
||||
- `hospital.html` — 机构管理 · 医院管理(编辑/删除)
|
||||
- `unit.html` — 机构管理 · 单位管理(单位-管理员关联、新增管理员/批量移除)
|
||||
- `dict.html` — 系统配置 · 数据字典(新增/编辑/删除、字典配置、新增分类)
|
||||
- `dict-category.html` — 系统配置 · 字典分类(新增分类/编辑/删除)
|
||||
- `variable.html` — 系统配置 · 变量配置(新增配置/编辑/删除/详情)
|
||||
- `version.html` — 系统配置 · 版本更新(新增版本/编辑/详情)
|
||||
- `announcement.html` — 通知管理 · 公告(新增公告/发布/删除、导出列表数据与导出任务)
|
||||
- `sms-send.html` — 通知管理 · 发送短信(新增/详情)
|
||||
- `sms-history.html` — 通知管理 · 短信发送历史(只读台账、详情)
|
||||
- `sms-template.html` — 通知管理 · 短信模板(新增/编辑/删除、发送测试、批量删除)
|
||||
- `D:\Work\platform-prototype\index.html` — 站点地图新增系统管理模块条目(入口 user-admin.html)
|
||||
@@ -0,0 +1,315 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>医院管理 | 系统管理</title>
|
||||
<style>
|
||||
*{box-sizing:border-box;margin:0;padding:0;}
|
||||
body{font-family:-apple-system,BlinkMacSystemFont,'PingFang SC','Microsoft YaHei',sans-serif;font-size:var(--font-sm);background:#F5F7FA;color:#333;min-width:1280px;}
|
||||
:root{
|
||||
--primary:#1890FF;--primary-light:#E6F7FF;--success:#52C41A;--warning:#FAAD14;--danger:#FF4D4F;
|
||||
--text-primary:#333;--text-secondary:#666;--text-placeholder:#999;--border:#E8E8E8;--background:#F5F7FA;
|
||||
--font-xs:11px;--font-sm:13px;--font-base:15px;--font-lg:17px;
|
||||
--radius-sm:4px;--radius-md:8px;--radius-lg:12px;
|
||||
--shadow-sm:0 1px 4px rgba(0,0,0,0.08);--shadow-md:0 4px 12px rgba(0,0,0,0.10);
|
||||
}
|
||||
.top-bar{display:flex;align-items:center;height:56px;background:#001529;padding:0 24px;position:fixed;top:0;left:0;right:0;z-index:100;}
|
||||
.top-bar__logo{display:flex;align-items:center;gap:8px;color:#fff;font-size:var(--font-lg);font-weight:600;white-space:nowrap;width:200px;flex-shrink:0;}
|
||||
.top-bar__logo svg{width:28px;height:28px;}
|
||||
.top-bar__nav{display:flex;align-items:center;gap:4px;flex:1;}
|
||||
.top-bar__nav a{color:rgba(255,255,255,0.65);text-decoration:none;padding:6px 14px;border-radius:var(--radius-sm);font-size:var(--font-sm);transition:all .2s;}
|
||||
.top-bar__nav a:hover{color:#fff;background:rgba(255,255,255,0.08);}
|
||||
.top-bar__nav a.active{color:#fff;background:var(--primary);}
|
||||
.top-bar__right{display:flex;align-items:center;gap:16px;color:rgba(255,255,255,0.65);font-size:var(--font-sm);}
|
||||
.btn-back{color:rgba(255,255,255,0.65);cursor:pointer;display:flex;align-items:center;gap:4px;text-decoration:none;}
|
||||
.btn-back:hover{color:#fff;}
|
||||
.avatar{width:32px;height:32px;border-radius:50%;background:#1890FF;display:flex;align-items:center;justify-content:center;color:#fff;font-size:var(--font-sm);cursor:pointer;}
|
||||
.sidebar{position:fixed;top:56px;left:0;bottom:0;width:240px;background:#001529;overflow-y:auto;z-index:90;padding-top:8px;padding-bottom:24px;}
|
||||
.sidebar-menu__title{color:rgba(255,255,255,0.35);font-size:var(--font-xs);padding:16px 24px 8px;letter-spacing:.5px;}
|
||||
.sidebar-item{display:flex;align-items:center;gap:8px;padding:9px 24px;color:rgba(255,255,255,0.65);font-size:var(--font-sm);cursor:pointer;transition:all .15s;text-decoration:none;}
|
||||
.sidebar-item:hover{color:#fff;background:rgba(255,255,255,0.06);}
|
||||
.sidebar-item.active{color:#fff;background:var(--primary);}
|
||||
.main{margin-left:240px;margin-top:56px;padding:24px;min-height:calc(100vh - 56px);}
|
||||
.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;}
|
||||
.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:180px;}
|
||||
.filter-input:focus{border-color:var(--primary);}
|
||||
.btn{height:36px;padding:0 16px;border-radius:var(--radius-sm);font-size:var(--font-sm);cursor:pointer;border:none;transition:all .2s;display:inline-flex;align-items:center;gap:6px;white-space:nowrap;}
|
||||
.btn-primary{background:var(--primary);color:#fff;}.btn-primary:hover{background:#40a9ff;}
|
||||
.btn-default{background:#fff;color:var(--text-primary);border:1px solid var(--border);}.btn-default:hover{color:var(--primary);border-color:var(--primary);}
|
||||
.btn-link{background:none;color:var(--primary);padding:0 4px;height:auto;}.btn-link:hover{color:#40a9ff;}
|
||||
.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);}
|
||||
.table-card{background:#fff;border-radius:0 0 var(--radius-md) var(--radius-md);box-shadow:var(--shadow-sm);overflow:hidden;}
|
||||
.table-card__content{overflow-x:auto;-webkit-overflow-scrolling:touch;}
|
||||
table{width:100%;border-collapse:separate;border-spacing:0;min-width:1200px;}
|
||||
thead th{background:#FAFAFA;padding:10px 14px;text-align:center;font-size:var(--font-sm);color:var(--text-secondary);font-weight:500;border-bottom:1px solid var(--border);white-space:nowrap;}
|
||||
tbody td{padding:12px 14px;text-align:center;font-size:var(--font-sm);color:var(--text-primary);border-bottom:1px solid #F0F0F0;white-space:nowrap;}
|
||||
tbody tr:last-child td{border-bottom:none;}
|
||||
tbody tr:hover{background:#F8FBFF;}
|
||||
thead tr th:last-child,tbody td:last-child{position:sticky;right:0;z-index:5;background:#fff;box-shadow:-4px 0 8px rgba(0,0,0,0.04);}
|
||||
thead tr th:last-child{z-index:8;background:#FAFAFA;}
|
||||
tbody tr:hover td:last-child{background:#F8FBFF;}
|
||||
.td-empty{text-align:center;padding:48px 0;color:var(--text-placeholder);}
|
||||
.badge{display:inline-block;padding:2px 10px;border-radius:10px;font-size:var(--font-xs);}
|
||||
.badge--info{background:#E6F7FF;color:#096DD9;border:1px solid #91D5FF;}
|
||||
.hospital-img{width:48px;height:48px;border-radius:var(--radius-sm);background:var(--primary-light);display:inline-flex;align-items:center;justify-content:center;color:var(--primary);}
|
||||
.hospital-img svg{width:26px;height:26px;}
|
||||
.pagination{display:flex;align-items:center;justify-content:flex-end;padding:16px 24px;gap:8px;border-top:1px solid var(--border);}
|
||||
.pagination span{font-size:var(--font-sm);color:var(--text-secondary);}
|
||||
.page-btn{min-width:32px;height:32px;border:1px solid var(--border);border-radius:var(--radius-sm);background:#fff;cursor:pointer;font-size:var(--font-sm);display:inline-flex;align-items:center;justify-content:center;padding:0 6px;transition:all .2s;}
|
||||
.page-btn:hover,.page-btn.active{background:var(--primary);color:#fff;border-color:var(--primary);}
|
||||
.page-btn:disabled{opacity:.4;cursor:not-allowed;}
|
||||
/* 弹窗 */
|
||||
.modal-mask{display:none;position:fixed;inset:0;background:rgba(0,0,0,.45);z-index:950;align-items:center;justify-content:center;}
|
||||
.modal-mask.open{display:flex;}
|
||||
.modal{width:920px;background:#fff;border-radius:var(--radius-md);box-shadow:var(--shadow-md);}
|
||||
.modal__head{display:flex;align-items:center;justify-content:space-between;padding:16px 24px;border-bottom:1px solid var(--border);font-size:var(--font-base);font-weight:600;}
|
||||
.modal__close{cursor:pointer;color:var(--text-placeholder);font-size:20px;line-height:1;border:none;background:none;}
|
||||
.modal__close:hover{color:var(--text-primary);}
|
||||
.modal__body{padding:24px;max-height:66vh;overflow-y:auto;}
|
||||
.modal__footer{display:flex;justify-content:flex-end;gap:8px;padding:12px 24px;border-top:1px solid var(--border);}
|
||||
.hospital-form{display:flex;gap:20px;}
|
||||
.hospital-form__left{flex:1;min-width:0;}
|
||||
.hospital-form__right{width:380px;flex-shrink:0;}
|
||||
.form-item{display:flex;align-items:flex-start;margin-bottom:18px;}
|
||||
.form-item label{width:88px;min-width:88px;text-align:right;padding-right:12px;font-size:var(--font-sm);color:var(--text-secondary);line-height:36px;}
|
||||
.form-item label .req{color:var(--danger);margin-right:2px;}
|
||||
.form-item .control{flex:1;}
|
||||
.form-input{width:100%;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;}
|
||||
.form-input:focus{border-color:var(--primary);box-shadow:0 0 0 2px rgba(24,144,255,0.1);}
|
||||
.form-input[readonly]{background:#F5F5F5;color:var(--text-secondary);}
|
||||
.form-textarea{width:100%;border:1px solid var(--border);border-radius:var(--radius-sm);padding:8px 12px;font-size:var(--font-sm);color:var(--text-primary);outline:none;resize:vertical;min-height:72px;line-height:1.6;}
|
||||
.form-textarea:focus{border-color:var(--primary);box-shadow:0 0 0 2px rgba(24,144,255,0.1);}
|
||||
.icon-upload{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);cursor:pointer;gap:4px;background:#FAFAFA;}
|
||||
.icon-upload:hover{border-color:var(--primary);color:var(--primary);}
|
||||
.icon-upload svg{width:24px;height:24px;}
|
||||
.map-wrap{position:relative;height:100%;min-height:440px;border:1px solid var(--border);border-radius:var(--radius-sm);overflow:hidden;background:#EAF2F8;}
|
||||
.map-search{position:absolute;top:12px;left:12px;z-index:5;width:260px;height:36px;border:1px solid var(--border);border-radius:var(--radius-sm);padding:0 12px;font-size:var(--font-sm);outline:none;box-shadow:var(--shadow-sm);}
|
||||
.map-placeholder{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;color:var(--text-placeholder);font-size:var(--font-sm);background:repeating-linear-gradient(45deg,#EAF2F8,#EAF2F8 20px,#E2ECF5 20px,#E2ECF5 40px);}
|
||||
.map-pin{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);color:var(--danger);}
|
||||
.map-pin svg{width:36px;height:36px;}
|
||||
.toast{position:fixed;top:80px;left:50%;transform:translateX(-50%);background:#333;color:#fff;padding:10px 24px;border-radius:var(--radius-sm);font-size:var(--font-sm);z-index:9999;opacity:0;transition:opacity .2s;pointer-events:none;}
|
||||
.toast.show{opacity:1;}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<!-- 顶部导航栏 -->
|
||||
<div class="top-bar">
|
||||
<div class="top-bar__logo"><svg viewBox="0 0 28 28" fill="none"><rect width="28" height="28" rx="6" fill="#1890FF"/><path d="M14 6.5l7 3.5v4.5c0 4.2-2.9 6.8-7 7.5-4.1-.7-7-3.3-7-7.5V10l7-3.5z" stroke="#fff" stroke-width="1.8" fill="none"/><path d="M11 13.5h6M14 10.5v6" stroke="#fff" stroke-width="1.8" stroke-linecap="round"/></svg> 系统管理</div>
|
||||
<nav class="top-bar__nav">
|
||||
<a href="user-admin.html">用户管理</a>
|
||||
<a href="application.html">权限管理</a>
|
||||
<a href="hospital.html" class="active">机构管理</a>
|
||||
<a href="dict.html">系统配置</a>
|
||||
<a href="announcement.html">通知管理</a>
|
||||
</nav>
|
||||
<div class="top-bar__right">
|
||||
<a class="btn-back" href="../../index.html"><svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M10 3L5 8l5 5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg> 返回首页</a>
|
||||
<div class="avatar">管</div>
|
||||
<span style="color:rgba(255,255,255,0.65);">系统管理员 ▾</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 侧边栏(当前一级分组「机构管理」的二级菜单) -->
|
||||
<aside class="sidebar">
|
||||
<div class="sidebar-menu__title">机构管理</div>
|
||||
<a href="hospital.html" class="sidebar-item active">医院管理</a>
|
||||
<a href="unit.html" class="sidebar-item">单位管理</a>
|
||||
</aside>
|
||||
|
||||
<!-- 主内容 -->
|
||||
<main class="main">
|
||||
<!-- [交互] 筛选栏 -->
|
||||
<div class="filter-bar">
|
||||
<div class="filter-item">
|
||||
<label>医院名称</label>
|
||||
<input class="filter-input" id="filterName" placeholder="请输入医院名称">
|
||||
</div>
|
||||
<button class="btn btn-primary" onclick="searchQuery()">
|
||||
<svg width="14" height="14" viewBox="0 0 14 14" fill="none"><circle cx="6" cy="6" r="4.5" stroke="#fff" stroke-width="1.3"/><path d="M9.5 9.5L13 13" stroke="#fff" stroke-width="1.3" stroke-linecap="round"/></svg>查询
|
||||
</button>
|
||||
<button class="btn btn-default" onclick="resetQuery()">重置</button>
|
||||
</div>
|
||||
|
||||
<!-- [交互] 操作栏 -->
|
||||
<div class="action-bar">
|
||||
<button class="btn btn-primary" onclick="openModal('add',null)">
|
||||
<svg width="14" height="14" viewBox="0 0 14 14" fill="none"><path d="M7 2v10M2 7h10" stroke="currentColor" stroke-width="1.4" stroke-linecap="round"/></svg>新增
|
||||
</button>
|
||||
<button class="btn btn-default" 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>
|
||||
<button class="btn btn-default" onclick="showToast('查看导出任务')">
|
||||
<svg width="14" height="14" viewBox="0 0 14 14" fill="none"><rect x="2" y="2" width="10" height="10" rx="1.5" stroke="currentColor" stroke-width="1.4"/><path d="M4 5h6M4 7.5h4" stroke="currentColor" stroke-width="1.2" stroke-linecap="round"/></svg>查看导出任务
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- 表格 -->
|
||||
<div class="table-card">
|
||||
<div class="table-card__content">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width:70px">序号</th>
|
||||
<th style="width:220px">医院名称</th>
|
||||
<th style="width:120px">医院图片</th>
|
||||
<th style="width:130px">医院等级</th>
|
||||
<th style="width:150px">联系电话</th>
|
||||
<th style="width:260px">医院地址</th>
|
||||
<th style="width:260px">医院简介</th>
|
||||
<th style="width:130px">操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="tableBody"></tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="pagination">
|
||||
<span>共 <b id="totalCount">0</b> 条</span>
|
||||
<button class="page-btn" onclick="showToast('演示数据仅一页')">上一页</button>
|
||||
<button class="page-btn active">1</button>
|
||||
<button class="page-btn" onclick="showToast('演示数据仅一页')">下一页</button>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<!-- [交互] 新增/编辑医院弹窗 -->
|
||||
<div class="modal-mask" id="hospitalMask">
|
||||
<div class="modal">
|
||||
<div class="modal__head"><span id="hospitalTitle">新增医院</span><button class="modal__close" onclick="closeModal()">×</button></div>
|
||||
<div class="modal__body">
|
||||
<div class="hospital-form">
|
||||
<div class="hospital-form__left">
|
||||
<div class="form-item">
|
||||
<label><span class="req">*</span>医院名称</label>
|
||||
<div class="control"><input class="form-input" id="fName" maxlength="30" placeholder="请输入医院名称"></div>
|
||||
</div>
|
||||
<div class="form-item">
|
||||
<label>医院等级</label>
|
||||
<div class="control"><select class="form-input" id="fLevel"><option value="">请选择</option><option>三级甲等</option><option>三级乙等</option><option>二级甲等</option><option>二级乙等</option><option>一级甲等</option></select></div>
|
||||
</div>
|
||||
<div class="form-item">
|
||||
<label>医院图片</label>
|
||||
<div class="control"><div class="icon-upload" onclick="showToast('上传医院图片')"><svg viewBox="0 0 24 24" fill="none"><path d="M12 16V4M8 8l4-4 4 4" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"/><path d="M4 16v3a1 1 0 001 1h14a1 1 0 001-1v-3" stroke="currentColor" stroke-width="1.6" stroke-linecap="round"/></svg><span style="font-size:var(--font-xs)">上传</span></div></div>
|
||||
</div>
|
||||
<div class="form-item">
|
||||
<label>联系电话</label>
|
||||
<div class="control"><input class="form-input" id="fMobile" placeholder="请输入联系电话"></div>
|
||||
</div>
|
||||
<div class="form-item">
|
||||
<label>医院地址</label>
|
||||
<div class="control"><input class="form-input" id="fAddress" readonly placeholder="地图选点自动填充"></div>
|
||||
</div>
|
||||
<div class="form-item">
|
||||
<label>地址详细信息</label>
|
||||
<div class="control"><textarea class="form-textarea" id="fDetail" maxlength="200" placeholder="输入地址详细信息"></textarea></div>
|
||||
</div>
|
||||
<div class="form-item">
|
||||
<label>医院简介</label>
|
||||
<div class="control"><textarea class="form-textarea" id="fIntro" maxlength="500" placeholder="请输入医院简介"></textarea></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="hospital-form__right">
|
||||
<div class="map-wrap">
|
||||
<input class="map-search" placeholder="输入地址或名称进行搜索">
|
||||
<div class="map-placeholder">地图选点区域</div>
|
||||
<div class="map-pin"><svg viewBox="0 0 24 24" fill="none"><path d="M12 21s-7-5.5-7-11a7 7 0 0114 0c0 5.5-7 11-7 11z" fill="#FF4D4F"/><circle cx="12" cy="10" r="3" fill="#fff"/></svg></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal__footer">
|
||||
<button class="btn btn-default" onclick="closeModal()">返回</button>
|
||||
<button class="btn btn-primary" onclick="submitForm()">确定</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="toast" id="toast"></div>
|
||||
|
||||
<script>
|
||||
var hospitals=[
|
||||
{id:'1',name:'CQ能源职工医院',level:'三级甲等',mobile:'029-86580000',address:'陕西省西安市未央区凤城三路',intro:'三级甲等综合医院,承担CQ能源职工及家属的医疗保健任务。',detail:'凤城三路与文景路交叉口东南角'},
|
||||
{id:'2',name:'西安市中心医院',level:'三级甲等',mobile:'029-87218916',address:'陕西省西安市新城区西五路161号',intro:'集医疗、教学、科研为一体的三级甲等综合医院。',detail:'西五路161号'},
|
||||
{id:'3',name:'延安大学附属医院',level:'三级甲等',mobile:'0911-2881000',address:'陕西省延安市宝塔区北大街43号',intro:'陕北地区最大的三级甲等综合医院。',detail:'北大街43号'},
|
||||
{id:'4',name:'庆阳市人民医院',level:'三级乙等',mobile:'0934-8213114',address:'甘肃省庆阳市西峰区南大街608号',intro:'陇东地区三级乙等综合医院,服务油田一线员工。',detail:'南大街608号'},
|
||||
{id:'5',name:'靖边县人民医院',level:'二级甲等',mobile:'0912-4621070',address:'陕西省榆林市靖边县统万路',intro:'二级甲等综合医院,靖边气田就近协作医院。',detail:'统万路与长庆路交叉口'}
|
||||
];
|
||||
var editingId=null;
|
||||
|
||||
function renderTable(){
|
||||
var kw=document.getElementById('filterName').value.trim();
|
||||
var list=hospitals.filter(function(h){return !kw||h.name.indexOf(kw)>=0;});
|
||||
document.getElementById('totalCount').textContent=list.length;
|
||||
document.getElementById('tableBody').innerHTML=list.length===0
|
||||
?'<tr><td colspan="8" class="td-empty">暂无数据</td></tr>'
|
||||
:list.map(function(h,i){
|
||||
return '<tr>'+
|
||||
'<td>'+(i+1)+'</td>'+
|
||||
'<td style="text-align:left;">'+h.name+'</td>'+
|
||||
'<td><span class="hospital-img"><svg viewBox="0 0 24 24" fill="none"><path d="M4 21V5a1 1 0 011-1h6v4h2V4h6a1 1 0 011 1v16" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/><path d="M8 21v-4M16 21v-4M12 21v-4M4 12h16" stroke="currentColor" stroke-width="1.5"/></svg></span></td>'+
|
||||
'<td><span class="badge badge--info">'+h.level+'</span></td>'+
|
||||
'<td>'+h.mobile+'</td>'+
|
||||
'<td style="text-align:left;">'+h.address+'</td>'+
|
||||
'<td style="text-align:left;">'+h.intro+'</td>'+
|
||||
'<td><button class="btn btn-link" onclick="openModal(\'edit\','+h.id+')">编辑</button><span style="color:var(--border);margin:0 4px;">|</span><button class="btn btn-link" style="color:var(--danger);" onclick="delHospital('+h.id+')">删除</button></td>'+
|
||||
'</tr>';
|
||||
}).join('');
|
||||
}
|
||||
function searchQuery(){renderTable();showToast('查询完成');}
|
||||
function resetQuery(){document.getElementById('filterName').value='';renderTable();}
|
||||
function delHospital(id){
|
||||
if(!confirm('确定删除该医院吗?'))return;
|
||||
hospitals=hospitals.filter(function(h){return h.id!==id;});
|
||||
renderTable();showToast('删除成功');
|
||||
}
|
||||
function openModal(type,id){
|
||||
editingId=id;
|
||||
document.getElementById('hospitalTitle').textContent=type==='add'?'新增医院':'编辑医院';
|
||||
document.getElementById('fName').value='';
|
||||
document.getElementById('fLevel').value='';
|
||||
document.getElementById('fMobile').value='';
|
||||
document.getElementById('fAddress').value='';
|
||||
document.getElementById('fDetail').value='';
|
||||
document.getElementById('fIntro').value='';
|
||||
if(type==='edit'&&id){
|
||||
var h=hospitals.find(function(x){return x.id===id;});
|
||||
if(h){
|
||||
document.getElementById('fName').value=h.name;
|
||||
document.getElementById('fLevel').value=h.level;
|
||||
document.getElementById('fMobile').value=h.mobile;
|
||||
document.getElementById('fAddress').value=h.address;
|
||||
document.getElementById('fDetail').value=h.detail;
|
||||
document.getElementById('fIntro').value=h.intro;
|
||||
}
|
||||
}
|
||||
document.getElementById('hospitalMask').classList.add('open');
|
||||
}
|
||||
function closeModal(){document.getElementById('hospitalMask').classList.remove('open');}
|
||||
function submitForm(){
|
||||
var name=document.getElementById('fName').value.trim();
|
||||
if(!name){showToast('请输入医院名称');return;}
|
||||
var level=document.getElementById('fLevel').value;
|
||||
var mobile=document.getElementById('fMobile').value.trim();
|
||||
var address=document.getElementById('fAddress').value.trim();
|
||||
var detail=document.getElementById('fDetail').value.trim();
|
||||
var intro=document.getElementById('fIntro').value.trim();
|
||||
if(editingId){
|
||||
var h=hospitals.find(function(x){return x.id===editingId;});
|
||||
if(h){h.name=name;h.level=level;h.mobile=mobile;h.address=address;h.detail=detail;h.intro=intro;}
|
||||
}else{
|
||||
hospitals.push({id:String(hospitals.length+1),name:name,level:level,mobile:mobile,address:address,detail:detail,intro:intro});
|
||||
}
|
||||
closeModal();renderTable();showToast(editingId?'编辑成功':'新增成功');
|
||||
}
|
||||
function showToast(msg){
|
||||
var t=document.getElementById('toast');t.textContent=msg;t.classList.add('show');
|
||||
setTimeout(function(){t.classList.remove('show');},1500);
|
||||
}
|
||||
document.addEventListener('click',function(e){if(e.target===document.getElementById('hospitalMask'))closeModal();});
|
||||
renderTable();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,421 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>菜单管理 | 系统管理</title>
|
||||
<style>
|
||||
*{box-sizing:border-box;margin:0;padding:0;}
|
||||
body{font-family:-apple-system,BlinkMacSystemFont,'PingFang SC','Microsoft YaHei',sans-serif;font-size:var(--font-sm);background:#F5F7FA;color:#333;min-width:1280px;}
|
||||
:root{
|
||||
--primary:#1890FF;--primary-light:#E6F7FF;--success:#52C41A;--warning:#FAAD14;--danger:#FF4D4F;
|
||||
--text-primary:#333;--text-secondary:#666;--text-placeholder:#999;--border:#E8E8E8;--background:#F5F7FA;
|
||||
--font-xs:11px;--font-sm:13px;--font-base:15px;--font-lg:17px;
|
||||
--radius-sm:4px;--radius-md:8px;--radius-lg:12px;
|
||||
--shadow-sm:0 1px 4px rgba(0,0,0,0.08);--shadow-md:0 4px 12px rgba(0,0,0,0.10);
|
||||
}
|
||||
.top-bar{display:flex;align-items:center;height:56px;background:#001529;padding:0 24px;position:fixed;top:0;left:0;right:0;z-index:100;}
|
||||
.top-bar__logo{display:flex;align-items:center;gap:8px;color:#fff;font-size:var(--font-lg);font-weight:600;white-space:nowrap;width:200px;flex-shrink:0;}
|
||||
.top-bar__logo svg{width:28px;height:28px;}
|
||||
.top-bar__nav{display:flex;align-items:center;gap:4px;flex:1;}
|
||||
.top-bar__nav a{color:rgba(255,255,255,0.65);text-decoration:none;padding:6px 14px;border-radius:var(--radius-sm);font-size:var(--font-sm);transition:all .2s;}
|
||||
.top-bar__nav a:hover{color:#fff;background:rgba(255,255,255,0.08);}
|
||||
.top-bar__nav a.active{color:#fff;background:var(--primary);}
|
||||
.top-bar__right{display:flex;align-items:center;gap:16px;color:rgba(255,255,255,0.65);font-size:var(--font-sm);}
|
||||
.btn-back{color:rgba(255,255,255,0.65);cursor:pointer;display:flex;align-items:center;gap:4px;text-decoration:none;}
|
||||
.btn-back:hover{color:#fff;}
|
||||
.avatar{width:32px;height:32px;border-radius:50%;background:#1890FF;display:flex;align-items:center;justify-content:center;color:#fff;font-size:var(--font-sm);cursor:pointer;}
|
||||
.sidebar{position:fixed;top:56px;left:0;bottom:0;width:240px;background:#001529;overflow-y:auto;z-index:90;padding-top:8px;padding-bottom:24px;}
|
||||
.sidebar-menu__title{color:rgba(255,255,255,0.35);font-size:var(--font-xs);padding:16px 24px 8px;letter-spacing:.5px;}
|
||||
.sidebar-item{display:flex;align-items:center;gap:8px;padding:9px 24px;color:rgba(255,255,255,0.65);font-size:var(--font-sm);cursor:pointer;transition:all .15s;text-decoration:none;}
|
||||
.sidebar-item:hover{color:#fff;background:rgba(255,255,255,0.06);}
|
||||
.sidebar-item.active{color:#fff;background:var(--primary);}
|
||||
.main{margin-left:240px;margin-top:56px;padding:24px;min-height:calc(100vh - 56px);}
|
||||
.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;}
|
||||
.filter-select{height:36px;min-width:180px;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:160px;}
|
||||
.filter-input:focus{border-color:var(--primary);}
|
||||
.btn{height:36px;padding:0 16px;border-radius:var(--radius-sm);font-size:var(--font-sm);cursor:pointer;border:none;transition:all .2s;display:inline-flex;align-items:center;gap:6px;white-space:nowrap;}
|
||||
.btn-primary{background:var(--primary);color:#fff;}.btn-primary:hover{background:#40a9ff;}
|
||||
.btn-default{background:#fff;color:var(--text-primary);border:1px solid var(--border);}.btn-default:hover{color:var(--primary);border-color:var(--primary);}
|
||||
.btn-link{background:none;color:var(--primary);padding:0 4px;height:auto;}.btn-link:hover{color:#40a9ff;}
|
||||
.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);}
|
||||
.table-card{background:#fff;border-radius:0 0 var(--radius-md) var(--radius-md);box-shadow:var(--shadow-sm);overflow:hidden;}
|
||||
.table-card__content{overflow-x:auto;-webkit-overflow-scrolling:touch;}
|
||||
table{width:100%;border-collapse:separate;border-spacing:0;min-width:1500px;}
|
||||
thead th{background:#FAFAFA;padding:10px 14px;text-align:center;font-size:var(--font-sm);color:var(--text-secondary);font-weight:500;border-bottom:1px solid var(--border);white-space:nowrap;}
|
||||
tbody td{padding:12px 14px;text-align:center;font-size:var(--font-sm);color:var(--text-primary);border-bottom:1px solid #F0F0F0;white-space:nowrap;}
|
||||
tbody tr:last-child td{border-bottom:none;}
|
||||
tbody tr:hover{background:#F8FBFF;}
|
||||
thead tr th:last-child,tbody td:last-child{position:sticky;right:0;z-index:5;background:#fff;box-shadow:-4px 0 8px rgba(0,0,0,0.04);}
|
||||
thead tr th:last-child{z-index:8;background:#FAFAFA;}
|
||||
tbody tr:hover td:last-child{background:#F8FBFF;}
|
||||
.td-empty{text-align:center;padding:48px 0;color:var(--text-placeholder);}
|
||||
.badge{display:inline-block;padding:2px 10px;border-radius:10px;font-size:var(--font-xs);}
|
||||
.badge--info{background:#E6F7FF;color:#096DD9;border:1px solid #91D5FF;}
|
||||
.badge--muted{background:#F5F5F5;color:var(--text-secondary);border:1px solid var(--border);}
|
||||
.tree-arrow{display:inline-block;width:18px;cursor:pointer;color:var(--text-placeholder);font-size:var(--font-xs);user-select:none;}
|
||||
.tree-arrow:hover{color:var(--primary);}
|
||||
.switch{position:relative;display:inline-block;width:44px;height:22px;cursor:pointer;vertical-align:middle;}
|
||||
.switch input{display:none;}
|
||||
.switch .track{position:absolute;inset:0;border-radius:11px;background:rgba(0,0,0,0.25);transition:all .2s;}
|
||||
.switch .thumb{position:absolute;top:2px;left:2px;width:18px;height:18px;border-radius:50%;background:#fff;transition:all .2s;box-shadow:0 1px 3px rgba(0,0,0,0.2);}
|
||||
.switch.on .track{background:var(--primary);}
|
||||
.switch.on .thumb{left:24px;}
|
||||
.modal-mask{display:none;position:fixed;inset:0;background:rgba(0,0,0,.45);z-index:950;align-items:center;justify-content:center;}
|
||||
.modal-mask.open{display:flex;}
|
||||
.modal{width:600px;background:#fff;border-radius:var(--radius-md);box-shadow:var(--shadow-md);}
|
||||
.modal__head{display:flex;align-items:center;justify-content:space-between;padding:16px 24px;border-bottom:1px solid var(--border);font-size:var(--font-base);font-weight:600;}
|
||||
.modal__close{cursor:pointer;color:var(--text-placeholder);font-size:20px;line-height:1;border:none;background:none;}
|
||||
.modal__close:hover{color:var(--text-primary);}
|
||||
.modal__body{padding:24px;max-height:62vh;overflow-y:auto;}
|
||||
.modal__footer{display:flex;justify-content:flex-end;gap:8px;padding:12px 24px;border-top:1px solid var(--border);}
|
||||
.form-item{display:flex;align-items:flex-start;margin-bottom:18px;}
|
||||
.form-item:last-child{margin-bottom:0;}
|
||||
.form-item label{width:90px;min-width:90px;text-align:right;padding-right:12px;font-size:var(--font-sm);color:var(--text-secondary);line-height:36px;}
|
||||
.form-item label .req{color:var(--danger);margin-right:2px;}
|
||||
.form-item .control{flex:1;}
|
||||
.form-input{width:100%;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;}
|
||||
.form-input:focus{border-color:var(--primary);box-shadow:0 0 0 2px rgba(24,144,255,0.1);}
|
||||
.form-textarea{width:100%;border:1px solid var(--border);border-radius:var(--radius-sm);padding:8px 12px;font-size:var(--font-sm);color:var(--text-primary);outline:none;resize:vertical;min-height:72px;line-height:1.6;}
|
||||
.form-textarea:focus{border-color:var(--primary);box-shadow:0 0 0 2px rgba(24,144,255,0.1);}
|
||||
.toast{position:fixed;top:80px;left:50%;transform:translateX(-50%);background:#333;color:#fff;padding:10px 24px;border-radius:var(--radius-sm);font-size:var(--font-sm);z-index:9999;opacity:0;transition:opacity .2s;pointer-events:none;}
|
||||
.toast.show{opacity:1;}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<!-- 顶部导航栏 -->
|
||||
<div class="top-bar">
|
||||
<div class="top-bar__logo"><svg viewBox="0 0 28 28" fill="none"><rect width="28" height="28" rx="6" fill="#1890FF"/><path d="M14 6.5l7 3.5v4.5c0 4.2-2.9 6.8-7 7.5-4.1-.7-7-3.3-7-7.5V10l7-3.5z" stroke="#fff" stroke-width="1.8" fill="none"/><path d="M11 13.5h6M14 10.5v6" stroke="#fff" stroke-width="1.8" stroke-linecap="round"/></svg> 系统管理</div>
|
||||
<nav class="top-bar__nav">
|
||||
<a href="user-admin.html">用户管理</a>
|
||||
<a href="application.html" class="active">权限管理</a>
|
||||
<a href="hospital.html">机构管理</a>
|
||||
<a href="dict.html">系统配置</a>
|
||||
<a href="announcement.html">通知管理</a>
|
||||
</nav>
|
||||
<div class="top-bar__right">
|
||||
<a class="btn-back" href="../../index.html"><svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M10 3L5 8l5 5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg> 返回首页</a>
|
||||
<div class="avatar">管</div>
|
||||
<span style="color:rgba(255,255,255,0.65);">系统管理员 ▾</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 侧边栏(当前一级分组「权限管理」的二级菜单) -->
|
||||
<aside class="sidebar">
|
||||
<div class="sidebar-menu__title">权限管理</div>
|
||||
<a href="application.html" class="sidebar-item">应用管理</a>
|
||||
<a href="menu.html" class="sidebar-item active">菜单管理</a>
|
||||
<a href="role.html" class="sidebar-item">角色管理</a>
|
||||
</aside>
|
||||
|
||||
<!-- 主内容 -->
|
||||
<main class="main">
|
||||
<!-- [交互] 筛选栏 -->
|
||||
<div class="filter-bar">
|
||||
<div class="filter-item">
|
||||
<label>应用名称</label>
|
||||
<select class="filter-select" id="filterApp" onchange="renderMenu()">
|
||||
<option value="">请选择应用名称</option>
|
||||
<option>员工健康APP</option>
|
||||
<option>应急救治APP</option>
|
||||
<option>健康数据中心</option>
|
||||
<option selected>系统管理</option>
|
||||
<option>一线医疗</option>
|
||||
</select>
|
||||
</div>
|
||||
<button class="btn btn-primary" onclick="searchQuery()">
|
||||
<svg width="14" height="14" viewBox="0 0 14 14" fill="none"><circle cx="6" cy="6" r="4.5" stroke="#fff" stroke-width="1.3"/><path d="M9.5 9.5L13 13" stroke="#fff" stroke-width="1.3" stroke-linecap="round"/></svg>查询
|
||||
</button>
|
||||
<button class="btn btn-default" onclick="resetQuery()">重置</button>
|
||||
</div>
|
||||
|
||||
<!-- [交互] 操作栏 -->
|
||||
<div class="action-bar">
|
||||
<button class="btn btn-primary" onclick="openModal('add',null,null)">
|
||||
<svg width="14" height="14" viewBox="0 0 14 14" fill="none"><path d="M7 2v10M2 7h10" stroke="currentColor" stroke-width="1.4" stroke-linecap="round"/></svg>新增菜单
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- 表格 -->
|
||||
<div class="table-card">
|
||||
<div class="table-card__content">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width:70px">序号</th>
|
||||
<th style="width:90px">类型</th>
|
||||
<th style="width:90px">图标</th>
|
||||
<th style="width:220px">名称</th>
|
||||
<th style="width:260px">文件地址</th>
|
||||
<th style="width:260px">跳转地址</th>
|
||||
<th style="width:200px">描述</th>
|
||||
<th style="width:100px">状态</th>
|
||||
<th style="width:180px">创建时间</th>
|
||||
<th style="width:220px">操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="tableBody"></tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<!-- [交互] 新增/编辑菜单弹窗 -->
|
||||
<div class="modal-mask" id="menuMask">
|
||||
<div class="modal">
|
||||
<div class="modal__head"><span id="menuTitle">新增菜单</span><button class="modal__close" onclick="closeModal()">×</button></div>
|
||||
<div class="modal__body">
|
||||
<div class="form-item">
|
||||
<label>父级菜单</label>
|
||||
<div class="control"><select class="form-input" id="fParent"><option value="">请选择父级菜单(不选则为顶级)</option></select></div>
|
||||
</div>
|
||||
<div class="form-item">
|
||||
<label><span class="req">*</span>元素类型</label>
|
||||
<div class="control"><select class="form-input" id="fElementType" onchange="onElementTypeChange()"><option value="0">菜单</option><option value="1">按钮</option></select></div>
|
||||
</div>
|
||||
<!-- 菜单类型字段组 -->
|
||||
<div id="menuFields">
|
||||
<div class="form-item">
|
||||
<label><span class="req">*</span>菜单名称</label>
|
||||
<div class="control"><input class="form-input" id="fName" maxlength="30" placeholder="请输入菜单名称"></div>
|
||||
</div>
|
||||
<div class="form-item">
|
||||
<label>菜单图标</label>
|
||||
<div class="control"><input class="form-input" id="fIcon" maxlength="30" placeholder="请输入菜单图标名称"></div>
|
||||
</div>
|
||||
<div class="form-item">
|
||||
<label>文件地址</label>
|
||||
<div class="control"><input class="form-input" id="fComponent" placeholder="请输入文件的存放地址"></div>
|
||||
</div>
|
||||
<div class="form-item">
|
||||
<label>跳转地址</label>
|
||||
<div class="control"><input class="form-input" id="fRoutePath" placeholder="请输入浏览器的跳转地址"></div>
|
||||
</div>
|
||||
<div class="form-item">
|
||||
<label>元素排序</label>
|
||||
<div class="control"><input class="form-input" id="fSort" type="number" min="1" placeholder="请输入元素排序"></div>
|
||||
</div>
|
||||
<div class="form-item">
|
||||
<label>元素描述</label>
|
||||
<div class="control"><textarea class="form-textarea" id="fDesc" maxlength="200" placeholder="请输入元素描述"></textarea></div>
|
||||
</div>
|
||||
<div class="form-item">
|
||||
<label>菜单状态</label>
|
||||
<div class="control"><div style="display:flex;align-items:center;height:36px;gap:8px;"><label class="switch on" id="fStatusSwitch" onclick="toggleStatus()"><input type="checkbox" checked><span class="track"></span><span class="thumb"></span></label><span id="fStatusText" style="color:var(--text-secondary);">启用</span></div></div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 按钮类型字段组 -->
|
||||
<div id="btnFields" style="display:none;">
|
||||
<div class="form-item">
|
||||
<label><span class="req">*</span>按钮名称</label>
|
||||
<div class="control"><input class="form-input" id="fBtnName" maxlength="30" placeholder="请输入按钮名称"></div>
|
||||
</div>
|
||||
<div class="form-item">
|
||||
<label>权限编码</label>
|
||||
<div class="control"><input class="form-input" id="fPerms" maxlength="200" placeholder="请输入权限编码"></div>
|
||||
</div>
|
||||
<div class="form-item">
|
||||
<label>描述</label>
|
||||
<div class="control"><textarea class="form-textarea" id="fBtnDesc" maxlength="200" placeholder="请输入描述"></textarea></div>
|
||||
</div>
|
||||
<div class="form-item">
|
||||
<label>按钮状态</label>
|
||||
<div class="control"><div style="display:flex;align-items:center;height:36px;gap:8px;"><label class="switch on" id="fBtnStatusSwitch" onclick="toggleBtnStatus()"><input type="checkbox" checked><span class="track"></span><span class="thumb"></span></label><span id="fBtnStatusText" style="color:var(--text-secondary);">启用</span></div></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal__footer">
|
||||
<button class="btn btn-default" onclick="closeModal()">取消</button>
|
||||
<button class="btn btn-primary" onclick="submitForm()">确定</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="toast" id="toast"></div>
|
||||
|
||||
<script>
|
||||
/* ===== 菜单树演示数据 ===== */
|
||||
var menuTree=[
|
||||
{id:'1',type:0,name:'用户管理',icon:'user',component:'views/system/userManagementModule/index',routePath:'/userManagementModule',desc:'用户账号管理',hidden:0,time:'2026-08-01 10:00',children:[
|
||||
{id:'11',type:0,name:'管理员账号',icon:'',component:'views/system/userManagementModule/administratorAccount/index',routePath:'/userManagementModule/administratorAccount',desc:'',hidden:0,time:'2026-08-01 10:00'},
|
||||
{id:'12',type:0,name:'全部用户',icon:'',component:'views/system/userManagementModule/allUsers/index',routePath:'/userManagementModule/allUsers',desc:'',hidden:0,time:'2026-08-01 10:00'},
|
||||
{id:'13',type:0,name:'食堂账号',icon:'',component:'views/system/userManagementModule/canteenAccount/index',routePath:'/userManagementModule/canteenAccount',desc:'',hidden:0,time:'2026-08-01 10:00'},
|
||||
{id:'14',type:0,name:'员工账号',icon:'',component:'views/system/userManagementModule/employeeAccount/index',routePath:'/userManagementModule/employeeAccount',desc:'',hidden:0,time:'2026-08-01 10:00'}
|
||||
]},
|
||||
{id:'2',type:0,name:'权限管理',icon:'lock',component:'views/system/permissionManagementModule/index',routePath:'/permissionManagementModule',desc:'权限与角色管理',hidden:0,time:'2026-08-01 10:00',children:[
|
||||
{id:'21',type:0,name:'应用管理',icon:'',component:'views/system/permissionManagementModule/applicationManagement/index',routePath:'/permissionManagementModule/applicationManagement',desc:'',hidden:0,time:'2026-08-01 10:00',children:[
|
||||
{id:'211',type:1,name:'新增应用',icon:'',component:'',routePath:'',desc:'新增应用按钮',hidden:0,time:'2026-08-01 10:00'},
|
||||
{id:'212',type:1,name:'编辑应用',icon:'',component:'',routePath:'',desc:'编辑应用按钮',hidden:0,time:'2026-08-01 10:00'}
|
||||
]},
|
||||
{id:'22',type:0,name:'菜单管理',icon:'',component:'views/system/permissionManagementModule/menuManagement/index',routePath:'/permissionManagementModule/menuManagement',desc:'',hidden:0,time:'2026-08-01 10:00'},
|
||||
{id:'23',type:0,name:'角色管理',icon:'',component:'views/system/permissionManagementModule/roleManagement/index',routePath:'/permissionManagementModule/roleManagement',desc:'',hidden:0,time:'2026-08-01 10:00'}
|
||||
]},
|
||||
{id:'3',type:0,name:'机构管理',icon:'apartment',component:'views/system/institutionalManagementModule/index',routePath:'/institutionalManagementModule',desc:'机构与单位管理',hidden:0,time:'2026-08-01 10:00'},
|
||||
{id:'4',type:0,name:'系统配置',icon:'setting',component:'views/system/systemConfigurationModule/index',routePath:'/systemConfigurationModule',desc:'系统参数与字典配置',hidden:0,time:'2026-08-01 10:00'},
|
||||
{id:'5',type:0,name:'通知管理',icon:'bell',component:'views/system/notificationManagementModule/index',routePath:'/notificationManagementModule',desc:'公告与短信通知',hidden:1,time:'2026-08-01 10:00'}
|
||||
];
|
||||
var collapsed={};
|
||||
var editingId=null;
|
||||
|
||||
function toggleCollapse(id){collapsed[id]=!collapsed[id];renderMenu();}
|
||||
|
||||
function renderMenu(){
|
||||
var body=document.getElementById('tableBody');
|
||||
var seq=0;
|
||||
var html='';
|
||||
function walk(nodes,level){
|
||||
nodes.forEach(function(n){
|
||||
seq++;
|
||||
var hasChildren=n.children&&n.children.length>0;
|
||||
var isCollapsed=collapsed[n.id];
|
||||
var indent=level*22;
|
||||
var arrow=hasChildren
|
||||
?'<span class="tree-arrow" onclick="toggleCollapse(\''+n.id+'\')">'+(isCollapsed?'▸':'▾')+'</span>'
|
||||
:'<span class="tree-arrow" style="visibility:hidden;">▸</span>';
|
||||
var iconHtml=n.icon?'<svg width="16" height="16" viewBox="0 0 16 16" fill="none"><rect x="1.5" y="1.5" width="13" height="13" rx="3" stroke="#1890FF" stroke-width="1.3"/><circle cx="8" cy="8" r="2.5" stroke="#1890FF" stroke-width="1.3"/></svg>':'';
|
||||
var typeHtml=n.type===0?'<span class="badge badge--info">菜单</span>':'<span class="badge badge--muted">按钮</span>';
|
||||
var statusHtml=n.hidden===0
|
||||
?'<label class="switch on" onclick="toggleHidden(\''+n.id+'\')"><input type="checkbox" checked><span class="track"></span><span class="thumb"></span></label>'
|
||||
:'<label class="switch" onclick="toggleHidden(\''+n.id+'\')"><input type="checkbox"><span class="track"></span><span class="thumb"></span></label>';
|
||||
var addSub=n.type===0?'<button class="btn btn-link" onclick="openModal(\'addSub\',\''+n.id+'\',null)">添加下级</button><span style="color:var(--border);margin:0 4px;">|</span>':'';
|
||||
html+='<tr>'+
|
||||
'<td>'+seq+'</td>'+
|
||||
'<td>'+typeHtml+'</td>'+
|
||||
'<td>'+iconHtml+'</td>'+
|
||||
'<td style="text-align:left;"><span style="padding-left:'+indent+'px;display:inline-block;">'+arrow+n.name+'</span></td>'+
|
||||
'<td style="text-align:left;">'+n.component+'</td>'+
|
||||
'<td style="text-align:left;">'+n.routePath+'</td>'+
|
||||
'<td style="text-align:left;">'+n.desc+'</td>'+
|
||||
'<td>'+statusHtml+'</td>'+
|
||||
'<td>'+n.time+'</td>'+
|
||||
'<td>'+
|
||||
'<button class="btn btn-link" onclick="openModal(\'edit\',null,\''+n.id+'\')">编辑</button>'+
|
||||
'<span style="color:var(--border);margin:0 4px;">|</span>'+
|
||||
addSub+
|
||||
'<button class="btn btn-link" style="color:var(--danger);" onclick="delMenu(\''+n.id+'\')">删除</button>'+
|
||||
'</td>'+
|
||||
'</tr>';
|
||||
if(hasChildren&&!isCollapsed){walk(n.children,level+1);}
|
||||
});
|
||||
}
|
||||
walk(menuTree,0);
|
||||
body.innerHTML=html||'<tr><td colspan="10" class="td-empty">暂无数据</td></tr>';
|
||||
}
|
||||
function findNode(nodes,id){
|
||||
for(var i=0;i<nodes.length;i++){
|
||||
if(nodes[i].id===id)return nodes[i];
|
||||
if(nodes[i].children){var r=findNode(nodes[i].children,id);if(r)return r;}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
function toggleHidden(id){
|
||||
var n=findNode(menuTree,id);
|
||||
if(n){n.hidden=n.hidden===0?1:0;renderMenu();showToast(n.hidden===0?'已启用':'已停用');}
|
||||
}
|
||||
function delMenu(id){
|
||||
if(!confirm('确定要删除该菜单吗?'))return;
|
||||
function rm(nodes){
|
||||
for(var i=nodes.length-1;i>=0;i--){
|
||||
if(nodes[i].id===id){nodes.splice(i,1);return true;}
|
||||
if(nodes[i].children&&rm(nodes[i].children))return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
rm(menuTree);renderMenu();showToast('删除成功');
|
||||
}
|
||||
function searchQuery(){renderMenu();showToast('查询完成');}
|
||||
function resetQuery(){document.getElementById('filterApp').value='';renderMenu();}
|
||||
|
||||
/* ===== 弹窗 ===== */
|
||||
function fillParentOptions(){
|
||||
var sel=document.getElementById('fParent');
|
||||
var opts='<option value="">请选择父级菜单(不选则为顶级)</option>';
|
||||
function walk(nodes,prefix){
|
||||
nodes.forEach(function(n){
|
||||
if(n.type===0){
|
||||
opts+='<option value="'+n.id+'">'+prefix+n.name+'</option>';
|
||||
if(n.children)walk(n.children,prefix+' ');
|
||||
}
|
||||
});
|
||||
}
|
||||
walk(menuTree,'');
|
||||
sel.innerHTML=opts;
|
||||
}
|
||||
function onElementTypeChange(){
|
||||
var type=document.getElementById('fElementType').value;
|
||||
document.getElementById('menuFields').style.display=type==='0'?'block':'none';
|
||||
document.getElementById('btnFields').style.display=type==='1'?'block':'none';
|
||||
}
|
||||
function openModal(mode,parentId,id){
|
||||
editingId=id;
|
||||
fillParentOptions();
|
||||
document.getElementById('menuTitle').textContent=(mode==='add'?'新增菜单':mode==='addSub'?'添加下级菜单':'编辑菜单');
|
||||
document.getElementById('fElementType').value='0';
|
||||
document.getElementById('fName').value='';
|
||||
document.getElementById('fIcon').value='';
|
||||
document.getElementById('fComponent').value='';
|
||||
document.getElementById('fRoutePath').value='';
|
||||
document.getElementById('fSort').value='';
|
||||
document.getElementById('fDesc').value='';
|
||||
document.getElementById('fBtnName').value='';
|
||||
document.getElementById('fPerms').value='';
|
||||
document.getElementById('fBtnDesc').value='';
|
||||
if(parentId)document.getElementById('fParent').value=parentId;else document.getElementById('fParent').value='';
|
||||
onElementTypeChange();
|
||||
if(mode==='edit'&&id){
|
||||
var n=findNode(menuTree,id);
|
||||
if(n){
|
||||
document.getElementById('fParent').value='';
|
||||
document.getElementById('fElementType').value=String(n.type);
|
||||
onElementTypeChange();
|
||||
if(n.type===0){
|
||||
document.getElementById('fName').value=n.name;
|
||||
document.getElementById('fIcon').value=n.icon;
|
||||
document.getElementById('fComponent').value=n.component;
|
||||
document.getElementById('fRoutePath').value=n.routePath;
|
||||
document.getElementById('fDesc').value=n.desc;
|
||||
}else{
|
||||
document.getElementById('fBtnName').value=n.name;
|
||||
document.getElementById('fPerms').value=n.routePath||'';
|
||||
document.getElementById('fBtnDesc').value=n.desc;
|
||||
}
|
||||
}
|
||||
}
|
||||
document.getElementById('menuMask').classList.add('open');
|
||||
}
|
||||
function closeModal(){document.getElementById('menuMask').classList.remove('open');}
|
||||
function toggleStatus(){
|
||||
var sw=document.getElementById('fStatusSwitch');
|
||||
var on=sw.classList.toggle('on');
|
||||
sw.querySelector('input').checked=on;
|
||||
document.getElementById('fStatusText').textContent=on?'启用':'停用';
|
||||
}
|
||||
function toggleBtnStatus(){
|
||||
var sw=document.getElementById('fBtnStatusSwitch');
|
||||
var on=sw.classList.toggle('on');
|
||||
sw.querySelector('input').checked=on;
|
||||
document.getElementById('fBtnStatusText').textContent=on?'启用':'停用';
|
||||
}
|
||||
function submitForm(){
|
||||
var type=document.getElementById('fElementType').value;
|
||||
if(type==='0'){
|
||||
var name=document.getElementById('fName').value.trim();
|
||||
if(!name){showToast('请输入菜单名称');return;}
|
||||
}else{
|
||||
var name=document.getElementById('fBtnName').value.trim();
|
||||
if(!name){showToast('请输入按钮名称');return;}
|
||||
}
|
||||
closeModal();renderMenu();showToast(editingId?'编辑成功':'新增成功');
|
||||
}
|
||||
function showToast(msg){
|
||||
var t=document.getElementById('toast');t.textContent=msg;t.classList.add('show');
|
||||
setTimeout(function(){t.classList.remove('show');},1500);
|
||||
}
|
||||
document.addEventListener('click',function(e){if(e.target===document.getElementById('menuMask'))closeModal();});
|
||||
renderMenu();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,575 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>角色管理 | 系统管理</title>
|
||||
<style>
|
||||
*{box-sizing:border-box;margin:0;padding:0;}
|
||||
body{font-family:-apple-system,BlinkMacSystemFont,'PingFang SC','Microsoft YaHei',sans-serif;font-size:var(--font-sm);background:#F5F7FA;color:#333;min-width:1280px;}
|
||||
:root{
|
||||
--primary:#1890FF;--primary-light:#E6F7FF;--success:#52C41A;--warning:#FAAD14;--danger:#FF4D4F;
|
||||
--text-primary:#333;--text-secondary:#666;--text-placeholder:#999;--border:#E8E8E8;--background:#F5F7FA;
|
||||
--font-xs:11px;--font-sm:13px;--font-base:15px;--font-lg:17px;
|
||||
--radius-sm:4px;--radius-md:8px;--radius-lg:12px;
|
||||
--shadow-sm:0 1px 4px rgba(0,0,0,0.08);--shadow-md:0 4px 12px rgba(0,0,0,0.10);
|
||||
}
|
||||
.top-bar{display:flex;align-items:center;height:56px;background:#001529;padding:0 24px;position:fixed;top:0;left:0;right:0;z-index:100;}
|
||||
.top-bar__logo{display:flex;align-items:center;gap:8px;color:#fff;font-size:var(--font-lg);font-weight:600;white-space:nowrap;width:200px;flex-shrink:0;}
|
||||
.top-bar__logo svg{width:28px;height:28px;}
|
||||
.top-bar__nav{display:flex;align-items:center;gap:4px;flex:1;}
|
||||
.top-bar__nav a{color:rgba(255,255,255,0.65);text-decoration:none;padding:6px 14px;border-radius:var(--radius-sm);font-size:var(--font-sm);transition:all .2s;}
|
||||
.top-bar__nav a:hover{color:#fff;background:rgba(255,255,255,0.08);}
|
||||
.top-bar__nav a.active{color:#fff;background:var(--primary);}
|
||||
.top-bar__right{display:flex;align-items:center;gap:16px;color:rgba(255,255,255,0.65);font-size:var(--font-sm);}
|
||||
.btn-back{color:rgba(255,255,255,0.65);cursor:pointer;display:flex;align-items:center;gap:4px;text-decoration:none;}
|
||||
.btn-back:hover{color:#fff;}
|
||||
.avatar{width:32px;height:32px;border-radius:50%;background:#1890FF;display:flex;align-items:center;justify-content:center;color:#fff;font-size:var(--font-sm);cursor:pointer;}
|
||||
.sidebar{position:fixed;top:56px;left:0;bottom:0;width:240px;background:#001529;overflow-y:auto;z-index:90;padding-top:8px;padding-bottom:24px;}
|
||||
.sidebar-menu__title{color:rgba(255,255,255,0.35);font-size:var(--font-xs);padding:16px 24px 8px;letter-spacing:.5px;}
|
||||
.sidebar-item{display:flex;align-items:center;gap:8px;padding:9px 24px;color:rgba(255,255,255,0.65);font-size:var(--font-sm);cursor:pointer;transition:all .15s;text-decoration:none;}
|
||||
.sidebar-item:hover{color:#fff;background:rgba(255,255,255,0.06);}
|
||||
.sidebar-item.active{color:#fff;background:var(--primary);}
|
||||
.main{margin-left:240px;margin-top:56px;padding:24px;min-height:calc(100vh - 56px);}
|
||||
.btn{height:36px;padding:0 16px;border-radius:var(--radius-sm);font-size:var(--font-sm);cursor:pointer;border:none;transition:all .2s;display:inline-flex;align-items:center;gap:6px;white-space:nowrap;}
|
||||
.btn-primary{background:var(--primary);color:#fff;}.btn-primary:hover{background:#40a9ff;}
|
||||
.btn-default{background:#fff;color:var(--text-primary);border:1px solid var(--border);}.btn-default:hover{color:var(--primary);border-color:var(--primary);}
|
||||
.btn-danger{background:var(--danger);color:#fff;}.btn-danger:hover{background:#ff7875;}
|
||||
.btn-link{background:none;color:var(--primary);padding:0 4px;height:auto;}.btn-link:hover{color:#40a9ff;}
|
||||
/* 左右分栏 */
|
||||
.role-layout{display:flex;gap:16px;align-items:stretch;}
|
||||
.card{background:#fff;border-radius:var(--radius-md);box-shadow:var(--shadow-sm);}
|
||||
.role-left{width:320px;flex-shrink:0;display:flex;flex-direction:column;max-height:calc(100vh - 104px);}
|
||||
.role-left__header{padding:16px 16px 12px;border-bottom:1px solid var(--border);}
|
||||
.role-left__header .row1{display:flex;align-items:center;justify-content:space-between;margin-bottom:12px;}
|
||||
.role-left__header .title{font-size:var(--font-base);font-weight:600;}
|
||||
.role-left__header .filters{display:flex;gap:16px;align-items:center;}
|
||||
.role-left__body{flex:1;overflow-y:auto;padding:12px;}
|
||||
.role-left__footer{padding:12px 16px;border-top:1px solid var(--border);}
|
||||
.role-tag{display:flex;align-items:center;justify-content:space-between;padding:10px 14px;border-radius:var(--radius-sm);cursor:pointer;border:1px solid transparent;margin-bottom:8px;transition:all .15s;}
|
||||
.role-tag:hover{background:#F0F8FF;}
|
||||
.role-tag.active{background:var(--primary-light);border-color:var(--primary);}
|
||||
.role-tag .name{font-size:var(--font-sm);color:var(--text-primary);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;flex:1;}
|
||||
.role-tag .count{font-size:var(--font-xs);color:var(--text-placeholder);display:flex;align-items:center;gap:4px;flex-shrink:0;}
|
||||
.role-tag.active .name{color:var(--primary);font-weight:500;}
|
||||
.role-empty{text-align:center;padding:40px 0;color:var(--text-placeholder);}
|
||||
.checkbox{display:inline-flex;align-items:center;gap:6px;cursor:pointer;font-size:var(--font-sm);color:var(--text-secondary);user-select:none;}
|
||||
.checkbox input{accent-color:var(--primary);width:14px;height:14px;cursor:pointer;}
|
||||
/* 右侧 tab */
|
||||
.role-right{flex:1;min-width:0;display:flex;flex-direction:column;max-height:calc(100vh - 104px);}
|
||||
.tabs{display:flex;border-bottom:1px solid var(--border);padding:0 16px;flex-shrink:0;}
|
||||
.tab{position:relative;padding:14px 16px;font-size:var(--font-sm);color:var(--text-secondary);cursor:pointer;user-select:none;}
|
||||
.tab:hover{color:var(--primary);}
|
||||
.tab.active{color:var(--primary);font-weight:500;}
|
||||
.tab.active::after{content:'';position:absolute;left:16px;right:16px;bottom:-1px;height:2px;background:var(--primary);}
|
||||
.tab-panel{flex:1;overflow-y:auto;display:none;flex-direction:column;}
|
||||
.tab-panel.active{display:flex;}
|
||||
.filter-bar{padding:16px;display:flex;align-items:center;gap:16px;flex-wrap:wrap;border-bottom:1px solid #F0F0F0;flex-shrink:0;}
|
||||
.filter-item{display:flex;align-items:center;gap:8px;}
|
||||
.filter-item label{font-size:var(--font-sm);color:var(--text-secondary);white-space:nowrap;}
|
||||
.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);}
|
||||
.org-wrap{position:relative;display:inline-block;}
|
||||
.org-trigger{height:36px;min-width:160px;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;display:flex;align-items:center;user-select:none;white-space:nowrap;}
|
||||
.org-trigger.open,.org-trigger:hover{border-color:var(--primary);}
|
||||
.org-panel{display:none;position:absolute;top:38px;left:0;z-index:310;background:#fff;border:1px solid var(--border);border-radius:var(--radius-sm);box-shadow:var(--shadow-md);width:380px;}
|
||||
.org-panel.open{display:flex;}
|
||||
.org-col{flex:1;overflow-y:auto;max-height:200px;border-right:1px solid var(--border);}
|
||||
.org-col:last-child{border-right:none;}
|
||||
.org-col__title{padding:6px 12px;font-size:var(--font-sm);color:var(--text-placeholder);background:#FAFAFA;border-bottom:1px solid var(--border);font-weight:500;}
|
||||
.org-item{padding:8px 12px;font-size:var(--font-sm);color:var(--text-primary);cursor:pointer;display:flex;align-items:center;justify-content:space-between;gap:4px;}
|
||||
.org-item:hover{background:#F0F8FF;color:var(--primary);}
|
||||
.org-item.active{background:var(--primary-light);color:var(--primary);font-weight:500;}
|
||||
.action-bar{display:flex;align-items:center;gap:8px;padding:12px 16px;flex-shrink:0;}
|
||||
.table-wrap{flex:1;overflow:auto;}
|
||||
table{width:100%;border-collapse:separate;border-spacing:0;min-width:900px;}
|
||||
thead th{background:#FAFAFA;padding:10px 14px;text-align:center;font-size:var(--font-sm);color:var(--text-secondary);font-weight:500;border-bottom:1px solid var(--border);white-space:nowrap;position:sticky;top:0;z-index:3;}
|
||||
tbody td{padding:12px 14px;text-align:center;font-size:var(--font-sm);color:var(--text-primary);border-bottom:1px solid #F0F0F0;white-space:nowrap;}
|
||||
tbody tr:last-child td{border-bottom:none;}
|
||||
tbody tr:hover{background:#F8FBFF;}
|
||||
thead tr th:last-child,tbody td:last-child{position:sticky;right:0;z-index:5;background:#fff;box-shadow:-4px 0 8px rgba(0,0,0,0.04);}
|
||||
thead tr th:last-child{z-index:8;background:#FAFAFA;}
|
||||
tbody tr:hover td:last-child{background:#F8FBFF;}
|
||||
.td-empty{text-align:center;padding:48px 0;color:var(--text-placeholder);}
|
||||
.badge{display:inline-block;padding:2px 10px;border-radius:10px;font-size:var(--font-xs);}
|
||||
.badge--success{background:#F6FFED;color:#389E0D;border:1px solid #B7EB8F;}
|
||||
.badge--muted{background:#F5F5F5;color:var(--text-secondary);border:1px solid var(--border);}
|
||||
.pagination{display:flex;align-items:center;justify-content:flex-end;padding:12px 16px;gap:8px;border-top:1px solid var(--border);flex-shrink:0;}
|
||||
.pagination span{font-size:var(--font-sm);color:var(--text-secondary);}
|
||||
.page-btn{min-width:28px;height:28px;border:1px solid var(--border);border-radius:var(--radius-sm);background:#fff;cursor:pointer;font-size:var(--font-sm);display:inline-flex;align-items:center;justify-content:center;padding:0 6px;transition:all .2s;}
|
||||
.page-btn:hover,.page-btn.active{background:var(--primary);color:#fff;border-color:var(--primary);}
|
||||
/* 菜单权限树 */
|
||||
.menu-perm-header{padding:16px;border-bottom:1px solid #F0F0F0;flex-shrink:0;display:flex;align-items:center;gap:12px;}
|
||||
.radio-group{display:inline-flex;border:1px solid var(--border);border-radius:var(--radius-sm);overflow:hidden;}
|
||||
.radio-group label{padding:6px 16px;font-size:var(--font-sm);cursor:pointer;color:var(--text-secondary);background:#fff;border-right:1px solid var(--border);}
|
||||
.radio-group label:last-child{border-right:none;}
|
||||
.radio-group label.on{background:var(--primary);color:#fff;}
|
||||
.menu-perm-body{flex:1;overflow-y:auto;padding:16px;}
|
||||
.tree-node{display:flex;align-items:center;padding:6px 0;cursor:pointer;}
|
||||
.tree-node input{accent-color:var(--primary);width:15px;height:15px;margin-right:8px;cursor:pointer;}
|
||||
.tree-node .arrow{width:16px;color:var(--text-placeholder);font-size:var(--font-xs);cursor:pointer;user-select:none;margin-right:2px;}
|
||||
.tree-node span{font-size:var(--font-sm);color:var(--text-primary);}
|
||||
.perm-footer{display:flex;gap:8px;padding:12px 16px;border-top:1px solid var(--border);flex-shrink:0;}
|
||||
/* 基础信息表单 */
|
||||
.info-body{flex:1;overflow-y:auto;padding:24px;}
|
||||
.info-footer{display:flex;gap:8px;padding:12px 16px;border-top:1px solid var(--border);flex-shrink:0;}
|
||||
.form-item{display:flex;align-items:flex-start;margin-bottom:20px;max-width:520px;}
|
||||
.form-item label{width:90px;min-width:90px;text-align:right;padding-right:12px;font-size:var(--font-sm);color:var(--text-secondary);line-height:36px;}
|
||||
.form-item .control{flex:1;font-size:var(--font-sm);line-height:36px;color:var(--text-primary);}
|
||||
.form-input{width:100%;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;}
|
||||
.form-input:focus{border-color:var(--primary);box-shadow:0 0 0 2px rgba(24,144,255,0.1);}
|
||||
.form-textarea{width:100%;border:1px solid var(--border);border-radius:var(--radius-sm);padding:8px 12px;font-size:var(--font-sm);color:var(--text-primary);outline:none;resize:vertical;min-height:80px;line-height:1.6;}
|
||||
.form-textarea:focus{border-color:var(--primary);box-shadow:0 0 0 2px rgba(24,144,255,0.1);}
|
||||
.empty-tip{flex:1;display:flex;align-items:center;justify-content:center;color:var(--text-placeholder);}
|
||||
/* 弹窗 */
|
||||
.modal-mask{display:none;position:fixed;inset:0;background:rgba(0,0,0,.45);z-index:950;align-items:center;justify-content:center;}
|
||||
.modal-mask.open{display:flex;}
|
||||
.modal{width:600px;background:#fff;border-radius:var(--radius-md);box-shadow:var(--shadow-md);}
|
||||
.modal--lg{width:760px;}
|
||||
.modal__head{display:flex;align-items:center;justify-content:space-between;padding:16px 24px;border-bottom:1px solid var(--border);font-size:var(--font-base);font-weight:600;}
|
||||
.modal__close{cursor:pointer;color:var(--text-placeholder);font-size:20px;line-height:1;border:none;background:none;}
|
||||
.modal__close:hover{color:var(--text-primary);}
|
||||
.modal__body{padding:24px;max-height:60vh;overflow-y:auto;}
|
||||
.modal__footer{display:flex;justify-content:flex-end;gap:8px;padding:12px 24px;border-top:1px solid var(--border);}
|
||||
.toast{position:fixed;top:80px;left:50%;transform:translateX(-50%);background:#333;color:#fff;padding:10px 24px;border-radius:var(--radius-sm);font-size:var(--font-sm);z-index:9999;opacity:0;transition:opacity .2s;pointer-events:none;}
|
||||
.toast.show{opacity:1;}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<!-- 顶部导航栏 -->
|
||||
<div class="top-bar">
|
||||
<div class="top-bar__logo"><svg viewBox="0 0 28 28" fill="none"><rect width="28" height="28" rx="6" fill="#1890FF"/><path d="M14 6.5l7 3.5v4.5c0 4.2-2.9 6.8-7 7.5-4.1-.7-7-3.3-7-7.5V10l7-3.5z" stroke="#fff" stroke-width="1.8" fill="none"/><path d="M11 13.5h6M14 10.5v6" stroke="#fff" stroke-width="1.8" stroke-linecap="round"/></svg> 系统管理</div>
|
||||
<nav class="top-bar__nav">
|
||||
<a href="user-admin.html">用户管理</a>
|
||||
<a href="application.html" class="active">权限管理</a>
|
||||
<a href="hospital.html">机构管理</a>
|
||||
<a href="dict.html">系统配置</a>
|
||||
<a href="announcement.html">通知管理</a>
|
||||
</nav>
|
||||
<div class="top-bar__right">
|
||||
<a class="btn-back" href="../../index.html"><svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M10 3L5 8l5 5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg> 返回首页</a>
|
||||
<div class="avatar">管</div>
|
||||
<span style="color:rgba(255,255,255,0.65);">系统管理员 ▾</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 侧边栏 -->
|
||||
<aside class="sidebar">
|
||||
<div class="sidebar-menu__title">权限管理</div>
|
||||
<a href="application.html" class="sidebar-item">应用管理</a>
|
||||
<a href="menu.html" class="sidebar-item">菜单管理</a>
|
||||
<a href="role.html" class="sidebar-item active">角色管理</a>
|
||||
</aside>
|
||||
|
||||
<!-- 主内容 -->
|
||||
<main class="main">
|
||||
<div class="role-layout">
|
||||
<!-- 左侧:角色列表 -->
|
||||
<div class="card role-left">
|
||||
<div class="role-left__header">
|
||||
<div class="row1">
|
||||
<div class="title">角色</div>
|
||||
<button class="btn btn-link" onclick="openRoleAdd()">
|
||||
<svg width="14" height="14" viewBox="0 0 14 14" fill="none"><path d="M7 2v10M2 7h10" stroke="currentColor" stroke-width="1.4" stroke-linecap="round"/></svg>新建角色
|
||||
</button>
|
||||
</div>
|
||||
<div class="filters">
|
||||
<label class="checkbox"><input type="checkbox" checked onchange="filterRoles()" id="chkBuiltin"> 系统内置</label>
|
||||
<label class="checkbox"><input type="checkbox" checked onchange="filterRoles()" id="chkCustom"> 自定义</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="role-left__body" id="roleList"></div>
|
||||
<div class="role-left__footer">
|
||||
<div class="pagination" style="border:none;padding:0;">
|
||||
<span>共 <b id="roleTotal">0</b> 条</span>
|
||||
<button class="page-btn" onclick="showToast('演示数据仅一页')">上一页</button>
|
||||
<button class="page-btn active">1</button>
|
||||
<button class="page-btn" onclick="showToast('演示数据仅一页')">下一页</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 右侧:3 个 tab -->
|
||||
<div class="card role-right">
|
||||
<div class="tabs">
|
||||
<div class="tab active" data-tab="userRole" onclick="switchTab('userRole')">角色用户</div>
|
||||
<div class="tab" data-tab="menuPerm" onclick="switchTab('menuPerm')">菜单权限</div>
|
||||
<div class="tab" data-tab="basicInfo" onclick="switchTab('basicInfo')">基础信息</div>
|
||||
</div>
|
||||
|
||||
<!-- Tab1: 角色用户 -->
|
||||
<div class="tab-panel active" id="panel-userRole">
|
||||
<div class="filter-bar">
|
||||
<div class="filter-item">
|
||||
<label>单位部门</label>
|
||||
<div class="org-wrap" id="orgWrap">
|
||||
<div class="org-trigger" id="orgTrigger" onclick="toggleOrg()">全部单位/部门</div>
|
||||
<div class="org-panel" id="orgPanel">
|
||||
<div class="org-col">
|
||||
<div class="org-col__title">单位</div>
|
||||
<div class="org-item active" onclick="selectUnit(this,'')">全部单位</div>
|
||||
<div class="org-item" onclick="selectUnit(this,'采油一厂')">采油一厂</div>
|
||||
<div class="org-item" onclick="selectUnit(this,'采油二厂')">采油二厂</div>
|
||||
<div class="org-item" onclick="selectUnit(this,'第四采油厂')">第四采油厂</div>
|
||||
</div>
|
||||
<div class="org-col">
|
||||
<div class="org-col__title">部门</div>
|
||||
<div class="org-item active" onclick="selectDept(this,'')">全部部门</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="filter-item"><label>姓名</label><input class="filter-input" id="urName" placeholder="请输入姓名"></div>
|
||||
<div class="filter-item"><label>账号</label><input class="filter-input" id="urAccount" placeholder="请输入账号"></div>
|
||||
<button class="btn btn-primary" onclick="renderRoleUsers()"><svg width="14" height="14" viewBox="0 0 14 14" fill="none"><circle cx="6" cy="6" r="4.5" stroke="#fff" stroke-width="1.3"/><path d="M9.5 9.5L13 13" stroke="#fff" stroke-width="1.3" stroke-linecap="round"/></svg>查询</button>
|
||||
<button class="btn btn-default" onclick="resetUserSearch()">重置</button>
|
||||
</div>
|
||||
<div class="action-bar" id="userRoleActions">
|
||||
<button class="btn btn-primary" onclick="openSelectUser()"><svg width="14" height="14" viewBox="0 0 14 14" fill="none"><path d="M7 2v10M2 7h10" stroke="currentColor" stroke-width="1.4" stroke-linecap="round"/></svg>选择用户</button>
|
||||
<button class="btn btn-danger" onclick="batchRemove()">批量移除</button>
|
||||
</div>
|
||||
<div class="table-wrap">
|
||||
<table>
|
||||
<thead><tr><th style="width:44px"><input type="checkbox" id="urCheckAll" onchange="toggleAllUsers(this)"></th><th>序号</th><th>账号</th><th>姓名</th><th>用户类型</th><th>单位</th><th>部门</th><th>状态</th><th style="width:80px">操作</th></tr></thead>
|
||||
<tbody id="userRoleBody"></tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="pagination"><span>共 <b id="urTotal">0</b> 条</span><button class="page-btn" onclick="showToast('演示数据仅一页')">上一页</button><button class="page-btn active">1</button><button class="page-btn" onclick="showToast('演示数据仅一页')">下一页</button></div>
|
||||
</div>
|
||||
|
||||
<!-- Tab2: 菜单权限 -->
|
||||
<div class="tab-panel" id="panel-menuPerm">
|
||||
<div class="menu-perm-header">
|
||||
<span style="color:var(--text-secondary);">选择应用分类</span>
|
||||
<div class="radio-group" id="customTypeGroup">
|
||||
<label class="on" onclick="switchCustomType(this,0)">通用</label>
|
||||
<label onclick="switchCustomType(this,1)">定制</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="menu-perm-body" id="menuPermBody"></div>
|
||||
<div class="perm-footer">
|
||||
<button class="btn btn-primary" onclick="showToast('菜单权限保存成功')">保存</button>
|
||||
<button class="btn btn-default" onclick="renderMenuPerm()">重置</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Tab3: 基础信息 -->
|
||||
<div class="tab-panel" id="panel-basicInfo">
|
||||
<div class="info-body" id="basicInfoBody"></div>
|
||||
<div class="info-footer" id="basicInfoFooter">
|
||||
<button class="btn btn-primary" onclick="showToast('保存成功')">保存</button>
|
||||
<button class="btn btn-default" onclick="renderBasicInfo()">重置</button>
|
||||
<button class="btn btn-danger" onclick="delRole()">删除角色</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<!-- [交互] 新建角色弹窗 -->
|
||||
<div class="modal-mask" id="roleAddMask">
|
||||
<div class="modal">
|
||||
<div class="modal__head"><span>新建角色</span><button class="modal__close" onclick="closeModal('roleAddMask')">×</button></div>
|
||||
<div class="modal__body">
|
||||
<div class="form-item"><label><span style="color:var(--danger);margin-right:2px;">*</span>角色名称</label><div class="control"><input class="form-input" id="raName" maxlength="30" placeholder="请输入角色名称"></div></div>
|
||||
<div class="form-item"><label><span style="color:var(--danger);margin-right:2px;">*</span>角色编码</label><div class="control"><input class="form-input" id="raCode" maxlength="30" placeholder="请输入角色编码"></div></div>
|
||||
<div class="form-item"><label>排序</label><div class="control"><input class="form-input" id="raSort" type="number" min="1" placeholder="请输入排序"></div></div>
|
||||
<div class="form-item"><label>描述</label><div class="control"><textarea class="form-textarea" id="raDesc" maxlength="200" placeholder="请输入描述"></textarea></div></div>
|
||||
</div>
|
||||
<div class="modal__footer">
|
||||
<button class="btn btn-default" onclick="closeModal('roleAddMask')">取消</button>
|
||||
<button class="btn btn-primary" onclick="submitRoleAdd()">确定</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- [交互] 选择用户弹窗 -->
|
||||
<div class="modal-mask" id="selectUserMask">
|
||||
<div class="modal modal--lg">
|
||||
<div class="modal__head"><span>选择用户</span><button class="modal__close" onclick="closeModal('selectUserMask')">×</button></div>
|
||||
<div class="modal__body">
|
||||
<div class="filter-bar" style="padding:0 0 16px;border:none;">
|
||||
<div class="filter-item"><label>员工姓名</label><input class="filter-input" id="suName" placeholder="请输入员工姓名"></div>
|
||||
<div class="filter-item"><label>员工账号</label><input class="filter-input" id="suAccount" placeholder="请输入员工账号"></div>
|
||||
<button class="btn btn-primary" onclick="renderSelectUser()">查询</button>
|
||||
<button class="btn btn-default" onclick="resetSelectUser()">重置</button>
|
||||
</div>
|
||||
<div class="table-wrap" style="max-height:320px;overflow:auto;">
|
||||
<table>
|
||||
<thead><tr><th style="width:44px"><input type="checkbox" onchange="toggleAllCand(this)"></th><th>序号</th><th>员工账号</th><th>员工姓名</th><th>用户类型</th><th>单位</th><th>部门</th><th>状态</th></tr></thead>
|
||||
<tbody id="selectUserBody"></tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal__footer">
|
||||
<button class="btn btn-default" onclick="closeModal('selectUserMask')">取消</button>
|
||||
<button class="btn btn-primary" onclick="submitSelectUser()">确认添加</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="toast" id="toast"></div>
|
||||
|
||||
<script>
|
||||
/* ===== 角色数据 ===== */
|
||||
var roles=[
|
||||
{id:'1',roleName:'超级管理员',roleCode:'super_admin',roleType:1,customType:0,userCount:2,sort:1,desc:'系统最高权限,管理全部应用'},
|
||||
{id:'2',roleName:'系统管理员',roleCode:'sys_admin',roleType:1,customType:0,userCount:5,sort:2,desc:'负责系统管理与配置'},
|
||||
{id:'3',roleName:'运营管理员',roleCode:'op_admin',roleType:1,customType:0,userCount:12,sort:3,desc:'负责平台日常运营管理'},
|
||||
{id:'4',roleName:'健康顾问',roleCode:'health_advisor',roleType:0,customType:0,userCount:34,sort:4,desc:'健康咨询顾问角色'},
|
||||
{id:'5',roleName:'体检医生',roleCode:'exam_doctor',roleType:0,customType:0,userCount:18,sort:5,desc:'体检检查与报告录入'},
|
||||
{id:'6',roleName:'医疗点医护',roleCode:'medical_staff',roleType:0,customType:1,userCount:26,sort:6,desc:'一线医疗点驻点医护'}
|
||||
];
|
||||
var selectedRoleId='4';
|
||||
var curTab='userRole';
|
||||
|
||||
/* 角色用户数据 */
|
||||
var roleUsers={
|
||||
'4':[
|
||||
{id:'u1',username:'zhangwei',realName:'张伟',personTypeName:'员工',orgName:'采油一厂',deptName:'安全环保科',statusName:'正常'},
|
||||
{id:'u2',username:'liyan',realName:'李艳',personTypeName:'员工',orgName:'采油二厂',deptName:'姬圪台联合站',statusName:'正常'},
|
||||
{id:'u3',username:'wangqiang',realName:'王强',personTypeName:'员工',orgName:'第四采油厂',deptName:'基地管理处',statusName:'正常'},
|
||||
{id:'u4',username:'zhaomin',realName:'赵敏',personTypeName:'员工',orgName:'采气一厂',deptName:'靖边净化厂',statusName:'锁定'}
|
||||
],
|
||||
'5':[
|
||||
{id:'u5',username:'chenjing',realName:'陈静',personTypeName:'员工',orgName:'采油一厂',deptName:'安全环保科',statusName:'正常'},
|
||||
{id:'u6',username:'liuming',realName:'刘明',personTypeName:'员工',orgName:'采油二厂',deptName:'信息中心',statusName:'正常'}
|
||||
],
|
||||
'6':[
|
||||
{id:'u7',username:'sunli',realName:'孙丽',personTypeName:'员工',orgName:'采油一厂',deptName:'采油大队',statusName:'正常'},
|
||||
{id:'u8',username:'zhoujie',realName:'周杰',personTypeName:'员工',orgName:'采气一厂',deptName:'生产技术部',statusName:'正常'},
|
||||
{id:'u9',username:'wujun',realName:'吴军',personTypeName:'员工',orgName:'第四采油厂',deptName:'健康管理部',statusName:'正常'}
|
||||
]
|
||||
};
|
||||
/* 候选用户数据 */
|
||||
var candidateUsers=[
|
||||
{id:'c1',username:'guolei',realName:'郭磊',personTypeName:'员工',orgName:'采油一厂',deptName:'安全环保科',statusName:'正常'},
|
||||
{id:'c2',username:'maxiao',realName:'马晓',personTypeName:'员工',orgName:'采油二厂',deptName:'姬圪台联合站',statusName:'正常'},
|
||||
{id:'c3',username:'hujun',realName:'胡军',personTypeName:'员工',orgName:'采气一厂',deptName:'苏里格南作业区',statusName:'正常'},
|
||||
{id:'c4',username:'linna',realName:'林娜',personTypeName:'员工',orgName:'第四采油厂',deptName:'财务部',statusName:'正常'},
|
||||
{id:'c5',username:'heping',realName:'何平',personTypeName:'员工',orgName:'采油二厂',deptName:'安全环保科',statusName:'锁定'}
|
||||
];
|
||||
|
||||
function getRole(id){return roles.find(function(r){return r.id===id;});}
|
||||
function selectedRole(){return getRole(selectedRoleId);}
|
||||
|
||||
/* ===== 角色列表 ===== */
|
||||
function filterRoles(){
|
||||
var builtin=document.getElementById('chkBuiltin').checked;
|
||||
var custom=document.getElementById('chkCustom').checked;
|
||||
var list=roles.filter(function(r){return (r.roleType===1&&builtin)||(r.roleType===0&&custom);});
|
||||
document.getElementById('roleTotal').textContent=list.length;
|
||||
document.getElementById('roleList').innerHTML=list.length===0
|
||||
?'<div class="role-empty">暂无角色数据</div>'
|
||||
:list.map(function(r){
|
||||
var label='('+(r.roleType===1?'系统内置':'自定义')+')'+r.roleName;
|
||||
return '<div class="role-tag'+(r.id===selectedRoleId?' active':'')+'" onclick="selectRole(\''+r.id+'\')">'+
|
||||
'<span class="name">'+label+'</span>'+
|
||||
'<span class="count"><svg width="12" height="12" viewBox="0 0 12 12" fill="none"><circle cx="6" cy="4" r="2.2" stroke="currentColor" stroke-width="1.1"/><path d="M2 10.5c0-2 1.8-3.2 4-3.2s4 1.2 4 3.2" stroke="currentColor" stroke-width="1.1"/></svg>'+r.userCount+'</span>'+
|
||||
'</div>';
|
||||
}).join('');
|
||||
}
|
||||
function selectRole(id){
|
||||
selectedRoleId=id;
|
||||
filterRoles();
|
||||
renderTabContent();
|
||||
}
|
||||
|
||||
/* ===== Tab 切换 ===== */
|
||||
function switchTab(tab){
|
||||
curTab=tab;
|
||||
document.querySelectorAll('.tab').forEach(function(t){t.classList.toggle('active',t.dataset.tab===tab);});
|
||||
document.getElementById('panel-userRole').classList.toggle('active',tab==='userRole');
|
||||
document.getElementById('panel-menuPerm').classList.toggle('active',tab==='menuPerm');
|
||||
document.getElementById('panel-basicInfo').classList.toggle('active',tab==='basicInfo');
|
||||
renderTabContent();
|
||||
}
|
||||
function renderTabContent(){
|
||||
if(curTab==='userRole')renderRoleUsers();
|
||||
else if(curTab==='menuPerm')renderMenuPerm();
|
||||
else renderBasicInfo();
|
||||
}
|
||||
|
||||
/* ===== Tab1: 角色用户 ===== */
|
||||
function renderRoleUsers(){
|
||||
var role=selectedRole();
|
||||
var isBuiltin=role.roleType===1;
|
||||
// 系统内置角色隐藏操作列与多选
|
||||
var body=document.getElementById('userRoleBody');
|
||||
document.getElementById('userRoleActions').style.display=isBuiltin?'none':'flex';
|
||||
var list=roleUsers[selectedRoleId]||[];
|
||||
document.getElementById('urTotal').textContent=list.length;
|
||||
body.innerHTML=list.length===0
|
||||
?'<tr><td colspan="9" class="td-empty">暂无数据</td></tr>'
|
||||
:list.map(function(u,i){
|
||||
var statusBadge=u.statusName==='正常'?'badge--success':'badge--muted';
|
||||
return '<tr>'+
|
||||
'<td>'+(isBuiltin?'':'<input type="checkbox" class="urCheck">')+'</td>'+
|
||||
'<td>'+(i+1)+'</td>'+
|
||||
'<td>'+u.username+'</td>'+
|
||||
'<td>'+u.realName+'</td>'+
|
||||
'<td>'+u.personTypeName+'</td>'+
|
||||
'<td>'+u.orgName+'</td>'+
|
||||
'<td>'+u.deptName+'</td>'+
|
||||
'<td><span class="badge '+statusBadge+'">'+u.statusName+'</span></td>'+
|
||||
'<td>'+(isBuiltin?'':'<button class="btn btn-link" style="color:var(--danger);" onclick="removeUser(\''+u.id+'\')">移除</button>')+'</td>'+
|
||||
'</tr>';
|
||||
}).join('');
|
||||
}
|
||||
function removeUser(id){
|
||||
if(!confirm('确定移除该用户吗?'))return;
|
||||
roleUsers[selectedRoleId]=roleUsers[selectedRoleId].filter(function(u){return u.id!==id;});
|
||||
renderRoleUsers();showToast('移除成功');
|
||||
}
|
||||
function toggleAllUsers(el){
|
||||
document.querySelectorAll('.urCheck').forEach(function(c){c.checked=el.checked;});
|
||||
}
|
||||
function batchRemove(){
|
||||
var checked=document.querySelectorAll('.urCheck:checked').length;
|
||||
if(checked===0){showToast('请先选择要移除的用户');return;}
|
||||
if(!confirm('确定移除选中的 '+checked+' 个用户吗?'))return;
|
||||
roleUsers[selectedRoleId]=roleUsers[selectedRoleId].filter(function(u,i){
|
||||
var c=document.querySelectorAll('.urCheck')[i];
|
||||
return !c.checked;
|
||||
});
|
||||
renderRoleUsers();showToast('批量移除成功');
|
||||
}
|
||||
|
||||
/* ===== Tab2: 菜单权限 ===== */
|
||||
var permTree=[
|
||||
{id:'p1',name:'用户管理',children:[
|
||||
{id:'p11',name:'管理员账号'},{id:'p12',name:'全部用户'},{id:'p13',name:'员工账号'}
|
||||
]},
|
||||
{id:'p2',name:'权限管理',children:[
|
||||
{id:'p21',name:'应用管理'},{id:'p22',name:'菜单管理'},{id:'p23',name:'角色管理'}
|
||||
]},
|
||||
{id:'p3',name:'机构管理',children:[{id:'p31',name:'医院管理'},{id:'p32',name:'单位管理'}]},
|
||||
{id:'p4',name:'系统配置',children:[{id:'p41',name:'数据字典'},{id:'p42',name:'变量配置'}]},
|
||||
{id:'p5',name:'通知管理',children:[{id:'p51',name:'公告'},{id:'p52',name:'短信管理'}]}
|
||||
];
|
||||
var permCollapsed={};
|
||||
function renderMenuPerm(){
|
||||
var role=selectedRole();
|
||||
if(role.roleCode==='user'){
|
||||
document.getElementById('menuPermBody').innerHTML='<div class="empty-tip">当前角色仅支持登录APP,无法配置后台菜单权限</div>';
|
||||
return;
|
||||
}
|
||||
var html='';
|
||||
function walk(nodes,level){
|
||||
nodes.forEach(function(n){
|
||||
var hasChildren=n.children&&n.children.length;
|
||||
var isCollapsed=permCollapsed[n.id];
|
||||
var arrow=hasChildren?'<span class="arrow" onclick="togglePerm(\''+n.id+'\')">'+(isCollapsed?'▸':'▾')+'</span>':'<span class="arrow" style="visibility:hidden;">▸</span>';
|
||||
html+='<div class="tree-node" style="padding-left:'+(level*24)+'px;"><input type="checkbox" checked>'+arrow+'<span>'+n.name+'</span></div>';
|
||||
if(hasChildren&&!isCollapsed)walk(n.children,level+1);
|
||||
});
|
||||
}
|
||||
walk(permTree,0);
|
||||
document.getElementById('menuPermBody').innerHTML=html;
|
||||
}
|
||||
function togglePerm(id){permCollapsed[id]=!permCollapsed[id];renderMenuPerm();}
|
||||
function switchCustomType(el,v){
|
||||
document.querySelectorAll('#customTypeGroup label').forEach(function(l){l.classList.remove('on');});
|
||||
el.classList.add('on');
|
||||
}
|
||||
|
||||
/* ===== Tab3: 基础信息 ===== */
|
||||
function renderBasicInfo(){
|
||||
var role=selectedRole();
|
||||
var isBuiltin=role.roleType===1;
|
||||
var nameField=isBuiltin?role.roleName:'<input class="form-input" id="biName" value="'+role.roleName+'" maxlength="30">';
|
||||
var codeField=isBuiltin?role.roleCode:'<input class="form-input" id="biCode" value="'+role.roleCode+'" maxlength="30">';
|
||||
var descField=isBuiltin?(role.desc||'-'):'<textarea class="form-textarea" id="biDesc" maxlength="200">'+role.desc+'</textarea>';
|
||||
document.getElementById('basicInfoBody').innerHTML=
|
||||
'<div class="form-item"><label>角色名称</label><div class="control">'+nameField+'</div></div>'+
|
||||
'<div class="form-item"><label>角色编码</label><div class="control">'+codeField+'</div></div>'+
|
||||
'<div class="form-item"><label>角色类型</label><div class="control">'+(role.roleType===1?'系统内置':'自定义')+'</div></div>'+
|
||||
'<div class="form-item"><label>列表排序</label><div class="control">'+(isBuiltin?role.sort:'<input class="form-input" id="biSort" type="number" min="1" value="'+role.sort+'">')+'</div></div>'+
|
||||
'<div class="form-item"><label>角色描述</label><div class="control">'+descField+'</div></div>';
|
||||
document.getElementById('basicInfoFooter').style.display=isBuiltin?'flex':'flex';
|
||||
// 系统内置角色不显示删除按钮
|
||||
var delBtn=document.querySelector('#basicInfoFooter .btn-danger');
|
||||
if(delBtn)delBtn.style.display=isBuiltin?'none':'inline-flex';
|
||||
}
|
||||
function delRole(){
|
||||
if(!confirm('确定删除该角色吗?'))return;
|
||||
roles=roles.filter(function(r){return r.id!==selectedRoleId;});
|
||||
if(roles.length>0){selectedRoleId=roles[0].id;}
|
||||
filterRoles();renderTabContent();showToast('删除成功');
|
||||
}
|
||||
|
||||
/* ===== 单位部门双列 ===== */
|
||||
var deptMap={'采油一厂':['安全环保科','采油大队','生产技术部'],'采油二厂':['姬圪台联合站','信息中心','安全环保科'],'第四采油厂':['基地管理处','健康管理部','财务部']};
|
||||
function toggleOrg(){document.getElementById('orgPanel').classList.toggle('open');document.getElementById('orgTrigger').classList.toggle('open');}
|
||||
function selectUnit(el,unit){
|
||||
document.querySelectorAll('#orgPanel .org-col:first-child .org-item').forEach(function(i){i.classList.remove('active');});
|
||||
el.classList.add('active');
|
||||
var deptCol=document.querySelectorAll('#orgPanel .org-col')[1];
|
||||
var depts=deptMap[unit]||[];
|
||||
deptCol.innerHTML='<div class="org-col__title">部门</div><div class="org-item active" onclick="selectDept(this,\'\')">全部部门</div>'+
|
||||
depts.map(function(d){return '<div class="org-item" onclick="selectDept(this,\''+d+'\')">'+d+'</div>';}).join('');
|
||||
}
|
||||
function selectDept(el,dept){
|
||||
document.querySelectorAll('#orgPanel .org-col:last-child .org-item').forEach(function(i){i.classList.remove('active');});
|
||||
el.classList.add('active');
|
||||
document.getElementById('orgTrigger').textContent=dept||'全部单位/部门';
|
||||
document.getElementById('orgPanel').classList.remove('open');
|
||||
document.getElementById('orgTrigger').classList.remove('open');
|
||||
}
|
||||
|
||||
/* ===== 新建角色弹窗 ===== */
|
||||
function openRoleAdd(){
|
||||
document.getElementById('raName').value='';
|
||||
document.getElementById('raCode').value='';
|
||||
document.getElementById('raSort').value='';
|
||||
document.getElementById('raDesc').value='';
|
||||
document.getElementById('roleAddMask').classList.add('open');
|
||||
}
|
||||
function submitRoleAdd(){
|
||||
var name=document.getElementById('raName').value.trim();
|
||||
if(!name){showToast('请输入角色名称');return;}
|
||||
var code=document.getElementById('raCode').value.trim();
|
||||
if(!code){showToast('请输入角色编码');return;}
|
||||
roles.push({id:String(roles.length+1),roleName:name,roleCode:code,roleType:0,customType:0,userCount:0,sort:parseInt(document.getElementById('raSort').value)||1,desc:document.getElementById('raDesc').value.trim()});
|
||||
closeModal('roleAddMask');filterRoles();showToast('新建角色成功');
|
||||
}
|
||||
|
||||
/* ===== 选择用户弹窗 ===== */
|
||||
function renderSelectUser(){
|
||||
var list=candidateUsers;
|
||||
document.getElementById('selectUserBody').innerHTML=list.map(function(u,i){
|
||||
return '<tr><td><input type="checkbox" class="candCheck"></td><td>'+(i+1)+'</td><td>'+u.username+'</td><td>'+u.realName+'</td><td>'+u.personTypeName+'</td><td>'+u.orgName+'</td><td>'+u.deptName+'</td><td><span class="badge '+(u.statusName==='正常'?'badge--success':'badge--muted')+'">'+u.statusName+'</span></td></tr>';
|
||||
}).join('');
|
||||
}
|
||||
function toggleAllCand(el){document.querySelectorAll('.candCheck').forEach(function(c){c.checked=el.checked;});}
|
||||
function openSelectUser(){
|
||||
if(!selectedRole()||selectedRole().roleType===1){showToast('系统内置角色不可配置用户');return;}
|
||||
renderSelectUser();
|
||||
document.getElementById('selectUserMask').classList.add('open');
|
||||
}
|
||||
function resetSelectUser(){document.getElementById('suName').value='';document.getElementById('suAccount').value='';renderSelectUser();}
|
||||
function submitSelectUser(){
|
||||
var checked=document.querySelectorAll('.candCheck:checked').length;
|
||||
if(checked===0){showToast('请选择要添加的用户');return;}
|
||||
closeModal('selectUserMask');showToast('已添加 '+checked+' 个用户');
|
||||
renderRoleUsers();
|
||||
}
|
||||
|
||||
function resetUserSearch(){document.getElementById('urName').value='';document.getElementById('urAccount').value='';renderRoleUsers();}
|
||||
function closeModal(id){document.getElementById(id).classList.remove('open');}
|
||||
function showToast(msg){
|
||||
var t=document.getElementById('toast');t.textContent=msg;t.classList.add('show');
|
||||
setTimeout(function(){t.classList.remove('show');},1500);
|
||||
}
|
||||
document.addEventListener('click',function(e){
|
||||
if(e.target.id==='roleAddMask')closeModal('roleAddMask');
|
||||
if(e.target.id==='selectUserMask')closeModal('selectUserMask');
|
||||
});
|
||||
|
||||
/* 初始化 */
|
||||
filterRoles();
|
||||
renderTabContent();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,163 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>短信发送历史 | 系统管理</title>
|
||||
<style>
|
||||
*{box-sizing:border-box;margin:0;padding:0;}
|
||||
body{font-family:-apple-system,BlinkMacSystemFont,'PingFang SC','Microsoft YaHei',sans-serif;font-size:var(--font-sm);background:#F5F7FA;color:#333;min-width:1280px;}
|
||||
:root{
|
||||
--primary:#1890FF;--primary-light:#E6F7FF;--success:#52C41A;--warning:#FAAD14;--danger:#FF4D4F;
|
||||
--text-primary:#333;--text-secondary:#666;--text-placeholder:#999;--border:#E8E8E8;--background:#F5F7FA;
|
||||
--font-xs:11px;--font-sm:13px;--font-base:15px;--font-lg:17px;
|
||||
--radius-sm:4px;--radius-md:8px;--radius-lg:12px;
|
||||
--shadow-sm:0 1px 4px rgba(0,0,0,0.08);--shadow-md:0 4px 12px rgba(0,0,0,0.10);
|
||||
}
|
||||
.top-bar{display:flex;align-items:center;height:56px;background:#001529;padding:0 24px;position:fixed;top:0;left:0;right:0;z-index:100;}
|
||||
.top-bar__logo{display:flex;align-items:center;gap:8px;color:#fff;font-size:var(--font-lg);font-weight:600;white-space:nowrap;width:200px;flex-shrink:0;}
|
||||
.top-bar__logo svg{width:28px;height:28px;}
|
||||
.top-bar__nav{display:flex;align-items:center;gap:4px;flex:1;}
|
||||
.top-bar__nav a{color:rgba(255,255,255,0.65);text-decoration:none;padding:6px 14px;border-radius:var(--radius-sm);font-size:var(--font-sm);transition:all .2s;}
|
||||
.top-bar__nav a:hover{color:#fff;background:rgba(255,255,255,0.08);}
|
||||
.top-bar__nav a.active{color:#fff;background:var(--primary);}
|
||||
.top-bar__right{display:flex;align-items:center;gap:16px;color:rgba(255,255,255,0.65);font-size:var(--font-sm);}
|
||||
.btn-back{color:rgba(255,255,255,0.65);cursor:pointer;display:flex;align-items:center;gap:4px;text-decoration:none;}
|
||||
.btn-back:hover{color:#fff;}
|
||||
.avatar{width:32px;height:32px;border-radius:50%;background:#1890FF;display:flex;align-items:center;justify-content:center;color:#fff;font-size:var(--font-sm);cursor:pointer;}
|
||||
.sidebar{position:fixed;top:56px;left:0;bottom:0;width:240px;background:#001529;overflow-y:auto;z-index:90;padding-top:8px;padding-bottom:24px;}
|
||||
.sidebar-menu__title{color:rgba(255,255,255,0.35);font-size:var(--font-xs);padding:16px 24px 8px;letter-spacing:.5px;}
|
||||
.sidebar-item{display:flex;align-items:center;gap:8px;padding:9px 24px;color:rgba(255,255,255,0.65);font-size:var(--font-sm);cursor:pointer;transition:all .15s;text-decoration:none;}
|
||||
.sidebar-item:hover{color:#fff;background:rgba(255,255,255,0.06);}
|
||||
.sidebar-item.active{color:#fff;background:var(--primary);}
|
||||
.main{margin-left:240px;margin-top:56px;padding:24px;min-height:calc(100vh - 56px);}
|
||||
.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;}
|
||||
.filter-select{height:36px;min-width:120px;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:120px;}
|
||||
.filter-input:focus{border-color:var(--primary);}
|
||||
.btn{height:36px;padding:0 16px;border-radius:var(--radius-sm);font-size:var(--font-sm);cursor:pointer;border:none;transition:all .2s;display:inline-flex;align-items:center;gap:6px;white-space:nowrap;}
|
||||
.btn-primary{background:var(--primary);color:#fff;}.btn-primary:hover{background:#40a9ff;}
|
||||
.btn-default{background:#fff;color:var(--text-primary);border:1px solid var(--border);}.btn-default:hover{color:var(--primary);border-color:var(--primary);}
|
||||
.btn-link{background:none;color:var(--primary);padding:0 4px;height:auto;}.btn-link:hover{color:#40a9ff;}
|
||||
.table-card{background:#fff;border-radius:var(--radius-md);box-shadow:var(--shadow-sm);overflow:hidden;margin-top:16px;}
|
||||
.table-card__content{overflow-x:auto;}
|
||||
table{width:100%;border-collapse:separate;border-spacing:0;min-width:1200px;}
|
||||
thead th{background:#FAFAFA;padding:10px 14px;text-align:center;font-size:var(--font-sm);color:var(--text-secondary);font-weight:500;border-bottom:1px solid var(--border);white-space:nowrap;}
|
||||
tbody td{padding:12px 14px;text-align:center;font-size:var(--font-sm);color:var(--text-primary);border-bottom:1px solid #F0F0F0;white-space:nowrap;}
|
||||
tbody tr:last-child td{border-bottom:none;}
|
||||
tbody tr:hover{background:#F8FBFF;}
|
||||
thead tr th:last-child,tbody td:last-child{position:sticky;right:0;z-index:5;background:#fff;box-shadow:-4px 0 8px rgba(0,0,0,0.04);}
|
||||
thead tr th:last-child{z-index:8;background:#FAFAFA;}
|
||||
tbody tr:hover td:last-child{background:#F8FBFF;}
|
||||
.td-empty{text-align:center;padding:48px 0;color:var(--text-placeholder);}
|
||||
.badge{display:inline-block;padding:2px 10px;border-radius:10px;font-size:var(--font-xs);}
|
||||
.badge--success{background:#F6FFED;color:#389E0D;border:1px solid #B7EB8F;}
|
||||
.badge--danger{background:#FFF1F0;color:#CF1322;border:1px solid #FFCCC7;}
|
||||
.pagination{display:flex;align-items:center;justify-content:flex-end;padding:16px 24px;gap:8px;border-top:1px solid var(--border);}
|
||||
.pagination span{font-size:var(--font-sm);color:var(--text-secondary);}
|
||||
.page-btn{min-width:32px;height:32px;border:1px solid var(--border);border-radius:var(--radius-sm);background:#fff;cursor:pointer;font-size:var(--font-sm);display:inline-flex;align-items:center;justify-content:center;padding:0 6px;transition:all .2s;}
|
||||
.page-btn:hover,.page-btn.active{background:var(--primary);color:#fff;border-color:var(--primary);}
|
||||
.modal-mask{display:none;position:fixed;inset:0;background:rgba(0,0,0,.45);z-index:950;align-items:center;justify-content:center;}
|
||||
.modal-mask.open{display:flex;}
|
||||
.modal{width:600px;background:#fff;border-radius:var(--radius-md);box-shadow:var(--shadow-md);}
|
||||
.modal__head{display:flex;align-items:center;justify-content:space-between;padding:16px 24px;border-bottom:1px solid var(--border);font-size:var(--font-base);font-weight:600;}
|
||||
.modal__close{cursor:pointer;color:var(--text-placeholder);font-size:20px;line-height:1;border:none;background:none;}
|
||||
.modal__body{padding:24px;max-height:60vh;overflow-y:auto;}
|
||||
.modal__footer{display:flex;justify-content:flex-end;gap:8px;padding:12px 24px;border-top:1px solid var(--border);}
|
||||
.detail-row{display:flex;padding:10px 0;border-bottom:1px solid #F0F0F0;font-size:var(--font-sm);}
|
||||
.detail-row:last-child{border-bottom:none;}
|
||||
.detail-row label{width:90px;min-width:90px;text-align:right;padding-right:12px;color:var(--text-secondary);}
|
||||
.detail-row .val{flex:1;color:var(--text-primary);line-height:1.7;word-break:break-all;}
|
||||
.toast{position:fixed;top:80px;left:50%;transform:translateX(-50%);background:#333;color:#fff;padding:10px 24px;border-radius:var(--radius-sm);font-size:var(--font-sm);z-index:9999;opacity:0;transition:opacity .2s;pointer-events:none;}
|
||||
.toast.show{opacity:1;}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="top-bar">
|
||||
<div class="top-bar__logo"><svg viewBox="0 0 28 28" fill="none"><rect width="28" height="28" rx="6" fill="#1890FF"/><path d="M14 6.5l7 3.5v4.5c0 4.2-2.9 6.8-7 7.5-4.1-.7-7-3.3-7-7.5V10l7-3.5z" stroke="#fff" stroke-width="1.8" fill="none"/><path d="M11 13.5h6M14 10.5v6" stroke="#fff" stroke-width="1.8" stroke-linecap="round"/></svg> 系统管理</div>
|
||||
<nav class="top-bar__nav">
|
||||
<a href="user-admin.html">用户管理</a>
|
||||
<a href="application.html">权限管理</a>
|
||||
<a href="hospital.html">机构管理</a>
|
||||
<a href="dict.html">系统配置</a>
|
||||
<a href="announcement.html" class="active">通知管理</a>
|
||||
</nav>
|
||||
<div class="top-bar__right">
|
||||
<a class="btn-back" href="../../index.html"><svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M10 3L5 8l5 5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg> 返回首页</a>
|
||||
<div class="avatar">管</div>
|
||||
<span style="color:rgba(255,255,255,0.65);">系统管理员 ▾</span>
|
||||
</div>
|
||||
</div>
|
||||
<aside class="sidebar">
|
||||
<div class="sidebar-menu__title">通知管理</div>
|
||||
<a href="announcement.html" class="sidebar-item">公告</a>
|
||||
<a href="sms-send.html" class="sidebar-item">发送短信</a>
|
||||
<a href="sms-history.html" class="sidebar-item active">短信发送历史</a>
|
||||
<a href="sms-template.html" class="sidebar-item">短信模板</a>
|
||||
</aside>
|
||||
|
||||
<main class="main">
|
||||
<div class="filter-bar">
|
||||
<div class="filter-item"><label>标题</label><input class="filter-input" id="filterTitle" placeholder="请输入"></div>
|
||||
<div class="filter-item"><label>接收人</label><input class="filter-input" id="filterReceiver" placeholder="请输入"></div>
|
||||
<div class="filter-item"><label>发送状态</label><select class="filter-select" id="filterStatus"><option value="">请选择</option><option>发送成功</option><option>发送失败</option></select></div>
|
||||
<div class="filter-item"><label>发送方式</label><select class="filter-select" id="filterType"><option value="">请选择</option><option>短信</option><option>站内信</option></select></div>
|
||||
<button class="btn btn-primary" onclick="searchQuery()"><svg width="14" height="14" viewBox="0 0 14 14" fill="none"><circle cx="6" cy="6" r="4.5" stroke="#fff" stroke-width="1.3"/><path d="M9.5 9.5L13 13" stroke="#fff" stroke-width="1.3" stroke-linecap="round"/></svg>查询</button>
|
||||
<button class="btn btn-default" onclick="resetQuery()">重置</button>
|
||||
</div>
|
||||
<div class="table-card">
|
||||
<div class="table-card__content">
|
||||
<table>
|
||||
<thead><tr><th style="width:60px">序号</th><th style="width:150px">标题</th><th style="width:280px">发送内容</th><th style="width:120px">接收人</th><th style="width:100px">发送状态</th><th style="width:180px">发送时间</th><th style="width:90px">发送方式</th><th style="width:80px">操作</th></tr></thead>
|
||||
<tbody id="tableBody"></tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="pagination"><span>共 <b id="totalCount">0</b> 条</span><button class="page-btn" onclick="showToast('演示数据仅一页')">上一页</button><button class="page-btn active">1</button><button class="page-btn" onclick="showToast('演示数据仅一页')">下一页</button></div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<div class="modal-mask" id="detailMask">
|
||||
<div class="modal">
|
||||
<div class="modal__head"><span>短信详情</span><button class="modal__close" onclick="closeDetail()">×</button></div>
|
||||
<div class="modal__body" id="detailBody"></div>
|
||||
<div class="modal__footer"><button class="btn btn-default" onclick="closeDetail()">关闭</button></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="toast" id="toast"></div>
|
||||
|
||||
<script>
|
||||
var history=[
|
||||
{id:'1',title:'体检提醒',content:'【健康CQ】您本年度的健康体检报告已出具,请及时登录平台查看。',receiver:'张伟',status:'发送成功',time:'2026-09-01 09:00',type:'短信'},
|
||||
{id:'2',title:'体检提醒',content:'【健康CQ】您本年度的健康体检报告已出具,请及时登录平台查看。',receiver:'李艳',status:'发送成功',time:'2026-09-01 09:00',type:'短信'},
|
||||
{id:'3',title:'健康讲座通知',content:'【健康CQ】本周五下午举办健康讲座,欢迎参加。',receiver:'王强',status:'发送成功',time:'2026-09-05 10:00',type:'站内信'},
|
||||
{id:'4',title:'随访提醒',content:'【健康CQ】您有一项健康随访待完成。',receiver:'赵敏',status:'发送失败',time:'2026-09-11 08:30',type:'短信'}
|
||||
];
|
||||
function renderTable(){
|
||||
var list=history;
|
||||
document.getElementById('totalCount').textContent=list.length;
|
||||
document.getElementById('tableBody').innerHTML=list.map(function(h,i){
|
||||
return '<tr><td>'+(i+1)+'</td><td style="text-align:left;">'+h.title+'</td><td style="text-align:left;">'+h.content+'</td><td>'+h.receiver+'</td><td><span class="badge '+(h.status==='发送成功'?'badge--success':'badge--danger')+'">'+h.status+'</span></td><td>'+h.time+'</td><td>'+h.type+'</td><td><button class="btn btn-link" onclick="openDetail('+h.id+')">详情</button></td></tr>';
|
||||
}).join('');
|
||||
}
|
||||
function searchQuery(){renderTable();showToast('查询完成');}
|
||||
function resetQuery(){document.getElementById('filterTitle').value='';document.getElementById('filterReceiver').value='';document.getElementById('filterStatus').value='';document.getElementById('filterType').value='';renderTable();}
|
||||
function openDetail(id){
|
||||
var h=history.find(function(x){return x.id===id;});
|
||||
document.getElementById('detailBody').innerHTML=
|
||||
'<div class="detail-row"><label>标题</label><div class="val">'+h.title+'</div></div>'+
|
||||
'<div class="detail-row"><label>发送内容</label><div class="val">'+h.content+'</div></div>'+
|
||||
'<div class="detail-row"><label>接收人</label><div class="val">'+h.receiver+'</div></div>'+
|
||||
'<div class="detail-row"><label>发送状态</label><div class="val">'+h.status+'</div></div>'+
|
||||
'<div class="detail-row"><label>发送时间</label><div class="val">'+h.time+'</div></div>'+
|
||||
'<div class="detail-row"><label>发送方式</label><div class="val">'+h.type+'</div></div>';
|
||||
document.getElementById('detailMask').classList.add('open');
|
||||
}
|
||||
function closeDetail(){document.getElementById('detailMask').classList.remove('open');}
|
||||
function showToast(msg){var t=document.getElementById('toast');t.textContent=msg;t.classList.add('show');setTimeout(function(){t.classList.remove('show');},1500);}
|
||||
document.addEventListener('click',function(e){if(e.target===document.getElementById('detailMask'))closeDetail();});
|
||||
renderTable();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,174 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>发送短信 | 系统管理</title>
|
||||
<style>
|
||||
*{box-sizing:border-box;margin:0;padding:0;}
|
||||
body{font-family:-apple-system,BlinkMacSystemFont,'PingFang SC','Microsoft YaHei',sans-serif;font-size:var(--font-sm);background:#F5F7FA;color:#333;min-width:1280px;}
|
||||
:root{
|
||||
--primary:#1890FF;--primary-light:#E6F7FF;--success:#52C41A;--warning:#FAAD14;--danger:#FF4D4F;
|
||||
--text-primary:#333;--text-secondary:#666;--text-placeholder:#999;--border:#E8E8E8;--background:#F5F7FA;
|
||||
--font-xs:11px;--font-sm:13px;--font-base:15px;--font-lg:17px;
|
||||
--radius-sm:4px;--radius-md:8px;--radius-lg:12px;
|
||||
--shadow-sm:0 1px 4px rgba(0,0,0,0.08);--shadow-md:0 4px 12px rgba(0,0,0,0.10);
|
||||
}
|
||||
.top-bar{display:flex;align-items:center;height:56px;background:#001529;padding:0 24px;position:fixed;top:0;left:0;right:0;z-index:100;}
|
||||
.top-bar__logo{display:flex;align-items:center;gap:8px;color:#fff;font-size:var(--font-lg);font-weight:600;white-space:nowrap;width:200px;flex-shrink:0;}
|
||||
.top-bar__logo svg{width:28px;height:28px;}
|
||||
.top-bar__nav{display:flex;align-items:center;gap:4px;flex:1;}
|
||||
.top-bar__nav a{color:rgba(255,255,255,0.65);text-decoration:none;padding:6px 14px;border-radius:var(--radius-sm);font-size:var(--font-sm);transition:all .2s;}
|
||||
.top-bar__nav a:hover{color:#fff;background:rgba(255,255,255,0.08);}
|
||||
.top-bar__nav a.active{color:#fff;background:var(--primary);}
|
||||
.top-bar__right{display:flex;align-items:center;gap:16px;color:rgba(255,255,255,0.65);font-size:var(--font-sm);}
|
||||
.btn-back{color:rgba(255,255,255,0.65);cursor:pointer;display:flex;align-items:center;gap:4px;text-decoration:none;}
|
||||
.btn-back:hover{color:#fff;}
|
||||
.avatar{width:32px;height:32px;border-radius:50%;background:#1890FF;display:flex;align-items:center;justify-content:center;color:#fff;font-size:var(--font-sm);cursor:pointer;}
|
||||
.sidebar{position:fixed;top:56px;left:0;bottom:0;width:240px;background:#001529;overflow-y:auto;z-index:90;padding-top:8px;padding-bottom:24px;}
|
||||
.sidebar-menu__title{color:rgba(255,255,255,0.35);font-size:var(--font-xs);padding:16px 24px 8px;letter-spacing:.5px;}
|
||||
.sidebar-item{display:flex;align-items:center;gap:8px;padding:9px 24px;color:rgba(255,255,255,0.65);font-size:var(--font-sm);cursor:pointer;transition:all .15s;text-decoration:none;}
|
||||
.sidebar-item:hover{color:#fff;background:rgba(255,255,255,0.06);}
|
||||
.sidebar-item.active{color:#fff;background:var(--primary);}
|
||||
.main{margin-left:240px;margin-top:56px;padding:24px;min-height:calc(100vh - 56px);}
|
||||
.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;}
|
||||
.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);}
|
||||
.btn{height:36px;padding:0 16px;border-radius:var(--radius-sm);font-size:var(--font-sm);cursor:pointer;border:none;transition:all .2s;display:inline-flex;align-items:center;gap:6px;white-space:nowrap;}
|
||||
.btn-primary{background:var(--primary);color:#fff;}.btn-primary:hover{background:#40a9ff;}
|
||||
.btn-default{background:#fff;color:var(--text-primary);border:1px solid var(--border);}.btn-default:hover{color:var(--primary);border-color:var(--primary);}
|
||||
.btn-link{background:none;color:var(--primary);padding:0 4px;height:auto;}.btn-link:hover{color:#40a9ff;}
|
||||
.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);}
|
||||
.table-card{background:#fff;border-radius:0 0 var(--radius-md) var(--radius-md);box-shadow:var(--shadow-sm);overflow:hidden;}
|
||||
.table-card__content{overflow-x:auto;}
|
||||
table{width:100%;border-collapse:separate;border-spacing:0;min-width:1100px;}
|
||||
thead th{background:#FAFAFA;padding:10px 14px;text-align:center;font-size:var(--font-sm);color:var(--text-secondary);font-weight:500;border-bottom:1px solid var(--border);white-space:nowrap;}
|
||||
tbody td{padding:12px 14px;text-align:center;font-size:var(--font-sm);color:var(--text-primary);border-bottom:1px solid #F0F0F0;white-space:nowrap;}
|
||||
tbody tr:last-child td{border-bottom:none;}
|
||||
tbody tr:hover{background:#F8FBFF;}
|
||||
thead tr th:last-child,tbody td:last-child{position:sticky;right:0;z-index:5;background:#fff;box-shadow:-4px 0 8px rgba(0,0,0,0.04);}
|
||||
thead tr th:last-child{z-index:8;background:#FAFAFA;}
|
||||
tbody tr:hover td:last-child{background:#F8FBFF;}
|
||||
.td-empty{text-align:center;padding:48px 0;color:var(--text-placeholder);}
|
||||
.badge{display:inline-block;padding:2px 10px;border-radius:10px;font-size:var(--font-xs);}
|
||||
.badge--success{background:#F6FFED;color:#389E0D;border:1px solid #B7EB8F;}
|
||||
.badge--warning{background:#FFFBE6;color:#D48806;border:1px solid #FFE58F;}
|
||||
.badge--info{background:#E6F7FF;color:#096DD9;border:1px solid #91D5FF;}
|
||||
.pagination{display:flex;align-items:center;justify-content:flex-end;padding:16px 24px;gap:8px;border-top:1px solid var(--border);}
|
||||
.pagination span{font-size:var(--font-sm);color:var(--text-secondary);}
|
||||
.page-btn{min-width:32px;height:32px;border:1px solid var(--border);border-radius:var(--radius-sm);background:#fff;cursor:pointer;font-size:var(--font-sm);display:inline-flex;align-items:center;justify-content:center;padding:0 6px;transition:all .2s;}
|
||||
.page-btn:hover,.page-btn.active{background:var(--primary);color:#fff;border-color:var(--primary);}
|
||||
.modal-mask{display:none;position:fixed;inset:0;background:rgba(0,0,0,.45);z-index:950;align-items:center;justify-content:center;}
|
||||
.modal-mask.open{display:flex;}
|
||||
.modal{width:600px;background:#fff;border-radius:var(--radius-md);box-shadow:var(--shadow-md);}
|
||||
.modal__head{display:flex;align-items:center;justify-content:space-between;padding:16px 24px;border-bottom:1px solid var(--border);font-size:var(--font-base);font-weight:600;}
|
||||
.modal__close{cursor:pointer;color:var(--text-placeholder);font-size:20px;line-height:1;border:none;background:none;}
|
||||
.modal__body{padding:24px;max-height:60vh;overflow-y:auto;}
|
||||
.modal__footer{display:flex;justify-content:flex-end;gap:8px;padding:12px 24px;border-top:1px solid var(--border);}
|
||||
.form-item{display:flex;align-items:flex-start;margin-bottom:18px;}
|
||||
.form-item label{width:88px;min-width:88px;text-align:right;padding-right:12px;font-size:var(--font-sm);color:var(--text-secondary);line-height:36px;}
|
||||
.form-item label .req{color:var(--danger);margin-right:2px;}
|
||||
.form-item .control{flex:1;}
|
||||
.form-input{width:100%;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;}
|
||||
.form-input:focus{border-color:var(--primary);box-shadow:0 0 0 2px rgba(24,144,255,0.1);}
|
||||
.form-textarea{width:100%;border:1px solid var(--border);border-radius:var(--radius-sm);padding:8px 12px;font-size:var(--font-sm);color:var(--text-primary);outline:none;resize:vertical;min-height:100px;line-height:1.6;}
|
||||
.form-textarea:focus{border-color:var(--primary);box-shadow:0 0 0 2px rgba(24,144,255,0.1);}
|
||||
.toast{position:fixed;top:80px;left:50%;transform:translateX(-50%);background:#333;color:#fff;padding:10px 24px;border-radius:var(--radius-sm);font-size:var(--font-sm);z-index:9999;opacity:0;transition:opacity .2s;pointer-events:none;}
|
||||
.toast.show{opacity:1;}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="top-bar">
|
||||
<div class="top-bar__logo"><svg viewBox="0 0 28 28" fill="none"><rect width="28" height="28" rx="6" fill="#1890FF"/><path d="M14 6.5l7 3.5v4.5c0 4.2-2.9 6.8-7 7.5-4.1-.7-7-3.3-7-7.5V10l7-3.5z" stroke="#fff" stroke-width="1.8" fill="none"/><path d="M11 13.5h6M14 10.5v6" stroke="#fff" stroke-width="1.8" stroke-linecap="round"/></svg> 系统管理</div>
|
||||
<nav class="top-bar__nav">
|
||||
<a href="user-admin.html">用户管理</a>
|
||||
<a href="application.html">权限管理</a>
|
||||
<a href="hospital.html">机构管理</a>
|
||||
<a href="dict.html">系统配置</a>
|
||||
<a href="announcement.html" class="active">通知管理</a>
|
||||
</nav>
|
||||
<div class="top-bar__right">
|
||||
<a class="btn-back" href="../../index.html"><svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M10 3L5 8l5 5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg> 返回首页</a>
|
||||
<div class="avatar">管</div>
|
||||
<span style="color:rgba(255,255,255,0.65);">系统管理员 ▾</span>
|
||||
</div>
|
||||
</div>
|
||||
<aside class="sidebar">
|
||||
<div class="sidebar-menu__title">通知管理</div>
|
||||
<a href="announcement.html" class="sidebar-item">公告</a>
|
||||
<a href="sms-send.html" class="sidebar-item active">发送短信</a>
|
||||
<a href="sms-history.html" class="sidebar-item">短信发送历史</a>
|
||||
<a href="sms-template.html" class="sidebar-item">短信模板</a>
|
||||
</aside>
|
||||
|
||||
<main class="main">
|
||||
<div class="filter-bar">
|
||||
<div class="filter-item"><label>消息标题</label><input class="filter-input" id="filterTitle" placeholder="请输入"></div>
|
||||
<div class="filter-item"><label>发送状态</label><select class="filter-select" id="filterStatus"><option value="">请选择</option><option>待发送</option><option>发送中</option><option>已发送</option><option>发送失败</option></select></div>
|
||||
<button class="btn btn-primary" onclick="searchQuery()"><svg width="14" height="14" viewBox="0 0 14 14" fill="none"><circle cx="6" cy="6" r="4.5" stroke="#fff" stroke-width="1.3"/><path d="M9.5 9.5L13 13" stroke="#fff" stroke-width="1.3" stroke-linecap="round"/></svg>搜索</button>
|
||||
<button class="btn btn-default" onclick="resetQuery()">重置</button>
|
||||
</div>
|
||||
<div class="action-bar">
|
||||
<button class="btn btn-primary" onclick="openAdd()"><svg width="14" height="14" viewBox="0 0 14 14" fill="none"><path d="M7 2v10M2 7h10" stroke="currentColor" stroke-width="1.4" stroke-linecap="round"/></svg>新增</button>
|
||||
</div>
|
||||
<div class="table-card">
|
||||
<div class="table-card__content">
|
||||
<table>
|
||||
<thead><tr><th style="width:60px">序号</th><th style="width:160px">标题</th><th style="width:240px">通知对象</th><th style="width:100px">发送状态</th><th style="width:100px">发送人</th><th style="width:180px">创建时间</th><th style="width:110px">发布进度</th><th style="width:100px">操作</th></tr></thead>
|
||||
<tbody id="tableBody"></tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="pagination"><span>共 <b id="totalCount">0</b> 条</span><button class="page-btn" onclick="showToast('演示数据仅一页')">上一页</button><button class="page-btn active">1</button><button class="page-btn" onclick="showToast('演示数据仅一页')">下一页</button></div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<div class="modal-mask" id="smsMask">
|
||||
<div class="modal">
|
||||
<div class="modal__head"><span>新增短信</span><button class="modal__close" onclick="closeModal()">×</button></div>
|
||||
<div class="modal__body">
|
||||
<div class="form-item"><label><span class="req">*</span>标题</label><div class="control"><input class="form-input" id="fTitle" placeholder="请输入标题"></div></div>
|
||||
<div class="form-item"><label><span class="req">*</span>通知对象</label><div class="control"><select class="form-input" id="fType" onchange="onTypeChange()"><option value="全员">全员</option><option value="指定机构">指定机构</option><option value="指定员工">指定员工</option><option value="指定专家">指定专家</option></select></div></div>
|
||||
<div class="form-item" id="selectUserRow" style="display:none;"><label>选择人员</label><div class="control"><input class="form-input" id="fUsers" readonly placeholder="点击选择人员" onclick="showToast('打开选择人员弹窗')"></div></div>
|
||||
<div class="form-item"><label><span class="req">*</span>短信内容</label><div class="control"><textarea class="form-textarea" id="fContent" placeholder="请输入短信内容"></textarea></div></div>
|
||||
</div>
|
||||
<div class="modal__footer"><button class="btn btn-default" onclick="closeModal()">取消</button><button class="btn btn-primary" onclick="submitForm()">确定</button></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="toast" id="toast"></div>
|
||||
|
||||
<script>
|
||||
var sms=[
|
||||
{id:'1',title:'体检提醒',target:'全员',status:'已发送',sender:'系统管理员',time:'2026-09-01 09:00',progress:'320/320'},
|
||||
{id:'2',title:'健康讲座通知',target:'采油一厂',status:'已发送',sender:'运营管理员',time:'2026-09-05 10:00',progress:'156/156'},
|
||||
{id:'3',title:'随访提醒',target:'高血压员工',status:'发送中',sender:'系统管理员',time:'2026-09-11 08:30',progress:'86/210'},
|
||||
{id:'4',title:'体检报告已出',target:'指定员工',status:'待发送',sender:'运营管理员',time:'2026-09-11 09:00',progress:'0/45'}
|
||||
];
|
||||
function statusBadge(s){return s==='已发送'?'badge--success':s==='发送中'?'badge--info':s==='待发送'?'badge--warning':'badge--warning';}
|
||||
function renderTable(){
|
||||
var list=sms;
|
||||
document.getElementById('totalCount').textContent=list.length;
|
||||
document.getElementById('tableBody').innerHTML=list.map(function(s,i){
|
||||
return '<tr><td>'+(i+1)+'</td><td style="text-align:left;">'+s.title+'</td><td>'+s.target+'</td><td><span class="badge '+statusBadge(s.status)+'">'+s.status+'</span></td><td>'+s.sender+'</td><td>'+s.time+'</td><td>'+s.progress+'</td><td><button class="btn btn-link" onclick="showToast(\'查看详情\')">详情</button></td></tr>';
|
||||
}).join('');
|
||||
}
|
||||
function searchQuery(){renderTable();showToast('搜索完成');}
|
||||
function resetQuery(){document.getElementById('filterTitle').value='';document.getElementById('filterStatus').value='';renderTable();}
|
||||
function onTypeChange(){var v=document.getElementById('fType').value;document.getElementById('selectUserRow').style.display=v==='全员'?'none':'flex';}
|
||||
function openAdd(){document.getElementById('fTitle').value='';document.getElementById('fContent').value='';document.getElementById('fType').value='全员';document.getElementById('fUsers').value='';onTypeChange();document.getElementById('smsMask').classList.add('open');}
|
||||
function closeModal(){document.getElementById('smsMask').classList.remove('open');}
|
||||
function submitForm(){
|
||||
var title=document.getElementById('fTitle').value.trim();if(!title){showToast('请输入标题');return;}
|
||||
var content=document.getElementById('fContent').value.trim();if(!content){showToast('请输入短信内容');return;}
|
||||
var target=document.getElementById('fType').value;
|
||||
sms.push({id:String(sms.length+1),title:title,target:target,status:'待发送',sender:'系统管理员',time:'2026-09-11 10:00',progress:'0/0'});
|
||||
closeModal();renderTable();showToast('新增成功');
|
||||
}
|
||||
function showToast(msg){var t=document.getElementById('toast');t.textContent=msg;t.classList.add('show');setTimeout(function(){t.classList.remove('show');},1500);}
|
||||
document.addEventListener('click',function(e){if(e.target===document.getElementById('smsMask'))closeModal();});
|
||||
renderTable();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,192 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>短信模板 | 系统管理</title>
|
||||
<style>
|
||||
*{box-sizing:border-box;margin:0;padding:0;}
|
||||
body{font-family:-apple-system,BlinkMacSystemFont,'PingFang SC','Microsoft YaHei',sans-serif;font-size:var(--font-sm);background:#F5F7FA;color:#333;min-width:1280px;}
|
||||
:root{
|
||||
--primary:#1890FF;--primary-light:#E6F7FF;--success:#52C41A;--warning:#FAAD14;--danger:#FF4D4F;
|
||||
--text-primary:#333;--text-secondary:#666;--text-placeholder:#999;--border:#E8E8E8;--background:#F5F7FA;
|
||||
--font-xs:11px;--font-sm:13px;--font-base:15px;--font-lg:17px;
|
||||
--radius-sm:4px;--radius-md:8px;--radius-lg:12px;
|
||||
--shadow-sm:0 1px 4px rgba(0,0,0,0.08);--shadow-md:0 4px 12px rgba(0,0,0,0.10);
|
||||
}
|
||||
.top-bar{display:flex;align-items:center;height:56px;background:#001529;padding:0 24px;position:fixed;top:0;left:0;right:0;z-index:100;}
|
||||
.top-bar__logo{display:flex;align-items:center;gap:8px;color:#fff;font-size:var(--font-lg);font-weight:600;white-space:nowrap;width:200px;flex-shrink:0;}
|
||||
.top-bar__logo svg{width:28px;height:28px;}
|
||||
.top-bar__nav{display:flex;align-items:center;gap:4px;flex:1;}
|
||||
.top-bar__nav a{color:rgba(255,255,255,0.65);text-decoration:none;padding:6px 14px;border-radius:var(--radius-sm);font-size:var(--font-sm);transition:all .2s;}
|
||||
.top-bar__nav a:hover{color:#fff;background:rgba(255,255,255,0.08);}
|
||||
.top-bar__nav a.active{color:#fff;background:var(--primary);}
|
||||
.top-bar__right{display:flex;align-items:center;gap:16px;color:rgba(255,255,255,0.65);font-size:var(--font-sm);}
|
||||
.btn-back{color:rgba(255,255,255,0.65);cursor:pointer;display:flex;align-items:center;gap:4px;text-decoration:none;}
|
||||
.btn-back:hover{color:#fff;}
|
||||
.avatar{width:32px;height:32px;border-radius:50%;background:#1890FF;display:flex;align-items:center;justify-content:center;color:#fff;font-size:var(--font-sm);cursor:pointer;}
|
||||
.sidebar{position:fixed;top:56px;left:0;bottom:0;width:240px;background:#001529;overflow-y:auto;z-index:90;padding-top:8px;padding-bottom:24px;}
|
||||
.sidebar-menu__title{color:rgba(255,255,255,0.35);font-size:var(--font-xs);padding:16px 24px 8px;letter-spacing:.5px;}
|
||||
.sidebar-item{display:flex;align-items:center;gap:8px;padding:9px 24px;color:rgba(255,255,255,0.65);font-size:var(--font-sm);cursor:pointer;transition:all .15s;text-decoration:none;}
|
||||
.sidebar-item:hover{color:#fff;background:rgba(255,255,255,0.06);}
|
||||
.sidebar-item.active{color:#fff;background:var(--primary);}
|
||||
.main{margin-left:240px;margin-top:56px;padding:24px;min-height:calc(100vh - 56px);}
|
||||
.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;}
|
||||
.filter-select{height:36px;min-width:120px;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);}
|
||||
.btn{height:36px;padding:0 16px;border-radius:var(--radius-sm);font-size:var(--font-sm);cursor:pointer;border:none;transition:all .2s;display:inline-flex;align-items:center;gap:6px;white-space:nowrap;}
|
||||
.btn-primary{background:var(--primary);color:#fff;}.btn-primary:hover{background:#40a9ff;}
|
||||
.btn-default{background:#fff;color:var(--text-primary);border:1px solid var(--border);}.btn-default:hover{color:var(--primary);border-color:var(--primary);}
|
||||
.btn-danger{background:var(--danger);color:#fff;}.btn-danger:hover{background:#ff7875;}
|
||||
.btn-link{background:none;color:var(--primary);padding:0 4px;height:auto;}.btn-link:hover{color:#40a9ff;}
|
||||
.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);}
|
||||
.table-card{background:#fff;border-radius:0 0 var(--radius-md) var(--radius-md);box-shadow:var(--shadow-sm);overflow:hidden;}
|
||||
.table-card__content{overflow-x:auto;}
|
||||
table{width:100%;border-collapse:separate;border-spacing:0;min-width:1100px;}
|
||||
thead th{background:#FAFAFA;padding:10px 14px;text-align:center;font-size:var(--font-sm);color:var(--text-secondary);font-weight:500;border-bottom:1px solid var(--border);white-space:nowrap;}
|
||||
tbody td{padding:12px 14px;text-align:center;font-size:var(--font-sm);color:var(--text-primary);border-bottom:1px solid #F0F0F0;white-space:nowrap;}
|
||||
tbody tr:last-child td{border-bottom:none;}
|
||||
tbody tr:hover{background:#F8FBFF;}
|
||||
thead tr th:last-child,tbody td:last-child{position:sticky;right:0;z-index:5;background:#fff;box-shadow:-4px 0 8px rgba(0,0,0,0.04);}
|
||||
thead tr th:last-child{z-index:8;background:#FAFAFA;}
|
||||
tbody tr:hover td:last-child{background:#F8FBFF;}
|
||||
.td-empty{text-align:center;padding:48px 0;color:var(--text-placeholder);}
|
||||
.badge{display:inline-block;padding:2px 10px;border-radius:10px;font-size:var(--font-xs);}
|
||||
.badge--success{background:#F6FFED;color:#389E0D;border:1px solid #B7EB8F;}
|
||||
.badge--muted{background:#F5F5F5;color:var(--text-secondary);border:1px solid var(--border);}
|
||||
.pagination{display:flex;align-items:center;justify-content:flex-end;padding:16px 24px;gap:8px;border-top:1px solid var(--border);}
|
||||
.pagination span{font-size:var(--font-sm);color:var(--text-secondary);}
|
||||
.page-btn{min-width:32px;height:32px;border:1px solid var(--border);border-radius:var(--radius-sm);background:#fff;cursor:pointer;font-size:var(--font-sm);display:inline-flex;align-items:center;justify-content:center;padding:0 6px;transition:all .2s;}
|
||||
.page-btn:hover,.page-btn.active{background:var(--primary);color:#fff;border-color:var(--primary);}
|
||||
.modal-mask{display:none;position:fixed;inset:0;background:rgba(0,0,0,.45);z-index:950;align-items:center;justify-content:center;}
|
||||
.modal-mask.open{display:flex;}
|
||||
.modal{width:600px;background:#fff;border-radius:var(--radius-md);box-shadow:var(--shadow-md);}
|
||||
.modal__head{display:flex;align-items:center;justify-content:space-between;padding:16px 24px;border-bottom:1px solid var(--border);font-size:var(--font-base);font-weight:600;}
|
||||
.modal__close{cursor:pointer;color:var(--text-placeholder);font-size:20px;line-height:1;border:none;background:none;}
|
||||
.modal__body{padding:24px;max-height:60vh;overflow-y:auto;}
|
||||
.modal__footer{display:flex;justify-content:flex-end;gap:8px;padding:12px 24px;border-top:1px solid var(--border);}
|
||||
.form-item{display:flex;align-items:flex-start;margin-bottom:18px;}
|
||||
.form-item label{width:88px;min-width:88px;text-align:right;padding-right:12px;font-size:var(--font-sm);color:var(--text-secondary);line-height:36px;}
|
||||
.form-item label .req{color:var(--danger);margin-right:2px;}
|
||||
.form-item .control{flex:1;}
|
||||
.form-input{width:100%;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;}
|
||||
.form-input:focus{border-color:var(--primary);box-shadow:0 0 0 2px rgba(24,144,255,0.1);}
|
||||
.form-textarea{width:100%;border:1px solid var(--border);border-radius:var(--radius-sm);padding:8px 12px;font-size:var(--font-sm);color:var(--text-primary);outline:none;resize:vertical;min-height:100px;line-height:1.6;}
|
||||
.form-textarea:focus{border-color:var(--primary);box-shadow:0 0 0 2px rgba(24,144,255,0.1);}
|
||||
.toast{position:fixed;top:80px;left:50%;transform:translateX(-50%);background:#333;color:#fff;padding:10px 24px;border-radius:var(--radius-sm);font-size:var(--font-sm);z-index:9999;opacity:0;transition:opacity .2s;pointer-events:none;}
|
||||
.toast.show{opacity:1;}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="top-bar">
|
||||
<div class="top-bar__logo"><svg viewBox="0 0 28 28" fill="none"><rect width="28" height="28" rx="6" fill="#1890FF"/><path d="M14 6.5l7 3.5v4.5c0 4.2-2.9 6.8-7 7.5-4.1-.7-7-3.3-7-7.5V10l7-3.5z" stroke="#fff" stroke-width="1.8" fill="none"/><path d="M11 13.5h6M14 10.5v6" stroke="#fff" stroke-width="1.8" stroke-linecap="round"/></svg> 系统管理</div>
|
||||
<nav class="top-bar__nav">
|
||||
<a href="user-admin.html">用户管理</a>
|
||||
<a href="application.html">权限管理</a>
|
||||
<a href="hospital.html">机构管理</a>
|
||||
<a href="dict.html">系统配置</a>
|
||||
<a href="announcement.html" class="active">通知管理</a>
|
||||
</nav>
|
||||
<div class="top-bar__right">
|
||||
<a class="btn-back" href="../../index.html"><svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M10 3L5 8l5 5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg> 返回首页</a>
|
||||
<div class="avatar">管</div>
|
||||
<span style="color:rgba(255,255,255,0.65);">系统管理员 ▾</span>
|
||||
</div>
|
||||
</div>
|
||||
<aside class="sidebar">
|
||||
<div class="sidebar-menu__title">通知管理</div>
|
||||
<a href="announcement.html" class="sidebar-item">公告</a>
|
||||
<a href="sms-send.html" class="sidebar-item">发送短信</a>
|
||||
<a href="sms-history.html" class="sidebar-item">短信发送历史</a>
|
||||
<a href="sms-template.html" class="sidebar-item active">短信模板</a>
|
||||
</aside>
|
||||
|
||||
<main class="main">
|
||||
<div class="filter-bar">
|
||||
<div class="filter-item"><label>标题</label><input class="filter-input" id="filterName" placeholder="请输入"></div>
|
||||
<div class="filter-item"><label>编码</label><input class="filter-input" id="filterCode" placeholder="请输入"></div>
|
||||
<div class="filter-item"><label>是否应用</label><select class="filter-select" id="filterStatus"><option value="">请选择</option><option>已应用</option><option>未应用</option></select></div>
|
||||
<button class="btn btn-primary" onclick="searchQuery()"><svg width="14" height="14" viewBox="0 0 14 14" fill="none"><circle cx="6" cy="6" r="4.5" stroke="#fff" stroke-width="1.3"/><path d="M9.5 9.5L13 13" stroke="#fff" stroke-width="1.3" stroke-linecap="round"/></svg>搜索</button>
|
||||
<button class="btn btn-default" onclick="resetQuery()">重置</button>
|
||||
</div>
|
||||
<div class="action-bar">
|
||||
<button class="btn btn-primary" onclick="openModal('add',null)"><svg width="14" height="14" viewBox="0 0 14 14" fill="none"><path d="M7 2v10M2 7h10" stroke="currentColor" stroke-width="1.4" stroke-linecap="round"/></svg>新增</button>
|
||||
<button class="btn btn-danger" onclick="batchDelete()">批量删除</button>
|
||||
</div>
|
||||
<div class="table-card">
|
||||
<div class="table-card__content">
|
||||
<table>
|
||||
<thead><tr><th style="width:44px"><input type="checkbox" onchange="toggleAll(this)"></th><th style="width:60px">序号</th><th style="width:150px">标题</th><th style="width:200px">编码</th><th style="width:280px">内容</th><th style="width:100px">是否应用</th><th style="width:220px">操作</th></tr></thead>
|
||||
<tbody id="tableBody"></tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="pagination"><span>共 <b id="totalCount">0</b> 条</span><button class="page-btn" onclick="showToast('演示数据仅一页')">上一页</button><button class="page-btn active">1</button><button class="page-btn" onclick="showToast('演示数据仅一页')">下一页</button></div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<div class="modal-mask" id="tplMask">
|
||||
<div class="modal">
|
||||
<div class="modal__head"><span id="tplTitle">新增模板</span><button class="modal__close" onclick="closeModal()">×</button></div>
|
||||
<div class="modal__body">
|
||||
<div class="form-item"><label><span class="req">*</span>模板标题</label><div class="control"><input class="form-input" id="fName" placeholder="请输入"></div></div>
|
||||
<div class="form-item"><label><span class="req">*</span>模板编码</label><div class="control"><input class="form-input" id="fCode" placeholder="请输入"></div></div>
|
||||
<div class="form-item"><label><span class="req">*</span>模板内容</label><div class="control"><textarea class="form-textarea" id="fContent" placeholder="请输入模板内容"></textarea></div></div>
|
||||
<div class="form-item"><label>是否应用</label><div class="control"><select class="form-input" id="fStatus"><option>已应用</option><option>未应用</option></select></div></div>
|
||||
</div>
|
||||
<div class="modal__footer"><button class="btn btn-default" onclick="closeModal()">取消</button><button class="btn btn-primary" onclick="submitForm()">确定</button></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="toast" id="toast"></div>
|
||||
|
||||
<script>
|
||||
var templates=[
|
||||
{id:'1',name:'体检报告通知',code:'SMS_HEALTH_REPORT',content:'【健康CQ】尊敬的{姓名},您本年度的健康体检报告已出具,请及时登录平台查看。',status:'已应用'},
|
||||
{id:'2',name:'体检预约提醒',code:'SMS_EXAM_APPOINT',content:'【健康CQ】您已成功预约{日期}的健康体检,请按时前往体检中心。',status:'已应用'},
|
||||
{id:'3',name:'随访提醒',code:'SMS_FOLLOW_UP',content:'【健康CQ】您有一项健康随访待完成,请及时处理。',status:'未应用'}
|
||||
];
|
||||
var editingId=null;
|
||||
function renderTable(){
|
||||
var list=templates;
|
||||
document.getElementById('totalCount').textContent=list.length;
|
||||
document.getElementById('tableBody').innerHTML=list.map(function(t,i){
|
||||
return '<tr><td><input type="checkbox" class="tplCheck"></td><td>'+(i+1)+'</td><td style="text-align:left;">'+t.name+'</td><td>'+t.code+'</td><td style="text-align:left;">'+t.content+'</td><td><span class="badge '+(t.status==='已应用'?'badge--success':'badge--muted')+'">'+t.status+'</span></td>'+
|
||||
'<td><button class="btn btn-link" onclick="showToast(\'发送测试短信\')">发送测试</button><span style="color:var(--border);margin:0 4px;">|</span><button class="btn btn-link" onclick="showToast(\'查看详情\')">详情</button><span style="color:var(--border);margin:0 4px;">|</span><button class="btn btn-link" onclick="openModal(\'edit\','+t.id+')">编辑</button><span style="color:var(--border);margin:0 4px;">|</span><button class="btn btn-link" style="color:var(--danger);" onclick="delTpl('+t.id+')">删除</button></td></tr>';
|
||||
}).join('');
|
||||
}
|
||||
function searchQuery(){renderTable();showToast('搜索完成');}
|
||||
function resetQuery(){document.getElementById('filterName').value='';document.getElementById('filterCode').value='';document.getElementById('filterStatus').value='';renderTable();}
|
||||
function toggleAll(el){document.querySelectorAll('.tplCheck').forEach(function(c){c.checked=el.checked;});}
|
||||
function batchDelete(){
|
||||
var checked=document.querySelectorAll('.tplCheck:checked').length;
|
||||
if(!checked){showToast('请先选择要删除的模板');return;}
|
||||
if(!confirm('确定删除选中的 '+checked+' 个模板吗?'))return;
|
||||
templates=templates.filter(function(t,i){return !document.querySelectorAll('.tplCheck')[i].checked;});
|
||||
renderTable();showToast('批量删除成功');
|
||||
}
|
||||
function delTpl(id){if(!confirm('确定删除该模板吗?'))return;templates=templates.filter(function(t){return t.id!==id;});renderTable();showToast('删除成功');}
|
||||
function openModal(type,id){
|
||||
editingId=id;
|
||||
document.getElementById('tplTitle').textContent=type==='add'?'新增模板':'编辑模板';
|
||||
document.getElementById('fName').value='';document.getElementById('fCode').value='';document.getElementById('fContent').value='';document.getElementById('fStatus').value='未应用';
|
||||
if(type==='edit'&&id){var t=templates.find(function(x){return x.id===id;});if(t){document.getElementById('fName').value=t.name;document.getElementById('fCode').value=t.code;document.getElementById('fContent').value=t.content;document.getElementById('fStatus').value=t.status;}}
|
||||
document.getElementById('tplMask').classList.add('open');
|
||||
}
|
||||
function closeModal(){document.getElementById('tplMask').classList.remove('open');}
|
||||
function submitForm(){
|
||||
var name=document.getElementById('fName').value.trim();if(!name){showToast('请输入模板标题');return;}
|
||||
var code=document.getElementById('fCode').value.trim();if(!code){showToast('请输入模板编码');return;}
|
||||
var content=document.getElementById('fContent').value.trim();if(!content){showToast('请输入模板内容');return;}
|
||||
var status=document.getElementById('fStatus').value;
|
||||
if(editingId){var t=templates.find(function(x){return x.id===editingId;});if(t){t.name=name;t.code=code;t.content=content;t.status=status;}}
|
||||
else templates.push({id:String(templates.length+1),name:name,code:code,content:content,status:status});
|
||||
closeModal();renderTable();showToast(editingId?'编辑成功':'新增成功');
|
||||
}
|
||||
function showToast(msg){var t=document.getElementById('toast');t.textContent=msg;t.classList.add('show');setTimeout(function(){t.classList.remove('show');},1500);}
|
||||
document.addEventListener('click',function(e){if(e.target===document.getElementById('tplMask'))closeModal();});
|
||||
renderTable();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,626 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>单位管理 | 系统管理</title>
|
||||
<style>
|
||||
*{box-sizing:border-box;margin:0;padding:0;}
|
||||
body{font-family:-apple-system,BlinkMacSystemFont,'PingFang SC','Microsoft YaHei',sans-serif;font-size:var(--font-sm);background:#F5F7FA;color:#333;min-width:1280px;}
|
||||
:root{
|
||||
--primary:#1890FF;--primary-light:#E6F7FF;--success:#52C41A;--warning:#FAAD14;--danger:#FF4D4F;
|
||||
--text-primary:#333;--text-secondary:#666;--text-placeholder:#999;--border:#E8E8E8;--background:#F5F7FA;
|
||||
--font-xs:11px;--font-sm:13px;--font-base:15px;--font-lg:17px;
|
||||
--radius-sm:4px;--radius-md:8px;--radius-lg:12px;
|
||||
--shadow-sm:0 1px 4px rgba(0,0,0,0.08);--shadow-md:0 4px 12px rgba(0,0,0,0.10);
|
||||
}
|
||||
.top-bar{display:flex;align-items:center;height:56px;background:#001529;padding:0 24px;position:fixed;top:0;left:0;right:0;z-index:100;}
|
||||
.top-bar__logo{display:flex;align-items:center;gap:8px;color:#fff;font-size:var(--font-lg);font-weight:600;white-space:nowrap;width:200px;flex-shrink:0;}
|
||||
.top-bar__logo svg{width:28px;height:28px;}
|
||||
.top-bar__nav{display:flex;align-items:center;gap:4px;flex:1;}
|
||||
.top-bar__nav a{color:rgba(255,255,255,0.65);text-decoration:none;padding:6px 14px;border-radius:var(--radius-sm);font-size:var(--font-sm);transition:all .2s;}
|
||||
.top-bar__nav a:hover{color:#fff;background:rgba(255,255,255,0.08);}
|
||||
.top-bar__nav a.active{color:#fff;background:var(--primary);}
|
||||
.top-bar__right{display:flex;align-items:center;gap:16px;color:rgba(255,255,255,0.65);font-size:var(--font-sm);}
|
||||
.btn-back{color:rgba(255,255,255,0.65);cursor:pointer;display:flex;align-items:center;gap:4px;text-decoration:none;}
|
||||
.btn-back:hover{color:#fff;}
|
||||
.avatar{width:32px;height:32px;border-radius:50%;background:#1890FF;display:flex;align-items:center;justify-content:center;color:#fff;font-size:var(--font-sm);cursor:pointer;}
|
||||
.sidebar{position:fixed;top:56px;left:0;bottom:0;width:240px;background:#001529;overflow-y:auto;z-index:90;padding-top:8px;padding-bottom:24px;}
|
||||
.sidebar-menu__title{color:rgba(255,255,255,0.35);font-size:var(--font-xs);padding:16px 24px 8px;letter-spacing:.5px;}
|
||||
.sidebar-item{display:flex;align-items:center;gap:8px;padding:9px 24px;color:rgba(255,255,255,0.65);font-size:var(--font-sm);cursor:pointer;transition:all .15s;text-decoration:none;}
|
||||
.sidebar-item:hover{color:#fff;background:rgba(255,255,255,0.06);}
|
||||
.sidebar-item.active{color:#fff;background:var(--primary);}
|
||||
.main{margin-left:240px;margin-top:56px;padding:24px;min-height:calc(100vh - 56px);}
|
||||
.btn{height:36px;padding:0 16px;border-radius:var(--radius-sm);font-size:var(--font-sm);cursor:pointer;border:none;transition:all .2s;display:inline-flex;align-items:center;gap:6px;white-space:nowrap;}
|
||||
.btn-primary{background:var(--primary);color:#fff;}.btn-primary:hover{background:#40a9ff;}
|
||||
.btn-default{background:#fff;color:var(--text-primary);border:1px solid var(--border);}.btn-default:hover{color:var(--primary);border-color:var(--primary);}
|
||||
.btn-danger{background:var(--danger);color:#fff;}.btn-danger:hover{background:#ff7875;}
|
||||
.btn-link{background:none;color:var(--primary);padding:0 4px;height:auto;}.btn-link:hover{color:#40a9ff;}
|
||||
/* 左右分栏 */
|
||||
.unit-layout{display:flex;gap:16px;align-items:stretch;}
|
||||
.card{background:#fff;border-radius:var(--radius-md);box-shadow:var(--shadow-sm);}
|
||||
.unit-left{width:340px;flex-shrink:0;display:flex;flex-direction:column;max-height:calc(100vh - 104px);}
|
||||
.unit-left__header{padding:16px 16px 12px;border-bottom:1px solid var(--border);}
|
||||
.unit-left__header .row1{display:flex;align-items:center;justify-content:space-between;margin-bottom:12px;}
|
||||
.unit-left__header .title{font-size:var(--font-base);font-weight:600;}
|
||||
.unit-left__header .btns{display:flex;gap:12px;align-items:center;}
|
||||
.unit-left__header .btns span{display:inline-flex;align-items:center;gap:4px;font-size:var(--font-sm);color:var(--text-secondary);cursor:pointer;}
|
||||
.unit-left__header .btns span:hover{color:var(--primary);}
|
||||
.unit-search{position:relative;margin-bottom:8px;}
|
||||
.unit-search input{width:100%;height:34px;border:1px solid var(--border);border-radius:var(--radius-sm);padding:0 12px;font-size:var(--font-sm);outline:none;}
|
||||
.unit-search input:focus{border-color:var(--primary);}
|
||||
.unit-left__body{flex:1;overflow-y:auto;padding:12px;}
|
||||
.unit-node__row{display:flex;align-items:center;padding:7px 8px;border-radius:var(--radius-sm);cursor:pointer;transition:background .12s;}
|
||||
.unit-node__row:hover{background:#F5F5F5;}
|
||||
.unit-node__row.active{background:var(--primary-light);}
|
||||
.unit-node__row.active .unit-node__name{color:var(--primary);font-weight:500;}
|
||||
.unit-node__arrow{width:16px;color:var(--text-placeholder);font-size:var(--font-xs);cursor:pointer;user-select:none;flex-shrink:0;}
|
||||
.unit-node__name{flex:1;font-size:var(--font-sm);color:var(--text-primary);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}
|
||||
.unit-node__actions{display:none;gap:2px;flex-shrink:0;}
|
||||
.unit-node__row:hover .unit-node__actions{display:flex;}
|
||||
.unit-node__actions span{font-size:var(--font-xs);color:var(--primary);padding:0 4px;cursor:pointer;}
|
||||
.unit-node__actions span.del{color:var(--danger);}
|
||||
.unit-empty{text-align:center;padding:40px 0;color:var(--text-placeholder);}
|
||||
/* 右侧 */
|
||||
.unit-right{flex:1;min-width:0;display:flex;flex-direction:column;max-height:calc(100vh - 104px);}
|
||||
.tabs{display:flex;border-bottom:1px solid var(--border);padding:0 16px;flex-shrink:0;}
|
||||
.tab{position:relative;padding:14px 16px;font-size:var(--font-sm);color:var(--text-secondary);cursor:pointer;user-select:none;}
|
||||
.tab:hover{color:var(--primary);}
|
||||
.tab.active{color:var(--primary);font-weight:500;}
|
||||
.tab.active::after{content:'';position:absolute;left:16px;right:16px;bottom:-1px;height:2px;background:var(--primary);}
|
||||
.tab-panel{flex:1;overflow-y:auto;display:none;padding:20px;}
|
||||
.tab-panel.active{display:block;}
|
||||
.right-empty{flex:1;display:flex;align-items:center;justify-content:center;color:var(--text-placeholder);}
|
||||
/* 表单 */
|
||||
.form-item{display:flex;align-items:flex-start;margin-bottom:16px;}
|
||||
.form-item label{width:90px;min-width:90px;text-align:right;padding-right:12px;font-size:var(--font-sm);color:var(--text-secondary);line-height:36px;}
|
||||
.form-item label .req{color:var(--danger);margin-right:2px;}
|
||||
.form-item .control{flex:1;font-size:var(--font-sm);line-height:36px;color:var(--text-primary);}
|
||||
.form-input{width:100%;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;}
|
||||
.form-input:focus{border-color:var(--primary);box-shadow:0 0 0 2px rgba(24,144,255,0.1);}
|
||||
.form-input[readonly]{background:#F5F5F5;color:var(--text-secondary);}
|
||||
.form-textarea{width:100%;border:1px solid var(--border);border-radius:var(--radius-sm);padding:8px 12px;font-size:var(--font-sm);color:var(--text-primary);outline:none;resize:vertical;min-height:68px;line-height:1.6;}
|
||||
.form-textarea:focus{border-color:var(--primary);box-shadow:0 0 0 2px rgba(24,144,255,0.1);}
|
||||
.basic-form{display:flex;gap:20px;}
|
||||
.basic-form__left{flex:1;min-width:0;}
|
||||
.basic-form__right{width:300px;flex-shrink:0;}
|
||||
.map-wrap{position:relative;height:260px;border:1px solid var(--border);border-radius:var(--radius-sm);overflow:hidden;background:#EAF2F8;}
|
||||
.map-placeholder{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;color:var(--text-placeholder);font-size:var(--font-sm);background:repeating-linear-gradient(45deg,#EAF2F8,#EAF2F8 20px,#E2ECF5 20px,#E2ECF5 40px);}
|
||||
.section-title{font-size:var(--font-sm);font-weight:600;color:var(--text-primary);padding:0 0 8px 10px;border-left:3px solid var(--primary);margin:8px 0 4px;}
|
||||
.form-footer{display:flex;gap:8px;padding:12px 0;justify-content:flex-end;border-top:1px solid var(--border);margin-top:8px;}
|
||||
/* 部门管理员 */
|
||||
.filter-bar{padding:0 0 16px;display:flex;align-items:center;gap:16px;flex-wrap:wrap;}
|
||||
.filter-item{display:flex;align-items:center;gap:8px;}
|
||||
.filter-item label{font-size:var(--font-sm);color:var(--text-secondary);white-space:nowrap;}
|
||||
.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);}
|
||||
.action-bar{display:flex;align-items:center;gap:8px;padding:0 0 16px;}
|
||||
.table-wrap{overflow-x:auto;}
|
||||
table{width:100%;border-collapse:separate;border-spacing:0;min-width:900px;}
|
||||
thead th{background:#FAFAFA;padding:10px 14px;text-align:center;font-size:var(--font-sm);color:var(--text-secondary);font-weight:500;border-bottom:1px solid var(--border);white-space:nowrap;}
|
||||
tbody td{padding:12px 14px;text-align:center;font-size:var(--font-sm);color:var(--text-primary);border-bottom:1px solid #F0F0F0;white-space:nowrap;}
|
||||
tbody tr:last-child td{border-bottom:none;}
|
||||
tbody tr:hover{background:#F8FBFF;}
|
||||
thead tr th:last-child,tbody td:last-child{position:sticky;right:0;z-index:5;background:#fff;box-shadow:-4px 0 8px rgba(0,0,0,0.04);}
|
||||
thead tr th:last-child{z-index:8;background:#FAFAFA;}
|
||||
tbody tr:hover td:last-child{background:#F8FBFF;}
|
||||
.td-empty{text-align:center;padding:40px 0;color:var(--text-placeholder);}
|
||||
.badge{display:inline-block;padding:2px 10px;border-radius:10px;font-size:var(--font-xs);}
|
||||
.badge--success{background:#F6FFED;color:#389E0D;border:1px solid #B7EB8F;}
|
||||
.pagination{display:flex;align-items:center;justify-content:flex-end;padding:16px 0 0;gap:8px;}
|
||||
.pagination span{font-size:var(--font-sm);color:var(--text-secondary);}
|
||||
.page-btn{min-width:32px;height:32px;border:1px solid var(--border);border-radius:var(--radius-sm);background:#fff;cursor:pointer;font-size:var(--font-sm);display:inline-flex;align-items:center;justify-content:center;padding:0 6px;transition:all .2s;}
|
||||
.page-btn:hover,.page-btn.active{background:var(--primary);color:#fff;border-color:var(--primary);}
|
||||
/* 弹窗 */
|
||||
.modal-mask{display:none;position:fixed;inset:0;background:rgba(0,0,0,.45);z-index:950;align-items:center;justify-content:center;}
|
||||
.modal-mask.open{display:flex;}
|
||||
.modal{width:600px;background:#fff;border-radius:var(--radius-md);box-shadow:var(--shadow-md);}
|
||||
.modal--lg{width:900px;}
|
||||
.modal--map{width:920px;}
|
||||
.modal__head{display:flex;align-items:center;justify-content:space-between;padding:16px 24px;border-bottom:1px solid var(--border);font-size:var(--font-base);font-weight:600;}
|
||||
.modal__close{cursor:pointer;color:var(--text-placeholder);font-size:20px;line-height:1;border:none;background:none;}
|
||||
.modal__close:hover{color:var(--text-primary);}
|
||||
.modal__body{padding:24px;max-height:62vh;overflow-y:auto;}
|
||||
.modal__footer{display:flex;justify-content:flex-end;gap:8px;padding:12px 24px;border-top:1px solid var(--border);}
|
||||
.modal__footer .left{flex:1;font-size:var(--font-sm);color:var(--text-secondary);line-height:36px;}
|
||||
.icon-upload{width:64px;height:64px;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);cursor:pointer;gap:2px;background:#FAFAFA;font-size:var(--font-xs);}
|
||||
.icon-upload:hover{border-color:var(--primary);color:var(--primary);}
|
||||
.toast{position:fixed;top:80px;left:50%;transform:translateX(-50%);background:#333;color:#fff;padding:10px 24px;border-radius:var(--radius-sm);font-size:var(--font-sm);z-index:9999;opacity:0;transition:opacity .2s;pointer-events:none;}
|
||||
.toast.show{opacity:1;}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<!-- 顶部导航栏 -->
|
||||
<div class="top-bar">
|
||||
<div class="top-bar__logo"><svg viewBox="0 0 28 28" fill="none"><rect width="28" height="28" rx="6" fill="#1890FF"/><path d="M14 6.5l7 3.5v4.5c0 4.2-2.9 6.8-7 7.5-4.1-.7-7-3.3-7-7.5V10l7-3.5z" stroke="#fff" stroke-width="1.8" fill="none"/><path d="M11 13.5h6M14 10.5v6" stroke="#fff" stroke-width="1.8" stroke-linecap="round"/></svg> 系统管理</div>
|
||||
<nav class="top-bar__nav">
|
||||
<a href="user-admin.html">用户管理</a>
|
||||
<a href="application.html">权限管理</a>
|
||||
<a href="hospital.html" class="active">机构管理</a>
|
||||
<a href="dict.html">系统配置</a>
|
||||
<a href="announcement.html">通知管理</a>
|
||||
</nav>
|
||||
<div class="top-bar__right">
|
||||
<a class="btn-back" href="../../index.html"><svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M10 3L5 8l5 5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg> 返回首页</a>
|
||||
<div class="avatar">管</div>
|
||||
<span style="color:rgba(255,255,255,0.65);">系统管理员 ▾</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 侧边栏 -->
|
||||
<aside class="sidebar">
|
||||
<div class="sidebar-menu__title">机构管理</div>
|
||||
<a href="hospital.html" class="sidebar-item">医院管理</a>
|
||||
<a href="unit.html" class="sidebar-item active">单位管理</a>
|
||||
</aside>
|
||||
|
||||
<!-- 主内容 -->
|
||||
<main class="main">
|
||||
<div class="unit-layout">
|
||||
<!-- 左侧:单位树 -->
|
||||
<div class="card unit-left">
|
||||
<div class="unit-left__header">
|
||||
<div class="row1">
|
||||
<div class="title">单位列表</div>
|
||||
<div class="btns">
|
||||
<span onclick="openEditRecord()"><svg width="14" height="14" viewBox="0 0 14 14" fill="none"><rect x="2" y="2" width="10" height="10" rx="1.5" stroke="currentColor" stroke-width="1.3"/><path d="M4 5h6M4 7.5h4" stroke="currentColor" stroke-width="1.1" stroke-linecap="round"/></svg>修改记录</span>
|
||||
<span onclick="openAddUnit()"><svg width="14" height="14" viewBox="0 0 14 14" fill="none"><path d="M7 2v10M2 7h10" stroke="currentColor" stroke-width="1.4" stroke-linecap="round"/></svg>新增</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="unit-search"><input id="unitSearch" placeholder="按部门名称搜索" oninput="renderUnitTree()"></div>
|
||||
</div>
|
||||
<div class="unit-left__body" id="unitTreeBody"></div>
|
||||
</div>
|
||||
|
||||
<!-- 右侧:2 个 tab -->
|
||||
<div class="card unit-right" id="unitRight">
|
||||
<div class="tabs" id="unitTabs" style="display:none;">
|
||||
<div class="tab active" data-tab="basic" onclick="switchUnitTab('basic')">基本信息</div>
|
||||
<div class="tab" data-tab="dept" onclick="switchUnitTab('dept')">部门管理员</div>
|
||||
</div>
|
||||
<div class="right-empty" id="unitEmpty">请选择左侧单位查看详情</div>
|
||||
|
||||
<div class="tab-panel" id="panel-basic">
|
||||
<div class="basic-form">
|
||||
<div class="basic-form__left">
|
||||
<div class="form-item"><label><span class="req">*</span>机构名称</label><div class="control"><input class="form-input" id="biName" placeholder="请输入机构名称"></div></div>
|
||||
<div class="form-item"><label>上级部门</label><div class="control" id="biParent">-</div></div>
|
||||
<div class="form-item"><label>排序</label><div class="control"><input class="form-input" id="biSort" placeholder="请输入排序"></div></div>
|
||||
<div class="form-item"><label>电话</label><div class="control"><input class="form-input" id="biMobile" placeholder="请输入电话"></div></div>
|
||||
<div class="form-item"><label>传真</label><div class="control"><input class="form-input" id="biFax" placeholder="请输入传真"></div></div>
|
||||
<div class="form-item"><label>机构地址</label><div class="control"><input class="form-input" id="biAddress" readonly placeholder="地图选点自动填充"></div></div>
|
||||
<div class="form-item"><label>地址详细信息</label><div class="control"><textarea class="form-textarea" id="biDetail" placeholder="请输入机构地址详细信息"></textarea></div></div>
|
||||
</div>
|
||||
<div class="basic-form__right">
|
||||
<div class="map-wrap"><div class="map-placeholder">地图选点区域</div></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section-title">健康管理员</div>
|
||||
<div class="form-item"><label>姓名</label><div class="control"><input class="form-input" id="biHealthName" readonly placeholder="点击选择健康管理员" onclick="openHealthPicker()"></div></div>
|
||||
<div class="form-item"><label>电话</label><div class="control"><input class="form-input" id="biHealthMobile" readonly placeholder="点击选择健康管理员" onclick="openHealthPicker()"></div></div>
|
||||
<div class="form-item"><label>地址</label><div class="control"><input class="form-input" id="biHealthAddr" placeholder="请输入健康管理员地址"></div></div>
|
||||
<div class="section-title">职业体检管理员</div>
|
||||
<div class="form-item"><label>姓名</label><div class="control"><input class="form-input" id="biExamName" placeholder="请输入职业体检管理员姓名"></div></div>
|
||||
<div class="form-item"><label>电话</label><div class="control"><input class="form-input" id="biExamMobile" placeholder="请输入职业体检管理员电话"></div></div>
|
||||
<div class="form-item"><label>地址</label><div class="control"><input class="form-input" id="biExamAddr" placeholder="请输入职业体检管理员地址"></div></div>
|
||||
<div class="section-title">健康监测管理员</div>
|
||||
<div class="form-item"><label>姓名</label><div class="control"><input class="form-input" id="biMonitorName" placeholder="请输入健康监测管理员姓名"></div></div>
|
||||
<div class="form-item"><label>电话</label><div class="control"><input class="form-input" id="biMonitorMobile" placeholder="请输入健康监测管理员电话"></div></div>
|
||||
<div class="form-item"><label>地址</label><div class="control"><input class="form-input" id="biMonitorAddr" placeholder="请输入健康监测管理员地址"></div></div>
|
||||
<div class="form-footer">
|
||||
<button class="btn btn-primary" onclick="showToast('保存成功')">保存</button>
|
||||
<button class="btn btn-default" onclick="showToast('已重置')">重置</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tab-panel" id="panel-dept">
|
||||
<div class="filter-bar">
|
||||
<div class="filter-item"><label>员工账号</label><input class="filter-input" id="dmAccount" placeholder="请输入员工账号"></div>
|
||||
<div class="filter-item"><label>员工姓名</label><input class="filter-input" id="dmName" placeholder="请输入员工姓名"></div>
|
||||
<button class="btn btn-primary" onclick="renderDeptManagers()"><svg width="14" height="14" viewBox="0 0 14 14" fill="none"><circle cx="6" cy="6" r="4.5" stroke="#fff" stroke-width="1.3"/><path d="M9.5 9.5L13 13" stroke="#fff" stroke-width="1.3" stroke-linecap="round"/></svg>查询</button>
|
||||
<button class="btn btn-default" onclick="resetDeptSearch()">重置</button>
|
||||
</div>
|
||||
<div class="action-bar">
|
||||
<button class="btn btn-primary" onclick="openAddManager()"><svg width="14" height="14" viewBox="0 0 14 14" fill="none"><path d="M7 2v10M2 7h10" stroke="currentColor" stroke-width="1.4" stroke-linecap="round"/></svg>新增管理员</button>
|
||||
<button class="btn btn-default" onclick="openMergeManager()">关联管理员</button>
|
||||
<button class="btn btn-danger" onclick="batchRemoveManager()">批量移除</button>
|
||||
</div>
|
||||
<div class="table-wrap">
|
||||
<table>
|
||||
<thead><tr><th style="width:44px"><input type="checkbox" onchange="toggleAllMgr(this)"></th><th>序号</th><th>员工账号</th><th>员工姓名</th><th>员工编号</th><th>单位</th><th>部门</th><th style="width:90px">操作</th></tr></thead>
|
||||
<tbody id="deptManagerBody"></tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="pagination"><span>共 <b id="dmTotal">0</b> 条</span><button class="page-btn" onclick="showToast('演示数据仅一页')">上一页</button><button class="page-btn active">1</button><button class="page-btn" onclick="showToast('演示数据仅一页')">下一页</button></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<!-- 弹窗1: 新增单位 -->
|
||||
<div class="modal-mask" id="addUnitMask">
|
||||
<div class="modal modal--map">
|
||||
<div class="modal__head"><span id="addUnitTitle">新增单位</span><button class="modal__close" onclick="closeModal('addUnitMask')">×</button></div>
|
||||
<div class="modal__body">
|
||||
<div class="basic-form">
|
||||
<div class="basic-form__left">
|
||||
<div class="form-item"><label><span class="req">*</span>机构名称</label><div class="control"><input class="form-input" id="auName" maxlength="50" placeholder="请输入机构名称"></div></div>
|
||||
<div class="form-item"><label>上级部门</label><div class="control" id="auParent">-</div></div>
|
||||
<div class="form-item"><label>排序</label><div class="control"><input class="form-input" id="auSort" placeholder="请输入排序"></div></div>
|
||||
<div class="form-item"><label>电话</label><div class="control"><input class="form-input" id="auMobile" placeholder="请输入电话"></div></div>
|
||||
<div class="form-item"><label>传真</label><div class="control"><input class="form-input" id="auFax" maxlength="20" placeholder="请输入传真"></div></div>
|
||||
<div class="form-item"><label>机构地址</label><div class="control"><input class="form-input" id="auAddress" readonly placeholder="地图选点自动填充"></div></div>
|
||||
<div class="form-item"><label>地址详细信息</label><div class="control"><textarea class="form-textarea" id="auDetail" placeholder="请输入机构地址详细信息"></textarea></div></div>
|
||||
</div>
|
||||
<div class="basic-form__right">
|
||||
<div class="map-wrap"><div class="map-placeholder">地图选点区域</div></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal__footer">
|
||||
<button class="btn btn-default" onclick="closeModal('addUnitMask')">取消</button>
|
||||
<button class="btn btn-primary" onclick="submitAddUnit()">保存</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 弹窗2: 修改记录 -->
|
||||
<div class="modal-mask" id="editRecordMask">
|
||||
<div class="modal modal--lg">
|
||||
<div class="modal__head"><span>修改记录</span><button class="modal__close" onclick="closeModal('editRecordMask')">×</button></div>
|
||||
<div class="modal__body">
|
||||
<div class="filter-bar">
|
||||
<div class="filter-item"><label>操作类型</label><select class="filter-input" id="erType" style="min-width:120px;"><option value="">请选择操作类型</option><option>新增</option><option>修改</option><option>删除</option></select></div>
|
||||
<div class="filter-item"><label>操作日期</label><input class="filter-input" type="date" id="erFrom"><span style="color:var(--text-placeholder);">至</span><input class="filter-input" type="date" id="erTo"></div>
|
||||
<button class="btn btn-primary" onclick="renderEditRecords()">查询</button>
|
||||
<button class="btn btn-default" onclick="resetEditRecords()">重置</button>
|
||||
</div>
|
||||
<div class="table-wrap">
|
||||
<table style="min-width:700px;">
|
||||
<thead><tr><th style="width:60px">序号</th><th style="width:120px">操作类型</th><th>修改内容</th><th style="width:120px">操作人</th><th style="width:170px">操作时间</th></tr></thead>
|
||||
<tbody id="editRecordBody"></tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal__footer"><button class="btn btn-default" onclick="closeModal('editRecordMask')">关闭</button></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 弹窗3: 新增管理员 -->
|
||||
<div class="modal-mask" id="addManagerMask">
|
||||
<div class="modal">
|
||||
<div class="modal__head"><span>新增管理员</span><button class="modal__close" onclick="closeModal('addManagerMask')">×</button></div>
|
||||
<div class="modal__body">
|
||||
<div class="form-item"><label>单位部门</label><div class="control" id="amOrg">-</div></div>
|
||||
<div style="border-top:1px solid #F0F0F0;margin:8px 0 16px;"></div>
|
||||
<div class="form-item"><label>头像</label><div class="control"><div class="icon-upload" onclick="showToast('上传头像')">上传头像</div></div></div>
|
||||
<div class="form-item"><label><span class="req">*</span>账号</label><div class="control"><input class="form-input" id="amAccount" placeholder="请输入账号"></div></div>
|
||||
<div class="form-item"><label><span class="req">*</span>密码</label><div class="control"><input class="form-input" id="amPassword" type="password" placeholder="请输入密码"></div></div>
|
||||
<div class="form-item"><label><span class="req">*</span>姓名</label><div class="control"><input class="form-input" id="amName" placeholder="请输入姓名"></div></div>
|
||||
<div class="form-item"><label><span class="req">*</span>角色</label><div class="control"><select class="form-input" id="amRole" multiple size="3"><option>健康管理员</option><option>体检管理员</option><option>监测管理员</option></select></div></div>
|
||||
<div class="form-item"><label>员工编号</label><div class="control"><input class="form-input" id="amWorkNo" placeholder="请输入员工编号"></div></div>
|
||||
</div>
|
||||
<div class="modal__footer">
|
||||
<button class="btn btn-default" onclick="closeModal('addManagerMask')">取消</button>
|
||||
<button class="btn btn-primary" onclick="submitAddManager()">确定</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 弹窗4: 关联管理员 -->
|
||||
<div class="modal-mask" id="mergeManagerMask">
|
||||
<div class="modal modal--lg">
|
||||
<div class="modal__head"><span>关联管理员</span><button class="modal__close" onclick="closeModal('mergeManagerMask')">×</button></div>
|
||||
<div class="modal__body">
|
||||
<div class="filter-bar">
|
||||
<div class="filter-item"><label>账号</label><input class="filter-input" id="mmAccount" placeholder="请输入员工账号"></div>
|
||||
<div class="filter-item"><label>姓名</label><input class="filter-input" id="mmName" placeholder="请输入员工姓名"></div>
|
||||
<button class="btn btn-primary" onclick="renderMergeList()">查询</button>
|
||||
<button class="btn btn-default" onclick="resetMergeSearch()">重置</button>
|
||||
</div>
|
||||
<div class="table-wrap" style="max-height:300px;overflow:auto;">
|
||||
<table>
|
||||
<thead><tr><th style="width:44px"><input type="checkbox" onchange="toggleAllMerge(this)"></th><th>序号</th><th>员工账号</th><th>员工姓名</th><th>员工编号</th><th>单位</th><th>部门</th></tr></thead>
|
||||
<tbody id="mergeBody"></tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal__footer">
|
||||
<div class="left" id="mergeSelectedTip">已选 0 人</div>
|
||||
<button class="btn btn-default" onclick="closeModal('mergeManagerMask')">取消</button>
|
||||
<button class="btn btn-primary" onclick="submitMerge()">确定</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 弹窗5: 健康管理师选择 -->
|
||||
<div class="modal-mask" id="healthPickerMask">
|
||||
<div class="modal modal--lg">
|
||||
<div class="modal__head"><span>选择健康管理员</span><button class="modal__close" onclick="closeModal('healthPickerMask')">×</button></div>
|
||||
<div class="modal__body">
|
||||
<div class="filter-bar">
|
||||
<div class="filter-item"><label>员工姓名</label><input class="filter-input" id="hpName" placeholder="请输入员工姓名"></div>
|
||||
<button class="btn btn-primary" onclick="renderHealthPicker()">查询</button>
|
||||
<button class="btn btn-default" onclick="resetHealthPicker()">重置</button>
|
||||
</div>
|
||||
<div class="table-wrap" style="max-height:300px;overflow:auto;">
|
||||
<table>
|
||||
<thead><tr><th style="width:44px"></th><th>序号</th><th>员工账号</th><th>员工姓名</th><th>员工编号</th><th>单位</th><th>部门</th></tr></thead>
|
||||
<tbody id="healthPickerBody"></tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal__footer">
|
||||
<div class="left" id="healthSelectedTip">已选:-</div>
|
||||
<button class="btn btn-default" onclick="closeModal('healthPickerMask')">取消</button>
|
||||
<button class="btn btn-primary" onclick="submitHealthPicker()">确定</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="toast" id="toast"></div>
|
||||
|
||||
<script>
|
||||
/* ===== 单位树数据 ===== */
|
||||
var unitTree=[
|
||||
{id:'1',name:'CQ能源',children:[
|
||||
{id:'11',name:'采油一厂',children:[
|
||||
{id:'111',name:'安全环保科'},
|
||||
{id:'112',name:'采油大队'},
|
||||
{id:'113',name:'生产技术部'}
|
||||
]},
|
||||
{id:'12',name:'采油二厂',children:[
|
||||
{id:'121',name:'姬圪台联合站'},
|
||||
{id:'122',name:'信息中心'}
|
||||
]},
|
||||
{id:'13',name:'采气一厂',children:[
|
||||
{id:'131',name:'靖边净化厂'},
|
||||
{id:'132',name:'苏里格南作业区'}
|
||||
]},
|
||||
{id:'14',name:'机关部门'}
|
||||
]}
|
||||
];
|
||||
var selectedUnitId='11';
|
||||
var curUnitTab='basic';
|
||||
|
||||
/* ===== 部门管理员数据 ===== */
|
||||
var deptManagers=[
|
||||
{id:'m1',username:'zhangwei',realName:'张伟',workNo:'CQ0101',orgName:'CQ能源',deptName:'采油一厂'},
|
||||
{id:'m2',username:'liyan',realName:'李艳',workNo:'CQ0102',orgName:'CQ能源',deptName:'采油一厂'},
|
||||
{id:'m3',username:'wangqiang',realName:'王强',workNo:'CQ0103',orgName:'CQ能源',deptName:'采油一厂'}
|
||||
];
|
||||
/* 候选管理员数据 */
|
||||
var mergeCandidates=[
|
||||
{id:'c1',username:'guolei',realName:'郭磊',workNo:'CQ0201',orgName:'CQ能源',deptName:'采油二厂'},
|
||||
{id:'c2',username:'maxiao',realName:'马晓',workNo:'CQ0202',orgName:'CQ能源',deptName:'采油二厂'},
|
||||
{id:'c3',username:'hujun',realName:'胡军',workNo:'CQ0301',orgName:'CQ能源',deptName:'采气一厂'},
|
||||
{id:'c4',username:'linna',realName:'林娜',workNo:'CQ0401',orgName:'CQ能源',deptName:'机关部门'}
|
||||
];
|
||||
var editRecords=[
|
||||
{type:'修改',content:'修改采油一厂健康管理员由"张伟"变更为"李艳"',operator:'系统管理员',time:'2026-09-10 14:23:15'},
|
||||
{type:'新增',content:'新增单位"采油一厂"',operator:'系统管理员',time:'2026-09-08 09:12:40'},
|
||||
{type:'修改',content:'修改采油一厂电话为 029-88886666',operator:'运营管理员',time:'2026-09-05 16:45:02'},
|
||||
{type:'删除',content:'删除部门"测试部门"',operator:'系统管理员',time:'2026-09-01 11:30:28'}
|
||||
];
|
||||
|
||||
/* ===== 单位树渲染 ===== */
|
||||
function findUnit(nodes,id){
|
||||
for(var i=0;i<nodes.length;i++){
|
||||
if(nodes[i].id===id)return nodes[i];
|
||||
if(nodes[i].children){var r=findUnit(nodes[i].children,id);if(r)return r;}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
function getParentName(nodes,id,parent){
|
||||
for(var i=0;i<nodes.length;i++){
|
||||
if(nodes[i].id===id)return parent?parent.name:'-';
|
||||
if(nodes[i].children){var r=getParentName(nodes[i].children,id,nodes[i]);if(r)return r;}
|
||||
}
|
||||
return '-';
|
||||
}
|
||||
function renderUnitTree(){
|
||||
var kw=document.getElementById('unitSearch').value.trim();
|
||||
var html='';
|
||||
var hasData=false;
|
||||
function walk(nodes,level){
|
||||
nodes.forEach(function(n){
|
||||
if(kw && n.name.indexOf(kw)<0)return;
|
||||
hasData=true;
|
||||
var hasChildren=n.children&&n.children.length;
|
||||
var indent=level*20;
|
||||
html+='<div class="unit-node__row'+(n.id===selectedUnitId?' active':'')+'" style="padding-left:'+(8+indent)+'px;" onclick="selectUnit(\''+n.id+'\')">'+
|
||||
'<span class="unit-node__arrow">'+(hasChildren?'▾':'')+'</span>'+
|
||||
'<span class="unit-node__name">'+n.name+'</span>'+
|
||||
'<span class="unit-node__actions"><span onclick="event.stopPropagation();openAddUnit(\''+n.id+'\')">添加下级</span><span class="del" onclick="event.stopPropagation();delUnit(\''+n.id+'\')">删除</span></span>'+
|
||||
'</div>';
|
||||
if(hasChildren)walk(n.children,level+1);
|
||||
});
|
||||
}
|
||||
walk(unitTree,0);
|
||||
document.getElementById('unitTreeBody').innerHTML=hasData?html:'<div class="unit-empty">没有找到相关单位部门</div>';
|
||||
}
|
||||
function selectUnit(id){
|
||||
selectedUnitId=id;
|
||||
renderUnitTree();
|
||||
document.getElementById('unitEmpty').style.display='none';
|
||||
document.getElementById('unitTabs').style.display='flex';
|
||||
document.getElementById('panel-basic').classList.add('active');
|
||||
document.getElementById('panel-dept').classList.remove('active');
|
||||
curUnitTab='basic';
|
||||
fillBasicInfo();
|
||||
renderDeptManagers();
|
||||
}
|
||||
function delUnit(id){
|
||||
if(!confirm('确定删除该单位吗?'))return;
|
||||
function rm(nodes){
|
||||
for(var i=nodes.length-1;i>=0;i--){
|
||||
if(nodes[i].id===id){nodes.splice(i,1);return true;}
|
||||
if(nodes[i].children&&rm(nodes[i].children))return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
rm(unitTree);
|
||||
if(selectedUnitId===id){selectedUnitId=unitTree.length?unitTree[0].id:null;}
|
||||
renderUnitTree();
|
||||
if(!selectedUnitId){document.getElementById('unitEmpty').style.display='flex';document.getElementById('unitTabs').style.display='none';}
|
||||
else selectUnit(selectedUnitId);
|
||||
showToast('删除成功');
|
||||
}
|
||||
|
||||
/* ===== Tab ===== */
|
||||
function switchUnitTab(tab){
|
||||
curUnitTab=tab;
|
||||
document.querySelectorAll('#unitTabs .tab').forEach(function(t){t.classList.toggle('active',t.dataset.tab===tab);});
|
||||
document.getElementById('panel-basic').classList.toggle('active',tab==='basic');
|
||||
document.getElementById('panel-dept').classList.toggle('active',tab==='dept');
|
||||
}
|
||||
|
||||
/* ===== 基本信息 ===== */
|
||||
function fillBasicInfo(){
|
||||
var u=findUnit(unitTree,selectedUnitId);
|
||||
if(!u)return;
|
||||
document.getElementById('biName').value=u.name;
|
||||
document.getElementById('biParent').textContent=getParentName(unitTree,selectedUnitId,null);
|
||||
document.getElementById('biSort').value='1';
|
||||
document.getElementById('biMobile').value='029-88886666';
|
||||
document.getElementById('biFax').value='';
|
||||
document.getElementById('biAddress').value='陕西省西安市未央区';
|
||||
document.getElementById('biDetail').value='';
|
||||
}
|
||||
|
||||
/* ===== 部门管理员 ===== */
|
||||
function renderDeptManagers(){
|
||||
var list=deptManagers;
|
||||
document.getElementById('dmTotal').textContent=list.length;
|
||||
document.getElementById('deptManagerBody').innerHTML=list.map(function(m,i){
|
||||
return '<tr><td><input type="checkbox" class="mgrCheck"></td><td>'+(i+1)+'</td><td>'+m.username+'</td><td>'+m.realName+'</td><td>'+m.workNo+'</td><td>'+m.orgName+'</td><td>'+m.deptName+'</td><td><button class="btn btn-link" style="color:var(--danger);" onclick="removeManager(\''+m.id+'\')">移除用户</button></td></tr>';
|
||||
}).join('');
|
||||
}
|
||||
function removeManager(id){
|
||||
if(!confirm('确定移除该用户吗?'))return;
|
||||
deptManagers=deptManagers.filter(function(m){return m.id!==id;});
|
||||
renderDeptManagers();showToast('移除成功');
|
||||
}
|
||||
function toggleAllMgr(el){document.querySelectorAll('.mgrCheck').forEach(function(c){c.checked=el.checked;});}
|
||||
function batchRemoveManager(){
|
||||
var checked=document.querySelectorAll('.mgrCheck:checked').length;
|
||||
if(!checked){showToast('请先选择要移除的管理员');return;}
|
||||
if(!confirm('确定移除选中的 '+checked+' 个管理员吗?'))return;
|
||||
deptManagers=deptManagers.filter(function(m,i){return !document.querySelectorAll('.mgrCheck')[i].checked;});
|
||||
renderDeptManagers();showToast('批量移除成功');
|
||||
}
|
||||
function resetDeptSearch(){document.getElementById('dmAccount').value='';document.getElementById('dmName').value='';renderDeptManagers();}
|
||||
|
||||
/* ===== 弹窗1: 新增单位 ===== */
|
||||
var addUnitParentId=null;
|
||||
function openAddUnit(parentId){
|
||||
addUnitParentId=parentId||null;
|
||||
document.getElementById('addUnitTitle').textContent=parentId?'新增下级单位':'新增单位';
|
||||
document.getElementById('auName').value='';
|
||||
document.getElementById('auParent').textContent=parentId?findUnit(unitTree,parentId).name:'-';
|
||||
document.getElementById('auSort').value='';
|
||||
document.getElementById('auMobile').value='';
|
||||
document.getElementById('auFax').value='';
|
||||
document.getElementById('auAddress').value='';
|
||||
document.getElementById('auDetail').value='';
|
||||
document.getElementById('addUnitMask').classList.add('open');
|
||||
}
|
||||
function submitAddUnit(){
|
||||
var name=document.getElementById('auName').value.trim();
|
||||
if(!name){showToast('请输入机构名称');return;}
|
||||
var newNode={id:String(Date.now()),name:name};
|
||||
if(addUnitParentId){
|
||||
var p=findUnit(unitTree,addUnitParentId);
|
||||
if(p){if(!p.children)p.children=[];p.children.push(newNode);}
|
||||
}else{
|
||||
unitTree.push(newNode);
|
||||
}
|
||||
closeModal('addUnitMask');renderUnitTree();showToast('新增成功');
|
||||
}
|
||||
|
||||
/* ===== 弹窗2: 修改记录 ===== */
|
||||
function renderEditRecords(){
|
||||
document.getElementById('editRecordBody').innerHTML=editRecords.map(function(r,i){
|
||||
var badge=r.type==='新增'?'badge--success':r.type==='删除'?'badge--muted':'badge--info';
|
||||
return '<tr><td>'+(i+1)+'</td><td><span class="badge '+badge+'">'+r.type+'</span></td><td style="text-align:left;">'+r.content+'</td><td>'+r.operator+'</td><td>'+r.time+'</td></tr>';
|
||||
}).join('');
|
||||
}
|
||||
function openEditRecord(){renderEditRecords();document.getElementById('editRecordMask').classList.add('open');}
|
||||
function resetEditRecords(){document.getElementById('erType').value='';document.getElementById('erFrom').value='';document.getElementById('erTo').value='';renderEditRecords();}
|
||||
|
||||
/* ===== 弹窗3: 新增管理员 ===== */
|
||||
function openAddManager(){
|
||||
document.getElementById('amOrg').textContent=findUnit(unitTree,selectedUnitId)?findUnit(unitTree,selectedUnitId).name:'-';
|
||||
document.getElementById('amAccount').value='';
|
||||
document.getElementById('amPassword').value='';
|
||||
document.getElementById('amName').value='';
|
||||
document.getElementById('amWorkNo').value='';
|
||||
document.getElementById('addManagerMask').classList.add('open');
|
||||
}
|
||||
function submitAddManager(){
|
||||
var account=document.getElementById('amAccount').value.trim();
|
||||
var name=document.getElementById('amName').value.trim();
|
||||
if(!account){showToast('请输入账号');return;}
|
||||
if(!name){showToast('请输入姓名');return;}
|
||||
deptManagers.push({id:'m'+Date.now(),username:account,realName:name,workNo:document.getElementById('amWorkNo').value.trim(),orgName:'CQ能源',deptName:findUnit(unitTree,selectedUnitId).name});
|
||||
closeModal('addManagerMask');renderDeptManagers();showToast('新增管理员成功');
|
||||
}
|
||||
|
||||
/* ===== 弹窗4: 关联管理员 ===== */
|
||||
function renderMergeList(){
|
||||
document.getElementById('mergeBody').innerHTML=mergeCandidates.map(function(m,i){
|
||||
return '<tr><td><input type="checkbox" class="mergeCheck" onchange="updateMergeTip()"></td><td>'+(i+1)+'</td><td>'+m.username+'</td><td>'+m.realName+'</td><td>'+m.workNo+'</td><td>'+m.orgName+'</td><td>'+m.deptName+'</td></tr>';
|
||||
}).join('');
|
||||
updateMergeTip();
|
||||
}
|
||||
function toggleAllMerge(el){document.querySelectorAll('.mergeCheck').forEach(function(c){c.checked=el.checked;});updateMergeTip();}
|
||||
function updateMergeTip(){document.getElementById('mergeSelectedTip').textContent='已选 '+document.querySelectorAll('.mergeCheck:checked').length+' 人';}
|
||||
function openMergeManager(){renderMergeList();document.getElementById('mergeManagerMask').classList.add('open');}
|
||||
function resetMergeSearch(){document.getElementById('mmAccount').value='';document.getElementById('mmName').value='';renderMergeList();}
|
||||
function submitMerge(){var n=document.querySelectorAll('.mergeCheck:checked').length;closeModal('mergeManagerMask');showToast('已关联 '+n+' 名管理员');}
|
||||
|
||||
/* ===== 弹窗5: 健康管理师选择 ===== */
|
||||
var healthCandidates=[
|
||||
{id:'h1',username:'zhangwei',realName:'张伟',workNo:'CQ0101',orgName:'CQ能源',deptName:'采油一厂'},
|
||||
{id:'h2',username:'liyan',realName:'李艳',workNo:'CQ0102',orgName:'CQ能源',deptName:'采油一厂'},
|
||||
{id:'h3',username:'chenjing',realName:'陈静',workNo:'CQ0104',orgName:'CQ能源',deptName:'采油一厂'}
|
||||
];
|
||||
var healthSelectedName='-';
|
||||
function renderHealthPicker(){
|
||||
document.getElementById('healthPickerBody').innerHTML=healthCandidates.map(function(m,i){
|
||||
return '<tr><td><input type="radio" name="healthPick" class="healthPick" onchange="updateHealthTip()"></td><td>'+(i+1)+'</td><td>'+m.username+'</td><td>'+m.realName+'</td><td>'+m.workNo+'</td><td>'+m.orgName+'</td><td>'+m.deptName+'</td></tr>';
|
||||
}).join('');
|
||||
updateHealthTip();
|
||||
}
|
||||
function updateHealthTip(){
|
||||
var checked=document.querySelector('.healthPick:checked');
|
||||
document.getElementById('healthSelectedTip').textContent='已选:'+(checked?healthCandidates[[].indexOf.call(document.querySelectorAll('.healthPick'),checked)].realName:'-');
|
||||
}
|
||||
function openHealthPicker(){renderHealthPicker();document.getElementById('healthPickerMask').classList.add('open');}
|
||||
function resetHealthPicker(){document.getElementById('hpName').value='';renderHealthPicker();}
|
||||
function submitHealthPicker(){
|
||||
var checked=document.querySelector('.healthPick:checked');
|
||||
if(!checked){showToast('请选择健康管理员');return;}
|
||||
var u=healthCandidates[[].indexOf.call(document.querySelectorAll('.healthPick'),checked)];
|
||||
document.getElementById('biHealthName').value=u.realName;
|
||||
document.getElementById('biHealthMobile').value='029-88886666';
|
||||
closeModal('healthPickerMask');showToast('已选择 '+u.realName);
|
||||
}
|
||||
|
||||
function closeModal(id){document.getElementById(id).classList.remove('open');}
|
||||
function showToast(msg){
|
||||
var t=document.getElementById('toast');t.textContent=msg;t.classList.add('show');
|
||||
setTimeout(function(){t.classList.remove('show');},1500);
|
||||
}
|
||||
document.addEventListener('click',function(e){
|
||||
['addUnitMask','editRecordMask','addManagerMask','mergeManagerMask','healthPickerMask'].forEach(function(id){
|
||||
if(e.target.id===id)closeModal(id);
|
||||
});
|
||||
});
|
||||
|
||||
/* 初始化 */
|
||||
renderUnitTree();
|
||||
selectUnit('11');
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,211 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>管理员账号 | 系统管理</title>
|
||||
<style>
|
||||
*{box-sizing:border-box;margin:0;padding:0;}
|
||||
body{font-family:-apple-system,BlinkMacSystemFont,'PingFang SC','Microsoft YaHei',sans-serif;font-size:var(--font-sm);background:#F5F7FA;color:#333;min-width:1280px;}
|
||||
:root{
|
||||
--primary:#1890FF;--primary-light:#E6F7FF;--success:#52C41A;--warning:#FAAD14;--danger:#FF4D4F;
|
||||
--text-primary:#333;--text-secondary:#666;--text-placeholder:#999;--border:#E8E8E8;--background:#F5F7FA;
|
||||
--font-xs:11px;--font-sm:13px;--font-base:15px;--font-lg:17px;
|
||||
--radius-sm:4px;--radius-md:8px;--radius-lg:12px;
|
||||
--shadow-sm:0 1px 4px rgba(0,0,0,0.08);--shadow-md:0 4px 12px rgba(0,0,0,0.10);
|
||||
}
|
||||
.top-bar{display:flex;align-items:center;height:56px;background:#001529;padding:0 24px;position:fixed;top:0;left:0;right:0;z-index:100;}
|
||||
.top-bar__logo{display:flex;align-items:center;gap:8px;color:#fff;font-size:var(--font-lg);font-weight:600;white-space:nowrap;width:200px;flex-shrink:0;}
|
||||
.top-bar__logo svg{width:28px;height:28px;}
|
||||
.top-bar__nav{display:flex;align-items:center;gap:4px;flex:1;}
|
||||
.top-bar__nav a{color:rgba(255,255,255,0.65);text-decoration:none;padding:6px 14px;border-radius:var(--radius-sm);font-size:var(--font-sm);transition:all .2s;}
|
||||
.top-bar__nav a:hover{color:#fff;background:rgba(255,255,255,0.08);}
|
||||
.top-bar__nav a.active{color:#fff;background:var(--primary);}
|
||||
.top-bar__right{display:flex;align-items:center;gap:16px;color:rgba(255,255,255,0.65);font-size:var(--font-sm);}
|
||||
.btn-back{color:rgba(255,255,255,0.65);cursor:pointer;display:flex;align-items:center;gap:4px;text-decoration:none;}
|
||||
.btn-back:hover{color:#fff;}
|
||||
.avatar{width:32px;height:32px;border-radius:50%;background:#1890FF;display:flex;align-items:center;justify-content:center;color:#fff;font-size:var(--font-sm);cursor:pointer;}
|
||||
.sidebar{position:fixed;top:56px;left:0;bottom:0;width:240px;background:#001529;overflow-y:auto;z-index:90;padding-top:8px;padding-bottom:24px;}
|
||||
.sidebar-menu__title{color:rgba(255,255,255,0.35);font-size:var(--font-xs);padding:16px 24px 8px;letter-spacing:.5px;}
|
||||
.sidebar-item{display:flex;align-items:center;gap:8px;padding:9px 24px;color:rgba(255,255,255,0.65);font-size:var(--font-sm);cursor:pointer;transition:all .15s;text-decoration:none;}
|
||||
.sidebar-item:hover{color:#fff;background:rgba(255,255,255,0.06);}
|
||||
.sidebar-item.active{color:#fff;background:var(--primary);}
|
||||
.main{margin-left:240px;margin-top:56px;padding:24px;min-height:calc(100vh - 56px);}
|
||||
.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;}
|
||||
.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);}
|
||||
.btn{height:36px;padding:0 16px;border-radius:var(--radius-sm);font-size:var(--font-sm);cursor:pointer;border:none;transition:all .2s;display:inline-flex;align-items:center;gap:6px;white-space:nowrap;}
|
||||
.btn-primary{background:var(--primary);color:#fff;}.btn-primary:hover{background:#40a9ff;}
|
||||
.btn-default{background:#fff;color:var(--text-primary);border:1px solid var(--border);}.btn-default:hover{color:var(--primary);border-color:var(--primary);}
|
||||
.btn-link{background:none;color:var(--primary);padding:0 4px;height:auto;}.btn-link:hover{color:#40a9ff;}
|
||||
.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);}
|
||||
.table-card{background:#fff;border-radius:0 0 var(--radius-md) var(--radius-md);box-shadow:var(--shadow-sm);overflow:hidden;}
|
||||
.table-card__content{overflow-x:auto;}
|
||||
table{width:100%;border-collapse:separate;border-spacing:0;min-width:1400px;}
|
||||
thead th{background:#FAFAFA;padding:10px 14px;text-align:center;font-size:var(--font-sm);color:var(--text-secondary);font-weight:500;border-bottom:1px solid var(--border);white-space:nowrap;}
|
||||
tbody td{padding:12px 14px;text-align:center;font-size:var(--font-sm);color:var(--text-primary);border-bottom:1px solid #F0F0F0;white-space:nowrap;}
|
||||
tbody tr:last-child td{border-bottom:none;}
|
||||
tbody tr:hover{background:#F8FBFF;}
|
||||
thead tr th:last-child,tbody td:last-child{position:sticky;right:0;z-index:5;background:#fff;box-shadow:-4px 0 8px rgba(0,0,0,0.04);}
|
||||
thead tr th:last-child{z-index:8;background:#FAFAFA;}
|
||||
tbody tr:hover td:last-child{background:#F8FBFF;}
|
||||
.td-empty{text-align:center;padding:48px 0;color:var(--text-placeholder);}
|
||||
.badge{display:inline-block;padding:2px 10px;border-radius:10px;font-size:var(--font-xs);}
|
||||
.badge--success{background:#F6FFED;color:#389E0D;border:1px solid #B7EB8F;}
|
||||
.badge--muted{background:#F5F5F5;color:var(--text-secondary);border:1px solid var(--border);}
|
||||
.pagination{display:flex;align-items:center;justify-content:flex-end;padding:16px 24px;gap:8px;border-top:1px solid var(--border);}
|
||||
.pagination span{font-size:var(--font-sm);color:var(--text-secondary);}
|
||||
.page-btn{min-width:32px;height:32px;border:1px solid var(--border);border-radius:var(--radius-sm);background:#fff;cursor:pointer;font-size:var(--font-sm);display:inline-flex;align-items:center;justify-content:center;padding:0 6px;transition:all .2s;}
|
||||
.page-btn:hover,.page-btn.active{background:var(--primary);color:#fff;border-color:var(--primary);}
|
||||
.modal-mask{display:none;position:fixed;inset:0;background:rgba(0,0,0,.45);z-index:950;align-items:center;justify-content:center;}
|
||||
.modal-mask.open{display:flex;}
|
||||
.modal{width:640px;background:#fff;border-radius:var(--radius-md);box-shadow:var(--shadow-md);}
|
||||
.modal__head{display:flex;align-items:center;justify-content:space-between;padding:16px 24px;border-bottom:1px solid var(--border);font-size:var(--font-base);font-weight:600;}
|
||||
.modal__close{cursor:pointer;color:var(--text-placeholder);font-size:20px;line-height:1;border:none;background:none;}
|
||||
.modal__body{padding:24px;max-height:60vh;overflow-y:auto;}
|
||||
.modal__footer{display:flex;justify-content:flex-end;gap:8px;padding:12px 24px;border-top:1px solid var(--border);}
|
||||
.form-item{display:flex;align-items:flex-start;margin-bottom:18px;}
|
||||
.form-item label{width:90px;min-width:90px;text-align:right;padding-right:12px;font-size:var(--font-sm);color:var(--text-secondary);line-height:36px;}
|
||||
.form-item label .req{color:var(--danger);margin-right:2px;}
|
||||
.form-item .control{flex:1;font-size:var(--font-sm);line-height:36px;color:var(--text-primary);}
|
||||
.form-input{width:100%;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;}
|
||||
.form-input:focus{border-color:var(--primary);box-shadow:0 0 0 2px rgba(24,144,255,0.1);}
|
||||
.icon-upload{width:64px;height:64px;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);cursor:pointer;gap:2px;background:#FAFAFA;font-size:var(--font-xs);}
|
||||
.icon-upload:hover{border-color:var(--primary);color:var(--primary);}
|
||||
.toast{position:fixed;top:80px;left:50%;transform:translateX(-50%);background:#333;color:#fff;padding:10px 24px;border-radius:var(--radius-sm);font-size:var(--font-sm);z-index:9999;opacity:0;transition:opacity .2s;pointer-events:none;}
|
||||
.toast.show{opacity:1;}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="top-bar">
|
||||
<div class="top-bar__logo"><svg viewBox="0 0 28 28" fill="none"><rect width="28" height="28" rx="6" fill="#1890FF"/><path d="M14 6.5l7 3.5v4.5c0 4.2-2.9 6.8-7 7.5-4.1-.7-7-3.3-7-7.5V10l7-3.5z" stroke="#fff" stroke-width="1.8" fill="none"/><path d="M11 13.5h6M14 10.5v6" stroke="#fff" stroke-width="1.8" stroke-linecap="round"/></svg> 系统管理</div>
|
||||
<nav class="top-bar__nav">
|
||||
<a href="user-admin.html" class="active">用户管理</a>
|
||||
<a href="application.html">权限管理</a>
|
||||
<a href="hospital.html">机构管理</a>
|
||||
<a href="dict.html">系统配置</a>
|
||||
<a href="announcement.html">通知管理</a>
|
||||
</nav>
|
||||
<div class="top-bar__right">
|
||||
<a class="btn-back" href="../../index.html"><svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M10 3L5 8l5 5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg> 返回首页</a>
|
||||
<div class="avatar">管</div>
|
||||
<span style="color:rgba(255,255,255,0.65);">系统管理员 ▾</span>
|
||||
</div>
|
||||
</div>
|
||||
<aside class="sidebar">
|
||||
<div class="sidebar-menu__title">用户管理</div>
|
||||
<a href="user-admin.html" class="sidebar-item active">管理员账号</a>
|
||||
<a href="user-all.html" class="sidebar-item">全部用户</a>
|
||||
<a href="user-consult.html" class="sidebar-item">咨询账号</a>
|
||||
<a href="user-emergency.html" class="sidebar-item">应急中心账号</a>
|
||||
<a href="user-employee.html" class="sidebar-item">员工账号</a>
|
||||
</aside>
|
||||
|
||||
<main class="main">
|
||||
<div class="filter-bar">
|
||||
<div class="filter-item"><label>账号</label><input class="filter-input" id="filterAccount" placeholder="请输入账号"></div>
|
||||
<div class="filter-item"><label>姓名</label><input class="filter-input" id="filterName" placeholder="请输入姓名"></div>
|
||||
<div class="filter-item"><label>角色</label><select class="filter-select" id="filterRole"><option value="">请选择角色</option><option>超级管理员</option><option>系统管理员</option><option>运营管理员</option></select></div>
|
||||
<div class="filter-item"><label>状态</label><select class="filter-select" id="filterStatus"><option value="">请选择状态</option><option>激活</option><option>锁定</option></select></div>
|
||||
<button class="btn btn-primary" onclick="searchQuery()"><svg width="14" height="14" viewBox="0 0 14 14" fill="none"><circle cx="6" cy="6" r="4.5" stroke="#fff" stroke-width="1.3"/><path d="M9.5 9.5L13 13" stroke="#fff" stroke-width="1.3" stroke-linecap="round"/></svg>查询</button>
|
||||
<button class="btn btn-default" onclick="resetQuery()">重置</button>
|
||||
</div>
|
||||
<div class="action-bar">
|
||||
<button class="btn btn-primary" onclick="openModal('add',null)"><svg width="14" height="14" viewBox="0 0 14 14" fill="none"><path d="M7 2v10M2 7h10" stroke="currentColor" stroke-width="1.4" stroke-linecap="round"/></svg>新增账号</button>
|
||||
<button class="btn btn-default" onclick="showToast('导出列表数据')">导出列表数据</button>
|
||||
<button class="btn btn-default" onclick="showToast('查看导出任务')">查看导出任务</button>
|
||||
</div>
|
||||
<div class="table-card">
|
||||
<div class="table-card__content">
|
||||
<table>
|
||||
<thead><tr><th style="width:70px">序号</th><th style="width:150px">账号</th><th style="width:110px">姓名</th><th style="width:140px">单位</th><th style="width:180px">部门</th><th style="width:180px">角色</th><th style="width:100px">状态</th><th style="width:180px">创建时间</th><th style="width:220px">操作</th></tr></thead>
|
||||
<tbody id="tableBody"></tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="pagination"><span>共 <b id="totalCount">0</b> 条</span><button class="page-btn" onclick="showToast('演示数据仅一页')">上一页</button><button class="page-btn active">1</button><button class="page-btn" onclick="showToast('演示数据仅一页')">下一页</button></div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<div class="modal-mask" id="userMask">
|
||||
<div class="modal">
|
||||
<div class="modal__head"><span id="userTitle">新增账号</span><button class="modal__close" onclick="closeModal()">×</button></div>
|
||||
<div class="modal__body">
|
||||
<div class="form-item"><label>头像</label><div class="control"><div class="icon-upload" onclick="showToast('上传头像')">上传头像</div></div></div>
|
||||
<div class="form-item"><label><span class="req">*</span>账号</label><div class="control"><input class="form-input" id="fAccount" placeholder="请输入账号"></div></div>
|
||||
<div class="form-item"><label><span class="req">*</span>密码</label><div class="control"><input class="form-input" id="fPassword" type="password" placeholder="请输入密码"></div></div>
|
||||
<div class="form-item"><label><span class="req">*</span>姓名</label><div class="control"><input class="form-input" id="fName" placeholder="请输入姓名"></div></div>
|
||||
<div class="form-item"><label>员工编号</label><div class="control"><input class="form-input" id="fWorkNo" placeholder="请输入员工编号"></div></div>
|
||||
<div class="form-item"><label>单位部门</label><div class="control"><select class="form-input" id="fOrg"><option value="">请选择单位部门</option><option>CQ能源/系统管理部</option><option>CQ能源/运营部</option><option>CQ能源/数据部</option></select></div></div>
|
||||
<div class="form-item"><label><span class="req">*</span>角色</label><div class="control"><select class="form-input" id="fRole"><option value="">请选择角色</option><option>超级管理员</option><option>系统管理员</option><option>运营管理员</option></select></div></div>
|
||||
<div class="form-item"><label>手机号</label><div class="control"><input class="form-input" id="fPhone" placeholder="请输入手机号"></div></div>
|
||||
<div class="form-item"><label>身份证号</label><div class="control"><input class="form-input" id="fIdCard" placeholder="请输入身份证号"></div></div>
|
||||
</div>
|
||||
<div class="modal__footer"><button class="btn btn-default" onclick="closeModal()">取消</button><button class="btn btn-primary" onclick="submitForm()">确定</button></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal-mask" id="pwdMask">
|
||||
<div class="modal">
|
||||
<div class="modal__head"><span>重置密码</span><button class="modal__close" onclick="closePwd()">×</button></div>
|
||||
<div class="modal__body">
|
||||
<div class="form-item"><label>账号</label><div class="control" id="pwdAccount">-</div></div>
|
||||
<div class="form-item"><label><span class="req">*</span>新密码</label><div class="control"><input class="form-input" id="pwdNew" type="password" placeholder="请输入新密码"></div></div>
|
||||
<div class="form-item"><label><span class="req">*</span>确认密码</label><div class="control"><input class="form-input" id="pwdConfirm" type="password" placeholder="请再次输入新密码"></div></div>
|
||||
</div>
|
||||
<div class="modal__footer"><button class="btn btn-default" onclick="closePwd()">取消</button><button class="btn btn-primary" onclick="submitPwd()">确定</button></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="toast" id="toast"></div>
|
||||
|
||||
<script>
|
||||
var users=[
|
||||
{id:'1',account:'admin',name:'系统管理员',org:'CQ能源',dept:'系统管理部',role:'超级管理员',status:'激活',time:'2026-08-01 10:00'},
|
||||
{id:'2',account:'op001',name:'运营管理员',org:'CQ能源',dept:'运营部',role:'运营管理员',status:'激活',time:'2026-08-01 10:00'},
|
||||
{id:'3',account:'data001',name:'数据管理员',org:'CQ能源',dept:'数据部',role:'数据管理员',status:'锁定',time:'2026-08-02 09:30'}
|
||||
];
|
||||
var editingId=null, pwdId=null;
|
||||
function renderTable(){
|
||||
var list=users;
|
||||
document.getElementById('totalCount').textContent=list.length;
|
||||
document.getElementById('tableBody').innerHTML=list.map(function(u,i){
|
||||
return '<tr><td>'+(i+1)+'</td><td>'+u.account+'</td><td>'+u.name+'</td><td>'+u.org+'</td><td>'+u.dept+'</td><td>'+u.role+'</td><td><span class="badge '+(u.status==='激活'?'badge--success':'badge--muted')+'">'+u.status+'</span></td><td>'+u.time+'</td>'+
|
||||
'<td><button class="btn btn-link" onclick="showToast(\'查看详情\')">详情</button><span style="color:var(--border);margin:0 4px;">|</span><button class="btn btn-link" onclick="openPwd('+u.id+')">重置密码</button><span style="color:var(--border);margin:0 4px;">|</span><button class="btn btn-link" onclick="openModal(\'edit\','+u.id+')">编辑</button><span style="color:var(--border);margin:0 4px;">|</span><button class="btn btn-link" onclick="toggleLock('+u.id+')">'+(u.status==='激活'?'锁定':'激活')+'</button><span style="color:var(--border);margin:0 4px;">|</span><button class="btn btn-link" style="color:var(--danger);" onclick="delUser('+u.id+')">删除</button></td></tr>';
|
||||
}).join('');
|
||||
}
|
||||
function searchQuery(){renderTable();showToast('查询完成');}
|
||||
function resetQuery(){document.getElementById('filterAccount').value='';document.getElementById('filterName').value='';document.getElementById('filterRole').value='';document.getElementById('filterStatus').value='';renderTable();}
|
||||
function toggleLock(id){var u=users.find(function(x){return x.id===id;});if(u){u.status=u.status==='激活'?'锁定':'激活';renderTable();showToast(u.status==='激活'?'已激活':'已锁定');}}
|
||||
function delUser(id){if(!confirm('确定删除该账号吗?'))return;users=users.filter(function(u){return u.id!==id;});renderTable();showToast('删除成功');}
|
||||
function openModal(type,id){
|
||||
editingId=id;
|
||||
document.getElementById('userTitle').textContent=type==='add'?'新增账号':'编辑账号';
|
||||
document.getElementById('fAccount').value='';document.getElementById('fPassword').value='';document.getElementById('fName').value='';document.getElementById('fWorkNo').value='';document.getElementById('fOrg').value='';document.getElementById('fRole').value='';document.getElementById('fPhone').value='';document.getElementById('fIdCard').value='';
|
||||
if(type==='edit'&&id){var u=users.find(function(x){return x.id===id;});if(u){document.getElementById('fAccount').value=u.account;document.getElementById('fName').value=u.name;document.getElementById('fRole').value=u.role;}}
|
||||
document.getElementById('userMask').classList.add('open');
|
||||
}
|
||||
function closeModal(){document.getElementById('userMask').classList.remove('open');}
|
||||
function submitForm(){
|
||||
var account=document.getElementById('fAccount').value.trim();if(!account){showToast('请输入账号');return;}
|
||||
var name=document.getElementById('fName').value.trim();if(!name){showToast('请输入姓名');return;}
|
||||
var role=document.getElementById('fRole').value;if(!role){showToast('请选择角色');return;}
|
||||
if(editingId){var u=users.find(function(x){return x.id===editingId;});if(u){u.account=account;u.name=name;u.role=role;}}
|
||||
else users.push({id:String(users.length+1),account:account,name:name,org:'CQ能源',dept:'系统管理部',role:role,status:'激活',time:'2026-09-11 10:00'});
|
||||
closeModal();renderTable();showToast(editingId?'编辑成功':'新增成功');
|
||||
}
|
||||
function openPwd(id){pwdId=id;var u=users.find(function(x){return x.id===id;});document.getElementById('pwdAccount').textContent=u?u.account:'-';document.getElementById('pwdNew').value='';document.getElementById('pwdConfirm').value='';document.getElementById('pwdMask').classList.add('open');}
|
||||
function closePwd(){document.getElementById('pwdMask').classList.remove('open');}
|
||||
function submitPwd(){
|
||||
var p1=document.getElementById('pwdNew').value;var p2=document.getElementById('pwdConfirm').value;
|
||||
if(!p1){showToast('请输入新密码');return;}
|
||||
if(p1!==p2){showToast('两次密码不一致');return;}
|
||||
closePwd();showToast('密码重置成功');
|
||||
}
|
||||
function showToast(msg){var t=document.getElementById('toast');t.textContent=msg;t.classList.add('show');setTimeout(function(){t.classList.remove('show');},1500);}
|
||||
document.addEventListener('click',function(e){if(e.target.id==='userMask')closeModal();if(e.target.id==='pwdMask')closePwd();});
|
||||
renderTable();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,131 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>全部用户 | 系统管理</title>
|
||||
<style>
|
||||
*{box-sizing:border-box;margin:0;padding:0;}
|
||||
body{font-family:-apple-system,BlinkMacSystemFont,'PingFang SC','Microsoft YaHei',sans-serif;font-size:var(--font-sm);background:#F5F7FA;color:#333;min-width:1280px;}
|
||||
:root{--primary:#1890FF;--primary-light:#E6F7FF;--success:#52C41A;--warning:#FAAD14;--danger:#FF4D4F;--text-primary:#333;--text-secondary:#666;--text-placeholder:#999;--border:#E8E8E8;--background:#F5F7FA;--font-xs:11px;--font-sm:13px;--font-base:15px;--font-lg:17px;--radius-sm:4px;--radius-md:8px;--radius-lg:12px;--shadow-sm:0 1px 4px rgba(0,0,0,0.08);--shadow-md:0 4px 12px rgba(0,0,0,0.10);}
|
||||
.top-bar{display:flex;align-items:center;height:56px;background:#001529;padding:0 24px;position:fixed;top:0;left:0;right:0;z-index:100;}
|
||||
.top-bar__logo{display:flex;align-items:center;gap:8px;color:#fff;font-size:var(--font-lg);font-weight:600;white-space:nowrap;width:200px;flex-shrink:0;}
|
||||
.top-bar__logo svg{width:28px;height:28px;}
|
||||
.top-bar__nav{display:flex;align-items:center;gap:4px;flex:1;}
|
||||
.top-bar__nav a{color:rgba(255,255,255,0.65);text-decoration:none;padding:6px 14px;border-radius:var(--radius-sm);font-size:var(--font-sm);transition:all .2s;}
|
||||
.top-bar__nav a:hover{color:#fff;background:rgba(255,255,255,0.08);}
|
||||
.top-bar__nav a.active{color:#fff;background:var(--primary);}
|
||||
.top-bar__right{display:flex;align-items:center;gap:16px;color:rgba(255,255,255,0.65);font-size:var(--font-sm);}
|
||||
.btn-back{color:rgba(255,255,255,0.65);cursor:pointer;display:flex;align-items:center;gap:4px;text-decoration:none;}
|
||||
.btn-back:hover{color:#fff;}
|
||||
.avatar{width:32px;height:32px;border-radius:50%;background:#1890FF;display:flex;align-items:center;justify-content:center;color:#fff;font-size:var(--font-sm);cursor:pointer;}
|
||||
.sidebar{position:fixed;top:56px;left:0;bottom:0;width:240px;background:#001529;overflow-y:auto;z-index:90;padding-top:8px;padding-bottom:24px;}
|
||||
.sidebar-menu__title{color:rgba(255,255,255,0.35);font-size:var(--font-xs);padding:16px 24px 8px;letter-spacing:.5px;}
|
||||
.sidebar-item{display:flex;align-items:center;gap:8px;padding:9px 24px;color:rgba(255,255,255,0.65);font-size:var(--font-sm);cursor:pointer;transition:all .15s;text-decoration:none;}
|
||||
.sidebar-item:hover{color:#fff;background:rgba(255,255,255,0.06);}
|
||||
.sidebar-item.active{color:#fff;background:var(--primary);}
|
||||
.main{margin-left:240px;margin-top:56px;padding:24px;min-height:calc(100vh - 56px);}
|
||||
.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;}
|
||||
.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);}
|
||||
.btn{height:36px;padding:0 16px;border-radius:var(--radius-sm);font-size:var(--font-sm);cursor:pointer;border:none;transition:all .2s;display:inline-flex;align-items:center;gap:6px;white-space:nowrap;}
|
||||
.btn-primary{background:var(--primary);color:#fff;}.btn-primary:hover{background:#40a9ff;}
|
||||
.btn-default{background:#fff;color:var(--text-primary);border:1px solid var(--border);}.btn-default:hover{color:var(--primary);border-color:var(--primary);}
|
||||
.btn-link{background:none;color:var(--primary);padding:0 4px;height:auto;}.btn-link:hover{color:#40a9ff;}
|
||||
.table-card{background:#fff;border-radius:var(--radius-md);box-shadow:var(--shadow-sm);overflow:hidden;margin-top:16px;}
|
||||
.table-card__content{overflow-x:auto;}
|
||||
table{width:100%;border-collapse:separate;border-spacing:0;min-width:1300px;}
|
||||
thead th{background:#FAFAFA;padding:10px 14px;text-align:center;font-size:var(--font-sm);color:var(--text-secondary);font-weight:500;border-bottom:1px solid var(--border);white-space:nowrap;}
|
||||
tbody td{padding:12px 14px;text-align:center;font-size:var(--font-sm);color:var(--text-primary);border-bottom:1px solid #F0F0F0;white-space:nowrap;}
|
||||
tbody tr:last-child td{border-bottom:none;}
|
||||
tbody tr:hover{background:#F8FBFF;}
|
||||
thead tr th:last-child,tbody td:last-child{position:sticky;right:0;z-index:5;background:#fff;box-shadow:-4px 0 8px rgba(0,0,0,0.04);}
|
||||
thead tr th:last-child{z-index:8;background:#FAFAFA;}
|
||||
tbody tr:hover td:last-child{background:#F8FBFF;}
|
||||
.td-empty{text-align:center;padding:48px 0;color:var(--text-placeholder);}
|
||||
.badge{display:inline-block;padding:2px 10px;border-radius:10px;font-size:var(--font-xs);}
|
||||
.badge--success{background:#F6FFED;color:#389E0D;border:1px solid #B7EB8F;}
|
||||
.badge--info{background:#E6F7FF;color:#096DD9;border:1px solid #91D5FF;}
|
||||
.badge--muted{background:#F5F5F5;color:var(--text-secondary);border:1px solid var(--border);}
|
||||
.pagination{display:flex;align-items:center;justify-content:flex-end;padding:16px 24px;gap:8px;border-top:1px solid var(--border);}
|
||||
.pagination span{font-size:var(--font-sm);color:var(--text-secondary);}
|
||||
.page-btn{min-width:32px;height:32px;border:1px solid var(--border);border-radius:var(--radius-sm);background:#fff;cursor:pointer;font-size:var(--font-sm);display:inline-flex;align-items:center;justify-content:center;padding:0 6px;transition:all .2s;}
|
||||
.page-btn:hover,.page-btn.active{background:var(--primary);color:#fff;border-color:var(--primary);}
|
||||
.toast{position:fixed;top:80px;left:50%;transform:translateX(-50%);background:#333;color:#fff;padding:10px 24px;border-radius:var(--radius-sm);font-size:var(--font-sm);z-index:9999;opacity:0;transition:opacity .2s;pointer-events:none;}
|
||||
.toast.show{opacity:1;}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="top-bar">
|
||||
<div class="top-bar__logo"><svg viewBox="0 0 28 28" fill="none"><rect width="28" height="28" rx="6" fill="#1890FF"/><path d="M14 6.5l7 3.5v4.5c0 4.2-2.9 6.8-7 7.5-4.1-.7-7-3.3-7-7.5V10l7-3.5z" stroke="#fff" stroke-width="1.8" fill="none"/><path d="M11 13.5h6M14 10.5v6" stroke="#fff" stroke-width="1.8" stroke-linecap="round"/></svg> 系统管理</div>
|
||||
<nav class="top-bar__nav">
|
||||
<a href="user-admin.html" class="active">用户管理</a>
|
||||
<a href="application.html">权限管理</a>
|
||||
<a href="hospital.html">机构管理</a>
|
||||
<a href="dict.html">系统配置</a>
|
||||
<a href="announcement.html">通知管理</a>
|
||||
</nav>
|
||||
<div class="top-bar__right">
|
||||
<a class="btn-back" href="../../index.html"><svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M10 3L5 8l5 5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg> 返回首页</a>
|
||||
<div class="avatar">管</div>
|
||||
<span style="color:rgba(255,255,255,0.65);">系统管理员 ▾</span>
|
||||
</div>
|
||||
</div>
|
||||
<aside class="sidebar">
|
||||
<div class="sidebar-menu__title">用户管理</div>
|
||||
<a href="user-admin.html" class="sidebar-item">管理员账号</a>
|
||||
<a href="user-all.html" class="sidebar-item active">全部用户</a>
|
||||
<a href="user-consult.html" class="sidebar-item">咨询账号</a>
|
||||
<a href="user-emergency.html" class="sidebar-item">应急中心账号</a>
|
||||
<a href="user-employee.html" class="sidebar-item">员工账号</a>
|
||||
</aside>
|
||||
|
||||
<main class="main">
|
||||
<div class="filter-bar">
|
||||
<div class="filter-item"><label>账号</label><input class="filter-input" id="filterAccount" placeholder="请输入账号"></div>
|
||||
<div class="filter-item"><label>姓名</label><input class="filter-input" id="filterName" placeholder="请输入姓名"></div>
|
||||
<div class="filter-item"><label>用户类型</label><select class="filter-select" id="filterType"><option value="">请选择用户类型</option><option>管理员</option><option>咨询小助手</option><option>员工</option><option>咨询专家</option></select></div>
|
||||
<div class="filter-item"><label>单位部门</label><select class="filter-select" id="filterOrg"><option value="">请选择单位部门</option><option>CQ能源/系统管理部</option><option>CQ能源/采油一厂</option><option>CQ能源/采油二厂</option></select></div>
|
||||
<button class="btn btn-primary" onclick="searchQuery()"><svg width="14" height="14" viewBox="0 0 14 14" fill="none"><circle cx="6" cy="6" r="4.5" stroke="#fff" stroke-width="1.3"/><path d="M9.5 9.5L13 13" stroke="#fff" stroke-width="1.3" stroke-linecap="round"/></svg>查询</button>
|
||||
<button class="btn btn-default" onclick="resetQuery()">重置</button>
|
||||
</div>
|
||||
<div class="table-card">
|
||||
<div class="table-card__content">
|
||||
<table>
|
||||
<thead><tr><th style="width:70px">序号</th><th style="width:140px">账号</th><th style="width:110px">姓名</th><th style="width:120px">用户类型</th><th style="width:140px">用户角色</th><th style="width:140px">单位</th><th style="width:160px">部门</th><th style="width:100px">状态</th><th style="width:180px">创建时间</th><th style="width:130px">操作</th></tr></thead>
|
||||
<tbody id="tableBody"></tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="pagination"><span>共 <b id="totalCount">0</b> 条</span><button class="page-btn" onclick="showToast('演示数据仅一页')">上一页</button><button class="page-btn active">1</button><button class="page-btn" onclick="showToast('演示数据仅一页')">下一页</button></div>
|
||||
</div>
|
||||
</main>
|
||||
<div class="toast" id="toast"></div>
|
||||
|
||||
<script>
|
||||
var allUsers=[
|
||||
{id:'1',account:'admin',name:'系统管理员',type:'管理员',role:'超级管理员',org:'CQ能源',dept:'系统管理部',status:'正常',time:'2026-08-01 10:00'},
|
||||
{id:'2',account:'zhangwei',name:'张伟',type:'员工',role:'员工',org:'CQ能源',dept:'采油一厂/安全环保科',status:'正常',time:'2026-08-01 10:00'},
|
||||
{id:'3',account:'liyan',name:'李艳',type:'员工',role:'员工',org:'CQ能源',dept:'采油二厂/姬圪台联合站',status:'正常',time:'2026-08-01 10:00'},
|
||||
{id:'4',account:'expert01',name:'王医生',type:'咨询专家',role:'咨询专家',org:'CQ能源职工医院',dept:'心内科',status:'正常',time:'2026-08-02 09:30'},
|
||||
{id:'5',account:'assist01',name:'小助手',type:'咨询小助手',role:'咨询小助手',org:'CQ能源',dept:'健康咨询中心',status:'正常',time:'2026-08-03 14:20'},
|
||||
{id:'6',account:'wangqiang',name:'王强',type:'员工',role:'员工',org:'CQ能源',dept:'第四采油厂/基地管理处',status:'锁定',time:'2026-08-03 15:00'}
|
||||
];
|
||||
function typeBadge(t){return t==='管理员'?'badge--info':t==='咨询专家'?'badge--info':t==='咨询小助手'?'badge--info':'badge--muted';}
|
||||
function renderTable(){
|
||||
var list=allUsers;
|
||||
document.getElementById('totalCount').textContent=list.length;
|
||||
document.getElementById('tableBody').innerHTML=list.map(function(u,i){
|
||||
return '<tr><td>'+(i+1)+'</td><td>'+u.account+'</td><td>'+u.name+'</td><td><span class="badge '+typeBadge(u.type)+'">'+u.type+'</span></td><td>'+u.role+'</td><td>'+u.org+'</td><td>'+u.dept+'</td><td><span class="badge '+(u.status==='正常'?'badge--success':'badge--muted')+'">'+u.status+'</span></td><td>'+u.time+'</td>'+
|
||||
'<td><button class="btn btn-link" onclick="showToast(\'查看详情\')">详情</button><span style="color:var(--border);margin:0 4px;">|</span><button class="btn btn-link" onclick="showToast(\'编辑\')">编辑</button></td></tr>';
|
||||
}).join('');
|
||||
}
|
||||
function searchQuery(){renderTable();showToast('查询完成');}
|
||||
function resetQuery(){document.getElementById('filterAccount').value='';document.getElementById('filterName').value='';document.getElementById('filterType').value='';document.getElementById('filterOrg').value='';renderTable();}
|
||||
function showToast(msg){var t=document.getElementById('toast');t.textContent=msg;t.classList.add('show');setTimeout(function(){t.classList.remove('show');},1500);}
|
||||
renderTable();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,156 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>咨询账号 | 系统管理</title>
|
||||
<style>
|
||||
*{box-sizing:border-box;margin:0;padding:0;}
|
||||
body{font-family:-apple-system,BlinkMacSystemFont,'PingFang SC','Microsoft YaHei',sans-serif;font-size:var(--font-sm);background:#F5F7FA;color:#333;min-width:1280px;}
|
||||
:root{--primary:#1890FF;--primary-light:#E6F7FF;--success:#52C41A;--warning:#FAAD14;--danger:#FF4D4F;--text-primary:#333;--text-secondary:#666;--text-placeholder:#999;--border:#E8E8E8;--background:#F5F7FA;--font-xs:11px;--font-sm:13px;--font-base:15px;--font-lg:17px;--radius-sm:4px;--radius-md:8px;--radius-lg:12px;--shadow-sm:0 1px 4px rgba(0,0,0,0.08);--shadow-md:0 4px 12px rgba(0,0,0,0.10);}
|
||||
.top-bar{display:flex;align-items:center;height:56px;background:#001529;padding:0 24px;position:fixed;top:0;left:0;right:0;z-index:100;}
|
||||
.top-bar__logo{display:flex;align-items:center;gap:8px;color:#fff;font-size:var(--font-lg);font-weight:600;white-space:nowrap;width:200px;flex-shrink:0;}
|
||||
.top-bar__logo svg{width:28px;height:28px;}
|
||||
.top-bar__nav{display:flex;align-items:center;gap:4px;flex:1;}
|
||||
.top-bar__nav a{color:rgba(255,255,255,0.65);text-decoration:none;padding:6px 14px;border-radius:var(--radius-sm);font-size:var(--font-sm);transition:all .2s;}
|
||||
.top-bar__nav a:hover{color:#fff;background:rgba(255,255,255,0.08);}
|
||||
.top-bar__nav a.active{color:#fff;background:var(--primary);}
|
||||
.top-bar__right{display:flex;align-items:center;gap:16px;color:rgba(255,255,255,0.65);font-size:var(--font-sm);}
|
||||
.btn-back{color:rgba(255,255,255,0.65);cursor:pointer;display:flex;align-items:center;gap:4px;text-decoration:none;}
|
||||
.btn-back:hover{color:#fff;}
|
||||
.avatar{width:32px;height:32px;border-radius:50%;background:#1890FF;display:flex;align-items:center;justify-content:center;color:#fff;font-size:var(--font-sm);cursor:pointer;}
|
||||
.sidebar{position:fixed;top:56px;left:0;bottom:0;width:240px;background:#001529;overflow-y:auto;z-index:90;padding-top:8px;padding-bottom:24px;}
|
||||
.sidebar-menu__title{color:rgba(255,255,255,0.35);font-size:var(--font-xs);padding:16px 24px 8px;letter-spacing:.5px;}
|
||||
.sidebar-item{display:flex;align-items:center;gap:8px;padding:9px 24px;color:rgba(255,255,255,0.65);font-size:var(--font-sm);cursor:pointer;transition:all .15s;text-decoration:none;}
|
||||
.sidebar-item:hover{color:#fff;background:rgba(255,255,255,0.06);}
|
||||
.sidebar-item.active{color:#fff;background:var(--primary);}
|
||||
.main{margin-left:240px;margin-top:56px;padding:24px;min-height:calc(100vh - 56px);}
|
||||
.radio-bar{background:#fff;padding:12px 24px;display:flex;align-items:center;gap:8px;border-radius:var(--radius-md);box-shadow:var(--shadow-sm);margin-bottom:16px;}
|
||||
.radio-group{display:inline-flex;border:1px solid var(--border);border-radius:var(--radius-sm);overflow:hidden;}
|
||||
.radio-group label{padding:8px 20px;font-size:var(--font-sm);cursor:pointer;color:var(--text-secondary);background:#fff;border-right:1px solid var(--border);}
|
||||
.radio-group label:last-child{border-right:none;}
|
||||
.radio-group label.on{background:var(--primary);color:#fff;}
|
||||
.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;}
|
||||
.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);}
|
||||
.btn{height:36px;padding:0 16px;border-radius:var(--radius-sm);font-size:var(--font-sm);cursor:pointer;border:none;transition:all .2s;display:inline-flex;align-items:center;gap:6px;white-space:nowrap;}
|
||||
.btn-primary{background:var(--primary);color:#fff;}.btn-primary:hover{background:#40a9ff;}
|
||||
.btn-default{background:#fff;color:var(--text-primary);border:1px solid var(--border);}.btn-default:hover{color:var(--primary);border-color:var(--primary);}
|
||||
.btn-link{background:none;color:var(--primary);padding:0 4px;height:auto;}.btn-link:hover{color:#40a9ff;}
|
||||
.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);}
|
||||
.table-card{background:#fff;border-radius:0 0 var(--radius-md) var(--radius-md);box-shadow:var(--shadow-sm);overflow:hidden;}
|
||||
.table-card__content{overflow-x:auto;}
|
||||
table{width:100%;border-collapse:separate;border-spacing:0;min-width:1400px;}
|
||||
thead th{background:#FAFAFA;padding:10px 14px;text-align:center;font-size:var(--font-sm);color:var(--text-secondary);font-weight:500;border-bottom:1px solid var(--border);white-space:nowrap;}
|
||||
tbody td{padding:12px 14px;text-align:center;font-size:var(--font-sm);color:var(--text-primary);border-bottom:1px solid #F0F0F0;white-space:nowrap;}
|
||||
tbody tr:last-child td{border-bottom:none;}
|
||||
tbody tr:hover{background:#F8FBFF;}
|
||||
thead tr th:last-child,tbody td:last-child{position:sticky;right:0;z-index:5;background:#fff;box-shadow:-4px 0 8px rgba(0,0,0,0.04);}
|
||||
thead tr th:last-child{z-index:8;background:#FAFAFA;}
|
||||
tbody tr:hover td:last-child{background:#F8FBFF;}
|
||||
.td-empty{text-align:center;padding:48px 0;color:var(--text-placeholder);}
|
||||
.badge{display:inline-block;padding:2px 10px;border-radius:10px;font-size:var(--font-xs);}
|
||||
.badge--success{background:#F6FFED;color:#389E0D;border:1px solid #B7EB8F;}
|
||||
.badge--info{background:#E6F7FF;color:#096DD9;border:1px solid #91D5FF;}
|
||||
.badge--muted{background:#F5F5F5;color:var(--text-secondary);border:1px solid var(--border);}
|
||||
.pagination{display:flex;align-items:center;justify-content:flex-end;padding:16px 24px;gap:8px;border-top:1px solid var(--border);}
|
||||
.pagination span{font-size:var(--font-sm);color:var(--text-secondary);}
|
||||
.page-btn{min-width:32px;height:32px;border:1px solid var(--border);border-radius:var(--radius-sm);background:#fff;cursor:pointer;font-size:var(--font-sm);display:inline-flex;align-items:center;justify-content:center;padding:0 6px;transition:all .2s;}
|
||||
.page-btn:hover,.page-btn.active{background:var(--primary);color:#fff;border-color:var(--primary);}
|
||||
.toast{position:fixed;top:80px;left:50%;transform:translateX(-50%);background:#333;color:#fff;padding:10px 24px;border-radius:var(--radius-sm);font-size:var(--font-sm);z-index:9999;opacity:0;transition:opacity .2s;pointer-events:none;}
|
||||
.toast.show{opacity:1;}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="top-bar">
|
||||
<div class="top-bar__logo"><svg viewBox="0 0 28 28" fill="none"><rect width="28" height="28" rx="6" fill="#1890FF"/><path d="M14 6.5l7 3.5v4.5c0 4.2-2.9 6.8-7 7.5-4.1-.7-7-3.3-7-7.5V10l7-3.5z" stroke="#fff" stroke-width="1.8" fill="none"/><path d="M11 13.5h6M14 10.5v6" stroke="#fff" stroke-width="1.8" stroke-linecap="round"/></svg> 系统管理</div>
|
||||
<nav class="top-bar__nav">
|
||||
<a href="user-admin.html" class="active">用户管理</a>
|
||||
<a href="application.html">权限管理</a>
|
||||
<a href="hospital.html">机构管理</a>
|
||||
<a href="dict.html">系统配置</a>
|
||||
<a href="announcement.html">通知管理</a>
|
||||
</nav>
|
||||
<div class="top-bar__right">
|
||||
<a class="btn-back" href="../../index.html"><svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M10 3L5 8l5 5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg> 返回首页</a>
|
||||
<div class="avatar">管</div>
|
||||
<span style="color:rgba(255,255,255,0.65);">系统管理员 ▾</span>
|
||||
</div>
|
||||
</div>
|
||||
<aside class="sidebar">
|
||||
<div class="sidebar-menu__title">用户管理</div>
|
||||
<a href="user-admin.html" class="sidebar-item">管理员账号</a>
|
||||
<a href="user-all.html" class="sidebar-item">全部用户</a>
|
||||
<a href="user-consult.html" class="sidebar-item active">咨询账号</a>
|
||||
<a href="user-emergency.html" class="sidebar-item">应急中心账号</a>
|
||||
<a href="user-employee.html" class="sidebar-item">员工账号</a>
|
||||
</aside>
|
||||
|
||||
<main class="main">
|
||||
<div class="radio-bar">
|
||||
<span style="color:var(--text-secondary);font-size:var(--font-sm);margin-right:4px;">账号类型</span>
|
||||
<div class="radio-group">
|
||||
<label class="on" data-type="expert" onclick="switchType('expert',this)">咨询专家</label>
|
||||
<label data-type="assistant" onclick="switchType('assistant',this)">咨询小助手</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="filter-bar">
|
||||
<div class="filter-item"><label>账号</label><input class="filter-input" id="filterAccount" placeholder="请输入账号"></div>
|
||||
<div class="filter-item"><label>姓名</label><input class="filter-input" id="filterName" placeholder="请输入姓名"></div>
|
||||
<div class="filter-item"><label>账号状态</label><select class="filter-select" id="filterStatus"><option value="">请选择状态</option><option>正常</option><option>锁定</option></select></div>
|
||||
<button class="btn btn-primary" onclick="renderTable()"><svg width="14" height="14" viewBox="0 0 14 14" fill="none"><circle cx="6" cy="6" r="4.5" stroke="#fff" stroke-width="1.3"/><path d="M9.5 9.5L13 13" stroke="#fff" stroke-width="1.3" stroke-linecap="round"/></svg>查询</button>
|
||||
<button class="btn btn-default" onclick="resetQuery()">重置</button>
|
||||
</div>
|
||||
<div class="action-bar"><button class="btn btn-primary" onclick="showToast('新增账号')"><svg width="14" height="14" viewBox="0 0 14 14" fill="none"><path d="M7 2v10M2 7h10" stroke="currentColor" stroke-width="1.4" stroke-linecap="round"/></svg>新增账号</button></div>
|
||||
<div class="table-card">
|
||||
<div class="table-card__content">
|
||||
<table>
|
||||
<thead id="tableHead"></thead>
|
||||
<tbody id="tableBody"></tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="pagination"><span>共 <b id="totalCount">0</b> 条</span><button class="page-btn" onclick="showToast('演示数据仅一页')">上一页</button><button class="page-btn active">1</button><button class="page-btn" onclick="showToast('演示数据仅一页')">下一页</button></div>
|
||||
</div>
|
||||
</main>
|
||||
<div class="toast" id="toast"></div>
|
||||
|
||||
<script>
|
||||
var curType='expert';
|
||||
var experts=[
|
||||
{id:'1',account:'expert01',no:'ZJ001',name:'王医生',hospital:'CQ能源职工医院',dept:'心内科',title:'主任医师',status:'正常',consult:'接诊中',fee:'收费',sort:1,recommend:'是'},
|
||||
{id:'2',account:'expert02',no:'ZJ002',name:'李医生',hospital:'西安市中心医院',dept:'内分泌科',title:'副主任医师',status:'正常',consult:'空闲',fee:'免费',sort:2,recommend:'否'}
|
||||
];
|
||||
var assistants=[
|
||||
{id:'1',account:'assist01',no:'XZS001',name:'小助手一号',hospital:'CQ能源',dept:'健康咨询中心',title:'咨询师',status:'正常',consult:'在线',fee:'-',sort:1,recommend:'否'}
|
||||
];
|
||||
var expertHead='<tr><th style="width:60px">序号</th><th>账号</th><th>专家编号</th><th>姓名</th><th>头像</th><th>医院</th><th>科室</th><th>职称</th><th>账号状态</th><th>咨询状态</th><th>收费类型</th><th>排序</th><th>是否推荐</th><th style="width:160px">操作</th></tr>';
|
||||
var assistantHead='<tr><th style="width:60px">序号</th><th>账号</th><th>姓名</th><th>头像</th><th>所属中心</th><th>职称</th><th>账号状态</th><th>在线状态</th><th style="width:160px">操作</th></tr>';
|
||||
function switchType(type,el){
|
||||
curType=type;
|
||||
document.querySelectorAll('.radio-group label').forEach(function(l){l.classList.remove('on');});
|
||||
el.classList.add('on');
|
||||
renderTable();
|
||||
}
|
||||
function renderTable(){
|
||||
var isExpert=curType==='expert';
|
||||
document.getElementById('tableHead').innerHTML=isExpert?expertHead:assistantHead;
|
||||
var list=isExpert?experts:assistants;
|
||||
document.getElementById('totalCount').textContent=list.length;
|
||||
document.getElementById('tableBody').innerHTML=list.map(function(u,i){
|
||||
var avatar='<span class="avatar" style="width:32px;height:32px;font-size:12px;">'+(u.name?u.name.charAt(0):'')+'</span>';
|
||||
var ops='<td><button class="btn btn-link" onclick="showToast(\'详情\')">详情</button><span style="color:var(--border);margin:0 4px;">|</span><button class="btn btn-link" onclick="showToast(\'编辑\')">编辑</button><span style="color:var(--border);margin:0 4px;">|</span><button class="btn btn-link" onclick="showToast(\'重置密码\')">重置密码</button></td>';
|
||||
if(isExpert){
|
||||
return '<tr><td>'+(i+1)+'</td><td>'+u.account+'</td><td>'+u.no+'</td><td>'+u.name+'</td><td>'+avatar+'</td><td>'+u.hospital+'</td><td>'+u.dept+'</td><td>'+u.title+'</td><td><span class="badge badge--success">'+u.status+'</span></td><td><span class="badge badge--info">'+u.consult+'</span></td><td>'+u.fee+'</td><td>'+u.sort+'</td><td>'+u.recommend+'</td>'+ops+'</tr>';
|
||||
}
|
||||
return '<tr><td>'+(i+1)+'</td><td>'+u.account+'</td><td>'+u.name+'</td><td>'+avatar+'</td><td>'+u.hospital+'</td><td>'+u.title+'</td><td><span class="badge badge--success">'+u.status+'</span></td><td><span class="badge badge--info">'+u.consult+'</span></td>'+ops+'</tr>';
|
||||
}).join('');
|
||||
}
|
||||
function resetQuery(){document.getElementById('filterAccount').value='';document.getElementById('filterName').value='';document.getElementById('filterStatus').value='';renderTable();}
|
||||
function showToast(msg){var t=document.getElementById('toast');t.textContent=msg;t.classList.add('show');setTimeout(function(){t.classList.remove('show');},1500);}
|
||||
renderTable();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,164 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>应急中心账号 | 系统管理</title>
|
||||
<style>
|
||||
*{box-sizing:border-box;margin:0;padding:0;}
|
||||
body{font-family:-apple-system,BlinkMacSystemFont,'PingFang SC','Microsoft YaHei',sans-serif;font-size:var(--font-sm);background:#F5F7FA;color:#333;min-width:1280px;}
|
||||
:root{--primary:#1890FF;--primary-light:#E6F7FF;--success:#52C41A;--warning:#FAAD14;--danger:#FF4D4F;--text-primary:#333;--text-secondary:#666;--text-placeholder:#999;--border:#E8E8E8;--background:#F5F7FA;--font-xs:11px;--font-sm:13px;--font-base:15px;--font-lg:17px;--radius-sm:4px;--radius-md:8px;--radius-lg:12px;--shadow-sm:0 1px 4px rgba(0,0,0,0.08);--shadow-md:0 4px 12px rgba(0,0,0,0.10);}
|
||||
.top-bar{display:flex;align-items:center;height:56px;background:#001529;padding:0 24px;position:fixed;top:0;left:0;right:0;z-index:100;}
|
||||
.top-bar__logo{display:flex;align-items:center;gap:8px;color:#fff;font-size:var(--font-lg);font-weight:600;white-space:nowrap;width:200px;flex-shrink:0;}
|
||||
.top-bar__logo svg{width:28px;height:28px;}
|
||||
.top-bar__nav{display:flex;align-items:center;gap:4px;flex:1;}
|
||||
.top-bar__nav a{color:rgba(255,255,255,0.65);text-decoration:none;padding:6px 14px;border-radius:var(--radius-sm);font-size:var(--font-sm);transition:all .2s;}
|
||||
.top-bar__nav a:hover{color:#fff;background:rgba(255,255,255,0.08);}
|
||||
.top-bar__nav a.active{color:#fff;background:var(--primary);}
|
||||
.top-bar__right{display:flex;align-items:center;gap:16px;color:rgba(255,255,255,0.65);font-size:var(--font-sm);}
|
||||
.btn-back{color:rgba(255,255,255,0.65);cursor:pointer;display:flex;align-items:center;gap:4px;text-decoration:none;}
|
||||
.btn-back:hover{color:#fff;}
|
||||
.avatar{width:32px;height:32px;border-radius:50%;background:#1890FF;display:flex;align-items:center;justify-content:center;color:#fff;font-size:var(--font-sm);cursor:pointer;}
|
||||
.sidebar{position:fixed;top:56px;left:0;bottom:0;width:240px;background:#001529;overflow-y:auto;z-index:90;padding-top:8px;padding-bottom:24px;}
|
||||
.sidebar-menu__title{color:rgba(255,255,255,0.35);font-size:var(--font-xs);padding:16px 24px 8px;letter-spacing:.5px;}
|
||||
.sidebar-item{display:flex;align-items:center;gap:8px;padding:9px 24px;color:rgba(255,255,255,0.65);font-size:var(--font-sm);cursor:pointer;transition:all .15s;text-decoration:none;}
|
||||
.sidebar-item:hover{color:#fff;background:rgba(255,255,255,0.06);}
|
||||
.sidebar-item.active{color:#fff;background:var(--primary);}
|
||||
.main{margin-left:240px;margin-top:56px;padding:24px;min-height:calc(100vh - 56px);}
|
||||
.radio-bar{background:#fff;padding:12px 24px;display:flex;align-items:center;gap:8px;border-radius:var(--radius-md);box-shadow:var(--shadow-sm);margin-bottom:16px;flex-wrap:wrap;}
|
||||
.radio-group{display:inline-flex;border:1px solid var(--border);border-radius:var(--radius-sm);overflow:hidden;flex-wrap:wrap;}
|
||||
.radio-group label{padding:8px 18px;font-size:var(--font-sm);cursor:pointer;color:var(--text-secondary);background:#fff;border-right:1px solid var(--border);}
|
||||
.radio-group label:last-child{border-right:none;}
|
||||
.radio-group label.on{background:var(--primary);color:#fff;}
|
||||
.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;}
|
||||
.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);}
|
||||
.btn{height:36px;padding:0 16px;border-radius:var(--radius-sm);font-size:var(--font-sm);cursor:pointer;border:none;transition:all .2s;display:inline-flex;align-items:center;gap:6px;white-space:nowrap;}
|
||||
.btn-primary{background:var(--primary);color:#fff;}.btn-primary:hover{background:#40a9ff;}
|
||||
.btn-default{background:#fff;color:var(--text-primary);border:1px solid var(--border);}.btn-default:hover{color:var(--primary);border-color:var(--primary);}
|
||||
.btn-link{background:none;color:var(--primary);padding:0 4px;height:auto;}.btn-link:hover{color:#40a9ff;}
|
||||
.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);}
|
||||
.table-card{background:#fff;border-radius:0 0 var(--radius-md) var(--radius-md);box-shadow:var(--shadow-sm);overflow:hidden;}
|
||||
.table-card__content{overflow-x:auto;}
|
||||
table{width:100%;border-collapse:separate;border-spacing:0;min-width:1100px;}
|
||||
thead th{background:#FAFAFA;padding:10px 14px;text-align:center;font-size:var(--font-sm);color:var(--text-secondary);font-weight:500;border-bottom:1px solid var(--border);white-space:nowrap;}
|
||||
tbody td{padding:12px 14px;text-align:center;font-size:var(--font-sm);color:var(--text-primary);border-bottom:1px solid #F0F0F0;white-space:nowrap;}
|
||||
tbody tr:last-child td{border-bottom:none;}
|
||||
tbody tr:hover{background:#F8FBFF;}
|
||||
thead tr th:last-child,tbody td:last-child{position:sticky;right:0;z-index:5;background:#fff;box-shadow:-4px 0 8px rgba(0,0,0,0.04);}
|
||||
thead tr th:last-child{z-index:8;background:#FAFAFA;}
|
||||
tbody tr:hover td:last-child{background:#F8FBFF;}
|
||||
.td-empty{text-align:center;padding:48px 0;color:var(--text-placeholder);}
|
||||
.badge{display:inline-block;padding:2px 10px;border-radius:10px;font-size:var(--font-xs);}
|
||||
.badge--success{background:#F6FFED;color:#389E0D;border:1px solid #B7EB8F;}
|
||||
.badge--muted{background:#F5F5F5;color:var(--text-secondary);border:1px solid var(--border);}
|
||||
.pagination{display:flex;align-items:center;justify-content:flex-end;padding:16px 24px;gap:8px;border-top:1px solid var(--border);}
|
||||
.pagination span{font-size:var(--font-sm);color:var(--text-secondary);}
|
||||
.page-btn{min-width:32px;height:32px;border:1px solid var(--border);border-radius:var(--radius-sm);background:#fff;cursor:pointer;font-size:var(--font-sm);display:inline-flex;align-items:center;justify-content:center;padding:0 6px;transition:all .2s;}
|
||||
.page-btn:hover,.page-btn.active{background:var(--primary);color:#fff;border-color:var(--primary);}
|
||||
.toast{position:fixed;top:80px;left:50%;transform:translateX(-50%);background:#333;color:#fff;padding:10px 24px;border-radius:var(--radius-sm);font-size:var(--font-sm);z-index:9999;opacity:0;transition:opacity .2s;pointer-events:none;}
|
||||
.toast.show{opacity:1;}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="top-bar">
|
||||
<div class="top-bar__logo"><svg viewBox="0 0 28 28" fill="none"><rect width="28" height="28" rx="6" fill="#1890FF"/><path d="M14 6.5l7 3.5v4.5c0 4.2-2.9 6.8-7 7.5-4.1-.7-7-3.3-7-7.5V10l7-3.5z" stroke="#fff" stroke-width="1.8" fill="none"/><path d="M11 13.5h6M14 10.5v6" stroke="#fff" stroke-width="1.8" stroke-linecap="round"/></svg> 系统管理</div>
|
||||
<nav class="top-bar__nav">
|
||||
<a href="user-admin.html" class="active">用户管理</a>
|
||||
<a href="application.html">权限管理</a>
|
||||
<a href="hospital.html">机构管理</a>
|
||||
<a href="dict.html">系统配置</a>
|
||||
<a href="announcement.html">通知管理</a>
|
||||
</nav>
|
||||
<div class="top-bar__right">
|
||||
<a class="btn-back" href="../../index.html"><svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M10 3L5 8l5 5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg> 返回首页</a>
|
||||
<div class="avatar">管</div>
|
||||
<span style="color:rgba(255,255,255,0.65);">系统管理员 ▾</span>
|
||||
</div>
|
||||
</div>
|
||||
<aside class="sidebar">
|
||||
<div class="sidebar-menu__title">用户管理</div>
|
||||
<a href="user-admin.html" class="sidebar-item">管理员账号</a>
|
||||
<a href="user-all.html" class="sidebar-item">全部用户</a>
|
||||
<a href="user-consult.html" class="sidebar-item">咨询账号</a>
|
||||
<a href="user-emergency.html" class="sidebar-item active">应急中心账号</a>
|
||||
<a href="user-employee.html" class="sidebar-item">员工账号</a>
|
||||
</aside>
|
||||
|
||||
<main class="main">
|
||||
<div class="radio-bar">
|
||||
<span style="color:var(--text-secondary);font-size:var(--font-sm);margin-right:4px;">账号类型</span>
|
||||
<div class="radio-group" id="typeGroup">
|
||||
<label class="on" data-type="admin" onclick="switchType('admin',this)">应急中心管理员</label>
|
||||
<label data-type="screen" onclick="switchType('screen',this)">应急大屏账号</label>
|
||||
<label data-type="operator" onclick="switchType('operator',this)">应急操作人员</label>
|
||||
<label data-type="professional" onclick="switchType('professional',this)">应急专业人员</label>
|
||||
<label data-type="onsite" onclick="switchType('onsite',this)">应急驻场人员</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="filter-bar">
|
||||
<div class="filter-item"><label>账号</label><input class="filter-input" id="filterAccount" placeholder="请输入账号"></div>
|
||||
<div class="filter-item"><label>姓名</label><input class="filter-input" id="filterName" placeholder="请输入姓名"></div>
|
||||
<div class="filter-item"><label>账号状态</label><select class="filter-select" id="filterStatus"><option value="">请选择状态</option><option>正常</option><option>锁定</option></select></div>
|
||||
<button class="btn btn-primary" onclick="renderTable()"><svg width="14" height="14" viewBox="0 0 14 14" fill="none"><circle cx="6" cy="6" r="4.5" stroke="#fff" stroke-width="1.3"/><path d="M9.5 9.5L13 13" stroke="#fff" stroke-width="1.3" stroke-linecap="round"/></svg>查询</button>
|
||||
<button class="btn btn-default" onclick="resetQuery()">重置</button>
|
||||
</div>
|
||||
<div class="action-bar"><button class="btn btn-primary" onclick="showToast('新增账号')"><svg width="14" height="14" viewBox="0 0 14 14" fill="none"><path d="M7 2v10M2 7h10" stroke="currentColor" stroke-width="1.4" stroke-linecap="round"/></svg>新增账号</button></div>
|
||||
<div class="table-card">
|
||||
<div class="table-card__content">
|
||||
<table>
|
||||
<thead><tr><th style="width:60px">序号</th><th>账号</th><th>姓名</th><th>头像</th><th>应急中心</th><th>账号状态</th><th style="width:160px">操作</th></tr></thead>
|
||||
<tbody id="tableBody"></tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="pagination"><span>共 <b id="totalCount">0</b> 条</span><button class="page-btn" onclick="showToast('演示数据仅一页')">上一页</button><button class="page-btn active">1</button><button class="page-btn" onclick="showToast('演示数据仅一页')">下一页</button></div>
|
||||
</div>
|
||||
</main>
|
||||
<div class="toast" id="toast"></div>
|
||||
|
||||
<script>
|
||||
var curType='admin';
|
||||
var accounts={
|
||||
admin:[
|
||||
{id:'1',account:'em_admin01',name:'应急管理员',center:'西安应急中心',status:'正常'},
|
||||
{id:'2',account:'em_admin02',name:'应急管理员2',center:'标准版应急中心',status:'正常'}
|
||||
],
|
||||
screen:[
|
||||
{id:'1',account:'em_screen01',name:'大屏账号',center:'西安应急中心',status:'正常'}
|
||||
],
|
||||
operator:[
|
||||
{id:'1',account:'em_op01',name:'操作员甲',center:'西安应急中心',status:'正常'},
|
||||
{id:'2',account:'em_op02',name:'操作员乙',center:'九厂应急中心',status:'锁定'}
|
||||
],
|
||||
professional:[
|
||||
{id:'1',account:'em_pro01',name:'专业医师',center:'西安应急中心',status:'正常'}
|
||||
],
|
||||
onsite:[
|
||||
{id:'1',account:'em_onsite01',name:'驻场人员',center:'采油一厂医疗点',status:'正常'},
|
||||
{id:'2',account:'em_onsite02',name:'驻场人员2',center:'采气一厂医疗点',status:'正常'}
|
||||
]
|
||||
};
|
||||
function switchType(type,el){
|
||||
curType=type;
|
||||
document.querySelectorAll('#typeGroup label').forEach(function(l){l.classList.remove('on');});
|
||||
el.classList.add('on');
|
||||
renderTable();
|
||||
}
|
||||
function renderTable(){
|
||||
var list=accounts[curType]||[];
|
||||
document.getElementById('totalCount').textContent=list.length;
|
||||
document.getElementById('tableBody').innerHTML=list.length===0?'<tr><td colspan="7" class="td-empty">暂无数据</td></tr>':list.map(function(u,i){
|
||||
var avatar='<span class="avatar" style="width:32px;height:32px;font-size:12px;">'+u.name.charAt(0)+'</span>';
|
||||
return '<tr><td>'+(i+1)+'</td><td>'+u.account+'</td><td>'+u.name+'</td><td>'+avatar+'</td><td>'+u.center+'</td><td><span class="badge '+(u.status==='正常'?'badge--success':'badge--muted')+'">'+u.status+'</span></td>'+
|
||||
'<td><button class="btn btn-link" onclick="showToast(\'详情\')">详情</button><span style="color:var(--border);margin:0 4px;">|</span><button class="btn btn-link" onclick="showToast(\'编辑\')">编辑</button><span style="color:var(--border);margin:0 4px;">|</span><button class="btn btn-link" onclick="showToast(\'重置密码\')">重置密码</button></td></tr>';
|
||||
}).join('');
|
||||
}
|
||||
function resetQuery(){document.getElementById('filterAccount').value='';document.getElementById('filterName').value='';document.getElementById('filterStatus').value='';renderTable();}
|
||||
function showToast(msg){var t=document.getElementById('toast');t.textContent=msg;t.classList.add('show');setTimeout(function(){t.classList.remove('show');},1500);}
|
||||
renderTable();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,177 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>员工账号 | 系统管理</title>
|
||||
<style>
|
||||
*{box-sizing:border-box;margin:0;padding:0;}
|
||||
body{font-family:-apple-system,BlinkMacSystemFont,'PingFang SC','Microsoft YaHei',sans-serif;font-size:var(--font-sm);background:#F5F7FA;color:#333;min-width:1280px;}
|
||||
:root{--primary:#1890FF;--primary-light:#E6F7FF;--success:#52C41A;--warning:#FAAD14;--danger:#FF4D4F;--text-primary:#333;--text-secondary:#666;--text-placeholder:#999;--border:#E8E8E8;--background:#F5F7FA;--font-xs:11px;--font-sm:13px;--font-base:15px;--font-lg:17px;--radius-sm:4px;--radius-md:8px;--radius-lg:12px;--shadow-sm:0 1px 4px rgba(0,0,0,0.08);--shadow-md:0 4px 12px rgba(0,0,0,0.10);}
|
||||
.top-bar{display:flex;align-items:center;height:56px;background:#001529;padding:0 24px;position:fixed;top:0;left:0;right:0;z-index:100;}
|
||||
.top-bar__logo{display:flex;align-items:center;gap:8px;color:#fff;font-size:var(--font-lg);font-weight:600;white-space:nowrap;width:200px;flex-shrink:0;}
|
||||
.top-bar__logo svg{width:28px;height:28px;}
|
||||
.top-bar__nav{display:flex;align-items:center;gap:4px;flex:1;}
|
||||
.top-bar__nav a{color:rgba(255,255,255,0.65);text-decoration:none;padding:6px 14px;border-radius:var(--radius-sm);font-size:var(--font-sm);transition:all .2s;}
|
||||
.top-bar__nav a:hover{color:#fff;background:rgba(255,255,255,0.08);}
|
||||
.top-bar__nav a.active{color:#fff;background:var(--primary);}
|
||||
.top-bar__right{display:flex;align-items:center;gap:16px;color:rgba(255,255,255,0.65);font-size:var(--font-sm);}
|
||||
.btn-back{color:rgba(255,255,255,0.65);cursor:pointer;display:flex;align-items:center;gap:4px;text-decoration:none;}
|
||||
.btn-back:hover{color:#fff;}
|
||||
.avatar{width:32px;height:32px;border-radius:50%;background:#1890FF;display:flex;align-items:center;justify-content:center;color:#fff;font-size:var(--font-sm);cursor:pointer;}
|
||||
.sidebar{position:fixed;top:56px;left:0;bottom:0;width:240px;background:#001529;overflow-y:auto;z-index:90;padding-top:8px;padding-bottom:24px;}
|
||||
.sidebar-menu__title{color:rgba(255,255,255,0.35);font-size:var(--font-xs);padding:16px 24px 8px;letter-spacing:.5px;}
|
||||
.sidebar-item{display:flex;align-items:center;gap:8px;padding:9px 24px;color:rgba(255,255,255,0.65);font-size:var(--font-sm);cursor:pointer;transition:all .15s;text-decoration:none;}
|
||||
.sidebar-item:hover{color:#fff;background:rgba(255,255,255,0.06);}
|
||||
.sidebar-item.active{color:#fff;background:var(--primary);}
|
||||
.main{margin-left:240px;margin-top:56px;padding:24px;min-height:calc(100vh - 56px);}
|
||||
.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;}
|
||||
.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);}
|
||||
.btn{height:36px;padding:0 16px;border-radius:var(--radius-sm);font-size:var(--font-sm);cursor:pointer;border:none;transition:all .2s;display:inline-flex;align-items:center;gap:6px;white-space:nowrap;}
|
||||
.btn-primary{background:var(--primary);color:#fff;}.btn-primary:hover{background:#40a9ff;}
|
||||
.btn-default{background:#fff;color:var(--text-primary);border:1px solid var(--border);}.btn-default:hover{color:var(--primary);border-color:var(--primary);}
|
||||
.btn-link{background:none;color:var(--primary);padding:0 4px;height:auto;}.btn-link:hover{color:#40a9ff;}
|
||||
.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);}
|
||||
.table-card{background:#fff;border-radius:0 0 var(--radius-md) var(--radius-md);box-shadow:var(--shadow-sm);overflow:hidden;}
|
||||
.table-card__content{overflow-x:auto;}
|
||||
table{width:100%;border-collapse:separate;border-spacing:0;min-width:1800px;}
|
||||
thead th{background:#FAFAFA;padding:10px 14px;text-align:center;font-size:var(--font-sm);color:var(--text-secondary);font-weight:500;border-bottom:1px solid var(--border);white-space:nowrap;}
|
||||
tbody td{padding:12px 14px;text-align:center;font-size:var(--font-sm);color:var(--text-primary);border-bottom:1px solid #F0F0F0;white-space:nowrap;}
|
||||
tbody tr:last-child td{border-bottom:none;}
|
||||
tbody tr:hover{background:#F8FBFF;}
|
||||
thead tr th:last-child,tbody td:last-child{position:sticky;right:0;z-index:5;background:#fff;box-shadow:-4px 0 8px rgba(0,0,0,0.04);}
|
||||
thead tr th:last-child{z-index:8;background:#FAFAFA;}
|
||||
tbody tr:hover td:last-child{background:#F8FBFF;}
|
||||
.td-empty{text-align:center;padding:48px 0;color:var(--text-placeholder);}
|
||||
.badge{display:inline-block;padding:2px 10px;border-radius:10px;font-size:var(--font-xs);}
|
||||
.badge--success{background:#F6FFED;color:#389E0D;border:1px solid #B7EB8F;}
|
||||
.badge--muted{background:#F5F5F5;color:var(--text-secondary);border:1px solid var(--border);}
|
||||
.pagination{display:flex;align-items:center;justify-content:flex-end;padding:16px 24px;gap:8px;border-top:1px solid var(--border);}
|
||||
.pagination span{font-size:var(--font-sm);color:var(--text-secondary);}
|
||||
.page-btn{min-width:32px;height:32px;border:1px solid var(--border);border-radius:var(--radius-sm);background:#fff;cursor:pointer;font-size:var(--font-sm);display:inline-flex;align-items:center;justify-content:center;padding:0 6px;transition:all .2s;}
|
||||
.page-btn:hover,.page-btn.active{background:var(--primary);color:#fff;border-color:var(--primary);}
|
||||
.modal-mask{display:none;position:fixed;inset:0;background:rgba(0,0,0,.45);z-index:950;align-items:center;justify-content:center;}
|
||||
.modal-mask.open{display:flex;}
|
||||
.modal{width:680px;background:#fff;border-radius:var(--radius-md);box-shadow:var(--shadow-md);}
|
||||
.modal__head{display:flex;align-items:center;justify-content:space-between;padding:16px 24px;border-bottom:1px solid var(--border);font-size:var(--font-base);font-weight:600;}
|
||||
.modal__close{cursor:pointer;color:var(--text-placeholder);font-size:20px;line-height:1;border:none;background:none;}
|
||||
.modal__body{padding:24px;max-height:62vh;overflow-y:auto;}
|
||||
.modal__footer{display:flex;justify-content:flex-end;gap:8px;padding:12px 24px;border-top:1px solid var(--border);}
|
||||
.form-item{display:flex;align-items:flex-start;margin-bottom:18px;}
|
||||
.form-item label{width:100px;min-width:100px;text-align:right;padding-right:12px;font-size:var(--font-sm);color:var(--text-secondary);line-height:36px;}
|
||||
.form-item label .req{color:var(--danger);margin-right:2px;}
|
||||
.form-item .control{flex:1;}
|
||||
.form-input{width:100%;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;}
|
||||
.form-input:focus{border-color:var(--primary);box-shadow:0 0 0 2px rgba(24,144,255,0.1);}
|
||||
.toast{position:fixed;top:80px;left:50%;transform:translateX(-50%);background:#333;color:#fff;padding:10px 24px;border-radius:var(--radius-sm);font-size:var(--font-sm);z-index:9999;opacity:0;transition:opacity .2s;pointer-events:none;}
|
||||
.toast.show{opacity:1;}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="top-bar">
|
||||
<div class="top-bar__logo"><svg viewBox="0 0 28 28" fill="none"><rect width="28" height="28" rx="6" fill="#1890FF"/><path d="M14 6.5l7 3.5v4.5c0 4.2-2.9 6.8-7 7.5-4.1-.7-7-3.3-7-7.5V10l7-3.5z" stroke="#fff" stroke-width="1.8" fill="none"/><path d="M11 13.5h6M14 10.5v6" stroke="#fff" stroke-width="1.8" stroke-linecap="round"/></svg> 系统管理</div>
|
||||
<nav class="top-bar__nav">
|
||||
<a href="user-admin.html" class="active">用户管理</a>
|
||||
<a href="application.html">权限管理</a>
|
||||
<a href="hospital.html">机构管理</a>
|
||||
<a href="dict.html">系统配置</a>
|
||||
<a href="announcement.html">通知管理</a>
|
||||
</nav>
|
||||
<div class="top-bar__right">
|
||||
<a class="btn-back" href="../../index.html"><svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M10 3L5 8l5 5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg> 返回首页</a>
|
||||
<div class="avatar">管</div>
|
||||
<span style="color:rgba(255,255,255,0.65);">系统管理员 ▾</span>
|
||||
</div>
|
||||
</div>
|
||||
<aside class="sidebar">
|
||||
<div class="sidebar-menu__title">用户管理</div>
|
||||
<a href="user-admin.html" class="sidebar-item">管理员账号</a>
|
||||
<a href="user-all.html" class="sidebar-item">全部用户</a>
|
||||
<a href="user-consult.html" class="sidebar-item">咨询账号</a>
|
||||
<a href="user-emergency.html" class="sidebar-item">应急中心账号</a>
|
||||
<a href="user-employee.html" class="sidebar-item active">员工账号</a>
|
||||
</aside>
|
||||
|
||||
<main class="main">
|
||||
<div class="filter-bar">
|
||||
<div class="filter-item"><label>姓名</label><input class="filter-input" id="filterName" placeholder="请输入姓名"></div>
|
||||
<div class="filter-item"><label>员工编号</label><input class="filter-input" id="filterNo" placeholder="请输入员工编号"></div>
|
||||
<div class="filter-item"><label>单位部门</label><select class="filter-select" id="filterOrg"><option value="">请选择单位部门</option><option>CQ能源/采油一厂</option><option>CQ能源/采油二厂</option><option>CQ能源/第四采油厂</option></select></div>
|
||||
<button class="btn btn-primary" onclick="searchQuery()"><svg width="14" height="14" viewBox="0 0 14 14" fill="none"><circle cx="6" cy="6" r="4.5" stroke="#fff" stroke-width="1.3"/><path d="M9.5 9.5L13 13" stroke="#fff" stroke-width="1.3" stroke-linecap="round"/></svg>查询</button>
|
||||
<button class="btn btn-default" onclick="resetQuery()">重置</button>
|
||||
</div>
|
||||
<div class="action-bar">
|
||||
<button class="btn btn-primary" onclick="openModal('add',null)"><svg width="14" height="14" viewBox="0 0 14 14" fill="none"><path d="M7 2v10M2 7h10" stroke="currentColor" stroke-width="1.4" stroke-linecap="round"/></svg>新增账号</button>
|
||||
<button class="btn btn-default" onclick="showToast('导出列表数据')">导出列表数据</button>
|
||||
</div>
|
||||
<div class="table-card">
|
||||
<div class="table-card__content">
|
||||
<table>
|
||||
<thead><tr>
|
||||
<th style="width:60px">序号</th><th>姓名</th><th>员工编号</th><th>性别</th><th>年龄</th><th>单位</th><th>部门</th><th>员工状态</th><th>账号状态</th><th>身份证号</th><th>手机号</th><th>入职日期</th><th>用工形式</th><th>岗位</th><th>岗位层次</th><th>创建时间</th><th style="width:130px">操作</th>
|
||||
</tr></thead>
|
||||
<tbody id="tableBody"></tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="pagination"><span>共 <b id="totalCount">0</b> 条</span><button class="page-btn" onclick="showToast('演示数据仅一页')">上一页</button><button class="page-btn active">1</button><button class="page-btn" onclick="showToast('演示数据仅一页')">下一页</button></div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<div class="modal-mask" id="empMask">
|
||||
<div class="modal">
|
||||
<div class="modal__head"><span id="empTitle">新增员工账号</span><button class="modal__close" onclick="closeModal()">×</button></div>
|
||||
<div class="modal__body">
|
||||
<div class="form-item"><label><span class="req">*</span>姓名</label><div class="control"><input class="form-input" id="fName" placeholder="请输入姓名"></div></div>
|
||||
<div class="form-item"><label>密码</label><div class="control"><input class="form-input" id="fPassword" type="password" placeholder="请输入密码"></div></div>
|
||||
<div class="form-item"><label>员工编号</label><div class="control"><input class="form-input" id="fWorkNo" placeholder="请输入员工编号"></div></div>
|
||||
<div class="form-item"><label>手机号</label><div class="control"><input class="form-input" id="fPhone" placeholder="请输入手机号"></div></div>
|
||||
<div class="form-item"><label>身份证号</label><div class="control"><input class="form-input" id="fIdCard" placeholder="请输入身份证号"></div></div>
|
||||
<div class="form-item"><label>单位部门</label><div class="control"><select class="form-input" id="fOrg"><option value="">请选择单位部门</option><option>CQ能源/采油一厂</option><option>CQ能源/采油二厂</option><option>CQ能源/第四采油厂</option></select></div></div>
|
||||
<div class="form-item"><label>岗位</label><div class="control"><select class="form-input" id="fPost"><option value="">请选择岗位</option><option>采油工</option><option>技术员</option><option>管理员</option></select></div></div>
|
||||
<div class="form-item"><label>岗位层级</label><div class="control"><select class="form-input" id="fLevel"><option value="">请选择岗位层级</option><option>初级</option><option>中级</option><option>高级</option></select></div></div>
|
||||
<div class="form-item"><label>用工形式</label><div class="control"><select class="form-input" id="fEmploy"><option value="">请选择用工形式</option><option>合同制</option><option>劳务派遣</option></select></div></div>
|
||||
</div>
|
||||
<div class="modal__footer"><button class="btn btn-default" onclick="closeModal()">取消</button><button class="btn btn-primary" onclick="submitForm()">确定</button></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="toast" id="toast"></div>
|
||||
|
||||
<script>
|
||||
var employees=[
|
||||
{id:'1',name:'张伟',no:'CQ0101',sex:'男',age:39,org:'CQ能源',dept:'采油一厂/安全环保科',empStatus:'在职',status:'正常',idCard:'6101**********1234',phone:'139****5678',join:'2010-07-01',employ:'合同制',post:'技术员',level:'中级',time:'2026-08-01 10:00'},
|
||||
{id:'2',name:'李艳',no:'CQ0102',sex:'女',age:36,org:'CQ能源',dept:'采油二厂/姬圪台联合站',empStatus:'在职',status:'正常',idCard:'6101**********5678',phone:'138****9012',join:'2013-09-01',employ:'合同制',post:'采油工',level:'初级',time:'2026-08-01 10:00'},
|
||||
{id:'3',name:'王强',no:'CQ0103',sex:'男',age:45,org:'CQ能源',dept:'第四采油厂/基地管理处',empStatus:'在职',status:'锁定',idCard:'6101**********9012',phone:'137****3456',join:'2005-03-01',employ:'合同制',post:'管理员',level:'高级',time:'2026-08-02 09:30'}
|
||||
];
|
||||
var editingId=null;
|
||||
function renderTable(){
|
||||
var list=employees;
|
||||
document.getElementById('totalCount').textContent=list.length;
|
||||
document.getElementById('tableBody').innerHTML=list.map(function(e,i){
|
||||
return '<tr><td>'+(i+1)+'</td><td>'+e.name+'</td><td>'+e.no+'</td><td>'+e.sex+'</td><td>'+e.age+'</td><td>'+e.org+'</td><td>'+e.dept+'</td><td><span class="badge badge--success">'+e.empStatus+'</span></td><td><span class="badge '+(e.status==='正常'?'badge--success':'badge--muted')+'">'+e.status+'</span></td><td>'+e.idCard+'</td><td>'+e.phone+'</td><td>'+e.join+'</td><td>'+e.employ+'</td><td>'+e.post+'</td><td>'+e.level+'</td><td>'+e.time+'</td>'+
|
||||
'<td><button class="btn btn-link" onclick="showToast(\'详情\')">详情</button><span style="color:var(--border);margin:0 4px;">|</span><button class="btn btn-link" onclick="openModal(\'edit\','+e.id+')">编辑</button><span style="color:var(--border);margin:0 4px;">|</span><button class="btn btn-link" onclick="showToast(\'重置密码\')">重置密码</button></td></tr>';
|
||||
}).join('');
|
||||
}
|
||||
function searchQuery(){renderTable();showToast('查询完成');}
|
||||
function resetQuery(){document.getElementById('filterName').value='';document.getElementById('filterNo').value='';document.getElementById('filterOrg').value='';renderTable();}
|
||||
function openModal(type,id){
|
||||
editingId=id;
|
||||
document.getElementById('empTitle').textContent=type==='add'?'新增员工账号':'编辑员工账号';
|
||||
document.getElementById('fName').value='';document.getElementById('fPassword').value='';document.getElementById('fWorkNo').value='';document.getElementById('fPhone').value='';document.getElementById('fIdCard').value='';document.getElementById('fOrg').value='';document.getElementById('fPost').value='';document.getElementById('fLevel').value='';document.getElementById('fEmploy').value='';
|
||||
if(type==='edit'&&id){var e=employees.find(function(x){return x.id===id;});if(e){document.getElementById('fName').value=e.name;document.getElementById('fWorkNo').value=e.no;}}
|
||||
document.getElementById('empMask').classList.add('open');
|
||||
}
|
||||
function closeModal(){document.getElementById('empMask').classList.remove('open');}
|
||||
function submitForm(){
|
||||
var name=document.getElementById('fName').value.trim();if(!name){showToast('请输入姓名');return;}
|
||||
closeModal();renderTable();showToast(editingId?'编辑成功':'新增成功');
|
||||
}
|
||||
function showToast(msg){var t=document.getElementById('toast');t.textContent=msg;t.classList.add('show');setTimeout(function(){t.classList.remove('show');},1500);}
|
||||
document.addEventListener('click',function(e){if(e.target===document.getElementById('empMask'))closeModal();});
|
||||
renderTable();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,193 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>变量配置 | 系统管理</title>
|
||||
<style>
|
||||
*{box-sizing:border-box;margin:0;padding:0;}
|
||||
body{font-family:-apple-system,BlinkMacSystemFont,'PingFang SC','Microsoft YaHei',sans-serif;font-size:var(--font-sm);background:#F5F7FA;color:#333;min-width:1280px;}
|
||||
:root{
|
||||
--primary:#1890FF;--primary-light:#E6F7FF;--success:#52C41A;--warning:#FAAD14;--danger:#FF4D4F;
|
||||
--text-primary:#333;--text-secondary:#666;--text-placeholder:#999;--border:#E8E8E8;--background:#F5F7FA;
|
||||
--font-xs:11px;--font-sm:13px;--font-base:15px;--font-lg:17px;
|
||||
--radius-sm:4px;--radius-md:8px;--radius-lg:12px;
|
||||
--shadow-sm:0 1px 4px rgba(0,0,0,0.08);--shadow-md:0 4px 12px rgba(0,0,0,0.10);
|
||||
}
|
||||
.top-bar{display:flex;align-items:center;height:56px;background:#001529;padding:0 24px;position:fixed;top:0;left:0;right:0;z-index:100;}
|
||||
.top-bar__logo{display:flex;align-items:center;gap:8px;color:#fff;font-size:var(--font-lg);font-weight:600;white-space:nowrap;width:200px;flex-shrink:0;}
|
||||
.top-bar__logo svg{width:28px;height:28px;}
|
||||
.top-bar__nav{display:flex;align-items:center;gap:4px;flex:1;}
|
||||
.top-bar__nav a{color:rgba(255,255,255,0.65);text-decoration:none;padding:6px 14px;border-radius:var(--radius-sm);font-size:var(--font-sm);transition:all .2s;}
|
||||
.top-bar__nav a:hover{color:#fff;background:rgba(255,255,255,0.08);}
|
||||
.top-bar__nav a.active{color:#fff;background:var(--primary);}
|
||||
.top-bar__right{display:flex;align-items:center;gap:16px;color:rgba(255,255,255,0.65);font-size:var(--font-sm);}
|
||||
.btn-back{color:rgba(255,255,255,0.65);cursor:pointer;display:flex;align-items:center;gap:4px;text-decoration:none;}
|
||||
.btn-back:hover{color:#fff;}
|
||||
.avatar{width:32px;height:32px;border-radius:50%;background:#1890FF;display:flex;align-items:center;justify-content:center;color:#fff;font-size:var(--font-sm);cursor:pointer;}
|
||||
.sidebar{position:fixed;top:56px;left:0;bottom:0;width:240px;background:#001529;overflow-y:auto;z-index:90;padding-top:8px;padding-bottom:24px;}
|
||||
.sidebar-menu__title{color:rgba(255,255,255,0.35);font-size:var(--font-xs);padding:16px 24px 8px;letter-spacing:.5px;}
|
||||
.sidebar-item{display:flex;align-items:center;gap:8px;padding:9px 24px;color:rgba(255,255,255,0.65);font-size:var(--font-sm);cursor:pointer;transition:all .15s;text-decoration:none;}
|
||||
.sidebar-item:hover{color:#fff;background:rgba(255,255,255,0.06);}
|
||||
.sidebar-item.active{color:#fff;background:var(--primary);}
|
||||
.main{margin-left:240px;margin-top:56px;padding:24px;min-height:calc(100vh - 56px);}
|
||||
.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;}
|
||||
.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:160px;}
|
||||
.filter-input:focus{border-color:var(--primary);}
|
||||
.btn{height:36px;padding:0 16px;border-radius:var(--radius-sm);font-size:var(--font-sm);cursor:pointer;border:none;transition:all .2s;display:inline-flex;align-items:center;gap:6px;white-space:nowrap;}
|
||||
.btn-primary{background:var(--primary);color:#fff;}.btn-primary:hover{background:#40a9ff;}
|
||||
.btn-default{background:#fff;color:var(--text-primary);border:1px solid var(--border);}.btn-default:hover{color:var(--primary);border-color:var(--primary);}
|
||||
.btn-link{background:none;color:var(--primary);padding:0 4px;height:auto;}.btn-link:hover{color:#40a9ff;}
|
||||
.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);}
|
||||
.table-card{background:#fff;border-radius:0 0 var(--radius-md) var(--radius-md);box-shadow:var(--shadow-sm);overflow:hidden;}
|
||||
.table-card__content{overflow-x:auto;}
|
||||
table{width:100%;border-collapse:separate;border-spacing:0;min-width:900px;}
|
||||
thead th{background:#FAFAFA;padding:10px 14px;text-align:center;font-size:var(--font-sm);color:var(--text-secondary);font-weight:500;border-bottom:1px solid var(--border);white-space:nowrap;}
|
||||
tbody td{padding:12px 14px;text-align:center;font-size:var(--font-sm);color:var(--text-primary);border-bottom:1px solid #F0F0F0;white-space:nowrap;}
|
||||
tbody tr:last-child td{border-bottom:none;}
|
||||
tbody tr:hover{background:#F8FBFF;}
|
||||
thead tr th:last-child,tbody td:last-child{position:sticky;right:0;z-index:5;background:#fff;box-shadow:-4px 0 8px rgba(0,0,0,0.04);}
|
||||
thead tr th:last-child{z-index:8;background:#FAFAFA;}
|
||||
tbody tr:hover td:last-child{background:#F8FBFF;}
|
||||
.td-empty{text-align:center;padding:48px 0;color:var(--text-placeholder);}
|
||||
.pagination{display:flex;align-items:center;justify-content:flex-end;padding:16px 24px;gap:8px;border-top:1px solid var(--border);}
|
||||
.pagination span{font-size:var(--font-sm);color:var(--text-secondary);}
|
||||
.page-btn{min-width:32px;height:32px;border:1px solid var(--border);border-radius:var(--radius-sm);background:#fff;cursor:pointer;font-size:var(--font-sm);display:inline-flex;align-items:center;justify-content:center;padding:0 6px;transition:all .2s;}
|
||||
.page-btn:hover,.page-btn.active{background:var(--primary);color:#fff;border-color:var(--primary);}
|
||||
.modal-mask{display:none;position:fixed;inset:0;background:rgba(0,0,0,.45);z-index:950;align-items:center;justify-content:center;}
|
||||
.modal-mask.open{display:flex;}
|
||||
.modal{width:520px;background:#fff;border-radius:var(--radius-md);box-shadow:var(--shadow-md);}
|
||||
.modal__head{display:flex;align-items:center;justify-content:space-between;padding:16px 24px;border-bottom:1px solid var(--border);font-size:var(--font-base);font-weight:600;}
|
||||
.modal__close{cursor:pointer;color:var(--text-placeholder);font-size:20px;line-height:1;border:none;background:none;}
|
||||
.modal__body{padding:24px;max-height:60vh;overflow-y:auto;}
|
||||
.modal__footer{display:flex;justify-content:flex-end;gap:8px;padding:12px 24px;border-top:1px solid var(--border);}
|
||||
.form-item{display:flex;align-items:flex-start;margin-bottom:18px;}
|
||||
.form-item label{width:88px;min-width:88px;text-align:right;padding-right:12px;font-size:var(--font-sm);color:var(--text-secondary);line-height:36px;}
|
||||
.form-item label .req{color:var(--danger);margin-right:2px;}
|
||||
.form-item .control{flex:1;font-size:var(--font-sm);line-height:36px;color:var(--text-primary);}
|
||||
.form-input{width:100%;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;}
|
||||
.form-input:focus{border-color:var(--primary);box-shadow:0 0 0 2px rgba(24,144,255,0.1);}
|
||||
.form-input[readonly]{background:#F5F5F5;color:var(--text-secondary);}
|
||||
.form-textarea{width:100%;border:1px solid var(--border);border-radius:var(--radius-sm);padding:8px 12px;font-size:var(--font-sm);color:var(--text-primary);outline:none;resize:vertical;min-height:68px;line-height:1.6;}
|
||||
.form-textarea:focus{border-color:var(--primary);box-shadow:0 0 0 2px rgba(24,144,255,0.1);}
|
||||
.toast{position:fixed;top:80px;left:50%;transform:translateX(-50%);background:#333;color:#fff;padding:10px 24px;border-radius:var(--radius-sm);font-size:var(--font-sm);z-index:9999;opacity:0;transition:opacity .2s;pointer-events:none;}
|
||||
.toast.show{opacity:1;}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="top-bar">
|
||||
<div class="top-bar__logo"><svg viewBox="0 0 28 28" fill="none"><rect width="28" height="28" rx="6" fill="#1890FF"/><path d="M14 6.5l7 3.5v4.5c0 4.2-2.9 6.8-7 7.5-4.1-.7-7-3.3-7-7.5V10l7-3.5z" stroke="#fff" stroke-width="1.8" fill="none"/><path d="M11 13.5h6M14 10.5v6" stroke="#fff" stroke-width="1.8" stroke-linecap="round"/></svg> 系统管理</div>
|
||||
<nav class="top-bar__nav">
|
||||
<a href="user-admin.html">用户管理</a>
|
||||
<a href="application.html">权限管理</a>
|
||||
<a href="hospital.html">机构管理</a>
|
||||
<a href="dict.html" class="active">系统配置</a>
|
||||
<a href="announcement.html">通知管理</a>
|
||||
</nav>
|
||||
<div class="top-bar__right">
|
||||
<a class="btn-back" href="../../index.html"><svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M10 3L5 8l5 5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg> 返回首页</a>
|
||||
<div class="avatar">管</div>
|
||||
<span style="color:rgba(255,255,255,0.65);">系统管理员 ▾</span>
|
||||
</div>
|
||||
</div>
|
||||
<aside class="sidebar">
|
||||
<div class="sidebar-menu__title">系统配置</div>
|
||||
<a href="dict.html" class="sidebar-item">数据字典</a>
|
||||
<a href="dict-category.html" class="sidebar-item">字典分类</a>
|
||||
<a href="variable.html" class="sidebar-item active">变量配置</a>
|
||||
<a href="version.html" class="sidebar-item">版本更新</a>
|
||||
</aside>
|
||||
|
||||
<main class="main">
|
||||
<div class="filter-bar">
|
||||
<div class="filter-item"><label>参数名</label><input class="filter-input" id="filterKey" placeholder="请输入参数名"></div>
|
||||
<div class="filter-item"><label>参数值</label><input class="filter-input" id="filterValue" placeholder="请输入参数值"></div>
|
||||
<button class="btn btn-primary" onclick="searchQuery()"><svg width="14" height="14" viewBox="0 0 14 14" fill="none"><circle cx="6" cy="6" r="4.5" stroke="#fff" stroke-width="1.3"/><path d="M9.5 9.5L13 13" stroke="#fff" stroke-width="1.3" stroke-linecap="round"/></svg>查询</button>
|
||||
<button class="btn btn-default" onclick="resetQuery()">重置</button>
|
||||
</div>
|
||||
<div class="action-bar">
|
||||
<button class="btn btn-primary" onclick="openModal('add',null)"><svg width="14" height="14" viewBox="0 0 14 14" fill="none"><path d="M7 2v10M2 7h10" stroke="currentColor" stroke-width="1.4" stroke-linecap="round"/></svg>新增配置</button>
|
||||
</div>
|
||||
<div class="table-card">
|
||||
<div class="table-card__content">
|
||||
<table>
|
||||
<thead><tr><th style="width:70px">序号</th><th style="width:160px">参数名</th><th style="width:220px">参数值</th><th style="width:180px">参数描述</th><th style="width:200px">创建时间</th><th style="width:200px">操作</th></tr></thead>
|
||||
<tbody id="tableBody"></tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="pagination"><span>共 <b id="totalCount">0</b> 条</span><button class="page-btn" onclick="showToast('演示数据仅一页')">上一页</button><button class="page-btn active">1</button><button class="page-btn" onclick="showToast('演示数据仅一页')">下一页</button></div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<div class="modal-mask" id="varMask">
|
||||
<div class="modal">
|
||||
<div class="modal__head"><span id="varTitle">新增配置</span><button class="modal__close" onclick="closeModal()">×</button></div>
|
||||
<div class="modal__body" id="varBody">
|
||||
<div class="form-item"><label><span class="req">*</span>参数名</label><div class="control"><input class="form-input" id="fKey" placeholder="请输入参数名"></div></div>
|
||||
<div class="form-item"><label><span class="req">*</span>参数值</label><div class="control"><input class="form-input" id="fValue" placeholder="请输入参数值"></div></div>
|
||||
<div class="form-item"><label>参数描述</label><div class="control"><input class="form-input" id="fDesc" placeholder="请输入参数描述"></div></div>
|
||||
</div>
|
||||
<div class="modal__footer" id="varFooter">
|
||||
<button class="btn btn-default" onclick="closeModal()">取消</button>
|
||||
<button class="btn btn-primary" onclick="submitForm()">确定</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="toast" id="toast"></div>
|
||||
|
||||
<script>
|
||||
var configs=[
|
||||
{id:'1',key:'sms_sign_name',value:'健康CQ',desc:'短信签名',time:'2026-08-01 10:00'},
|
||||
{id:'2',key:'default_page_size',value:'20',desc:'默认分页大小',time:'2026-08-01 10:00'},
|
||||
{id:'3',key:'consult_timeout_minutes',value:'30',desc:'咨询超时时长(分钟)',time:'2026-08-02 09:30'},
|
||||
{id:'4',key:'health_report_expire_days',value:'365',desc:'体检报告有效期(天)',time:'2026-08-03 14:20'}
|
||||
];
|
||||
var editingId=null;
|
||||
function renderTable(){
|
||||
var kw=document.getElementById('filterKey').value.trim();
|
||||
var list=configs.filter(function(c){return !kw||c.key.indexOf(kw)>=0;});
|
||||
document.getElementById('totalCount').textContent=list.length;
|
||||
document.getElementById('tableBody').innerHTML=list.length===0?'<tr><td colspan="6" class="td-empty">暂无数据</td></tr>':list.map(function(c,i){
|
||||
return '<tr><td>'+(i+1)+'</td><td>'+c.key+'</td><td>'+c.value+'</td><td style="text-align:left;">'+c.desc+'</td><td>'+c.time+'</td>'+
|
||||
'<td><button class="btn btn-link" onclick="openModal(\'info\','+c.id+')">详情</button><span style="color:var(--border);margin:0 4px;">|</span><button class="btn btn-link" onclick="openModal(\'edit\','+c.id+')">编辑</button><span style="color:var(--border);margin:0 4px;">|</span><button class="btn btn-link" style="color:var(--danger);" onclick="delConfig('+c.id+')">删除</button></td></tr>';
|
||||
}).join('');
|
||||
}
|
||||
function searchQuery(){renderTable();showToast('查询完成');}
|
||||
function resetQuery(){document.getElementById('filterKey').value='';document.getElementById('filterValue').value='';renderTable();}
|
||||
function delConfig(id){if(!confirm('确定删除该配置吗?'))return;configs=configs.filter(function(c){return c.id!==id;});renderTable();showToast('删除成功');}
|
||||
function openModal(type,id){
|
||||
editingId=type==='edit'?id:null;
|
||||
document.getElementById('varTitle').textContent=type==='add'?'新增配置':type==='edit'?'编辑配置':'配置详情';
|
||||
var body=document.getElementById('varBody');
|
||||
var c=id?configs.find(function(x){return x.id===id;}):null;
|
||||
if(type==='info'){
|
||||
body.innerHTML='<div class="form-item"><label>参数名</label><div class="control">'+c.key+'</div></div>'+
|
||||
'<div class="form-item"><label>参数值</label><div class="control">'+c.value+'</div></div>'+
|
||||
'<div class="form-item"><label>参数描述</label><div class="control">'+(c.desc||'-')+'</div></div>';
|
||||
document.getElementById('varFooter').style.display='none';
|
||||
}else{
|
||||
body.innerHTML='<div class="form-item"><label><span class="req">*</span>参数名</label><div class="control"><input class="form-input" id="fKey" placeholder="请输入参数名"></div></div>'+
|
||||
'<div class="form-item"><label><span class="req">*</span>参数值</label><div class="control"><input class="form-input" id="fValue" placeholder="请输入参数值"></div></div>'+
|
||||
'<div class="form-item"><label>参数描述</label><div class="control"><input class="form-input" id="fDesc" placeholder="请输入参数描述"></div></div>';
|
||||
document.getElementById('varFooter').style.display='flex';
|
||||
if(type==='edit'&&c){document.getElementById('fKey').value=c.key;document.getElementById('fValue').value=c.value;document.getElementById('fDesc').value=c.desc;}
|
||||
}
|
||||
document.getElementById('varMask').classList.add('open');
|
||||
}
|
||||
function closeModal(){document.getElementById('varMask').classList.remove('open');}
|
||||
function submitForm(){
|
||||
var key=document.getElementById('fKey').value.trim();if(!key){showToast('请输入参数名');return;}
|
||||
var value=document.getElementById('fValue').value.trim();if(!value){showToast('请输入参数值');return;}
|
||||
var desc=document.getElementById('fDesc').value.trim();
|
||||
if(editingId){var c=configs.find(function(x){return x.id===editingId;});if(c){c.key=key;c.value=value;c.desc=desc;}}
|
||||
else configs.push({id:String(configs.length+1),key:key,value:value,desc:desc,time:'2026-09-11 10:00'});
|
||||
closeModal();renderTable();showToast(editingId?'编辑成功':'新增成功');
|
||||
}
|
||||
function showToast(msg){var t=document.getElementById('toast');t.textContent=msg;t.classList.add('show');setTimeout(function(){t.classList.remove('show');},1500);}
|
||||
document.addEventListener('click',function(e){if(e.target===document.getElementById('varMask'))closeModal();});
|
||||
renderTable();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,300 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>版本更新 | 系统管理</title>
|
||||
<style>
|
||||
*{box-sizing:border-box;margin:0;padding:0;}
|
||||
body{font-family:-apple-system,BlinkMacSystemFont,'PingFang SC','Microsoft YaHei',sans-serif;font-size:var(--font-sm);background:#F5F7FA;color:#333;min-width:1280px;}
|
||||
:root{
|
||||
--primary:#1890FF;--primary-light:#E6F7FF;--success:#52C41A;--warning:#FAAD14;--danger:#FF4D4F;
|
||||
--text-primary:#333;--text-secondary:#666;--text-placeholder:#999;--border:#E8E8E8;--background:#F5F7FA;
|
||||
--font-xs:11px;--font-sm:13px;--font-base:15px;--font-lg:17px;
|
||||
--radius-sm:4px;--radius-md:8px;--radius-lg:12px;
|
||||
--shadow-sm:0 1px 4px rgba(0,0,0,0.08);--shadow-md:0 4px 12px rgba(0,0,0,0.10);
|
||||
}
|
||||
.top-bar{display:flex;align-items:center;height:56px;background:#001529;padding:0 24px;position:fixed;top:0;left:0;right:0;z-index:100;}
|
||||
.top-bar__logo{display:flex;align-items:center;gap:8px;color:#fff;font-size:var(--font-lg);font-weight:600;white-space:nowrap;width:200px;flex-shrink:0;}
|
||||
.top-bar__logo svg{width:28px;height:28px;}
|
||||
.top-bar__nav{display:flex;align-items:center;gap:4px;flex:1;}
|
||||
.top-bar__nav a{color:rgba(255,255,255,0.65);text-decoration:none;padding:6px 14px;border-radius:var(--radius-sm);font-size:var(--font-sm);transition:all .2s;}
|
||||
.top-bar__nav a:hover{color:#fff;background:rgba(255,255,255,0.08);}
|
||||
.top-bar__nav a.active{color:#fff;background:var(--primary);}
|
||||
.top-bar__right{display:flex;align-items:center;gap:16px;color:rgba(255,255,255,0.65);font-size:var(--font-sm);}
|
||||
.btn-back{color:rgba(255,255,255,0.65);cursor:pointer;display:flex;align-items:center;gap:4px;text-decoration:none;}
|
||||
.btn-back:hover{color:#fff;}
|
||||
.avatar{width:32px;height:32px;border-radius:50%;background:#1890FF;display:flex;align-items:center;justify-content:center;color:#fff;font-size:var(--font-sm);cursor:pointer;}
|
||||
.sidebar{position:fixed;top:56px;left:0;bottom:0;width:240px;background:#001529;overflow-y:auto;z-index:90;padding-top:8px;padding-bottom:24px;}
|
||||
.sidebar-menu__title{color:rgba(255,255,255,0.35);font-size:var(--font-xs);padding:16px 24px 8px;letter-spacing:.5px;}
|
||||
.sidebar-item{display:flex;align-items:center;gap:8px;padding:9px 24px;color:rgba(255,255,255,0.65);font-size:var(--font-sm);cursor:pointer;transition:all .15s;text-decoration:none;}
|
||||
.sidebar-item:hover{color:#fff;background:rgba(255,255,255,0.06);}
|
||||
.sidebar-item.active{color:#fff;background:var(--primary);}
|
||||
.main{margin-left:240px;margin-top:56px;padding:24px;min-height:calc(100vh - 56px);}
|
||||
.btn{height:36px;padding:0 16px;border-radius:var(--radius-sm);font-size:var(--font-sm);cursor:pointer;border:none;transition:all .2s;display:inline-flex;align-items:center;gap:6px;white-space:nowrap;}
|
||||
.btn-primary{background:var(--primary);color:#fff;}.btn-primary:hover{background:#40a9ff;}
|
||||
.btn-default{background:#fff;color:var(--text-primary);border:1px solid var(--border);}.btn-default:hover{color:var(--primary);border-color:var(--primary);}
|
||||
.btn-link{background:none;color:var(--primary);padding:0 4px;height:auto;}.btn-link:hover{color:#40a9ff;}
|
||||
.version-layout{display:flex;gap:16px;align-items:stretch;}
|
||||
.card{background:#fff;border-radius:var(--radius-md);box-shadow:var(--shadow-sm);}
|
||||
.app-left{width:320px;flex-shrink:0;display:flex;flex-direction:column;max-height:calc(100vh - 104px);}
|
||||
.app-left__header{padding:16px 16px 12px;border-bottom:1px solid var(--border);}
|
||||
.app-left__header .row1{display:flex;align-items:center;justify-content:space-between;margin-bottom:12px;}
|
||||
.app-left__header .title{font-size:var(--font-base);font-weight:600;}
|
||||
.app-search{position:relative;}
|
||||
.app-search input{width:100%;height:34px;border:1px solid var(--border);border-radius:var(--radius-sm);padding:0 12px;font-size:var(--font-sm);outline:none;}
|
||||
.app-search input:focus{border-color:var(--primary);}
|
||||
.app-left__body{flex:1;overflow-y:auto;padding:12px;}
|
||||
.app-tag{display:flex;align-items:center;justify-content:space-between;padding:10px 14px;border-radius:var(--radius-sm);cursor:pointer;border:1px solid transparent;margin-bottom:8px;transition:all .15s;}
|
||||
.app-tag:hover{background:#F0F8FF;}
|
||||
.app-tag.active{background:var(--primary-light);border-color:var(--primary);}
|
||||
.app-tag .name{font-size:var(--font-sm);color:var(--text-primary);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;flex:1;}
|
||||
.app-tag.active .name{color:var(--primary);font-weight:500;}
|
||||
.app-empty{text-align:center;padding:40px 0;color:var(--text-placeholder);}
|
||||
.app-left__footer{padding:12px 16px;border-top:1px solid var(--border);}
|
||||
.app-right{flex:1;min-width:0;display:flex;flex-direction:column;max-height:calc(100vh - 104px);}
|
||||
.tabs{display:flex;border-bottom:1px solid var(--border);padding:0 16px;flex-shrink:0;}
|
||||
.tab{position:relative;padding:14px 16px;font-size:var(--font-sm);color:var(--text-secondary);cursor:pointer;user-select:none;}
|
||||
.tab:hover{color:var(--primary);}
|
||||
.tab.active{color:var(--primary);font-weight:500;}
|
||||
.tab.active::after{content:'';position:absolute;left:16px;right:16px;bottom:-1px;height:2px;background:var(--primary);}
|
||||
.tab-panel{flex:1;overflow-y:auto;display:none;padding:20px;}
|
||||
.tab-panel.active{display:block;}
|
||||
.filter-bar{padding:0 0 16px;display:flex;align-items:center;gap:16px;flex-wrap:wrap;}
|
||||
.filter-item{display:flex;align-items:center;gap:8px;}
|
||||
.filter-item label{font-size:var(--font-sm);color:var(--text-secondary);white-space:nowrap;}
|
||||
.filter-select{height:36px;min-width:120px;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);}
|
||||
.action-bar{display:flex;align-items:center;gap:8px;padding:0 0 16px;}
|
||||
.table-wrap{overflow-x:auto;}
|
||||
table{width:100%;border-collapse:separate;border-spacing:0;min-width:900px;}
|
||||
thead th{background:#FAFAFA;padding:10px 14px;text-align:center;font-size:var(--font-sm);color:var(--text-secondary);font-weight:500;border-bottom:1px solid var(--border);white-space:nowrap;}
|
||||
tbody td{padding:12px 14px;text-align:center;font-size:var(--font-sm);color:var(--text-primary);border-bottom:1px solid #F0F0F0;white-space:nowrap;}
|
||||
tbody tr:last-child td{border-bottom:none;}
|
||||
tbody tr:hover{background:#F8FBFF;}
|
||||
thead tr th:last-child,tbody td:last-child{position:sticky;right:0;z-index:5;background:#fff;box-shadow:-4px 0 8px rgba(0,0,0,0.04);}
|
||||
thead tr th:last-child{z-index:8;background:#FAFAFA;}
|
||||
tbody tr:hover td:last-child{background:#F8FBFF;}
|
||||
.td-empty{text-align:center;padding:40px 0;color:var(--text-placeholder);}
|
||||
.badge{display:inline-block;padding:2px 10px;border-radius:10px;font-size:var(--font-xs);}
|
||||
.badge--success{background:#F6FFED;color:#389E0D;border:1px solid #B7EB8F;}
|
||||
.badge--info{background:#E6F7FF;color:#096DD9;border:1px solid #91D5FF;}
|
||||
.badge--muted{background:#F5F5F5;color:var(--text-secondary);border:1px solid var(--border);}
|
||||
.pagination{display:flex;align-items:center;justify-content:flex-end;padding:16px 0 0;gap:8px;}
|
||||
.pagination span{font-size:var(--font-sm);color:var(--text-secondary);}
|
||||
.page-btn{min-width:32px;height:32px;border:1px solid var(--border);border-radius:var(--radius-sm);background:#fff;cursor:pointer;font-size:var(--font-sm);display:inline-flex;align-items:center;justify-content:center;padding:0 6px;transition:all .2s;}
|
||||
.page-btn:hover,.page-btn.active{background:var(--primary);color:#fff;border-color:var(--primary);}
|
||||
.form-item{display:flex;align-items:flex-start;margin-bottom:18px;max-width:520px;}
|
||||
.form-item label{width:90px;min-width:90px;text-align:right;padding-right:12px;font-size:var(--font-sm);color:var(--text-secondary);line-height:36px;}
|
||||
.form-item label .req{color:var(--danger);margin-right:2px;}
|
||||
.form-item .control{flex:1;font-size:var(--font-sm);line-height:36px;color:var(--text-primary);}
|
||||
.form-input{width:100%;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;}
|
||||
.form-input:focus{border-color:var(--primary);box-shadow:0 0 0 2px rgba(24,144,255,0.1);}
|
||||
.form-textarea{width:100%;border:1px solid var(--border);border-radius:var(--radius-sm);padding:8px 12px;font-size:var(--font-sm);color:var(--text-primary);outline:none;resize:vertical;min-height:80px;line-height:1.6;}
|
||||
.form-textarea:focus{border-color:var(--primary);box-shadow:0 0 0 2px rgba(24,144,255,0.1);}
|
||||
.modal-mask{display:none;position:fixed;inset:0;background:rgba(0,0,0,.45);z-index:950;align-items:center;justify-content:center;}
|
||||
.modal-mask.open{display:flex;}
|
||||
.modal{width:560px;background:#fff;border-radius:var(--radius-md);box-shadow:var(--shadow-md);}
|
||||
.modal__head{display:flex;align-items:center;justify-content:space-between;padding:16px 24px;border-bottom:1px solid var(--border);font-size:var(--font-base);font-weight:600;}
|
||||
.modal__close{cursor:pointer;color:var(--text-placeholder);font-size:20px;line-height:1;border:none;background:none;}
|
||||
.modal__body{padding:24px;max-height:60vh;overflow-y:auto;}
|
||||
.modal__footer{display:flex;justify-content:flex-end;gap:8px;padding:12px 24px;border-top:1px solid var(--border);}
|
||||
.toast{position:fixed;top:80px;left:50%;transform:translateX(-50%);background:#333;color:#fff;padding:10px 24px;border-radius:var(--radius-sm);font-size:var(--font-sm);z-index:9999;opacity:0;transition:opacity .2s;pointer-events:none;}
|
||||
.toast.show{opacity:1;}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="top-bar">
|
||||
<div class="top-bar__logo"><svg viewBox="0 0 28 28" fill="none"><rect width="28" height="28" rx="6" fill="#1890FF"/><path d="M14 6.5l7 3.5v4.5c0 4.2-2.9 6.8-7 7.5-4.1-.7-7-3.3-7-7.5V10l7-3.5z" stroke="#fff" stroke-width="1.8" fill="none"/><path d="M11 13.5h6M14 10.5v6" stroke="#fff" stroke-width="1.8" stroke-linecap="round"/></svg> 系统管理</div>
|
||||
<nav class="top-bar__nav">
|
||||
<a href="user-admin.html">用户管理</a>
|
||||
<a href="application.html">权限管理</a>
|
||||
<a href="hospital.html">机构管理</a>
|
||||
<a href="dict.html" class="active">系统配置</a>
|
||||
<a href="announcement.html">通知管理</a>
|
||||
</nav>
|
||||
<div class="top-bar__right">
|
||||
<a class="btn-back" href="../../index.html"><svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M10 3L5 8l5 5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg> 返回首页</a>
|
||||
<div class="avatar">管</div>
|
||||
<span style="color:rgba(255,255,255,0.65);">系统管理员 ▾</span>
|
||||
</div>
|
||||
</div>
|
||||
<aside class="sidebar">
|
||||
<div class="sidebar-menu__title">系统配置</div>
|
||||
<a href="dict.html" class="sidebar-item">数据字典</a>
|
||||
<a href="dict-category.html" class="sidebar-item">字典分类</a>
|
||||
<a href="variable.html" class="sidebar-item">变量配置</a>
|
||||
<a href="version.html" class="sidebar-item active">版本更新</a>
|
||||
</aside>
|
||||
|
||||
<main class="main">
|
||||
<div class="version-layout">
|
||||
<div class="card app-left">
|
||||
<div class="app-left__header">
|
||||
<div class="row1">
|
||||
<div class="title">APP列表</div>
|
||||
<button class="btn btn-link" onclick="openAppModal()"><svg width="14" height="14" viewBox="0 0 14 14" fill="none"><path d="M7 2v10M2 7h10" stroke="currentColor" stroke-width="1.4" stroke-linecap="round"/></svg>新增</button>
|
||||
</div>
|
||||
<div class="app-search"><input id="appSearch" placeholder="按照APP名称搜索" oninput="renderApps()"></div>
|
||||
</div>
|
||||
<div class="app-left__body" id="appList"></div>
|
||||
<div class="app-left__footer">
|
||||
<div class="pagination" style="padding:0;"><span>共 <b id="appTotal">0</b> 条</span><button class="page-btn" onclick="showToast('演示数据仅一页')">上一页</button><button class="page-btn active">1</button><button class="page-btn" onclick="showToast('演示数据仅一页')">下一页</button></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card app-right">
|
||||
<div class="tabs">
|
||||
<div class="tab active" data-tab="history" onclick="switchTab('history')">版本记录</div>
|
||||
<div class="tab" data-tab="basic" onclick="switchTab('basic')">基本信息</div>
|
||||
</div>
|
||||
<div class="tab-panel active" id="panel-history">
|
||||
<div class="filter-bar">
|
||||
<div class="filter-item"><label>版本名称</label><input class="filter-input" id="vhName" placeholder="请输入版本名称"></div>
|
||||
<div class="filter-item"><label>强制更新</label><select class="filter-select" id="vhForced"><option value="">请选择</option><option>是</option><option>否</option></select></div>
|
||||
<div class="filter-item"><label>是否有效</label><select class="filter-select" id="vhValid"><option value="">请选择</option><option>有效</option><option>无效</option></select></div>
|
||||
<button class="btn btn-primary" onclick="renderVersions()"><svg width="14" height="14" viewBox="0 0 14 14" fill="none"><circle cx="6" cy="6" r="4.5" stroke="#fff" stroke-width="1.3"/><path d="M9.5 9.5L13 13" stroke="#fff" stroke-width="1.3" stroke-linecap="round"/></svg>查询</button>
|
||||
<button class="btn btn-default" onclick="resetVersionSearch()">重置</button>
|
||||
</div>
|
||||
<div class="action-bar"><button class="btn btn-primary" onclick="openVersionModal('add',null)"><svg width="14" height="14" viewBox="0 0 14 14" fill="none"><path d="M7 2v10M2 7h10" stroke="currentColor" stroke-width="1.4" stroke-linecap="round"/></svg>新增版本</button></div>
|
||||
<div class="table-wrap">
|
||||
<table>
|
||||
<thead><tr><th style="width:70px">序号</th><th style="width:180px">版本名称</th><th style="width:120px">版本号</th><th style="width:120px">系统类型</th><th style="width:200px">更新时间</th><th style="width:100px">强制更新</th><th style="width:100px">是否有效</th><th style="width:130px">操作</th></tr></thead>
|
||||
<tbody id="versionBody"></tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tab-panel" id="panel-basic">
|
||||
<div class="form-item"><label>APP名称</label><div class="control" id="baAppName">-</div></div>
|
||||
<div class="form-item"><label>包名</label><div class="control" id="baPackage">-</div></div>
|
||||
<div class="form-item"><label>创建人</label><div class="control" id="baCreator">-</div></div>
|
||||
<div class="form-item"><label>描述</label><div class="control" id="baDesc">-</div></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<!-- 新建APP弹窗 -->
|
||||
<div class="modal-mask" id="appMask">
|
||||
<div class="modal">
|
||||
<div class="modal__head"><span>新增APP</span><button class="modal__close" onclick="closeModal('appMask')">×</button></div>
|
||||
<div class="modal__body">
|
||||
<div class="form-item"><label><span class="req">*</span>APP名称</label><div class="control"><input class="form-input" id="aName" placeholder="请输入APP名称"></div></div>
|
||||
<div class="form-item"><label><span class="req">*</span>包名</label><div class="control"><input class="form-input" id="aPackage" placeholder="请输入包名"></div></div>
|
||||
<div class="form-item"><label>APP描述</label><div class="control"><textarea class="form-textarea" id="aDesc" placeholder="请输入描述"></textarea></div></div>
|
||||
</div>
|
||||
<div class="modal__footer"><button class="btn btn-default" onclick="closeModal('appMask')">取消</button><button class="btn btn-primary" onclick="submitApp()">确定</button></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 版本新增/编辑/详情弹窗 -->
|
||||
<div class="modal-mask" id="versionMask">
|
||||
<div class="modal">
|
||||
<div class="modal__head"><span id="versionTitle">新增版本</span><button class="modal__close" onclick="closeModal('versionMask')">×</button></div>
|
||||
<div class="modal__body" id="versionBodyInner">
|
||||
<div class="form-item"><label><span class="req">*</span>版本名称</label><div class="control"><input class="form-input" id="vName" placeholder="请输入版本名称"></div></div>
|
||||
<div class="form-item"><label>系统类型</label><div class="control"><select class="form-input" id="vDevice"><option value="">请选择系统类型</option><option>Android</option><option>iOS</option><option>鸿蒙</option></select></div></div>
|
||||
<div class="form-item"><label><span class="req">*</span>版本号</label><div class="control"><input class="form-input" id="vNo" placeholder="请输入版本号"></div></div>
|
||||
<div class="form-item"><label>上传地址</label><div class="control"><input class="form-input" id="vUrl" placeholder="请输入上传地址"></div></div>
|
||||
<div class="form-item"><label>强制更新</label><div class="control"><select class="form-input" id="vForced"><option>否</option><option>是</option></select></div></div>
|
||||
<div class="form-item"><label>是否有效</label><div class="control"><select class="form-input" id="vValid"><option>有效</option><option>无效</option></select></div></div>
|
||||
<div class="form-item"><label>更新内容</label><div class="control"><textarea class="form-textarea" id="vContent" placeholder="请输入更新内容"></textarea></div></div>
|
||||
</div>
|
||||
<div class="modal__footer"><button class="btn btn-default" onclick="closeModal('versionMask')">取消</button><button class="btn btn-primary" onclick="submitVersion()">确定</button></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="toast" id="toast"></div>
|
||||
|
||||
<script>
|
||||
var apps=[
|
||||
{id:'1',name:'员工健康APP',package:'com.cq.employee.health',creator:'系统管理员',desc:'员工端健康管理应用'},
|
||||
{id:'2',name:'应急救治APP',package:'com.cq.emergency.medical',creator:'系统管理员',desc:'应急救治调度应用'},
|
||||
{id:'3',name:'健康数据中心',package:'com.cq.health.data',creator:'运营管理员',desc:'健康数据可视化'},
|
||||
{id:'4',name:'系统管理',package:'com.cq.system.manage',creator:'系统管理员',desc:'系统管理后台'}
|
||||
];
|
||||
var selectedAppId='1';
|
||||
var versions={
|
||||
'1':[
|
||||
{id:'v1',name:'员工健康v1.1.0',no:'1.1.0',device:'Android',time:'2026-09-01 10:00',forced:'否',valid:'有效',content:'优化体检报告展示'},
|
||||
{id:'v2',name:'员工健康v1.0.0',no:'1.0.0',device:'Android',time:'2026-08-15 10:00',forced:'否',valid:'有效',content:'首个正式版本'}
|
||||
],
|
||||
'2':[
|
||||
{id:'v3',name:'应急救治v1.0.0',no:'1.0.0',device:'iOS',time:'2026-08-20 10:00',forced:'是',valid:'有效',content:'应急调度上线'}
|
||||
]
|
||||
};
|
||||
var editingVersionId=null, curTab='history';
|
||||
|
||||
function renderApps(){
|
||||
var kw=document.getElementById('appSearch').value.trim();
|
||||
var list=apps.filter(function(a){return !kw||a.name.indexOf(kw)>=0;});
|
||||
document.getElementById('appTotal').textContent=list.length;
|
||||
document.getElementById('appList').innerHTML=list.length===0?'<div class="app-empty">暂无APP数据</div>':list.map(function(a){
|
||||
return '<div class="app-tag'+(a.id===selectedAppId?' active':'')+'" onclick="selectApp(\''+a.id+'\')"><span class="name">'+a.name+'</span></div>';
|
||||
}).join('');
|
||||
}
|
||||
function selectApp(id){selectedAppId=id;renderApps();renderTabContent();}
|
||||
function switchTab(tab){
|
||||
curTab=tab;
|
||||
document.querySelectorAll('.tabs .tab').forEach(function(t){t.classList.toggle('active',t.dataset.tab===tab);});
|
||||
document.getElementById('panel-history').classList.toggle('active',tab==='history');
|
||||
document.getElementById('panel-basic').classList.toggle('active',tab==='basic');
|
||||
renderTabContent();
|
||||
}
|
||||
function renderTabContent(){if(curTab==='history')renderVersions();else renderBasic();}
|
||||
function renderVersions(){
|
||||
var list=versions[selectedAppId]||[];
|
||||
document.getElementById('versionBody').innerHTML=list.length===0?'<tr><td colspan="8" class="td-empty">暂无数据</td></tr>':list.map(function(v,i){
|
||||
return '<tr><td>'+(i+1)+'</td><td>'+v.name+'</td><td>'+v.no+'</td><td><span class="badge badge--info">'+v.device+'</span></td><td>'+v.time+'</td><td>'+v.forced+'</td><td><span class="badge '+(v.valid==='有效'?'badge--success':'badge--muted')+'">'+v.valid+'</span></td>'+
|
||||
'<td><button class="btn btn-link" onclick="openVersionModal(\'info\',\''+v.id+'\')">详情</button><span style="color:var(--border);margin:0 4px;">|</span><button class="btn btn-link" onclick="openVersionModal(\'edit\',\''+v.id+'\')">编辑</button></td></tr>';
|
||||
}).join('');
|
||||
}
|
||||
function resetVersionSearch(){document.getElementById('vhName').value='';document.getElementById('vhForced').value='';document.getElementById('vhValid').value='';renderVersions();}
|
||||
function renderBasic(){
|
||||
var a=apps.find(function(x){return x.id===selectedAppId;});
|
||||
document.getElementById('baAppName').textContent=a?a.name:'-';
|
||||
document.getElementById('baPackage').textContent=a?a.package:'-';
|
||||
document.getElementById('baCreator').textContent=a?a.creator:'-';
|
||||
document.getElementById('baDesc').textContent=a?a.desc:'-';
|
||||
}
|
||||
function openAppModal(){document.getElementById('aName').value='';document.getElementById('aPackage').value='';document.getElementById('aDesc').value='';document.getElementById('appMask').classList.add('open');}
|
||||
function submitApp(){
|
||||
var name=document.getElementById('aName').value.trim();if(!name){showToast('请输入APP名称');return;}
|
||||
var pkg=document.getElementById('aPackage').value.trim();if(!pkg){showToast('请输入包名');return;}
|
||||
apps.push({id:String(apps.length+1),name:name,package:pkg,creator:'系统管理员',desc:document.getElementById('aDesc').value.trim()});
|
||||
closeModal('appMask');renderApps();showToast('新增成功');
|
||||
}
|
||||
function openVersionModal(type,id){
|
||||
editingVersionId=type==='edit'?id:null;
|
||||
document.getElementById('versionTitle').textContent=type==='add'?'新增版本':type==='edit'?'编辑版本':'版本详情';
|
||||
var c=id?findVersion(id):null;
|
||||
document.getElementById('vName').value='';document.getElementById('vDevice').value='';document.getElementById('vNo').value='';document.getElementById('vUrl').value='';document.getElementById('vForced').value='否';document.getElementById('vValid').value='有效';document.getElementById('vContent').value='';
|
||||
if(type==='info'&&c){
|
||||
document.getElementById('versionBodyInner').innerHTML='<div class="form-item"><label>版本名称</label><div class="control">'+c.name+'</div></div>'+
|
||||
'<div class="form-item"><label>系统类型</label><div class="control">'+c.device+'</div></div>'+
|
||||
'<div class="form-item"><label>版本号</label><div class="control">'+c.no+'</div></div>'+
|
||||
'<div class="form-item"><label>强制更新</label><div class="control">'+c.forced+'</div></div>'+
|
||||
'<div class="form-item"><label>是否有效</label><div class="control">'+c.valid+'</div></div>'+
|
||||
'<div class="form-item"><label>更新内容</label><div class="control">'+(c.content||'-')+'</div></div>';
|
||||
document.querySelector('#versionMask .modal__footer').style.display='none';
|
||||
}else{
|
||||
document.querySelector('#versionMask .modal__footer').style.display='flex';
|
||||
if(type==='edit'&&c){document.getElementById('vName').value=c.name;document.getElementById('vDevice').value=c.device;document.getElementById('vNo').value=c.no;document.getElementById('vForced').value=c.forced;document.getElementById('vValid').value=c.valid;document.getElementById('vContent').value=c.content;}
|
||||
}
|
||||
document.getElementById('versionMask').classList.add('open');
|
||||
}
|
||||
function findVersion(id){var list=versions[selectedAppId]||[];return list.find(function(v){return v.id===id;});}
|
||||
function submitVersion(){
|
||||
var name=document.getElementById('vName').value.trim();if(!name){showToast('请输入版本名称');return;}
|
||||
var no=document.getElementById('vNo').value.trim();if(!no){showToast('请输入版本号');return;}
|
||||
if(editingVersionId){var v=findVersion(editingVersionId);if(v){v.name=name;v.no=no;v.device=document.getElementById('vDevice').value;v.forced=document.getElementById('vForced').value;v.valid=document.getElementById('vValid').value;v.content=document.getElementById('vContent').value.trim();}}
|
||||
else {if(!versions[selectedAppId])versions[selectedAppId]=[];versions[selectedAppId].push({id:'v'+Date.now(),name:name,no:no,device:document.getElementById('vDevice').value,time:'2026-09-11 10:00',forced:document.getElementById('vForced').value,valid:document.getElementById('vValid').value,content:document.getElementById('vContent').value.trim()});}
|
||||
closeModal('versionMask');renderVersions();showToast(editingVersionId?'编辑成功':'新增成功');
|
||||
}
|
||||
function closeModal(id){document.getElementById(id).classList.remove('open');}
|
||||
function showToast(msg){var t=document.getElementById('toast');t.textContent=msg;t.classList.add('show');setTimeout(function(){t.classList.remove('show');},1500);}
|
||||
document.addEventListener('click',function(e){if(e.target.id==='appMask')closeModal('appMask');if(e.target.id==='versionMask')closeModal('versionMask');});
|
||||
renderApps();
|
||||
renderTabContent();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user