feat: 会议劳务/会务材料分轨审核 + 注册页标题 + 下拉空值修复
会议材料分轨 (material_audit_stage 单轨 → labor/service 双轨): - biz_meeting: labor_audit_stage/labor_compliance_approved + service_audit_stage/service_compliance_approved 四列替换原单轨两列 - StageDeriver: 单轨状态机(R/N/C0/C1/A) + 角色优先级选代表轨 + 会议物理态取两轨最小进度 - MeetingAuditStageEnum / 前端 meetingStage.js 镜像: 分轨推导 + 颜色跟随角色展示阶段(避免文案与颜色错位) - BizMeetingController/ServiceImpl/AuditLog + mapper + MeetingStageScheduler 同步分轨字段 - MeetingDetail/Meetings/doctor/executor Meetings/ManagerProjectDetail/ManagerProjectsAssign/PublicityDetail 同步双轨 其它: - 注册页 (执行单位/专家/支持单位) 加居中页标题 - DoctorDeptSelect/DoctorTitleSelect 空字符串统一 null, 避免挂载必填项飘红 - BizOrgMapper sponsor/executor options 加 status 字段 - sponsor/NewPerson 编辑态 orgName 只读
This commit is contained in:
@@ -44,10 +44,10 @@
|
||||
<el-table-column prop="orgName" label="名称" min-width="160" show-overflow-tooltip />
|
||||
<el-table-column prop="sessions" label="场次" width="90" align="right" />
|
||||
<el-table-column label="金额" width="130" align="right">
|
||||
<template #default="{ row }">¥ {{ fmtMoney(row.amount) }}</template>
|
||||
<template #default="{ row }"><span class="money">¥ {{ fmtMoney(row.amount) }}</span></template>
|
||||
</el-table-column>
|
||||
<template #empty>
|
||||
<span style="color:#c0c4cc">暂无分配 (到 项目管理 / 项目分配 添加)</span>
|
||||
<span style="color:#909399">暂无分配 (到 项目管理 / 项目分配 添加)</span>
|
||||
</template>
|
||||
</el-table>
|
||||
</el-form-item>
|
||||
@@ -71,7 +71,7 @@
|
||||
<tbody>
|
||||
<tr v-for="(r, idx) in form.roleRows" :key="idx">
|
||||
<td>{{ r.role || '-' }}</td>
|
||||
<td style="text-align:right">¥ {{ fmtMoney(r.amount) }}</td>
|
||||
<td class="money" style="text-align:right">¥ {{ fmtMoney(r.amount) }}</td>
|
||||
</tr>
|
||||
<tr v-if="!form.roleRows.length"><td colspan="2" class="empty-row">暂无角色</td></tr>
|
||||
</tbody>
|
||||
@@ -104,6 +104,11 @@
|
||||
|
||||
<!-- 公告预览 (只读) -->
|
||||
<Preview v-model="previewOpen" :url="previewUrl" :title="previewTitle" />
|
||||
|
||||
<!-- 底部操作: 返回 (按角色回退) -->
|
||||
<div class="form-actions">
|
||||
<el-button @click="goBack">返回</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -148,7 +153,7 @@ const notices = computed(() => {
|
||||
return items.map(m => ({
|
||||
label: m.label,
|
||||
url: m.url,
|
||||
name: m.url ? (m.url.split('/').pop() || '') : ''
|
||||
name: fileNameFromUrl(m.url)
|
||||
}))
|
||||
})
|
||||
|
||||
@@ -176,6 +181,17 @@ function fmtDate(v) {
|
||||
const m = s.match(/^(\d{4})-(\d{2})-(\d{2})/)
|
||||
return m ? `${m[1]}.${m[2]}.${m[3]}` : s
|
||||
}
|
||||
// 从 OSS URL 提取并解码文件名 (中文文件名是 URL 编码的, 需 decodeURIComponent 还原)
|
||||
function fileNameFromUrl(url) {
|
||||
if (!url) return ''
|
||||
try {
|
||||
const path = String(url).split('?')[0]
|
||||
return decodeURIComponent(path.split('/').pop() || '')
|
||||
} catch (e) {
|
||||
// 非标准编码导致解码失败 → 退回原始最后一段
|
||||
return String(url).split('?')[0].split('/').pop() || ''
|
||||
}
|
||||
}
|
||||
|
||||
// ===================== 加载 =====================
|
||||
async function loadProject() {
|
||||
@@ -279,9 +295,9 @@ onMounted(async () => {
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/* 1:1 抄列表页 (manager/Projects.vue) 风格 */
|
||||
/* 项目详情 — 统一排版: 正文 14px, 章节标题/表头 600, 金额等宽, 三级灰 strong/regular/muted */
|
||||
.page-card { background: #fff; padding: 16px 20px; border-radius: 6px; border: 1px solid #f0f0f0; max-width: 1200px; }
|
||||
.breadcrumb { font-size: 13px; color: #8c8c8c; margin-bottom: 12px; }
|
||||
.breadcrumb { font-size: 13px; color: #909399; margin-bottom: 12px; }
|
||||
.breadcrumb .current { color: #262626; font-weight: 500; }
|
||||
|
||||
/* 章节标题 (与编辑页 ProjectsNew.vue 保持一致) */
|
||||
@@ -292,15 +308,21 @@ onMounted(async () => {
|
||||
}
|
||||
.new-card-title:first-child { margin-top: 0; }
|
||||
|
||||
/* 项目信息: 11 字段, 一列竖排 (el-form + 文本, 无分隔线) */
|
||||
/* 底部操作按钮 (返回) */
|
||||
.form-actions { margin-top: 24px; display: flex; gap: 8px; }
|
||||
|
||||
/* 项目信息: 只读 el-form, 标签 14px/regular, 值 14px/strong */
|
||||
.info-form { padding-top: 4px; }
|
||||
.info-form :deep(.el-form-item) { margin-bottom: 8px; }
|
||||
.info-form :deep(.el-form-item__label) {
|
||||
font-size: 14px; color: #595959; width: 130px; padding-right: 16px;
|
||||
font-size: 14px; color: #606266; width: 130px; padding-right: 16px;
|
||||
}
|
||||
.info-value { font-size: 15px; color: #1a1a1a; font-weight: 500; }
|
||||
.info-value.money {
|
||||
font-family: ui-monospace, "Courier New", monospace;
|
||||
.info-value { font-size: 14px; color: #262626; font-weight: 400; }
|
||||
|
||||
/* 金额: 统一等宽字体 + tabular 数字对齐 (表单值 + 两处表格通用) */
|
||||
.money {
|
||||
font-family: ui-monospace, "SF Mono", "JetBrains Mono", Consolas, "Courier New", monospace;
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
|
||||
/* 监督员 */
|
||||
@@ -310,31 +332,33 @@ onMounted(async () => {
|
||||
padding: 8px 12px; background: #fafafa; border-radius: 4px;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
.monitor-num { width: 24px; color: #8c8c8c; font-size: 13px; }
|
||||
.monitor-name { flex: 1; font-size: 14px; color: #1a1a1a; }
|
||||
.empty-hint { text-align: center; color: #c0c4cc; padding: 12px 0; font-size: 13px; }
|
||||
.monitor-num { width: 24px; color: #909399; font-size: 13px; }
|
||||
.monitor-name { flex: 1; font-size: 14px; color: #262626; }
|
||||
.empty-hint { text-align: center; color: #909399; padding: 12px 0; font-size: 13px; }
|
||||
|
||||
/* 角色劳务表格 */
|
||||
.info-table { width: 100%; border-collapse: collapse; font-size: 13px; }
|
||||
/* 角色劳务表格 + 服务公司表格: 统一 14px, 表头 600/strong, 单元格 strong */
|
||||
.info-table { width: 100%; border-collapse: collapse; font-size: 14px; }
|
||||
.role-labor-table { width: auto; border: 1px solid #ebeef5; } /* 角色劳务表格按内容紧凑显示, 不撑满卡片 */
|
||||
.role-labor-table th,
|
||||
.role-labor-table td { border-right: 1px solid #ebeef5; }
|
||||
.role-labor-table th:last-child,
|
||||
.role-labor-table td:last-child { border-right: none; }
|
||||
/* 服务公司表格 (el-table in form): 紧凑, 不要撑满整张卡片 */
|
||||
.assign-table-el { width: auto; max-width: 560px; }
|
||||
.assign-table-el { width: auto; max-width: 560px; font-size: 14px; }
|
||||
.assign-table-el :deep(.el-table__empty-block) { min-height: 48px; }
|
||||
.info-table th { background: #fafafa; padding: 10px 12px; text-align: left; color: #1a1a1a; font-weight: 600; border-bottom: 1px solid #f0f0f0; white-space: nowrap; }
|
||||
.info-table td { padding: 10px 12px; border-bottom: 1px solid #f5f5f5; color: #595959; vertical-align: middle; }
|
||||
.empty-row { text-align: center; color: #c0c4cc; }
|
||||
.assign-table-el :deep(th.el-table__cell) { color: #262626; font-weight: 600; background: #fafafa; }
|
||||
.assign-table-el :deep(td.el-table__cell) { color: #262626; }
|
||||
.info-table th { background: #fafafa; padding: 10px 12px; text-align: left; color: #262626; font-weight: 600; border-bottom: 1px solid #f0f0f0; white-space: nowrap; }
|
||||
.info-table td { padding: 10px 12px; border-bottom: 1px solid #f5f5f5; color: #262626; vertical-align: middle; }
|
||||
.empty-row { text-align: center; color: #909399; }
|
||||
|
||||
/* 公告文件 (只读 4 行: 邀请函/支持函/通知/日程) */
|
||||
.notice-list { display: flex; flex-direction: column; gap: 6px; }
|
||||
.notice-row { display: flex; align-items: center; gap: 12px; padding: 6px 0; }
|
||||
.notice-label { width: 90px; flex-shrink: 0; color: #606266; font-size: 14px; }
|
||||
.notice-file { flex: 1; display: flex; align-items: center; gap: 12px; min-width: 0; }
|
||||
.file-name { color: #1a1a1a; font-size: 14px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||
.file-empty { color: #c0c4cc; font-size: 13px; }
|
||||
.file-name { color: #262626; font-size: 14px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||
.file-empty { color: #909399; font-size: 13px; }
|
||||
|
||||
/* 提示 (灰色, 跟 ProjectsNew 一致) */
|
||||
.hint-text { font-size: 12px; color: #909399; margin: 8px 0; line-height: 1.6; }
|
||||
|
||||
Reference in New Issue
Block a user