From 36b34d66950458cebb5caaaa0b30bba36a74d64a Mon Sep 17 00:00:00 2001 From: Codewoc <947380458@qq.com> Date: Wed, 25 Mar 2026 17:07:15 +0800 Subject: [PATCH] =?UTF-8?q?feat(review-frontend):=20=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E4=BC=9A=E8=AE=AE=E8=AF=84=E5=AE=A1=E9=A1=B5=E9=9D=A2=E4=BA=A4?= =?UTF-8?q?=E4=BA=92?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/review/meeting.ts | 29 ++++ src/api/review/project.ts | 13 +- src/views/review/meeting/AllProjectList.vue | 33 ++-- src/views/review/meeting/MeetingEdit.vue | 172 +++++++++++++++++++- src/views/review/meeting/ProjectDetail.vue | 13 +- src/views/review/meeting/ProjectList.vue | 135 +++++++++++++-- src/views/review/meeting/index.vue | 49 +++++- 7 files changed, 401 insertions(+), 43 deletions(-) diff --git a/src/api/review/meeting.ts b/src/api/review/meeting.ts index 227a67198..2bbc3bc18 100644 --- a/src/api/review/meeting.ts +++ b/src/api/review/meeting.ts @@ -19,16 +19,22 @@ export interface ReviewProjectItemVO { export interface ReviewMeetingSaveReqVO { id?: number name: string + organizationUnit?: string startTime?: string | number endTime?: string | number materialViewStartTime?: string | number materialViewEndTime?: string | number materialViewRemark?: string location: string + host?: string agendaAttachmentName?: string agendaAttachmentUrl?: string agendaAttachmentType?: string agendaAttachmentSize?: number + minutesAttachmentName?: string + minutesAttachmentUrl?: string + minutesAttachmentType?: string + minutesAttachmentSize?: number expertIds: number[] projects?: ReviewProjectItemVO[] } @@ -46,16 +52,22 @@ export interface ReviewMeetingPageReqVO { export interface ReviewMeetingRespVO { id: number name: string + organizationUnit?: string startTime: string endTime: string materialViewStartTime?: string materialViewEndTime?: string materialViewRemark?: string location: string + host?: string agendaAttachmentName?: string agendaAttachmentUrl?: string agendaAttachmentType?: string agendaAttachmentSize?: number + minutesAttachmentName?: string + minutesAttachmentUrl?: string + minutesAttachmentType?: string + minutesAttachmentSize?: number status: number // 0-草稿 1-已邀约 2-已结束 3-已取消 expertIds: number[] expertCount: number @@ -115,6 +127,10 @@ export const cancelReviewMeeting = (id: number) => export const finishReviewMeeting = (id: number) => request.put({ url: '/project/review-meeting/finish', params: { id } }) +/** 复制会议(仅已结束/已取消) */ +export const copyReviewMeeting = (id: number) => + request.post({ url: '/project/review-meeting/copy', params: { id } }) + /** 获取会议详情 */ export const getReviewMeeting = (id: number) => request.get({ url: '/project/review-meeting/get', params: { id } }) @@ -160,6 +176,19 @@ export const uploadAgendaAttachment = (file: File): Promise res?.data as ReviewMeetingAgendaAttachmentRespVO) } +/** 上传会议纪要附件(Word/PDF/图片) */ +export const uploadMinutesAttachment = ( + id: number, + file: File +): Promise => { + const formData = new FormData() + formData.append('id', String(id)) + formData.append('file', file) + return request + .upload({ url: '/project/review-meeting/upload-minutes-attachment', data: formData }) + .then((res) => res?.data as ReviewMeetingAgendaAttachmentRespVO) +} + /** 下载导入模板 */ export const getImportTemplate = () => request.download({ url: '/project/review-meeting/get-import-template' }) diff --git a/src/api/review/project.ts b/src/api/review/project.ts index 10daaeeef..1f906e3c3 100644 --- a/src/api/review/project.ts +++ b/src/api/review/project.ts @@ -16,7 +16,14 @@ export interface ReviewMeetingProjectRespVO { projectTitle: string reporter: string reporterUnit: string - host: string + host?: string + reviewDate?: string + reviewResult?: 'PASS' | 'REJECT' +} + +export interface ReviewMeetingProjectSeqUpdateReqVO { + id: number + seqNo: number } export interface ReviewMeetingProjectPageReqVO { @@ -79,6 +86,10 @@ export const createReviewProject = (data: Partial) = export const updateReviewProject = (data: Partial) => 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(',') } }) diff --git a/src/views/review/meeting/AllProjectList.vue b/src/views/review/meeting/AllProjectList.vue index bf93c31b7..f1edf5103 100644 --- a/src/views/review/meeting/AllProjectList.vue +++ b/src/views/review/meeting/AllProjectList.vue @@ -72,14 +72,10 @@ - + + @@ -121,8 +117,14 @@ - - + + + + + + + + @@ -90,6 +92,14 @@ + + @@ -103,6 +113,7 @@ import { finishReviewMeeting, sendSmsInvitation, sendMailInvitation, + uploadMinutesAttachment, type ReviewMeetingRespVO, type ReviewMeetingPageReqVO } from '@/api/review/meeting' @@ -133,9 +144,10 @@ const queryParams = reactive() +const pendingMinutesMeeting = ref() const getList = async () => { loading.value = true @@ -182,6 +194,41 @@ const handleFinish = async (row: ReviewMeetingRespVO) => { getList() } +const handleCopy = async (row: ReviewMeetingRespVO) => { + router.push({ + name: 'ReviewMeetingEdit', + query: { copyFromId: String(row.id) } + }) +} + +const triggerUploadMinutes = (row: ReviewMeetingRespVO) => { + pendingMinutesMeeting.value = row + minutesUploadInputRef.value?.click() +} + +const handleMinutesFileChange = async (event: Event) => { + const input = event.target as HTMLInputElement + const file = input.files?.[0] + if (!file || !pendingMinutesMeeting.value) { + return + } + const ext = file.name.includes('.') ? file.name.substring(file.name.lastIndexOf('.') + 1).toLowerCase() : '' + const allowed = ['doc', 'docx', 'pdf', 'png', 'jpg', 'jpeg', 'gif', 'bmp', 'webp'] + if (!allowed.includes(ext)) { + ElMessage.error('会议纪要仅支持 Word、PDF 或图片') + input.value = '' + return + } + try { + await uploadMinutesAttachment(pendingMinutesMeeting.value.id, file) + ElMessage.success('会议纪要上传成功') + getList() + } finally { + input.value = '' + pendingMinutesMeeting.value = undefined + } +} + const handleSendSms = async (row: ReviewMeetingRespVO) => { await ElMessageBox.confirm( `确认向 ${row.expertCount} 位专家发送「${row.name}」会议邀约短信?`,