feat(front): 项目/会议管理 admin 端补齐 + 删除按钮 + 级联 UI + 角色劳务组件
admin 会议管理: - 新建 admin/AdminMeetings.vue (查看/删除/批量删除, 面包屑 首页/项目管理/会议管理) - AdminLayout.vue 加 /admin/meetings 菜单 - router/index.js 加 admin-meetings + admin-meetings-detail 路由 - MeetingDetail.vue admin 删除按钮改 admin+manager 双角色可触发 (onAdminDelete 跳回按角色) manager 会议管理: - Meetings.vue 加批量删除 + 删除按钮 + 删除确认文案 (6 张表级联) - MeetingDetail.vue 删除按钮 v-if 改 canDeleteMeeting = isAdmin || isManager manager 项目管理: - Projects.vue 加批量删除 + 删除项 + doDelete 改走 cascade (5 张项目表 + 会议链) - ProjectsNew.vue style-alignment: page-card 居左 (max-width 1200px, 无 margin auto), form-actions 包在 el-form 内 - Projects.vue + Meetings.vue + AdminMeetings.vue 删页内冗余删除提示 store + 组件: - store/user.js 加 isAdmin getter - components/ProjectRoleSelect.vue 新建 (项目级角色劳务下拉, 接 roleLabor)
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="page-card">
|
||||
<div class="page-card manager-projects-new">
|
||||
<!-- 面包屑 -->
|
||||
<div class="breadcrumb">
|
||||
首页 / 项目管理 / <span class="current">{{ isEdit ? '编辑项目' : '新建项目' }}</span>
|
||||
@@ -121,14 +121,14 @@
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</el-form>
|
||||
|
||||
<!-- 底部按钮 -->
|
||||
<div class="form-actions">
|
||||
<el-button @click="confirmCancel">取消</el-button>
|
||||
<el-button type="warning" :loading="submitting" @click="submit('publish')">保存并发布公告</el-button>
|
||||
<el-button type="primary" :loading="submitting" @click="submit('save')">保存</el-button>
|
||||
</div>
|
||||
<!-- 底部按钮 (skill: 用 el-form-item 包裹, 不另起 div.form-actions) -->
|
||||
<el-form-item class="form-actions">
|
||||
<el-button @click="confirmCancel">取消</el-button>
|
||||
<el-button type="warning" :loading="submitting" @click="submit('publish')">保存并发布公告</el-button>
|
||||
<el-button type="primary" :loading="submitting" @click="submit('save')">保存</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -226,6 +226,12 @@ async function loadProject() {
|
||||
form.endTime = p.endTime || ''
|
||||
form.leadUserId = p.leadUserId || null
|
||||
form.isBidProject = p.isBidProject || 'N'
|
||||
// 角色劳务反显: biz_project.role_labor JSON 数组 [{role, customName, amount}]
|
||||
// 空数组/解析失败 → 保留 form 默认 5 行 (主席/主持/讲者/点评/评审/讨论)
|
||||
try {
|
||||
const rl = (typeof p.roleLabor === 'string') ? JSON.parse(p.roleLabor || '[]') : p.roleLabor
|
||||
if (Array.isArray(rl) && rl.length) form.roleRows = rl
|
||||
} catch (e) { /* keep default */ }
|
||||
// 公告文件反显: 优先 publicityFiles JSON 数组, 否则兼容旧字段
|
||||
const files = []
|
||||
if (Array.isArray(p.publicityFiles)) files.push(...p.publicityFiles)
|
||||
@@ -305,6 +311,16 @@ async function submit(mode = 'save') {
|
||||
leadUserId: form.leadUserId,
|
||||
isBidProject: form.isBidProject
|
||||
}
|
||||
// 角色劳务: 过滤空 role, 序列化为 JSON 字符串存到 biz_project.role_labor (TEXT 列)
|
||||
// "其他" 角色把 customName 作为 role 显示名 (与 ManagerProjectDetail 渲染一致)
|
||||
const roleRowsPayload = form.roleRows
|
||||
.filter(r => r.role && String(r.role).trim() !== '')
|
||||
.map(r => ({
|
||||
role: r.role,
|
||||
customName: r.role === '其他' ? (r.customName || '') : '',
|
||||
amount: Number(r.amount) || 0
|
||||
}))
|
||||
payload.roleLabor = JSON.stringify(roleRowsPayload)
|
||||
// 公告文件以 publicityFiles JSON 数组存储 (替代旧 invitationUrl/supportLetterUrl/publishUrl 独立列)
|
||||
payload.publicityFiles = JSON.stringify(uploaded.map(n => ({
|
||||
type: n.key,
|
||||
@@ -339,8 +355,6 @@ async function submit(mode = 'save') {
|
||||
// bizAdd 返回 { code, msg, data: { projectId: '...' } } 或 直接 data
|
||||
savedProjectId = r?.data?.projectId || r?.projectId || r?.data
|
||||
}
|
||||
const roleText = form.roleRows.filter(r => r.role).map(r => `${r.role === '其他' ? (r.customName || '其他') : r.role}=${r.amount}`).join(', ')
|
||||
if (roleText) console.info('[new-project.roleLabor]', form.projectNo, roleText)
|
||||
const successText = isEdit
|
||||
? (mode === 'publish' ? '更新并发布公告成功' : '更新成功')
|
||||
: (mode === 'publish' ? '保存并发布公告成功' : '保存成功')
|
||||
@@ -355,8 +369,14 @@ async function submit(mode = 'save') {
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/* 整页面板 (与 People.vue 风格一致, 1 层) */
|
||||
.page-card { background: #fff; padding: 16px 20px; border-radius: 6px; border: 1px solid #f0f0f0; }
|
||||
/* 整页面板 (与 ManagerProjectDetail.vue 风格一致: 新建/编辑页 max-width 1200px, 居左, 不居中) */
|
||||
.manager-projects-new {
|
||||
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 .current { color: #262626; font-weight: 500; }
|
||||
|
||||
@@ -399,6 +419,19 @@ async function submit(mode = 'save') {
|
||||
.notice-uploader :deep(.file-icon) { font-size: 18px; }
|
||||
.notice-uploader :deep(.file-icon svg) { width: 18px; height: 18px; }
|
||||
|
||||
/* 底部按钮 */
|
||||
.form-actions { display: flex; justify-content: center; gap: 16px; padding: 20px 0 4px; border-top: 1px solid #f0f0f0; margin-top: 8px; }
|
||||
/* 底部按钮 (skill: 用 el-form-item 包裹, 不用 div.form-actions) */
|
||||
.form-actions {
|
||||
margin-top: 24px;
|
||||
padding-top: 24px;
|
||||
border-top: 1px solid #f0f0f0;
|
||||
}
|
||||
/* 按钮所在 form-item 不显示 label 列 (skill form-actions 包裹的标准做法) */
|
||||
.form-actions :deep(.el-form-item__label) {
|
||||
display: none;
|
||||
}
|
||||
.form-actions :deep(.el-form-item__content) {
|
||||
margin-left: 0 !important;
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user