refactor: 合并 biz_support_unit/biz_execution_unit/biz_service_org 为 biz_org, 删除 2 张孤儿表, 改 biz_person.work_unit → org_id FK

主要改动:
- SQL: biz_support_unit → biz_org, 加 org_type, 加 business_nature; 删 biz_execution_unit, biz_service_org
- SQL: biz_project.support_unit_id/name + service_org_id/name → org_id/name/type
- SQL: biz_meeting.support_unit_name → org_name
- SQL: biz_person.work_unit → org_id (FK)
- 后端: 新 BizOrg entity/mapper/service/controller
- 后端: BizProject/BizMeeting 字段重命名
- 后端: 删 12 个 BizSupportUnit/BizExecutionUnit/BizServiceOrg Java 文件
- 后端: BizPersonImportVO.workUnit → orgName (导入时查 biz_org 取 org_id)
- 后端: BizAuthController.registerExecutor 完整实现 (原 registerSupplier stub)
- 前端: 新 admin/Orgs.vue + manager/Orgs.vue (原 SupportUnits)
- 前端: RegisterExecutor.vue (原 RegisterSupplier, 单页 2 步)
- 前端: sponsor/executor/manager 多个文件 workUnit → orgId/orgName 重命名
- 前端: 统一 supplier → executor, 业务命名 sponsor(赞助方) / executor(执行方=供应商)
- 前端: 全工程 execution → executor (company type / role / person unit_type)
This commit is contained in:
郭庆泰
2026-08-15 12:41:10 +08:00
commit cf5790229a
694 changed files with 102090 additions and 0 deletions
+177
View File
@@ -0,0 +1,177 @@
<template>
<div class="page-card">
<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-select v-model="q.projectForm" placeholder="请选择" clearable style="width: 160px">
<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>
</el-form-item>
<el-form-item label="备注"><el-input v-model="q.remark" placeholder="输入备注" clearable style="width: 200px" /></el-form-item>
<el-form-item><el-button type="primary" @click="load">查找</el-button><el-button @click="reset">重置</el-button></el-form-item>
</el-form>
<div class="toolbar">
<el-button type="primary" @click="onCreate">新建投稿</el-button>
<el-button @click="onBatch" :disabled="!selected.length">批量提交</el-button>
</div>
<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="projectForm" label="形式" width="100" />
<el-table-column label="设计文件" width="100">
<template #default="{ row }">
<el-link v-if="row.designFileUrl" type="primary" :href="row.designFileUrl" target="_blank">下载</el-link>
<span v-else>-</span>
</template>
</el-table-column>
<el-table-column label="状态" width="100">
<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>
</template>
</el-table-column>
<el-table-column prop="remark" label="备注" min-width="180" show-overflow-tooltip />
<el-table-column label="操作" width="220" fixed="right">
<template #default="{ row }">
<el-button link type="primary" @click="onView(row)">查看</el-button>
<el-button v-if="canModify(row)" link type="primary" @click="onEdit(row)">修改</el-button>
<el-button v-if="canSubmit(row)" link type="primary" @click="onSubmit(row)">提交</el-button>
<el-button link type="primary" :disabled="!row.designFileUrl" @click="onDownload(row)">下载</el-button>
</template>
</el-table-column>
</el-table>
<el-pagination
v-model:current-page="page.pageNum"
v-model:page-size="page.pageSize"
:total="page.total"
:page-sizes="[10, 20, 50]"
layout="total, sizes, prev, pager, next, jumper"
@current-change="load"
@size-change="load"
style="margin-top: 12px; text-align: right;"
/>
</div>
</template>
<script setup>
import { reactive, ref } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import { useRouter } from 'vue-router'
import { bizList, bizUpdate } from '@/api/public'
import { STATUS_OPTIONS, statusLabel, statusType, isLocked } from '@/utils/submissionStatus'
const router = useRouter()
const q = reactive({ title: '', direction: '', projectForm: '', status: '', remark: '' })
const page = reactive({ pageNum: 1, pageSize: 10, total: 0 })
const rows = ref([])
const loading = ref(false)
const selected = ref([])
async function load() {
loading.value = true
try {
const { data } = await bizList('submission', { ...q, pageNum: page.pageNum, pageSize: page.pageSize })
rows.value = data?.rows || []
page.total = data?.total || 0
} catch (e) { rows.value = []; page.total = 0 }
finally { loading.value = false }
}
function reset() {
q.title = ''
q.direction = ''
q.projectForm = ''
q.status = ''
q.remark = ''
page.pageNum = 1
load()
}
// 原型规则: "待审核和审核通过后, 操作只显示查看按钮, 无法进行修改"
// 字典驱动: 通过 isLocked() 判断, true 表示锁定(待审核 0 / 审核通过 1)
function canModify(row) {
return !isLocked(row.status)
}
function canSubmit(row) {
// 锁定的不能再次提交; 其他状态(未结题/已结题/已退回/待提交)均可提交进入待审核
return !isLocked(row.status)
}
function onSelectionChange(arr) { selected.value = arr }
function onCreate() {
router.push({ path: '/doctor/submission/new' })
}
function onView(row) {
router.push({ path: `/doctor/submission/detail/${row.subId}` })
}
function onEdit(row) {
router.push({ path: `/doctor/submission/edit/${row.subId}` })
}
function onDownload(row) {
if (!row.designFileUrl) { ElMessage.warning('该投稿暂无设计文件'); return }
window.open(row.designFileUrl, '_blank')
}
async function onSubmit(row) {
if (row.status === 'APPROVED') { ElMessage.info('该投稿已审核通过,无需重复提交'); return }
try {
await ElMessageBox.confirm(`确定要提交投稿「${row.title}」吗?提交后将进入审核流程`, '提交确认', { type: 'warning' })
} catch { return }
try {
// 提交后状态变为 PENDING(待审核)
await bizUpdate('submission', { subId: row.subId, status: 'PENDING' })
ElMessage.success('已提交,等待审核')
load()
} catch (e) { ElMessage.error(e?.msg || '提交失败') }
}
async function onBatch() {
if (!selected.value.length) { ElMessage.warning('请先勾选要提交的投稿'); return }
try {
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 {}
}
ElMessage.success(`已提交 ${ok}`)
load()
}
load()
</script>
<style scoped>
.page-card { background: #fff; padding: 16px 20px; border-radius: 6px; border: 1px solid #f0f0f0; }
.breadcrumb { font-size: 13px; color: #8c8c8c; margin-bottom: 12px; }
.filter-form { display: flex; flex-wrap: wrap; gap: 0 16px; padding-bottom: 12px; border-bottom: 1px solid #f0f0f0; margin-bottom: 12px; }
.toolbar { display: flex; align-items: center; gap: 8px; margin-bottom: 12px; }
.status { font-size: 13px; color: #595959; }
:deep(.el-button--primary) { background: var(--brand-primary); border-color: var(--brand-primary); border-radius: 4px; }
:deep(.el-button--primary:hover) { background: var(--brand-primary-deep, var(--brand-primary)); border-color: var(--brand-primary-deep, var(--brand-primary)); }
:deep(.el-table .el-button) { border-radius: 4px; }
:deep(.el-table .el-button.is-link) { color: var(--brand-primary); background: transparent; border: none; }
:deep(.el-table .el-button.is-link:hover) { color: var(--brand-primary-deep, var(--brand-primary)); background: transparent; }
:deep(.el-table .el-button.is-link.is-disabled) { color: #c0c4cc; background: transparent; }
</style>