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:
@@ -0,0 +1,72 @@
|
||||
// OSS 直传工具 - 配合后端 /common/oss/sign
|
||||
// 流程: 1) GET /common/oss/sign?dir=xxx 拿签名
|
||||
// 2) POST 到 OSS bucket, formData 携带 policy/signature/key/accessKeyId
|
||||
// 3) 拿回 OSS URL 写回表单
|
||||
import request from '@/utils/request'
|
||||
|
||||
/**
|
||||
* 获取 OSS 上传签名
|
||||
* @param {string} dir 上传目录 (如 'ry8080/invitation/')
|
||||
* @returns {Promise<{host, dir, accessKeyId, policy, signature, expire}>}
|
||||
*/
|
||||
export async function getOssSign(dir) {
|
||||
const res = await request({
|
||||
url: '/common/oss/sign',
|
||||
method: 'get',
|
||||
params: { dir }
|
||||
})
|
||||
if (res.code !== 200) {
|
||||
throw new Error(res.msg || 'OSS 签名失败')
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
/**
|
||||
* 直接上传 File 到 OSS bucket
|
||||
* @param {File} file 要上传的文件
|
||||
* @param {string} dir 上传目录
|
||||
* @returns {Promise<string>} 完整 URL (https://bucket.xxx/key)
|
||||
*/
|
||||
// 根据文件扩展名返回正确的 MIME,避免 OSS 默认给 application/octet-stream
|
||||
function getMimeByExt(name) {
|
||||
const ext = (name || '').split('.').pop().toLowerCase()
|
||||
const map = {
|
||||
pdf: 'application/pdf',
|
||||
doc: 'application/msword',
|
||||
docx: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
|
||||
png: 'image/png',
|
||||
jpg: 'image/jpeg',
|
||||
jpeg: 'image/jpeg',
|
||||
gif: 'image/gif',
|
||||
webp: 'image/webp'
|
||||
}
|
||||
return map[ext] || 'application/octet-stream'
|
||||
}
|
||||
|
||||
export async function uploadToOss(file, dir) {
|
||||
const sign = await getOssSign(dir)
|
||||
const ext = (file.name || '').split('.').pop() || 'bin'
|
||||
const key = sign.dir + Date.now() + '_' + Math.random().toString(36).slice(2, 8) + '.' + ext
|
||||
// 显式传 Content-Type,让 OSS 按此存文件元数据, 浏览器拿到 application/pdf 即可内嵌预览
|
||||
const mime = getMimeByExt(file.name)
|
||||
|
||||
const fd = new FormData()
|
||||
fd.append('key', key)
|
||||
fd.append('policy', sign.policy)
|
||||
fd.append('OSSAccessKeyId', sign.accessKeyId)
|
||||
fd.append('signature', sign.signature)
|
||||
fd.append('success_action_status', '200')
|
||||
fd.append('Content-Type', mime)
|
||||
fd.append('file', file)
|
||||
|
||||
// ⚠️ 不要手动设置 Content-Type header,会让 multipart/form-data boundary 丢失
|
||||
// FormData 会自动生成正确的 multipart 格式
|
||||
const resp = await fetch(sign.host, {
|
||||
method: 'POST',
|
||||
body: fd
|
||||
})
|
||||
if (!resp.ok) {
|
||||
throw new Error('OSS 上传失败: HTTP ' + resp.status)
|
||||
}
|
||||
return sign.host + '/' + key
|
||||
}
|
||||
Reference in New Issue
Block a user