diff --git a/fund-mobile/src/api/index.ts b/fund-mobile/src/api/index.ts index 5ffd08b..4dd61fe 100644 --- a/fund-mobile/src/api/index.ts +++ b/fund-mobile/src/api/index.ts @@ -23,6 +23,30 @@ export function updatePassword(data: { oldPassword: string; newPassword: string; return request.put('/sys/profile/password', data) } +// ===================== 文件管理 ===================== + +export function uploadFile(file: File, businessType?: string, businessId?: number, description?: string) { + const formData = new FormData() + formData.append('file', file) + if (businessType) formData.append('businessType', businessType) + if (businessId) formData.append('businessId', String(businessId)) + if (description) formData.append('description', description) + + return request.post('/file/upload', formData, { + headers: { + 'Content-Type': 'multipart/form-data' + } + }) +} + +export function getFileList(params?: { pageNum: number; pageSize: number; businessType?: string; businessId?: number; fileType?: string }) { + return request.get('/file/page', { params }) +} + +export function deleteFile(id: number) { + return request.delete(`/file/${id}`) +} + // ===================== 项目管理 ===================== export function getProjectList(params?: { pageNum: number; pageSize: number; keyword?: string }) { diff --git a/fund-mobile/src/views/expense/Add.vue b/fund-mobile/src/views/expense/Add.vue index 3ae272e..867964e 100644 --- a/fund-mobile/src/views/expense/Add.vue +++ b/fund-mobile/src/views/expense/Add.vue @@ -87,14 +87,14 @@ import { ref, reactive, onMounted } from 'vue' import { useRouter } from 'vue-router' import { showToast, showSuccessToast, showFailToast, ImagePreview } from 'vant' -import { createExpense, getExpenseTypeTree } from '@/api' +import { createExpense, getExpenseTypeTree, uploadFile } from '@/api' const router = useRouter() const loading = ref(false) const showTypePicker = ref(false) const showDatePicker = ref(false) const fileList = ref([]) -const uploadedAttachments = ref([]) +const uploadedAttachments = ref([]) // 存储 COS 返回的文件路径 const form = reactive({ title: '', @@ -120,22 +120,29 @@ const onDateConfirm = ({ selectedValues }: any) => { showDatePicker.value = false } -// 附件上传处理 +// 附件上传处理 - 使用 COS 上传 const onAfterRead = async (file: any) => { - // 这里模拟上传,实际应该调用文件上传 API - // 由于项目使用 fund-file 服务,暂时先保存为 base64 - if (file.file) { - const reader = new FileReader() - reader.onload = (e) => { - const base64 = e.target?.result as string - // 提取 base64 数据部分(去掉 data:image/jpeg;base64,前缀) - const base64Data = base64.split(',')[1] - if (base64Data) { - uploadedAttachments.value.push(base64Data) - console.log('已添加附件:', base64Data.substring(0, 50) + '...') - } + if (!file.file) return + + try { + // 显示上传提示 + showToast('上传中...') + + // 调用 uploadFile API 上传到 COS + const res: any = await uploadFile(file.file, 'expense', undefined, '支出附件') + + // 从响应中获取文件路径 + const filePath = res.data?.filePath || res.data?.url + if (filePath) { + uploadedAttachments.value.push(filePath) + console.log('文件上传成功:', filePath) + showSuccessToast('上传成功') + } else { + showFailToast('上传失败:未获取文件路径') } - reader.readAsDataURL(file.file) + } catch (error: any) { + console.error('上传失败:', error) + showFailToast(error.message || '上传失败') } } @@ -145,10 +152,12 @@ const onBeforeDelete = (file: any, detail: any) => { return true } -// 预览图片 +// 预览图片(通过后端下载 URL) const onPreviewImage = (index: number) => { + // 这里需要后端提供文件预览或下载接口 + // 暂时使用后端返回的完整 URL ImagePreview.show({ - images: uploadedAttachments.value.map(b64 => `data:image/jpeg;base64,${b64}`), + images: uploadedAttachments.value, startPosition: index, }) } @@ -176,7 +185,7 @@ const handleSubmit = async () => { // 转换日期格式为 LocalDateTime 格式 const expenseDateTime = form.expenseDate ? `${form.expenseDate}T12:00:00` : null - // 处理附件:将 base64 数组转为逗号分隔的字符串 + // 处理附件:将 COS 文件路径数组转为逗号分隔的字符串 const attachmentsStr = uploadedAttachments.value.length > 0 ? uploadedAttachments.value.join(',') : null