refactor(meetings): 修改/复制跳独立页 /manager/meetings/new?meetingId=xxx[&mode=copy], 移除列表页 edit dialog
This commit is contained in:
@@ -1,13 +1,13 @@
|
||||
<template>
|
||||
<div class="page-card manager-meeting-new">
|
||||
<!-- 面包屑 -->
|
||||
<div class="breadcrumb">首页 / 会议管理 / 新建会议</div>
|
||||
<!-- 面包屑: 标题随 mode 变 (新建/修改/复制) -->
|
||||
<div class="breadcrumb">首页 / 会议管理 / {{ pageTitle }}</div>
|
||||
|
||||
<!-- 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 对齐) -->
|
||||
<!-- 2 列布局 (跟原型 .form-grid 一致: grid-auto-flow: column 让左 6 右 7 对齐) -->
|
||||
<div class="form-grid">
|
||||
<!-- 左列 6 项只读快照 (来自 biz_project 派生) -->
|
||||
<!-- 左列 6 项只读快照 (来自 biz_project 派生, 来自 meeting.projectId) -->
|
||||
<el-form-item label="项目编号">
|
||||
<span class="form-value code">{{ snap.projectNo }}</span>
|
||||
</el-form-item>
|
||||
@@ -27,12 +27,20 @@
|
||||
<span class="form-value">{{ snap.createUserName }}</span>
|
||||
</el-form-item>
|
||||
|
||||
<!-- 右列 5 项: 1 只读 + 4 输入 -->
|
||||
<el-form-item label="会议名称">
|
||||
<span class="form-value">{{ form.meetingName }}</span>
|
||||
<!-- 右列 7 项可编辑: meetingName/periodNo/projectForm/startTime/endTime/totalPeriods/remark -->
|
||||
<el-form-item label="会议名称" prop="meetingName">
|
||||
<el-input v-model="form.meetingName" placeholder="请输入会议名称" />
|
||||
</el-form-item>
|
||||
<el-form-item label="期数" prop="periodNo">
|
||||
<el-input v-model="form.periodNo" placeholder="请填写第几期" />
|
||||
<el-input-number v-model="form.periodNo" :min="1" :precision="0" placeholder="请填写第几期" />
|
||||
</el-form-item>
|
||||
<el-form-item label="项目形式" prop="projectForm">
|
||||
<el-select v-model="form.projectForm" placeholder="请选择项目形式" style="width:100%">
|
||||
<el-option label="线上" value="线上" />
|
||||
<el-option label="线下" value="线下" />
|
||||
<el-option label="线上+线下" value="线上+线下" />
|
||||
<el-option label="其他" value="其他" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="会议开始时间" prop="startTime">
|
||||
<el-date-picker v-model="form.startTime" type="datetime" value-format="YYYY-MM-DD HH:mm:ss" placeholder="选择开始时间" />
|
||||
@@ -40,14 +48,17 @@
|
||||
<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="备注">
|
||||
<el-input v-model="form.remark" placeholder="请输入备注" />
|
||||
<el-form-item label="总期数" prop="totalPeriods">
|
||||
<el-input-number v-model="form.totalPeriods" :min="1" :precision="0" />
|
||||
</el-form-item>
|
||||
<el-form-item label="备注" class="full-row">
|
||||
<el-input v-model="form.remark" type="textarea" :rows="3" placeholder="请输入备注" />
|
||||
</el-form-item>
|
||||
</div>
|
||||
|
||||
<!-- 底部按钮 (skill: 用 el-form-item 包裹, 不另起 div.form-actions) -->
|
||||
<el-form-item class="form-actions">
|
||||
<el-button type="primary" @click="onSave">保存</el-button>
|
||||
<el-button type="primary" :loading="submitting" @click="onSave">保存</el-button>
|
||||
<el-button @click="goBack">取消</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
@@ -55,17 +66,32 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, onMounted } from 'vue'
|
||||
import { ref, reactive, computed, onMounted } from 'vue'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { bizAdd, bizGet } from '@/api/public'
|
||||
import { bizAdd, bizGet, bizUpdate } from '@/api/public'
|
||||
import { ElMessage } from 'element-plus'
|
||||
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
const preselectProjectId = route.query.projectId || ''
|
||||
const formRef = ref(null)
|
||||
|
||||
// 项目只读快照 (左列 6 项)
|
||||
// ========== mode 判定 ==========
|
||||
// 3 种模式:
|
||||
// new: ?projectId=xxx → POST /business/meeting (新建)
|
||||
// edit: ?meetingId=xxx → PUT /business/meeting/{id} (修改)
|
||||
// copy: ?meetingId=xxx&mode=copy → POST /business/meeting (复制)
|
||||
const meetingId = route.query.meetingId || ''
|
||||
const projectId = route.query.projectId || ''
|
||||
const mode = computed(() => {
|
||||
if (meetingId && route.query.mode === 'copy') return 'copy'
|
||||
if (meetingId) return 'edit'
|
||||
return 'new'
|
||||
})
|
||||
const pageTitle = computed(() => ({ new: '新建会议', edit: '修改会议', copy: '复制会议' }[mode.value]))
|
||||
|
||||
const formRef = ref(null)
|
||||
const submitting = ref(false)
|
||||
|
||||
// ========== 项目只读快照 (左列 6 项) ==========
|
||||
const snap = reactive({
|
||||
projectNo: '',
|
||||
projectName: '',
|
||||
@@ -75,51 +101,34 @@ const snap = reactive({
|
||||
createUserName: ''
|
||||
})
|
||||
|
||||
// 表单 (右列 5 项: meetingName 只读 + 4 输入)
|
||||
// ========== 表单 (右列 7 项可编辑) ==========
|
||||
const form = reactive({
|
||||
projectId: preselectProjectId ? Number(preselectProjectId) : null,
|
||||
projectId: null,
|
||||
projectNo: '',
|
||||
projectName: '',
|
||||
meetingName: '',
|
||||
periodNo: '',
|
||||
periodNo: 1,
|
||||
projectForm: '',
|
||||
startTime: '',
|
||||
endTime: '',
|
||||
totalPeriods: 1,
|
||||
remark: ''
|
||||
})
|
||||
|
||||
const rules = {
|
||||
meetingName: [{ required: true, message: '请输入会议名称', trigger: 'blur' }],
|
||||
periodNo: [{ required: true, message: '请填写第几期', trigger: 'blur' }],
|
||||
projectForm: [{ required: true, message: '请选择项目形式', trigger: 'change' }],
|
||||
startTime: [{ required: true, message: '请选择会议开始时间', trigger: 'change' }],
|
||||
endTime: [{ required: true, message: '请选择会议结束时间', trigger: 'change' }]
|
||||
endTime: [{ required: true, message: '请选择会议结束时间', trigger: 'change' }],
|
||||
totalPeriods: [{ required: true, message: '请填写总期数', trigger: 'blur' }]
|
||||
}
|
||||
|
||||
async function onSave() {
|
||||
try { await formRef.value.validate() } catch (e) { return }
|
||||
// ========== 加载项目快照 ==========
|
||||
async function loadProjectSnapshot(pid) {
|
||||
if (!pid) return
|
||||
try {
|
||||
// __silentError: 拦截器不自动 toast, 错误统一由下方 catch 处理 (避免双 toast)
|
||||
await bizAdd('meeting', {
|
||||
projectId: form.projectId,
|
||||
projectNo: form.projectNo,
|
||||
projectName: form.projectName,
|
||||
meetingName: form.meetingName,
|
||||
periodNo: form.periodNo,
|
||||
startTime: form.startTime,
|
||||
endTime: form.endTime,
|
||||
remark: form.remark
|
||||
}, { __silentError: true })
|
||||
ElMessage.success('会议创建成功')
|
||||
goBack()
|
||||
} catch (e) {
|
||||
ElMessage.error(e?.msg || '保存失败')
|
||||
}
|
||||
}
|
||||
|
||||
function goBack() { router.push('/manager/projects') }
|
||||
|
||||
onMounted(async () => {
|
||||
if (!preselectProjectId) return
|
||||
try {
|
||||
const r = await bizGet('project', preselectProjectId)
|
||||
const r = await bizGet('project', pid)
|
||||
const d = (r && r.data) || {}
|
||||
snap.projectNo = d.projectNo || ''
|
||||
snap.projectName = d.projectName || ''
|
||||
@@ -127,11 +136,78 @@ onMounted(async () => {
|
||||
snap.sponsorOrgName = d.sponsorOrgName || ''
|
||||
snap.createTime = d.createTime || ''
|
||||
snap.createUserName = d.createUserName || d.createBy || ''
|
||||
// 会议名称默认 = 项目名称 (跟红字提示一致)
|
||||
form.projectNo = d.projectNo || ''
|
||||
form.projectName = d.projectName || ''
|
||||
form.meetingName = d.projectName || ''
|
||||
} catch (e) {}
|
||||
} catch (e) { /* 静默, 不阻塞主流程 */ }
|
||||
}
|
||||
|
||||
// ========== 加载会议详情 (edit/copy 模式用) ==========
|
||||
async function loadMeeting(mid) {
|
||||
if (!mid) return
|
||||
const r = await bizGet('meeting', mid)
|
||||
const d = (r && r.data) || {}
|
||||
form.meetingId = d.meetingId
|
||||
form.projectId = d.projectId ?? null
|
||||
form.projectNo = d.projectNo || ''
|
||||
form.projectName = d.projectName || ''
|
||||
form.meetingName = d.meetingName || ''
|
||||
form.periodNo = d.periodNo || 1
|
||||
form.projectForm = d.projectForm || ''
|
||||
form.startTime = d.startTime || ''
|
||||
form.endTime = d.endTime || ''
|
||||
form.totalPeriods = d.totalPeriods || 1
|
||||
form.remark = d.remark || ''
|
||||
// 左列快照来自 meeting.projectId
|
||||
await loadProjectSnapshot(d.projectId)
|
||||
}
|
||||
|
||||
// ========== 保存 ==========
|
||||
async function onSave() {
|
||||
try { await formRef.value.validate() } catch (e) { return }
|
||||
submitting.value = true
|
||||
try {
|
||||
const payload = { ...form }
|
||||
if (mode.value === 'edit') {
|
||||
// 修改: 走 bizUpdate, 带 meetingId (后端 WHERE 用, 不能 delete)
|
||||
// __silentError: 拦截器不自动 toast, 错误统一由下方 catch 处理 (避免双 toast)
|
||||
await bizUpdate('meeting', payload, { __silentError: true })
|
||||
ElMessage.success('修改成功')
|
||||
} else {
|
||||
// 新建 / 复制: 走 bizAdd, 不传 meetingId (AUTO_INCREMENT)
|
||||
delete payload.meetingId
|
||||
await bizAdd('meeting', payload, { __silentError: true })
|
||||
ElMessage.success(mode.value === 'copy' ? '复制成功' : '创建成功')
|
||||
}
|
||||
goBack()
|
||||
} catch (e) {
|
||||
ElMessage.error(e?.msg || (mode.value === 'edit' ? '修改失败' : '保存失败'))
|
||||
} finally {
|
||||
submitting.value = false
|
||||
}
|
||||
}
|
||||
|
||||
function goBack() {
|
||||
// 跳回列表 (用 name 而非 path, hash 模式 + 路由可复用)
|
||||
router.push({ name: 'manager-meetings' })
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
if (mode.value === 'edit') {
|
||||
// 修改: 加载会议详情 (左列项目快照由 meeting.projectId 派生)
|
||||
await loadMeeting(meetingId)
|
||||
} else if (mode.value === 'copy') {
|
||||
// 复制: 加载会议详情, name 加 " 副本", periodNo reset 为 1 (用户填)
|
||||
await loadMeeting(meetingId)
|
||||
form.meetingName = (form.meetingName || '') + ' 副本'
|
||||
form.periodNo = 1 // 复制后让用户重新填期数
|
||||
} else {
|
||||
// 新建: 加载项目快照, meetingName 默认 = 项目名
|
||||
if (projectId) {
|
||||
form.projectId = Number(projectId) || null
|
||||
await loadProjectSnapshot(projectId)
|
||||
form.projectNo = snap.projectNo
|
||||
form.projectName = snap.projectName
|
||||
form.meetingName = snap.projectName // 默认会议名 = 项目名
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -149,12 +225,12 @@ onMounted(async () => {
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
/* === 2 列布局 (跟原型 .form-grid 一致, grid-auto-flow: column 让左 6 右 5 对齐) === */
|
||||
/* === 2 列布局 (跟原型 .form-grid 一致, grid-auto-flow: column 让左 6 右 7 对齐) === */
|
||||
.form-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
grid-auto-flow: column;
|
||||
grid-template-rows: repeat(6, auto);
|
||||
grid-template-rows: repeat(7, auto);
|
||||
gap: 20px 32px;
|
||||
max-width: 900px;
|
||||
}
|
||||
@@ -162,6 +238,10 @@ onMounted(async () => {
|
||||
.form-grid :deep(.el-form-item) {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
/* 备注占满整行 (第 7 项右列最后一行, 跨 2 列) */
|
||||
.form-grid :deep(.full-row) {
|
||||
grid-column: 2 / 3;
|
||||
}
|
||||
|
||||
/* 只读值样式 */
|
||||
.form-value {
|
||||
|
||||
@@ -103,38 +103,14 @@
|
||||
</el-descriptions>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 修改 / 复制 dialog (editMode 区分, 复制走 bizAdd, 修改走 bizUpdate) -->
|
||||
<el-dialog v-model="editOpen" :title="editMode === 'copy' ? '复制会议' : '修改会议'" width="640px">
|
||||
<el-form :model="editForm" label-width="100px">
|
||||
<el-form-item label="会议名称"><el-input v-model="editForm.meetingName" /></el-form-item>
|
||||
<el-form-item label="项目形式">
|
||||
<el-select v-model="editForm.projectForm">
|
||||
<el-option label="线上" value="线上" />
|
||||
<el-option label="线下" value="线下" />
|
||||
<el-option label="线上+线下" value="线上+线下" />
|
||||
<el-option label="其他" value="其他" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="开始时间">
|
||||
<el-date-picker v-model="editForm.startTime" type="datetime" value-format="YYYY-MM-DD HH:mm:ss" style="width:100%" />
|
||||
</el-form-item>
|
||||
<el-form-item label="结束时间">
|
||||
<el-date-picker v-model="editForm.endTime" type="datetime" value-format="YYYY-MM-DD HH:mm:ss" style="width:100%" />
|
||||
</el-form-item>
|
||||
<el-form-item label="总期数"><el-input-number v-model="editForm.totalPeriods" :min="1" /></el-form-item>
|
||||
<el-form-item label="备注"><el-input v-model="editForm.remark" type="textarea" :rows="2" /></el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click="editOpen = false">取消</el-button>
|
||||
<el-button type="primary" :loading="editSubmitting" @click="submitEdit">确定</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
<!-- 修改 / 复制: 跳转到 /manager/meetings/new?meetingId=xxx[&mode=copy] (由 MeetingNew.vue 独立页处理) -->
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, onMounted } from 'vue'
|
||||
import { bizList, bizUpdate, bizAdd } from '@/api/public'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { bizList, bizUpdate } from '@/api/public'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
|
||||
// ========== 筛选 (按实际 8 项: 项目编号/会议ID/会议名称/第?期/会议时间/项目形式/当前阶段/备注) ==========
|
||||
@@ -216,56 +192,13 @@ const detailOpen = ref(false)
|
||||
const currentRow = ref(null)
|
||||
function onView(row) { currentRow.value = row; detailOpen.value = true }
|
||||
|
||||
// ========== 修改 / 复制 ==========
|
||||
const editOpen = ref(false)
|
||||
const editSubmitting = ref(false)
|
||||
// editMode 区分当前 dialog 是 "修改" 还是 "复制", 决定 submitEdit 走 bizUpdate 还是 bizAdd
|
||||
const editMode = ref('edit') // 'edit' | 'copy'
|
||||
const editForm = reactive({
|
||||
meetingId: '', meetingName: '',
|
||||
projectId: null, projectNo: '', projectName: '',
|
||||
projectForm: '', startTime: '', endTime: '',
|
||||
totalPeriods: 1, currentStage: '未执行',
|
||||
remark: ''
|
||||
})
|
||||
// ========== 修改 / 复制 (跳 MeetingNew.vue 独立页, ?meetingId=xxx[&mode=copy]) ==========
|
||||
const router = useRouter()
|
||||
function onEdit(row) {
|
||||
editMode.value = 'edit'
|
||||
Object.assign(editForm, {
|
||||
meetingId: row.meetingId,
|
||||
projectId: row.projectId ?? null,
|
||||
projectNo: row.projectNo || '',
|
||||
projectName: row.projectName || '',
|
||||
meetingName: row.meetingName || '',
|
||||
projectForm: row.projectForm || '',
|
||||
startTime: row.startTime || '',
|
||||
endTime: row.endTime || '',
|
||||
totalPeriods: row.totalPeriods || 1,
|
||||
currentStage: row.currentStage || '未执行',
|
||||
remark: row.remark || ''
|
||||
})
|
||||
editOpen.value = true
|
||||
router.push({ name: 'manager-meetings-new', query: { meetingId: row.meetingId } })
|
||||
}
|
||||
async function submitEdit() {
|
||||
editSubmitting.value = true
|
||||
const isCopy = editMode.value === 'copy'
|
||||
try {
|
||||
const payload = { ...editForm }
|
||||
if (isCopy) {
|
||||
// 复制: 走 bizAdd, 不传 meetingId (AUTO_INCREMENT) 和 businessId (后端兜底)
|
||||
delete payload.meetingId
|
||||
await bizAdd('meeting', payload, { __silentError: true })
|
||||
} else {
|
||||
// 修改: 走 bizUpdate
|
||||
await bizUpdate('meeting', payload, { __silentError: true })
|
||||
}
|
||||
ElMessage.success(isCopy ? '复制成功' : '修改成功')
|
||||
editOpen.value = false
|
||||
load()
|
||||
} catch (e) {
|
||||
ElMessage.error(e?.msg || (isCopy ? '复制失败' : '修改失败'))
|
||||
} finally {
|
||||
editSubmitting.value = false
|
||||
}
|
||||
function onCopy(row) {
|
||||
router.push({ name: 'manager-meetings-new', query: { meetingId: row.meetingId, mode: 'copy' } })
|
||||
}
|
||||
|
||||
// ========== 提交 (单条) ==========
|
||||
@@ -278,26 +211,6 @@ async function onSubmit(row) {
|
||||
} catch (e) { ElMessage.error(e?.msg || '提交失败') }
|
||||
}
|
||||
|
||||
// ========== 复制 (单条) ==========
|
||||
function onCopy(row) {
|
||||
// 复制行到会议名 + ' 副本' 打开 dialog, 走 bizAdd 创建新会议 (跟 onEdit 共用同一 dialog, editMode='copy')
|
||||
editMode.value = 'copy'
|
||||
Object.assign(editForm, {
|
||||
meetingId: '',
|
||||
projectId: row.projectId ?? null,
|
||||
projectNo: row.projectNo || '',
|
||||
projectName: row.projectName || '',
|
||||
meetingName: (row.meetingName || '') + ' 副本',
|
||||
projectForm: row.projectForm || '',
|
||||
startTime: row.startTime || '',
|
||||
endTime: row.endTime || '',
|
||||
totalPeriods: row.totalPeriods || 1,
|
||||
currentStage: '未执行',
|
||||
remark: row.remark || ''
|
||||
})
|
||||
editOpen.value = true
|
||||
}
|
||||
|
||||
// ========== 批量提交 ==========
|
||||
async function onBatchSubmit() {
|
||||
if (!selectedIds.value.length) return
|
||||
|
||||
Reference in New Issue
Block a user