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
+197
View File
@@ -0,0 +1,197 @@
<template>
<div class="executor-meetings">
<div class="breadcrumb">首页 / 会议列表</div>
<div class="filter-card">
<el-form :inline="true" :model="q" size="default">
<el-form-item label="项目编号:">
<el-input v-model="q.projectNo" clearable placeholder="输入项目编号" style="width:160px" />
</el-form-item>
<el-form-item label="会议名称:">
<el-input v-model="q.meetingName" clearable placeholder="输入会议名称" style="width:200px" />
</el-form-item>
<el-form-item label="是否系列会:">
<el-select v-model="q.isSeries" clearable placeholder="请选择" style="width:140px">
<el-option label="是" value="1" />
<el-option label="否" value="0" />
</el-select>
</el-form-item>
<el-form-item label="是否结题:">
<el-select v-model="q.isFinished" clearable placeholder="请选择" style="width:140px">
<el-option label="已结题" value="1" />
<el-option label="未结题" value="0" />
</el-select>
</el-form-item>
<el-form-item label="期数:">
<el-input v-model="q.sessionNo" clearable placeholder="输入期数" style="width:100px" />
</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>
<div class="page-card">
<div class="toolbar">
<span class="hint">已选 {{ selected.length }} </span>
</div>
<el-table :data="rows" v-loading="loading" stripe border @selection-change="onSelect">
<el-table-column type="selection" width="48" />
<el-table-column prop="projectNo" label="项目编号" width="120" />
<el-table-column prop="meetingName" label="会议名称" min-width="200" show-overflow-tooltip />
<el-table-column prop="isSeries" label="是否系列会" width="100" align="center">
<template #default="{ row }">
<el-tag :type="row.isSeries === '1' || row.isSeries === '是' ? 'success' : 'info'" size="small">
{{ row.isSeries === '1' || row.isSeries === '是' ? '是' : '否' }}
</el-tag>
</template>
</el-table-column>
<el-table-column prop="seriesTopic" label="系列会主题" min-width="160" show-overflow-tooltip />
<el-table-column label="期数/总期数" width="110" align="center">
<template #default="{ row }">{{ row.periodNo || 0 }}/{{ row.totalPeriods || 0 }}</template>
</el-table-column>
<el-table-column prop="currentStage" label="当前阶段" width="100" align="center">
<template #default="{ row }">
<el-tag :type="row.currentStage === '执行中' ? 'success' : 'info'" size="small">{{ row.currentStage || '-' }}</el-tag>
</template>
</el-table-column>
<el-table-column prop="isFinished" label="是否结题" width="90" align="center">
<template #default="{ row }">
<el-tag :type="row.isFinished === '1' || row.isFinished === '已结题' ? 'warning' : 'info'" size="small">
{{ row.isFinished === '1' || row.isFinished === '已结题' ? '已结题' : '未结题' }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="操作" width="220" fixed="right">
<template #default="{ row }">
<el-button link type="primary" @click="onView(row)">查看</el-button>
<el-button link type="warning" @click="onSupervision(row)">查看监督意见</el-button>
</template>
</el-table-column>
</el-table>
<div class="pager">
<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" />
</div>
</div>
<!-- 监督意见 弹窗 -->
<el-dialog v-model="supOpen" title="监督意见" width="560px">
<el-form label-width="100px">
<el-form-item label="会议名称">
<span>{{ supRow.meetingName }}</span>
</el-form-item>
<el-form-item label="监督结论">
<el-radio-group v-model="supForm.rating">
<el-radio value="good">满意</el-radio>
<el-radio value="normal">一般</el-radio>
<el-radio value="bad">存在需整改的问题</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="监督意见">
<el-input v-model="supForm.opinion" type="textarea" :rows="4" maxlength="500" show-word-limit placeholder="请输入监督意见(0/500" />
</el-form-item>
</el-form>
<template #footer>
<el-button @click="supOpen=false">取消</el-button>
<el-button type="primary" @click="onSaveSup">确定</el-button>
</template>
</el-dialog>
<el-dialog v-model="viewOpen" title="会议详情" width="640px">
<el-descriptions :column="2" border>
<el-descriptions-item label="项目编号">{{ view.projectNo }}</el-descriptions-item>
<el-descriptions-item label="会议ID">{{ view.meetingId }}</el-descriptions-item>
<el-descriptions-item label="会议名称" :span="2">{{ view.meetingName }}</el-descriptions-item>
<el-descriptions-item label="项目形式">{{ view.projectForm }}</el-descriptions-item>
<el-descriptions-item label="当前阶段">{{ view.currentStage }}</el-descriptions-item>
<el-descriptions-item label="期数/总期数">{{ view.periodNo }}/{{ view.totalPeriods }}</el-descriptions-item>
<el-descriptions-item label="是否系列会">{{ view.isSeries }}</el-descriptions-item>
<el-descriptions-item label="开始时间" :span="2">{{ view.startTime || '-' }}</el-descriptions-item>
<el-descriptions-item label="结束时间" :span="2">{{ view.endTime || '-' }}</el-descriptions-item>
<el-descriptions-item label="监督意见" :span="2">{{ view.supervisionOpinion || '暂无' }}</el-descriptions-item>
</el-descriptions>
<template #footer><el-button @click="viewOpen=false">关闭</el-button></template>
</el-dialog>
</div>
</template>
<script setup>
import { ref, reactive, onMounted } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import { bizList, bizUpdate } from '@/api/public'
const q = ref({ projectNo: '', meetingName: '', isSeries: '', isFinished: '', sessionNo: '' })
const rows = ref([])
const loading = ref(false)
const page = reactive({ pageNum: 1, pageSize: 10, total: 0 })
const selected = ref([])
const supOpen = ref(false)
const supRow = ref({})
const supForm = reactive({ rating: 'good', opinion: '' })
const viewOpen = ref(false)
const view = ref({})
async function load() {
loading.value = true
try {
const { data } = await bizList('meeting', { ...q.value, pageNum: page.pageNum, pageSize: page.pageSize })
rows.value = data?.rows || []
page.total = data?.total || 0
} catch { rows.value = []; page.total = 0 }
finally { loading.value = false }
}
function reset() {
q.value = { projectNo: '', meetingName: '', isSeries: '', isFinished: '', sessionNo: '' }
page.pageNum = 1
load()
}
function onSelect(arr) { selected.value = arr }
function onView(row) { view.value = row; viewOpen.value = true }
function onSupervision(row) {
supRow.value = row
supForm.rating = 'good'
supForm.opinion = row.supervisionOpinion || ''
supOpen.value = true
}
async function onSaveSup() {
try {
await bizUpdate('meeting', {
meetingId: supRow.value.meetingId,
supervisionOpinion: supForm.opinion,
supervisionRating: supForm.rating
})
ElMessage.success('已保存监督意见')
supOpen.value = false
load()
} catch (e) {
ElMessage.error(e?.msg || '保存失败')
}
}
onMounted(load)
</script>
<style scoped>
.executor-meetings { padding: 0; }
.breadcrumb { color: #909399; font-size: 13px; margin-bottom: 12px; }
.filter-card, .page-card { background: #fff; border-radius: 4px; padding: 16px; border: 1px solid #ebeef5; margin-bottom: 12px; }
.toolbar { display: flex; align-items: center; gap: 12px; margin-bottom: 12px; }
.hint { font-size: 13px; color: #909399; }
.pager { display: flex; justify-content: flex-end; margin-top: 12px; }
: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); border-color: var(--brand-primary-deep); }
: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); background: transparent; }
:deep(.el-table .el-button.is-link.is-disabled) { color: #c0c4cc; background: transparent; }
</style>