refactor(doctor/submissions): 合并到 biz_project_plan + 删除 biz_submission 死代码
- /doctor/submissions 改走 biz_project_plan,与 /manager/plans 字段/组件/状态字典完全对齐 - BizProjectPlan 加 submitter_id (BIGINT) + submitter_name (LEFT JOIN 查询字段) - mapper 改 LEFT JOIN biz_person + sys_user,COALESCE(bp.name, u.user_name) 兜底 - biz_person.user_id 加 UNIQUE 索引 (1:1 LEFT JOIN 无笛卡尔积) - controller 加 doctor 角色自动过滤: list 按 submitter_id, add/edit 强制 submitter_id - 删除 7 个 BizSubmission 死代码 (Controller/Service/Mapper/Domain/XML/Enum) + 1 utils - 路由参数 :subId → :planId (路径名 submission 保留产品文案) - 新增 migration_submission_to_projectPlan_2026_08_18.sql
This commit is contained in:
@@ -3,18 +3,29 @@
|
||||
<div class="breadcrumb">首页 / 我的项目设计投稿</div>
|
||||
|
||||
<el-form inline :model="q" class="filter-form">
|
||||
<el-form-item label="投稿名称"><el-input v-model="q.title" placeholder="输入投稿名称" clearable style="width: 200px" /></el-form-item>
|
||||
<el-form-item label="学科方向"><el-input v-model="q.direction" placeholder="输入学科方向" clearable style="width: 160px" /></el-form-item>
|
||||
<el-form-item label="策划方案名称"><el-input v-model="q.planName" placeholder="输入策划方案名称" clearable style="width: 200px" /></el-form-item>
|
||||
<el-form-item label="项目方向">
|
||||
<el-select v-model="q.planDirectionId" placeholder="请选择" clearable style="width: 200px">
|
||||
<el-option v-for="opt in planDirectionOptions" :key="opt.id" :label="opt.title" :value="opt.id" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="项目类别">
|
||||
<dict-select v-model="q.planCategory" dict-type="biz_project_category" value-field="label" style="width: 160px" />
|
||||
</el-form-item>
|
||||
<el-form-item label="形式">
|
||||
<el-select v-model="q.projectForm" placeholder="请选择" clearable style="width: 160px">
|
||||
<el-select v-model="q.projectForm" placeholder="请选择" clearable style="width: 140px">
|
||||
<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-select v-model="q.status" placeholder="请选择" clearable style="width: 180px">
|
||||
<el-option v-for="opt in STATUS_OPTIONS" :key="opt.value" :label="opt.label" :value="opt.value" />
|
||||
<el-select v-model="q.status" placeholder="请选择" clearable style="width: 140px">
|
||||
<el-option label="待提交" value="0" />
|
||||
<el-option label="待审核" value="1" />
|
||||
<el-option label="通过" value="2" />
|
||||
<el-option label="拒绝" value="3" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="备注"><el-input v-model="q.remark" placeholder="输入备注" clearable style="width: 200px" /></el-form-item>
|
||||
@@ -28,8 +39,11 @@
|
||||
|
||||
<el-table :data="rows" v-loading="loading" stripe border @selection-change="onSelectionChange">
|
||||
<el-table-column type="selection" width="48" />
|
||||
<el-table-column prop="title" label="投稿名称" min-width="220" show-overflow-tooltip />
|
||||
<el-table-column prop="direction" label="学科方向" width="120" />
|
||||
<el-table-column prop="planName" label="投稿名称" min-width="220" show-overflow-tooltip />
|
||||
<el-table-column label="项目方向" min-width="220" show-overflow-tooltip>
|
||||
<template #default="{ row }">{{ row.planDirectionTitle || row.planDirection || '-' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="planCategory" label="项目类别" width="120" />
|
||||
<el-table-column prop="projectForm" label="形式" width="100" />
|
||||
<el-table-column label="设计文件" width="100">
|
||||
<template #default="{ row }">
|
||||
@@ -37,11 +51,9 @@
|
||||
<span v-else>-</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="状态" width="100">
|
||||
<el-table-column label="状态" width="100" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-tag v-if="row.status !== null && row.status !== undefined && row.status !== ''" :type="statusType(row.status)" disable-transitions>
|
||||
{{ statusLabel(row.status) }}
|
||||
</el-tag>
|
||||
<audit-status-tag :status="row.status" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="remark" label="备注" min-width="180" show-overflow-tooltip />
|
||||
@@ -70,24 +82,42 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { reactive, ref } from 'vue'
|
||||
import { reactive, ref, onMounted } from 'vue'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import { useRouter } from 'vue-router'
|
||||
import request from '@/utils/request'
|
||||
import { bizList, bizUpdate } from '@/api/public'
|
||||
import { STATUS_OPTIONS, statusLabel, statusType, isLocked } from '@/utils/submissionStatus'
|
||||
import DictSelect from '@/components/DictSelect.vue'
|
||||
import AuditStatusTag from '@/components/AuditStatusTag.vue'
|
||||
|
||||
const router = useRouter()
|
||||
|
||||
const q = reactive({ title: '', direction: '', projectForm: '', status: '', remark: '' })
|
||||
const q = reactive({
|
||||
planName: '',
|
||||
planDirectionId: '',
|
||||
planCategory: '',
|
||||
projectForm: '',
|
||||
status: '',
|
||||
remark: ''
|
||||
})
|
||||
const page = reactive({ pageNum: 1, pageSize: 10, total: 0 })
|
||||
const rows = ref([])
|
||||
const loading = ref(false)
|
||||
const selected = ref([])
|
||||
|
||||
// 项目方向 options (复用 manager 侧接口)
|
||||
const planDirectionOptions = ref([])
|
||||
async function loadPlanDirectionOptions() {
|
||||
try {
|
||||
const { data } = await request.get('/business/specialPlan/options')
|
||||
planDirectionOptions.value = (data && data.data) || data || []
|
||||
} catch { planDirectionOptions.value = [] }
|
||||
}
|
||||
|
||||
async function load() {
|
||||
loading.value = true
|
||||
try {
|
||||
const { data } = await bizList('submission', { ...q, pageNum: page.pageNum, pageSize: page.pageSize })
|
||||
const { data } = await bizList('projectPlan', { ...q, pageNum: page.pageNum, pageSize: page.pageSize })
|
||||
rows.value = data?.rows || []
|
||||
page.total = data?.total || 0
|
||||
} catch (e) { rows.value = []; page.total = 0 }
|
||||
@@ -95,8 +125,9 @@ async function load() {
|
||||
}
|
||||
|
||||
function reset() {
|
||||
q.title = ''
|
||||
q.direction = ''
|
||||
q.planName = ''
|
||||
q.planDirectionId = ''
|
||||
q.planCategory = ''
|
||||
q.projectForm = ''
|
||||
q.status = ''
|
||||
q.remark = ''
|
||||
@@ -104,14 +135,13 @@ function reset() {
|
||||
load()
|
||||
}
|
||||
|
||||
// 原型规则: "待审核和审核通过后, 操作只显示查看按钮, 无法进行修改"
|
||||
// 字典驱动: 通过 isLocked() 判断, true 表示锁定(待审核 0 / 审核通过 1)
|
||||
// 锁定的状态 (待审核 '1' / 通过 '2') 不可修改/提交; 未提交 '0' / 拒绝 '3' 可操作
|
||||
function canModify(row) {
|
||||
return !isLocked(row.status)
|
||||
return row.status !== '1' && row.status !== '2'
|
||||
}
|
||||
function canSubmit(row) {
|
||||
// 锁定的不能再次提交; 其他状态(未结题/已结题/已退回/待提交)均可提交进入待审核
|
||||
return !isLocked(row.status)
|
||||
// 已通过 '2' 无需再提交; 待审核 '1' 也不允许重复提交; 只有未提交 '0' / 拒绝 '3' 可提交
|
||||
return row.status === '0' || row.status === '3'
|
||||
}
|
||||
|
||||
function onSelectionChange(arr) { selected.value = arr }
|
||||
@@ -120,10 +150,10 @@ function onCreate() {
|
||||
router.push({ path: '/doctor/submission/new' })
|
||||
}
|
||||
function onView(row) {
|
||||
router.push({ path: `/doctor/submission/detail/${row.subId}` })
|
||||
router.push({ path: `/doctor/submission/detail/${row.planId}` })
|
||||
}
|
||||
function onEdit(row) {
|
||||
router.push({ path: `/doctor/submission/edit/${row.subId}` })
|
||||
router.push({ path: `/doctor/submission/edit/${row.planId}` })
|
||||
}
|
||||
function onDownload(row) {
|
||||
if (!row.designFileUrl) { ElMessage.warning('该投稿暂无设计文件'); return }
|
||||
@@ -131,13 +161,12 @@ function onDownload(row) {
|
||||
}
|
||||
|
||||
async function onSubmit(row) {
|
||||
if (row.status === 'APPROVED') { ElMessage.info('该投稿已审核通过,无需重复提交'); return }
|
||||
try {
|
||||
await ElMessageBox.confirm(`确定要提交投稿「${row.title}」吗?提交后将进入审核流程`, '提交确认', { type: 'warning' })
|
||||
await ElMessageBox.confirm(`确定要提交投稿「${row.planName}」吗?提交后将进入审核流程`, '提交确认', { type: 'warning' })
|
||||
} catch { return }
|
||||
try {
|
||||
// 提交后状态变为 PENDING(待审核)
|
||||
await bizUpdate('submission', { subId: row.subId, status: 'PENDING' })
|
||||
// 提交后状态变为 '1' (待审核)
|
||||
await bizUpdate('projectPlan', { planId: row.planId, status: '1' })
|
||||
ElMessage.success('已提交,等待审核')
|
||||
load()
|
||||
} catch (e) { ElMessage.error(e?.msg || '提交失败') }
|
||||
@@ -146,19 +175,21 @@ async function onSubmit(row) {
|
||||
async function onBatch() {
|
||||
if (!selected.value.length) { ElMessage.warning('请先勾选要提交的投稿'); return }
|
||||
try {
|
||||
await ElMessageBox.confirm(`确定要批量提交选中的 ${selected.value.length} 条投稿吗?`, '批量提交', { type: 'warning' })
|
||||
await ElMessageBox.confirm(`确定要批量提交选中的 ${selected.value.length} 条投稿吗?`, '批量提交', { type: 'warning' })
|
||||
} catch { return }
|
||||
let ok = 0
|
||||
for (const r of selected.value) {
|
||||
// 锁定状态 (PENDING 待审核 / APPROVED 审核通过) 跳过提交
|
||||
if (isLocked(r.status)) continue
|
||||
try { await bizUpdate('submission', { subId: r.subId, status: 'PENDING' }); ok++ } catch {}
|
||||
if (!canSubmit(r)) continue
|
||||
try { await bizUpdate('projectPlan', { planId: r.planId, status: '1' }); ok++ } catch {}
|
||||
}
|
||||
ElMessage.success(`已提交 ${ok} 条`)
|
||||
load()
|
||||
}
|
||||
|
||||
load()
|
||||
onMounted(() => {
|
||||
loadPlanDirectionOptions()
|
||||
load()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
Reference in New Issue
Block a user