feat: 生产部署 + 会议全链路 (执行方分配/费用结算/签到脱敏/H5相机)

- 生产 nginx 三路径: ry-vue3 /hg/, ry-h5 /camera/, API /hg-api, .env 分环境
- 签约链接/摄像头 base-url 走 yml, 不再硬编码 /hg 与 localhost
- 新增 biz_project_executor_assign (镜像 sponsor_assign) 执行方项目级分配
- 会议费用后台汇总 FeeCalcScheduler + 结算回写项目金额 + 状态流转调度
- 签到表拍照高斯模糊脱敏 extra_oss_url, 新增 PosterService/StageDeriver
- 清理 biz_support_intent 旧表 (6 Java/XML 删除)
- ry-h5 相机黑屏修复: 显式 video.play() + 动态 apiBase 上传
- 资源: simhei 字体 / logo.png / qrcode_1.png / favicon.ico

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
郭庆泰
2026-08-24 01:00:09 +08:00
co-authored by Claude
parent 80a276e661
commit 904e28710f
123 changed files with 6008 additions and 1706 deletions
+23 -27
View File
@@ -5,41 +5,36 @@
<!-- el-form 包裹 + label-width 110px (跟原型一致) -->
<el-form ref="formRef" :model="form" :rules="rules" label-width="110px">
<!-- 2 列布局 (跟原型 .form-grid 一致: grid-auto-flow: column 让左 6 右 5 对齐) -->
<!-- 只读快照 (直接显示, 放上面) -->
<div class="form-grid">
<!-- 左列 6 项只读快照 (来自 biz_project 派生) -->
<el-form-item label="项目编号">
<span class="form-value code">{{ snap.projectNo }}</span>
</el-form-item>
<el-form-item label="项目名称">
<span class="form-value">{{ snap.projectName }}</span>
</el-form-item>
<el-form-item label="总场次/总期数">
<span class="form-value">{{ snap.totalSessions }}</span>
<el-form-item label="会议名称">
<span class="form-value">{{ form.meetingName }}</span>
</el-form-item>
<el-form-item label="支持单位">
<span class="form-value">{{ snap.sponsorOrgName }}</span>
</el-form-item>
<el-form-item label="创建时间">
<span class="form-value">{{ snap.createTime }}</span>
</el-form-item>
<el-form-item label="创建人员">
<span class="form-value">{{ snap.createUserName }}</span>
<el-form-item label="总场次/总期数">
<span class="form-value">{{ snap.totalSessions }}</span>
</el-form-item>
</div>
<!-- 右列 5 项: 1 只读 (会议名称 = 项目名) + 4 输入 -->
<el-form-item label="会议名称">
<span class="form-value">{{ form.meetingName }}</span>
</el-form-item>
<el-form-item label="期数" prop="periodNo">
<el-input v-model="form.periodNo" placeholder="请填写第几期" />
</el-form-item>
<!-- 待填写 (放下面) -->
<div class="form-grid form-grid-inputs">
<el-form-item label="会议开始时间" prop="startTime">
<el-date-picker v-model="form.startTime" type="datetime" value-format="YYYY-MM-DD HH:mm:ss" placeholder="选择开始时间" />
</el-form-item>
<el-form-item label="会议结束时间" prop="endTime">
<el-date-picker v-model="form.endTime" type="datetime" value-format="YYYY-MM-DD HH:mm:ss" placeholder="选择结束时间" />
</el-form-item>
<el-form-item label="期数" prop="periodNo">
<el-input v-model="form.periodNo" placeholder="请填写第几期" />
</el-form-item>
<el-form-item label="备注">
<el-input v-model="form.remark" placeholder="请输入备注" />
</el-form-item>
@@ -87,14 +82,12 @@ const pageTitle = computed(() => ({ new: '新建会议', edit: '修改会议', c
const formRef = ref(null)
const submitting = ref(false)
// ========== 项目只读快照 (左列 6 项) ==========
// ========== 项目只读快照 (左列 4 项) ==========
const snap = reactive({
projectNo: '',
projectName: '',
totalSessions: '',
sponsorOrgName: '',
createTime: '',
createUserName: ''
sponsorOrgName: ''
})
// ========== 表单 (右列 5 项: meetingName 只读 + 4 输入) ==========
@@ -125,8 +118,6 @@ async function loadProjectSnapshot(pid) {
snap.projectName = d.projectName || ''
snap.totalSessions = d.totalSessions ?? ''
snap.sponsorOrgName = d.sponsorOrgName || ''
snap.createTime = d.createTime || ''
snap.createUserName = d.createUserName || d.createBy || ''
} catch (e) { /* 静默, 不阻塞主流程 */ }
}
@@ -147,7 +138,7 @@ async function loadMeeting(mid) {
// 左列快照 projectNo/projectName 用 meeting 冗余字段 (即使 project_id 为 NULL 也能显示)
snap.projectNo = d.projectNo || ''
snap.projectName = d.projectName || ''
// 总场次/支持单位/创建时间/创建人员 优先用 URL projectId, 其次 meeting.projectId
// 总场次/支持单位 优先用 URL projectId, 其次 meeting.projectId
const pid = urlProjectId || d.projectId
if (pid) {
await loadProjectSnapshot(pid)
@@ -180,7 +171,8 @@ async function onSave() {
await bizAdd('meeting', payload, { __silentError: true })
ElMessage.success(mode.value === 'copy' ? '复制成功' : '会议创建成功')
}
goBack()
// 建会/修改/复制成功 → 跳会议列表 (不再返回项目列表, executor/manager 一致)
router.push(meetingsBase.value)
} catch (e) {
ElMessage.error(e?.msg || (mode.value === 'edit' ? '修改失败' : '保存失败'))
} finally {
@@ -234,15 +226,19 @@ onMounted(async () => {
margin-bottom: 24px;
}
/* === 2 列布局 (跟原型 .form-grid 一致, grid-auto-flow: column 让左 6 右 5 对齐) === */
/* === 2 列布局 (只读区/填写区 各一个 grid, 行优先流) === */
.form-grid {
display: grid;
grid-template-columns: 1fr 1fr;
grid-auto-flow: column;
grid-template-rows: repeat(6, auto);
gap: 20px 32px;
max-width: 900px;
}
/* 填写区: 与上方只读区分隔 */
.form-grid-inputs {
margin-top: 24px;
padding-top: 24px;
border-top: 1px solid #f0f0f0;
}
/* grid 内的 el-form-item 不再加默认 margin-bottom (由 grid 控制间距) */
.form-grid :deep(.el-form-item) {
margin-bottom: 0;