admin-vue3/src/api/review/project.ts

264 lines
7.7 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

import request from '@/config/axios'
import axios from 'axios'
import * as FileApi from '@/api/infra/file'
// ============================================================
// 类型定义
// ============================================================
export interface ReviewMeetingProjectRespVO {
id: number
reviewMeetingId: number
seqNo: number
startTime: string
endTime: string
agendaCategory: string
projectTitle: string
reporter: string
reporterUnit: string
host?: string
reviewDate?: string
reviewResult?: 'PASS' | 'REJECT'
preMeetingMaterialsComplete?: boolean
postMeetingMaterialsComplete?: boolean
aiSummaryStatus?: number
aiSummaryUpdatedTime?: string
}
export const REVIEW_AGENDA_CATEGORY_OPTIONS = ['项目立项', '预验收', '项目终验'] as const
export type ReviewAgendaCategory = (typeof REVIEW_AGENDA_CATEGORY_OPTIONS)[number]
export interface ReviewMeetingProjectSeqUpdateReqVO {
id: number
seqNo: number
}
export interface ReviewMeetingProjectPageReqVO {
pageNo?: number
pageSize?: number
reviewMeetingId: number
projectTitle?: string
agendaCategory?: string
reporter?: string
reviewResult?: 'PASS' | 'REJECT'
reviewDate?: string
}
/** 独立项目列表查询meetingId 可选,用于独立菜单页) */
export interface ReviewProjectPageReqVO {
pageNo?: number
pageSize?: number
reviewMeetingId?: number
projectTitle?: string
agendaCategory?: string
reporter?: string
reporterUnit?: string
reviewResult?: 'PASS' | 'REJECT'
reviewDate?: string
}
export interface ReviewMeetingFileRespVO {
id: number
reviewMeetingId: number
reviewMeetingProjectId: number
materialCode?: string
materialNameSnapshot?: string
agendaTypeSnapshot?: string
version?: number
fileName: string
fileUrl: string
fileSize: number
fileType: string
aiBuildStatus?: number
aiBuildStatusName?: string
aiBuildErrorMessage?: string
aiBuildTime?: string
creator: string
createTime: string
}
export interface ReviewMeetingFileRegisterReqVO {
reviewMeetingId: number
reviewMeetingProjectId: number
fileName: string
fileUrl: string
fileSize: number
fileType?: string
}
export interface ReviewMeetingMaterialItemRespVO {
materialCode: string
materialName: string
required: boolean
acceptExts: string
tabletVisible: boolean
latestFile?: ReviewMeetingFileRespVO
}
export interface ReviewMeetingMaterialSummaryRespVO {
agendaType: string
templateAvailable: boolean
materials: ReviewMeetingMaterialItemRespVO[]
}
export interface ReviewMeetingMaterialHistoryRespVO {
materialCode: string
materialName: string
file: ReviewMeetingFileRespVO
}
export interface ReviewMeetingMaterialUploadReqVO {
reviewMeetingId: number
reviewMeetingProjectId: number
materialCode: string
fileName: string
fileUrl: string
fileSize: number
fileType?: string
}
// ============================================================
// API 调用
// ============================================================
/** 分页查询评审项目列表(需要 meetingId */
export const getReviewProjectPage = (params: ReviewMeetingProjectPageReqVO) =>
request.get({ url: '/project/review-project/page', params })
/** 独立分页查询评审项目列表meetingId 可选) */
export const getReviewProjectPageStandalone = (params: ReviewProjectPageReqVO) =>
request.get({ url: '/project/review-project/page', params })
/** 创建评审项目 */
export const createReviewProject = (data: Partial<ReviewMeetingProjectRespVO>) =>
request.post({ url: '/project/review-project/create', data })
/** 更新评审项目信息 */
export const updateReviewProject = (data: Partial<ReviewMeetingProjectRespVO>) =>
request.put({ url: '/project/review-project/update', data })
/** 批量更新会中序号 */
export const updateReviewProjectSeqBatch = (data: ReviewMeetingProjectSeqUpdateReqVO[]) =>
request.put({ url: '/project/review-project/update-seq-batch', data })
/** 删除评审项目 */
export const deleteReviewProject = (ids: number[]) =>
request.delete({ url: '/project/review-project/delete', params: { ids: ids.join(',') } })
/** 更新评审项目主持人 */
export const updateProjectHost = (projectId: number, host: string) =>
request.put({ url: '/project/review-project/update-host', params: { projectId, host } })
/** 上传会议文件 */
export const uploadMeetingFile = (
reviewMeetingId: number,
reviewMeetingProjectId: number,
file: File
) => {
return uploadMeetingFileByPresignedUrl(reviewMeetingId, reviewMeetingProjectId, file)
}
/** 登记会议文件 */
export const registerMeetingFile = (data: ReviewMeetingFileRegisterReqVO) =>
request.post<ReviewMeetingFileRespVO>({ url: '/project/review-project/register-file', data })
/** 获取项目文件列表 */
export const getMeetingFileList = (reviewMeetingProjectId: number) =>
request.get({
url: '/project/review-project/file-list',
params: { reviewMeetingProjectId }
})
/** 删除会议文件 */
export const deleteMeetingFile = (id: number) =>
request.delete({ url: '/project/review-project/delete-file', params: { id } })
/** 获取结构化材料汇总 */
export const getProjectMaterialSummary = (reviewMeetingProjectId: number) =>
request.get<ReviewMeetingMaterialSummaryRespVO>({
url: '/project/review-project/material-summary',
params: { reviewMeetingProjectId }
})
/** 获取材料历史版本 */
export const getProjectMaterialHistory = (reviewMeetingProjectId: number, materialCode: string) =>
request.get<ReviewMeetingMaterialHistoryRespVO[]>({
url: '/project/review-project/material-history',
params: { reviewMeetingProjectId, materialCode }
})
/** 下载当前议程分类模板包 */
export const downloadProjectTemplateBundle = (agendaType: string) =>
request.download({
url: '/project/review-project/download-template-bundle',
params: { agendaType }
})
/** 上传结构化材料(预签名直传) */
export const uploadProjectMaterial = async (
reviewMeetingId: number,
reviewMeetingProjectId: number,
materialCode: string,
file: File
) => {
const presignedInfo = await FileApi.getFilePresignedUrl(file.name, 'review-meeting')
await axios.put(presignedInfo.uploadUrl, file, {
headers: {
'Content-Type': file.type || 'application/octet-stream'
}
})
await FileApi.createFile({
configId: presignedInfo.configId,
url: presignedInfo.url,
path: presignedInfo.path,
name: file.name,
type: file.type || 'application/octet-stream',
size: file.size
})
return request.post<ReviewMeetingFileRespVO>({
url: '/project/review-project/upload-material',
data: {
reviewMeetingId,
reviewMeetingProjectId,
materialCode,
fileName: file.name,
fileUrl: presignedInfo.url,
fileSize: file.size,
fileType: file.name.includes('.') ? file.name.split('.').pop()?.toLowerCase() : ''
} satisfies ReviewMeetingMaterialUploadReqVO
})
}
const uploadMeetingFileByPresignedUrl = async (
reviewMeetingId: number,
reviewMeetingProjectId: number,
file: File
) => {
const presignedInfo = await FileApi.getFilePresignedUrl(file.name, 'review-meeting')
await axios.put(presignedInfo.uploadUrl, file, {
headers: {
'Content-Type': file.type || 'application/octet-stream'
}
})
await FileApi.createFile({
configId: presignedInfo.configId,
url: presignedInfo.url,
path: presignedInfo.path,
name: file.name,
type: file.type || 'application/octet-stream',
size: file.size
})
return registerMeetingFile({
reviewMeetingId,
reviewMeetingProjectId,
fileName: file.name,
fileUrl: presignedInfo.url,
fileSize: file.size,
fileType: file.name.includes('.') ? file.name.split('.').pop()?.toLowerCase() : ''
})
}