Files
guoju0808/proto/html/components/sponsor-meetings.html
T
郭庆泰 cf5790229a refactor: 合并 biz_support_unit/biz_execution_unit/biz_service_org 为 biz_org, 删除 2 张孤儿表, 改 biz_person.work_unit → org_id FK
主要改动:
- SQL: biz_support_unit → biz_org, 加 org_type, 加 business_nature; 删 biz_execution_unit, biz_service_org
- SQL: biz_project.support_unit_id/name + service_org_id/name → org_id/name/type
- SQL: biz_meeting.support_unit_name → org_name
- SQL: biz_person.work_unit → org_id (FK)
- 后端: 新 BizOrg entity/mapper/service/controller
- 后端: BizProject/BizMeeting 字段重命名
- 后端: 删 12 个 BizSupportUnit/BizExecutionUnit/BizServiceOrg Java 文件
- 后端: BizPersonImportVO.workUnit → orgName (导入时查 biz_org 取 org_id)
- 后端: BizAuthController.registerExecutor 完整实现 (原 registerSupplier stub)
- 前端: 新 admin/Orgs.vue + manager/Orgs.vue (原 SupportUnits)
- 前端: RegisterExecutor.vue (原 RegisterSupplier, 单页 2 步)
- 前端: sponsor/executor/manager 多个文件 workUnit → orgId/orgName 重命名
- 前端: 统一 supplier → executor, 业务命名 sponsor(赞助方) / executor(执行方=供应商)
- 前端: 全工程 execution → executor (company type / role / person unit_type)
2026-08-15 12:41:10 +08:00

307 lines
23 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<!-- 角色:赞助方 父级:sponsor.html 原型:原型/会议列表.html
补全(2026-08-08 测试反馈):
筛选区(6 字段):
- 项目编号(u9704 label 左:281 + u9706 input 左:348)
- 会议名称(u9707 label 左:515 + u9709 input 左:582)
- 第X期(u9714「第」左:758 + u9713 input 左:783 + u9715「期」左:946)
- 会议时间(u9863 label 左:984 + u9895 input 左:1051)
- 当前阶段(u9716 label 左:1228 + u9722 select 选项:请选择/已执行/未执行)
- 查找按钮(u9710 左:1377)
表格列(10 列,按 left 升序):
- u9694 项目编号 左:302
- u9846 会议ID 左:429
- u9848 项目形式 左:521 (线上/线下/线上+线下/其他)
- u9844 会议名称 左:644
- u9850 会议开始时间 左:794
- u9852 会议结束时间 左:940
- u9854 总期数 左:1070
- u9858 期数 左:1147
- u9716 已执行未传材料 左:1232
- u9702 操作 左:1377
红色注释:
- u9768 *会议详情页,增加学会已审核及审核意见...
- u9770 *支持方状态(当前阶段)未执行/已执行未传材料/待监管/监管通过/待整改/待结算/已结算
- u9776 *支持方点击监察意见保存确认后,按钮变为查看监察意见 -->
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>会议列表</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font-family: -apple-system, "PingFang SC", "Microsoft YaHei", sans-serif; color: #333; background: #fafafa; min-height: 100vh; }
.content { padding: 24px 32px; }
.page-title { font-size: 22px; font-weight: 600; color: #1a1a1a; margin-bottom: 20px; }
.card { background: #fff; border-radius: 8px; padding: 20px 24px; margin-bottom: 16px; border: 1px solid #f0f0f0; }
.filter-row { display: flex; flex-wrap: wrap; gap: 12px; align-items: center; }
.filter-field { display: flex; align-items: center; gap: 8px; }
.filter-label { font-size: 14px; color: #595959; white-space: nowrap; }
.filter-input,.filter-select,.filter-date { width: 180px; height: 32px; padding: 0 12px; border: 1px solid #d9d9d9; border-radius: 4px; font-size: 13px; color: #333; background: #fff; outline: none; }
.filter-date { width: 140px; }
.filter-range { display: flex; align-items: center; gap: 6px; }
.filter-range-sep { color: #8c8c8c; font-size: 13px; }
.filter-prefix,.filter-suffix { font-size: 13px; color: #595959; }
.filter-select { cursor: pointer; appearance: none; background: #fff url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23999' stroke-width='2'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E") no-repeat right 10px center / 14px; padding-right: 28px; }
.filter-input:focus,.filter-select:focus,.filter-date:focus { border-color: #1890ff; box-shadow: 0 0 0 3px rgba(24,144,255,0.1); }
.filter-btn { height: 32px; padding: 0 20px; background: #1890ff; color: #fff; border: none; border-radius: 4px; font-size: 13px; cursor: pointer; }
.filter-btn:hover { background: #096dd9; }
.hint-red { font-size: 12px; color: #ff0000; line-height: 1.7; }
.hint-red-block { background: #fff5f5; border-left: 3px solid #ff0000; padding: 10px 14px; border-radius: 4px; margin-bottom: 12px; }
.hint-red-block .hint-red-title { font-weight: 600; margin-bottom: 4px; }
.data-card { padding: 0; overflow-x: auto; }
.data-table { width: 100%; border-collapse: collapse; font-size: 13px; }
.data-table th { background: #fafafa; padding: 10px 12px; text-align: left; color: #1a1a1a; font-weight: 600; border-bottom: 1px solid #f0f0f0; white-space: nowrap; }
.data-table td { padding: 10px 12px; border-bottom: 1px solid #f5f5f5; color: #595959; vertical-align: middle; white-space: nowrap; }
.data-table tr:hover { background: #fafcff; }
.data-table input[type="checkbox"] { cursor: pointer; width: 14px; height: 14px; accent-color: #1890ff; }
.col-code { color: #1890ff; font-family: ui-monospace, "Courier New", monospace; }
.col-name { color: #1a1a1a; font-weight: 500; }
.col-datetime { font-family: ui-monospace, "Courier New", monospace; color: #595959; font-size: 12px; }
.col-period { color: #722ed1; font-weight: 500; cursor: pointer; }
.col-period:hover { color: #1890ff; text-decoration: underline; }
.status-tag { display: inline-block; padding: 2px 10px; border-radius: 10px; font-size: 12px; }
.status-pending { background: #fff7e6; color: #fa8c16; border: 1px solid #ffd591; }
.status-done { background: #f6ffed; color: #52c41a; border: 1px solid #b7eb8f; }
.status-warn { background: #fffbe6; color: #faad14; border: 1px solid #ffe58f; }
.status-process { background: #e6f4ff; color: #1890ff; border: 1px solid #91d5ff; }
.status-purple { background: #f9f0ff; color: #722ed1; border: 1px solid #d3adf7; }
.form-tag { display: inline-block; padding: 2px 8px; border-radius: 4px; font-size: 12px; }
.form-online { background: #e6f4ff; color: #1890ff; border: 1px solid #91d5ff; }
.form-offline { background: #fff7e6; color: #fa8c16; border: 1px solid #ffd591; }
.form-mixed { background: #f9f0ff; color: #722ed1; border: 1px solid #d3adf7; }
.op-link { color: #1890ff; text-decoration: none; font-size: 13px; cursor: pointer; }
.op-link:hover { text-decoration: underline; }
/* Modal */
.modal-mask { display: none; position: fixed; inset: 0; background: rgba(0,0,0,.45); z-index: 1000; align-items: center; justify-content: center; }
.modal-mask.show { display: flex; }
.modal { background: #fff; border-radius: 8px; width: 520px; max-width: 90vw; max-height: 90vh; overflow-y: auto; box-shadow: 0 10px 40px rgba(0,0,0,.2); }
.modal-header { padding: 20px 24px; border-bottom: 1px solid #f0f0f0; display: flex; align-items: center; justify-content: space-between; }
.modal-title { font-size: 16px; font-weight: 600; color: #1a1a1a; }
.modal-close { cursor: pointer; color: #8c8c8c; font-size: 20px; background: none; border: none; padding: 4px; line-height: 1; }
.modal-close:hover { color: #1a1a1a; }
.modal-body { padding: 24px; }
.modal-row { margin-bottom: 14px; }
.modal-row-label { font-size: 13px; color: #595959; margin-bottom: 4px; }
.modal-row-value { font-size: 14px; color: #1a1a1a; }
.opinion-box { background: #fafafa; border-left: 3px solid #1890ff; padding: 12px; border-radius: 4px; color: #595959; font-size: 13px; line-height: 1.7; }
.modal-footer { padding: 16px 24px; border-top: 1px solid #f0f0f0; text-align: right; }
.btn-default { height: 32px; padding: 0 20px; background: #fff; color: #333; border: 1px solid #d9d9d9; border-radius: 4px; font-size: 13px; cursor: pointer; }
.btn-primary { height: 32px; padding: 0 20px; background: #1890ff; color: #fff; border: 1px solid #1890ff; border-radius: 4px; font-size: 13px; cursor: pointer; margin-left: 8px; }
.btn-primary:hover { background: #096dd9; }
@media (max-width:768px) { .content { padding: 16px; } .data-table { font-size: 12px; } .modal { width: 96vw; } }
</style>
</head>
<body>
<main class="content">
<h1 class="page-title">会议列表</h1>
<div class="card">
<div class="filter-row">
<div class="filter-field"><span class="filter-label">项目编号:</span><input type="text" class="filter-input" placeholder="输入项目编号"></div>
<div class="filter-field"><span class="filter-label">会议名称:</span><input type="text" class="filter-input" placeholder="输入会议名称"></div>
<div class="filter-field">
<span class="filter-label"></span>
<input type="text" class="filter-input" placeholder="期数" style="width:80px">
<span class="filter-suffix"></span>
</div>
<div class="filter-field">
<span class="filter-label">会议时间:</span>
<div class="filter-range">
<input type="date" class="filter-date" value="2026-01-01">
<span class="filter-range-sep"></span>
<input type="date" class="filter-date" value="2026-12-31">
</div>
</div>
<div class="filter-field"><span class="filter-label">当前阶段:</span>
<select class="filter-select">
<option value="">请选择</option>
<option>已执行</option>
<option>未执行</option>
</select>
</div>
<button class="filter-btn">查找</button>
</div>
</div>
<div class="card data-card">
<table class="data-table">
<thead>
<tr>
<th style="width:40px"><input type="checkbox" id="selectAll"></th>
<th>项目编号</th>
<th>会议ID</th>
<th>项目形式</th>
<th>会议名称</th>
<th>会议开始时间</th>
<th>会议结束时间</th>
<th>总期数</th>
<th>期数</th>
<th>当前阶段</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr><td><input type="checkbox" class="row-check"></td><td><a class="col-code" href="javascript:void(0)">ZH-2026-658</a></td><td>5643145673</td><td><span class="form-tag form-online">线上</span></td><td><a class="col-name" href="javascript:void(0)">小牛血清创新应用研讨会</a></td><td class="col-datetime">2026-05-11 11:30</td><td class="col-datetime">2026-05-11 14:30</td><td style="text-align:center">26</td><td style="text-align:center"><a class="col-period" title="点击可筛选该系列会所有会议">第 3 期</a></td><td><span class="status-tag status-pending">待监管</span></td><td><a class="op-link" href="sponsor-meeting-detail.html">查看</a><a class="op-link" onclick="openOpinion(this)">监察意见</a></td></tr>
<tr><td><input type="checkbox" class="row-check"></td><td><a class="col-code" href="javascript:void(0)">ZH-2026-650</a></td><td>5643145674</td><td><span class="form-tag form-offline">线下</span></td><td><a class="col-name" href="javascript:void(0)">整合医学学会项目评审会</a></td><td class="col-datetime">2026-04-01 09:00</td><td class="col-datetime">2026-04-01 17:00</td><td style="text-align:center">18</td><td style="text-align:center"><a class="col-period" title="点击可筛选该系列会所有会议">第 18 期</a></td><td><span class="status-tag status-done">监管通过</span></td><td><a class="op-link" href="sponsor-meeting-detail.html">查看</a><a class="op-link" onclick="openOpinion(this)">查看监察意见</a></td></tr>
<tr><td><input type="checkbox" class="row-check"></td><td><a class="col-code" href="javascript:void(0)">ZH-2026-645</a></td><td>5643145675</td><td><span class="form-tag form-mixed">线上+线下</span></td><td><a class="col-name" href="javascript:void(0)">智慧医院建设项目方案论证会</a></td><td class="col-datetime">2026-03-15 14:00</td><td class="col-datetime">2026-03-15 16:30</td><td style="text-align:center">12</td><td style="text-align:center"><a class="col-period" title="点击可筛选该系列会所有会议">第 7 期</a></td><td><span class="status-tag status-warn">待整改</span></td><td><a class="op-link" href="sponsor-meeting-detail.html">查看</a><a class="op-link" onclick="openOpinion(this)">监察意见</a></td></tr>
<tr><td><input type="checkbox" class="row-check"></td><td><a class="col-code" href="javascript:void(0)">ZH-2026-640</a></td><td>5643145676</td><td><span class="form-tag form-online">线上</span></td><td><a class="col-name" href="javascript:void(0)">基层医疗改革试点中期评估会</a></td><td class="col-datetime">2026-02-01 09:30</td><td class="col-datetime">2026-02-01 12:00</td><td style="text-align:center">20</td><td style="text-align:center"><a class="col-period" title="点击可筛选该系列会所有会议">第 14 期</a></td><td><span class="status-tag status-purple">已结算</span></td><td><a class="op-link" href="sponsor-meeting-detail.html">查看</a><a class="op-link" onclick="openOpinion(this)">查看监察意见</a></td></tr>
<tr><td><input type="checkbox" class="row-check"></td><td><a class="col-code" href="javascript:void(0)">ZH-2026-635</a></td><td>5643145677</td><td><span class="form-tag form-offline">线下</span></td><td><a class="col-name" href="javascript:void(0)">数字化医疗转型方案评审会</a></td><td class="col-datetime">2026-01-10 10:00</td><td class="col-datetime">2026-01-10 17:00</td><td style="text-align:center">22</td><td style="text-align:center"><a class="col-period" title="点击可筛选该系列会所有会议">第 15 期</a></td><td><span class="status-tag status-purple">已结题</span></td><td><a class="op-link" href="sponsor-meeting-detail.html">查看</a><a class="op-link" onclick="openOpinion(this)">监察意见</a></td></tr>
</tbody>
</table>
</div>
<p class="hint-red" style="margin-top:12px">*支持方点击监察意见保存确认后,按钮变为查看监察意见</p>
<div class="hint-red-block" style="margin-top:16px">
<p class="hint-red">*会议详情页,增加学会已审核及审核意见,增加支持方监督意见详情,两个意见,合规人员能看到,执行方也可看到</p>
</div>
<div class="hint-red-block">
<p class="hint-red hint-red-title">*支持方状态(当前阶段):</p>
<p class="hint-red">未执行:会议开始时间前,显示为未执行;</p>
<p class="hint-red">已执行未传材料:合规人员未审核通过前,一直显示该状态;</p>
<p class="hint-red">待监管:支持方未填写监管意见时,显示该状态;</p>
<p class="hint-red">监管通过:支持方选择确认无误后,则显示该状态;监管通过默认只显示 1 个工作日,之后显示为待结算</p>
<p class="hint-red">待整改:监管未通过后,则显示该状态;</p>
<p class="hint-red">待结算:支持方监管通过后,1 个工作日后变为待结算,显示该状态;</p>
<p class="hint-red">已结算:合规人员当操作结算后,状态变为已结算;</p>
</div>
</main>
<!-- 监督意见 Modal (原型 u9942) -->
<div class="modal-mask" id="opinionModal">
<div class="modal">
<div class="modal-header">
<span class="modal-title" id="modalTitle">监督意见</span>
<button class="modal-close" onclick="closeModal()">×</button>
</div>
<div class="modal-body">
<div class="modal-row">
<div class="modal-row-label">会议名称</div>
<div class="modal-row-value" id="modalName"></div>
</div>
<!-- 编辑态:单选 + 文本框 + 字数 -->
<div id="editView">
<div class="modal-row">
<label style="display:flex;align-items:center;gap:8px;cursor:pointer">
<input type="radio" name="opinionType" value="ok" checked onchange="toggleTextarea()">
<span>确认无误</span>
</label>
</div>
<div class="modal-row">
<label style="display:flex;align-items:center;gap:8px;cursor:pointer">
<input type="radio" name="opinionType" value="fix" onchange="toggleTextarea()">
<span>存在需整改的问题</span>
</label>
</div>
<div class="modal-row" id="textareaWrap" style="display:none">
<div style="display:flex;align-items:center;gap:4px;margin-bottom:4px">
<span style="color:#ff4d4f">*</span>
<span class="modal-row-label" style="margin:0">详细意见</span>
<span style="flex:1"></span>
<span style="font-size:12px;color:#8c8c8c"><span id="charCount">0</span>/500</span>
</div>
<textarea class="modal-textarea" id="opinionText" maxlength="500" placeholder="请输入详细意见..." style="width:100%;min-height:90px;padding:8px 12px;border:1px solid #d9d9d9;border-radius:4px;font-size:13px;resize:vertical;outline:none;box-sizing:border-box;font-family:inherit" oninput="document.getElementById('charCount').textContent=this.value.length"></textarea>
</div>
<p class="hint-red">*3个工作日之内如果未填写,则默认为确认无误</p>
<p class="hint-red">*点击存在需整改的问题时,才显示详细意见</p>
</div>
<!-- 查看态:已保存的意见 -->
<div id="viewView" style="display:none">
<div class="modal-row">
<div class="modal-row-label">监督结果</div>
<div class="modal-row-value" id="viewResult"></div>
</div>
<div class="modal-row" id="viewOpinionWrap" style="display:none">
<div class="modal-row-label">详细意见</div>
<div class="opinion-box" id="viewOpinion"></div>
</div>
</div>
</div>
<div class="modal-footer" id="modalFooter">
<button class="btn-default" onclick="closeModal()">取消</button>
<button class="btn-primary" id="saveBtn" onclick="saveOpinion()">保存</button>
</div>
</div>
</div>
<script>
document.getElementById('selectAll').addEventListener('change', function () { document.querySelectorAll('.row-check').forEach(c => c.checked = this.checked); });
// 当前操作的会议数据(简化:从行内取)
function getRowData(btn) {
var tr = btn.closest('tr');
return {
name: tr.querySelector('.col-name').textContent,
stage: tr.querySelector('.status-tag').textContent,
tr: tr
};
}
function openOpinion(btn) {
var data = getRowData(btn);
var isView = btn.textContent.trim() === '查看监察意见' || data.stage !== '待监管';
document.getElementById('modalName').textContent = data.name;
if (isView) {
// 查看态(读取 data-tr 上的 data-opinion 属性,无则给默认值)
var saved = btn.getAttribute('data-opinion') || '已确认无误';
var savedFix = btn.getAttribute('data-opinion-fix') || '';
document.getElementById('viewResult').textContent = saved;
if (savedFix) {
document.getElementById('viewOpinionWrap').style.display = 'block';
document.getElementById('viewOpinion').textContent = savedFix;
}
document.getElementById('editView').style.display = 'none';
document.getElementById('viewView').style.display = 'block';
document.getElementById('modalFooter').innerHTML = '<button class="btn-default" onclick="closeModal()">关闭</button>';
} else {
// 编辑态
document.getElementById('editView').style.display = 'block';
document.getElementById('viewView').style.display = 'none';
document.getElementById('modalFooter').innerHTML = '<button class="btn-default" onclick="closeModal()">取消</button><button class="btn-primary" onclick="saveOpinion()">保存</button>';
document.querySelector('input[name="opinionType"][value="ok"]').checked = true;
toggleTextarea();
document.getElementById('opinionText').value = '';
document.getElementById('charCount').textContent = '0';
}
document.getElementById('opinionModal').classList.add('show');
}
function toggleTextarea() {
var isFix = document.querySelector('input[name="opinionType"]:checked').value === 'fix';
document.getElementById('textareaWrap').style.display = isFix ? 'block' : 'none';
}
function saveOpinion() {
var type = document.querySelector('input[name="opinionType"]:checked').value;
var text = document.getElementById('opinionText').value.trim();
if (type === 'fix' && !text) {
alert('请填写详细意见');
return;
}
// 找出当前行(简化:从 modal 反查)
var name = document.getElementById('modalName').textContent;
var rows = document.querySelectorAll('.data-table tbody tr');
for (var i = 0; i < rows.length; i++) {
var tr = rows[i];
if (tr.querySelector('.col-name').textContent === name) {
var btn = tr.querySelector('.op-link[onclick*="openOpinion"]');
if (btn) {
btn.setAttribute('data-opinion', type === 'ok' ? '已确认无误' : '存在需整改的问题');
if (type === 'fix') btn.setAttribute('data-opinion-fix', text);
btn.textContent = '查看监察意见';
}
var stage = tr.querySelector('.status-tag');
stage.className = 'status-tag status-done';
stage.textContent = '监管通过';
break;
}
}
alert('监督意见已保存');
closeModal();
}
function closeModal() { document.getElementById('opinionModal').classList.remove('show'); }
document.getElementById('opinionModal').addEventListener('click', function (e) { if (e.target === this) closeModal(); });
</script>
</body>
</html>