主要改动: - 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)
280 lines
10 KiB
Vue
280 lines
10 KiB
Vue
<template>
|
||
<div class="submission-new">
|
||
<!-- 面包屑 -->
|
||
<div class="breadcrumb">
|
||
<a @click="goBack">我的项目设计投稿</a> > {{ isEdit ? '修改项目设计投稿' : '新建项目设计投稿' }}
|
||
</div>
|
||
|
||
<!-- 表单卡片 -->
|
||
<el-card v-loading="loadingDetail" shadow="never" class="form-card">
|
||
<el-form :model="form" :rules="rules" ref="formRef" label-width="120px">
|
||
<el-row :gutter="12">
|
||
<el-col :span="12">
|
||
<el-form-item label="策划方案名称" prop="title">
|
||
<el-input v-model="form.title" placeholder="请输入策划方案名称" maxlength="200" show-word-limit />
|
||
</el-form-item>
|
||
</el-col>
|
||
<el-col :span="12">
|
||
<el-form-item label="项目方向" prop="direction">
|
||
<el-select v-model="form.direction" placeholder="请选择" style="width:100%">
|
||
<el-option label="学术项目" value="学术项目" />
|
||
<el-option label="科研项目" value="科研项目" />
|
||
<el-option label="共识" value="共识" />
|
||
<el-option label="指南" value="指南" />
|
||
<el-option label="会议项目" value="会议项目" />
|
||
<el-option label="对外交流" value="对外交流" />
|
||
</el-select>
|
||
</el-form-item>
|
||
</el-col>
|
||
</el-row>
|
||
|
||
<el-row :gutter="12">
|
||
<el-col :span="12">
|
||
<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-col>
|
||
<el-col :span="12">
|
||
<el-form-item label="项目类别" prop="projectCategory">
|
||
<el-select v-model="form.projectCategory" placeholder="请选择" style="width:100%">
|
||
<el-option label="学术会议类" value="学术会议类" />
|
||
<el-option label="专项科研类" value="专项科研类" />
|
||
<el-option label="调研征集类" value="调研征集类" />
|
||
<el-option label="慈善帮扶类" value="慈善帮扶类" />
|
||
<el-option label="标准制定类" value="标准制定类" />
|
||
<el-option label="患者援助类" value="患者援助类" />
|
||
<el-option label="专业培训类" value="专业培训类" />
|
||
</el-select>
|
||
</el-form-item>
|
||
</el-col>
|
||
</el-row>
|
||
|
||
<el-row :gutter="12">
|
||
<el-col :span="24">
|
||
<el-form-item label="设计文件" prop="designFileUrl">
|
||
<el-upload
|
||
class="design-uploader"
|
||
drag
|
||
action="#"
|
||
accept=".pdf,.doc,.docx,.png,.jpg,.jpeg"
|
||
:show-file-list="true"
|
||
:file-list="designFileList"
|
||
:before-upload="beforeDesignUpload"
|
||
:http-request="uploadDesign"
|
||
:on-remove="onDesignRemove"
|
||
>
|
||
<i class="el-icon-upload"></i>
|
||
<div class="el-upload__text">将设计文件拖到此处,或<em>点击上传</em></div>
|
||
<div class="el-upload__tip" slot="tip">支持 PDF / Word / 图片, 单文件 ≤ 20MB</div>
|
||
</el-upload>
|
||
</el-form-item>
|
||
</el-col>
|
||
</el-row>
|
||
|
||
<el-row :gutter="12">
|
||
<el-col :span="24">
|
||
<el-form-item label="备注" prop="remark">
|
||
<el-input v-model="form.remark" type="textarea" :rows="4" placeholder="请输入备注 (0/500)" maxlength="500" show-word-limit />
|
||
</el-form-item>
|
||
</el-col>
|
||
</el-row>
|
||
</el-form>
|
||
</el-card>
|
||
|
||
<!-- 操作按钮 -->
|
||
<div class="form-actions">
|
||
<el-button type="primary" :loading="saving" @click="onSave">保存</el-button>
|
||
<el-button @click="confirmCancel">取消</el-button>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup>
|
||
import { reactive, ref, onMounted } from 'vue'
|
||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||
import { useRoute, useRouter } from 'vue-router'
|
||
import { useUserStore } from '@/store/user'
|
||
import request from '@/utils/request'
|
||
import { uploadToOss } from '@/utils/oss'
|
||
|
||
const router = useRouter()
|
||
const route = useRoute()
|
||
const userStore = useUserStore()
|
||
|
||
const formRef = ref(null)
|
||
const saving = ref(false)
|
||
const loadingDetail = ref(false)
|
||
const designFileList = ref([])
|
||
const designUploading = ref(false)
|
||
const isEdit = !!route.params.subId
|
||
|
||
const form = reactive({
|
||
subId: null,
|
||
title: '',
|
||
direction: '',
|
||
projectForm: '',
|
||
projectCategory: '',
|
||
designFileUrl: '',
|
||
status: 'DRAFT',
|
||
remark: ''
|
||
})
|
||
|
||
const rules = {
|
||
title: [{ required: true, message: '请输入策划方案名称', trigger: 'blur' }],
|
||
direction: [{ required: true, message: '请选择项目方向', trigger: 'change' }],
|
||
projectForm: [{ required: true, message: '请选择项目形式', trigger: 'change' }],
|
||
projectCategory: [{ required: true, message: '请选择项目类别', trigger: 'change' }],
|
||
designFileUrl: [{ required: true, message: '请上传设计文件', trigger: 'change' }]
|
||
}
|
||
|
||
function beforeDesignUpload(file) {
|
||
const max = 20 * 1024 * 1024
|
||
if (file.size > max) { ElMessage.error('设计文件不能超过 20MB'); return false }
|
||
const accept = ['.pdf', '.doc', '.docx', '.png', '.jpg', '.jpeg']
|
||
const ext = '.' + (file.name.split('.').pop() || '').toLowerCase()
|
||
if (!accept.includes(ext)) { ElMessage.error('仅支持 PDF / Word / 图片格式'); return false }
|
||
return true
|
||
}
|
||
|
||
async function uploadDesign(opts) {
|
||
const file = opts.file
|
||
designUploading.value = true
|
||
try {
|
||
const url = await uploadToOss(file, 'ry8080/submission/design/')
|
||
form.designFileUrl = url
|
||
designFileList.value = [{ name: file.name, url }]
|
||
ElMessage.success('设计文件上传成功')
|
||
} catch (e) {
|
||
ElMessage.error('上传失败: ' + (e?.message || e))
|
||
// 上传失败时清空 file-list,避免 el-upload 保留失败文件
|
||
designFileList.value = []
|
||
} finally {
|
||
designUploading.value = false
|
||
}
|
||
}
|
||
|
||
function onDesignRemove() {
|
||
form.designFileUrl = ''
|
||
designFileList.value = []
|
||
}
|
||
|
||
async function loadDetail() {
|
||
const subId = route.params.subId
|
||
if (!subId) return
|
||
loadingDetail.value = true
|
||
try {
|
||
const res = await request.get(`/business/submission/${subId}`)
|
||
if (res?.code === 200 && res.data) {
|
||
const d = res.data
|
||
form.subId = d.subId
|
||
form.title = d.title || ''
|
||
form.direction = d.direction || ''
|
||
form.projectForm = d.projectForm || ''
|
||
form.projectCategory = d.projectCategory || ''
|
||
form.designFileUrl = d.designFileUrl || ''
|
||
form.status = d.status && String(d.status).trim() ? String(d.status).trim().toUpperCase() : 'DRAFT'
|
||
form.remark = d.remark || ''
|
||
// 已上传的设计文件回显到 file-list
|
||
if (d.designFileUrl) {
|
||
const name = d.designFileUrl.split('/').pop() || `${d.title || '设计文件'}.pdf`
|
||
designFileList.value = [{ name, url: d.designFileUrl }]
|
||
}
|
||
} else {
|
||
ElMessage.error(res?.msg || '加载失败')
|
||
goBack()
|
||
}
|
||
} catch (e) {
|
||
console.error('[submission-new/edit] loadDetail failed', e)
|
||
ElMessage.error(e?.msg || '加载失败')
|
||
goBack()
|
||
} finally {
|
||
loadingDetail.value = false
|
||
}
|
||
}
|
||
|
||
function goBack() {
|
||
router.push({ path: '/doctor/submissions', query: { _t: Date.now() } })
|
||
}
|
||
|
||
function confirmCancel() {
|
||
// 检查表单是否有内容
|
||
const hasContent = form.title || form.direction || form.projectForm || form.projectCategory || form.designFileUrl || form.remark
|
||
if (!hasContent) { goBack(); return }
|
||
ElMessageBox.confirm('确定取消新建?未保存的内容将丢失', '提示', { type: 'warning' })
|
||
.then(() => goBack())
|
||
.catch(() => {})
|
||
}
|
||
|
||
async function onSave() {
|
||
try {
|
||
await formRef.value.validate()
|
||
} catch (e) {
|
||
ElMessage.warning('请填写必填项')
|
||
return
|
||
}
|
||
saving.value = true
|
||
try {
|
||
let payload = { ...form }
|
||
if (!isEdit) {
|
||
// 新建: 强制设为 DRAFT(待提交)
|
||
payload.status = 'DRAFT'
|
||
// 写入当前登录用户信息
|
||
payload.submitterId = userStore.user?.userId || null
|
||
payload.submitterName = userStore.user?.userName || userStore.user?.nickName || ''
|
||
} else if (!payload.status) {
|
||
// 修改: 如果状态丢失, 兜底 DRAFT(待提交)
|
||
payload.status = 'DRAFT'
|
||
}
|
||
let res
|
||
if (isEdit) {
|
||
// 修改: 走 PUT /business/submission
|
||
res = await request.put('/business/submission', payload)
|
||
} else {
|
||
// 新建: 走 POST /business/submission
|
||
res = await request.post('/business/submission', payload)
|
||
}
|
||
if (res?.code === 200) {
|
||
ElMessage.success(isEdit ? '修改成功' : '新建成功')
|
||
goBack()
|
||
} else {
|
||
ElMessage.error(res?.msg || (isEdit ? '修改失败' : '保存失败'))
|
||
}
|
||
} catch (e) {
|
||
console.error('[submission-new] save failed', e)
|
||
ElMessage.error(e?.msg || (isEdit ? '修改失败' : '保存失败'))
|
||
} finally {
|
||
saving.value = false
|
||
}
|
||
}
|
||
|
||
onMounted(() => {
|
||
if (isEdit) loadDetail()
|
||
})
|
||
</script>
|
||
|
||
<style scoped>
|
||
.submission-new { max-width: 1000px; }
|
||
.breadcrumb { font-size: 13px; color: #8c8c8c; margin-bottom: 16px; }
|
||
.breadcrumb a { color: var(--brand-primary); cursor: pointer; text-decoration: none; }
|
||
.breadcrumb a:hover { color: var(--brand-primary-deep, var(--brand-primary)); }
|
||
|
||
.form-card { border-radius: 6px; }
|
||
:deep(.form-card .el-card__body) { padding: 24px 28px; }
|
||
|
||
.form-actions { margin-top: 16px; display: flex; gap: 8px; }
|
||
|
||
: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-button) { border-radius: 4px; }
|
||
:deep(.el-input__wrapper), :deep(.el-textarea__inner) { border-radius: 4px; }
|
||
|
||
/* 设计文件上传控件: 占满表单行宽 */
|
||
.design-uploader { width: 100%; }
|
||
.design-uploader :deep(.el-upload) { width: 100%; }
|
||
.design-uploader :deep(.el-upload-dragger) { width: 100%; }
|
||
</style> |