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:
@@ -33,7 +33,7 @@
|
||||
<el-col :span="12"><el-form-item label="项目负责人"><span class="info-value">{{ row.leadUserName || '-' }}</span></el-form-item></el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="12">
|
||||
<el-col :span="12"><el-form-item label="支持公司"><span class="info-value">{{ row.sponsorAdminUserName || '-' }}</span></el-form-item></el-col>
|
||||
<el-col :span="12"><el-form-item label="支持公司"><span class="info-value">{{ row.sponsorOrgName || '-' }}</span></el-form-item></el-col>
|
||||
<el-col :span="12"><el-form-item label="项目评价"><span class="info-value">{{ fmtScore(row.managerScore) }}</span></el-form-item></el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="12">
|
||||
@@ -89,18 +89,18 @@
|
||||
|
||||
<!-- (已分配执行方 已折叠进上方"项目信息"section, 此处不再重复) -->
|
||||
|
||||
<!-- ================= 4. 已发布公告 (只读, 仅查看) ================= -->
|
||||
<div class="new-card-title">已发布公告</div>
|
||||
<el-table v-loading="loading" :data="announcements" border>
|
||||
<el-table-column prop="title" label="公告标题" min-width="200" show-overflow-tooltip />
|
||||
<el-table-column prop="createTime" label="发布时间" width="160" align="center" :formatter="(r)=>fmtDate(r.createTime)" />
|
||||
<el-table-column prop="creatorName" label="发布人" width="120" align="center" />
|
||||
<el-table-column label="操作" width="100" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-button link type="primary" @click="openPreview(row.fileUrl || row.url, row.title)">查看</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<!-- ================= 4. 公告文件 (只读, 仅查看: 邀请函/支持函/通知/日程) ================= -->
|
||||
<div class="new-card-title">公告文件</div>
|
||||
<div class="notice-list">
|
||||
<div v-for="(n, idx) in notices" :key="idx" class="notice-row">
|
||||
<span class="notice-label">{{ n.label }}</span>
|
||||
<span v-if="n.url" class="notice-file">
|
||||
<span class="file-name">{{ n.name || '已上传' }}</span>
|
||||
<el-button link type="primary" @click="openPreview(n.url, n.label)">查看</el-button>
|
||||
</span>
|
||||
<span v-else class="file-empty">未上传</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 公告预览 (只读) -->
|
||||
<Preview v-model="previewOpen" :url="previewUrl" :title="previewTitle" />
|
||||
@@ -108,9 +108,9 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, onMounted } from 'vue'
|
||||
import { ref, reactive, computed, onMounted } from 'vue'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { bizGet, bizList } from '@/api/public'
|
||||
import { bizGet } from '@/api/public'
|
||||
import { listExecutorOrgs } from '@/api/system'
|
||||
import request from '@/utils/request'
|
||||
import Preview from '@/components/Preview.vue'
|
||||
@@ -135,8 +135,22 @@ const form = reactive({
|
||||
// 监督员 (从 biz_project.monitors JSON 字段读)
|
||||
const monitors = ref([])
|
||||
|
||||
// 已发布公告
|
||||
const announcements = ref([])
|
||||
// 公告文件 (邀请函/支持函/通知/日程) — 数据源 biz_project 4 个独立列, 与 ProjectsNew 反显逻辑一致
|
||||
// 注: 后端无 publicityFiles 字段 (前端传了但不落库), 实际落库是 invitation_url/support_letter_url/publish_url/schedule_url
|
||||
const notices = computed(() => {
|
||||
const r = row.value || {}
|
||||
const items = [
|
||||
{ label: '邀请函', url: r.invitationUrl },
|
||||
{ label: '支持函', url: r.supportLetterUrl },
|
||||
{ label: '通知', url: r.publishUrl },
|
||||
{ label: '日程', url: r.scheduleUrl }
|
||||
]
|
||||
return items.map(m => ({
|
||||
label: m.label,
|
||||
url: m.url,
|
||||
name: m.url ? (m.url.split('/').pop() || '') : ''
|
||||
}))
|
||||
})
|
||||
|
||||
// 公告预览
|
||||
const previewOpen = ref(false)
|
||||
@@ -186,17 +200,6 @@ async function loadProject() {
|
||||
}
|
||||
}
|
||||
|
||||
async function loadAnnouncements() {
|
||||
try {
|
||||
const resp = await bizList('publicity', { projectId: projectId.value })
|
||||
const arr = (resp && resp.rows) || ((resp && resp.data) && (resp && resp.data).rows) || (resp && resp.data) || []
|
||||
announcements.value = Array.isArray(arr) ? arr : []
|
||||
} catch (e) {
|
||||
console.error('[project-detail] announcements load failed', e)
|
||||
announcements.value = []
|
||||
}
|
||||
}
|
||||
|
||||
// ===================== 已分配执行方 (服务公司) =====================
|
||||
/**
|
||||
* 数据源同 manager/projects/edit/{id} 的 loadAssigns:
|
||||
@@ -272,7 +275,6 @@ function openPreview(url, title) {
|
||||
onMounted(async () => {
|
||||
await loadProject()
|
||||
await Promise.all([loadAssigns(), loadMonitors()])
|
||||
await loadAnnouncements()
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -326,6 +328,14 @@ onMounted(async () => {
|
||||
.info-table td { padding: 10px 12px; border-bottom: 1px solid #f5f5f5; color: #595959; vertical-align: middle; }
|
||||
.empty-row { text-align: center; color: #c0c4cc; }
|
||||
|
||||
/* 公告文件 (只读 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; }
|
||||
|
||||
/* 提示 (灰色, 跟 ProjectsNew 一致) */
|
||||
.hint-text { font-size: 12px; color: #909399; margin: 8px 0; line-height: 1.6; }
|
||||
.hint-text p { margin-bottom: 4px; }
|
||||
|
||||
Reference in New Issue
Block a user