feat: 会议ID应用赋值 + 会议表单/详情优化 + admin工作台统计与用户管理

- meetingId 由 DB 自增改为应用赋值 10 位数字 (yyMMdd + 4 位序列, Redis 按日期计数)
- 会议开始时间不能晚于结束时间校验; 参会人表单身份证附件/角色单独一行
- 会议详情左右列比例 7:3 -> 8:2 (材料审核列收窄)
- admin/workbench 用户总数/角色类型数/各角色分布统计修复 (改用 listByRole 按 role_type 过滤)
- 新增 admin 用户管理接口 + 门户页脚 + H5 签到/上传优化
This commit is contained in:
郭庆泰
2026-08-25 23:33:14 +08:00
parent 591a43fe61
commit ea2024d083
66 changed files with 1454 additions and 1228 deletions
+30 -2
View File
@@ -51,9 +51,10 @@
</template>
<script setup>
import { ref, reactive, computed, onMounted } from 'vue'
import { ref, reactive, computed, onMounted, onBeforeUnmount, watchEffect } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { bizAdd, bizGet, bizUpdate } from '@/api/public'
import { bizAdd, bizGet, bizUpdate, getProjectAssignedSessions } from '@/api/public'
import { setPageTitle, clearPageTitle } from '@/utils/pageTitle'
import { ElMessage } from 'element-plus'
const route = useRoute()
@@ -82,6 +83,10 @@ const mode = computed(() => {
})
const pageTitle = computed(() => ({ new: '新建会议', edit: '修改会议', copy: '复制会议' }[mode.value]))
// 同步标题到 navbar 顶栏 (route.meta 是 shallowRef 不响应嵌套改动, 改用共享 pageTitle util)
watchEffect(() => { setPageTitle(pageTitle.value) })
onBeforeUnmount(clearPageTitle)
const formRef = ref(null)
const submitting = ref(false)
@@ -121,6 +126,14 @@ async function loadProjectSnapshot(pid) {
snap.projectName = d.projectName || ''
snap.totalSessions = d.totalSessions ?? ''
snap.sponsorOrgName = d.sponsorOrgName || ''
// executor: "总场次" = 分配给本执行方(公司)的场次, 不是项目总场次
if (roleSegment.value === 'executor') {
try {
const ar = await getProjectAssignedSessions(pid)
const ad = (ar && ar.data) || {}
if (ad.assignedSessions != null) snap.totalSessions = ad.assignedSessions
} catch (e) { /* 静默, 不阻塞主流程 */ }
}
} catch (e) { /* 静默, 不阻塞主流程 */ }
}
@@ -151,6 +164,21 @@ async function loadMeeting(mid) {
// ========== 保存 ==========
async function onSave() {
try { await formRef.value.validate() } catch (e) { return }
// 会议开始时间不能晚于会议结束时间 (通用校验)
if (form.startTime && form.endTime
&& new Date(form.startTime.replace(' ', 'T')) > new Date(form.endTime.replace(' ', 'T'))) {
ElMessage.error('会议开始时间不能晚于会议结束时间')
return
}
// executor: 期数不得超过分配给本机构的场次 (快照 totalSessions 已换成 executor 口径)
if (roleSegment.value === 'executor') {
const pn = Number(form.periodNo)
const total = Number(snap.totalSessions)
if (!Number.isNaN(pn) && !Number.isNaN(total) && pn > total) {
ElMessage.error(`期数不能超过分配给本机构的场次 (共 ${total} 场)`)
return
}
}
submitting.value = true
try {
const payload = {