diff --git a/src/api/match/usereventrecord..js b/src/api/match/usereventrecord..js index 87d6932..638356e 100644 --- a/src/api/match/usereventrecord..js +++ b/src/api/match/usereventrecord..js @@ -96,7 +96,6 @@ export const usereventrecordMaterialPost = (registrationid, data) => { * @param {File} data.File - 凭证图片 (单张) * @param {number} data.PayAmount - 支付金额 * @param {string} data.PayTime - 支付时间 (ISO格式) - * @param {string} [data.TransactionId] - 交易流水号 (可选) * @returns {Promise<{ * code: number, * message: string, @@ -113,7 +112,6 @@ export const usereventrecordVoucherPost = (registrationid, data) => { formData.append('File', data.File); formData.append('PayAmount', data.PayAmount); formData.append('PayTime', data.PayTime); - if (data.TransactionId) formData.append('TransactionId', data.TransactionId); return http.post(`/usereventrecord/voucher/${registrationid}`, formData, { headers: { diff --git a/src/components/editor/index.vue b/src/components/editor/index.vue index c5fed8a..19f0ced 100644 --- a/src/components/editor/index.vue +++ b/src/components/editor/index.vue @@ -16,8 +16,10 @@ // https://www.wangeditor.com/v5/for-frame.html#vue3 import '@wangeditor/editor/dist/css/style.css'; import { reactive, shallowRef, watch, onBeforeUnmount } from 'vue'; -import { IDomEditor } from '@wangeditor/editor'; +import { IDomEditor, IEditorConfig, IToolbarConfig } from '@wangeditor/editor'; import { Toolbar, Editor } from '@wangeditor/editor-for-vue'; +import { ElMessage } from 'element-plus'; +import http from '/@/utils/http'; // 定义父组件传过来的值 const props = defineProps({ @@ -51,12 +53,63 @@ const props = defineProps({ // 定义子组件向父组件传值/事件 const emit = defineEmits(['update:getHtml', 'update:getText']); -// 定义变量内容 -const editorRef = shallowRef(); -const state = reactive({ - editorConfig: { - placeholder: props.placeholder, +// 自定义上传图片 +const customUploadImage = async (file: File, insertFn: (url: string, alt: string, href: string) => void) => { + // 检查文件类型 + if (!file.type.startsWith('image/')) { + ElMessage.error('请上传图片类型的文件'); + return; + } + + // 检查文件大小(限制 5M) + const maxSize = 5 * 1024 * 1024; + if (file.size > maxSize) { + ElMessage.error('图片大小不能超过 5M'); + return; + } + + const formData = new FormData(); + formData.append('file', file); + + try { + const data = await http.instance.post(`/file/upload`, formData, { + headers: { + 'Content-Type': 'multipart/form-data', + }, + }); + + if (data && data[0] && data[0].url) { + const url = data[0].url; + insertFn(url, file.name, url); + ElMessage.success('图片上传成功'); + } else { + ElMessage.error('图片上传失败,未获取到有效URL'); + } + } catch (error) { + console.error('上传图片失败', error); + ElMessage.error('图片上传失败,请重试'); + } +}; + +// 定义编辑器配置 +const editorConfig: Partial = { + placeholder: props.placeholder, + MENU_CONF: { + uploadImage: { + customUpload: customUploadImage, + // 也可以使用 server 方式,但这里我们使用自定义上传 + // server: '/api/file/upload', + // fieldName: 'file', + // maxFileSize: 5 * 1024 * 1024, + // allowedFileTypes: ['image/*'], + }, }, +}; + +// 定义变量内容 +const editorRef = shallowRef(); +const state = reactive({ + editorConfig, editorVal: props.getHtml, }); diff --git a/src/views/user/record/index.vue b/src/views/user/record/index.vue index f2788d9..6f60067 100644 --- a/src/views/user/record/index.vue +++ b/src/views/user/record/index.vue @@ -163,22 +163,40 @@ - + - + - - - - - + + -
请上传凭证文件
+
请上传凭证文件(仅支持jpg、jpeg、png、pdf格式,不超过5MB)
@@ -907,30 +925,45 @@ const submitMaterial = async () => { const isShowVoucherDialog = ref(false); const voucherSubmitting = ref(false); const voucherForm = reactive({ - PayAmount: 0, + PayAmount: null, PayTime: '', - TransactionId: '', File: null, }); const voucherUploadFileList = ref([]); const voucherFormRef = ref(); +// 允许的文件类型 +const allowedFileTypes = ['image/jpeg', 'image/jpg', 'image/png', 'application/pdf']; +// 允许的文件扩展名 +const allowedFileExtensions = ['.jpg', '.jpeg', '.png', '.pdf']; +// 最大文件大小 5MB +const maxFileSize = 5 * 1024 * 1024; + const voucherRules = reactive({ PayAmount: [ + { required: true, message: '请输入支付金额', trigger: ['blur', 'change'] }, { validator: (_rule, value, callback) => { - if (value === '' || value === null || value === undefined) return callback(new Error('请输入支付金额')); - if (Number(value) < 0) return callback(new Error('支付金额不能为负数')); + if (value === '' || value === null || value === undefined) { + return callback(new Error('请输入支付金额')); + } + const numValue = Number(value); + if (isNaN(numValue) || numValue <= 0) { + return callback(new Error('支付金额必须大于0')); + } return callback(); }, - trigger: 'change', + trigger: ['blur', 'change'], }, ], - PayTime: [{ required: true, message: '请选择支付时间', trigger: 'change' }], + PayTime: [{ required: true, message: '请选择支付时间', trigger: ['blur', 'change'] }], File: [ + { required: true, message: '请上传凭证文件', trigger: 'change' }, { validator: (_rule, value, callback) => { - if (!value) return callback(new Error('请上传凭证文件')); + if (!value) { + return callback(new Error('请上传凭证文件')); + } return callback(); }, trigger: 'change', @@ -941,32 +974,118 @@ const voucherRules = reactive({ const openVoucherDialog = (row) => { if (row) currentRow.value = row; voucherSubmitting.value = false; - voucherForm.PayAmount = 0; + voucherForm.PayAmount = null; voucherForm.PayTime = ''; - voucherForm.TransactionId = ''; voucherForm.File = null; voucherUploadFileList.value = []; + // 打开对话框后清除之前的验证状态 + nextTick(() => { + if (voucherFormRef.value) { + voucherFormRef.value.clearValidate(); + } + }); isShowVoucherDialog.value = true; }; +const handlePayAmountChange = (value) => { + // 当金额改变时,触发表单验证 + if (voucherFormRef.value) { + voucherFormRef.value.validateField('PayAmount'); + } +}; + +const validateFile = (file) => { + // 检查文件类型 + const fileName = file.name.toLowerCase(); + const hasValidExtension = allowedFileExtensions.some(ext => fileName.endsWith(ext)); + const hasValidType = allowedFileTypes.includes(file.type); + + if (!hasValidExtension && !hasValidType) { + ElMessage.error('仅支持jpg、jpeg、png、pdf格式的文件'); + return false; + } + + // 检查文件大小 + if (file.size > maxFileSize) { + ElMessage.error('文件大小不能超过5MB'); + return false; + } + + return true; +}; + const onVoucherFileChange = (_file, fileList) => { + // 如果有文件被添加,验证它 + if (fileList && fileList.length > 0) { + const lastFile = fileList[fileList.length - 1]; + if (lastFile.raw && !validateFile(lastFile.raw)) { + // 验证失败,移除该文件 + voucherUploadFileList.value = []; + voucherForm.File = null; + // 触发表单验证 + if (voucherFormRef.value) { + voucherFormRef.value.validateField('File'); + } + return; + } + } + voucherUploadFileList.value = fileList; const first = (fileList ?? []).find((f) => f?.raw); voucherForm.File = first?.raw ?? null; + + // 触发表单验证 + if (voucherFormRef.value) { + voucherFormRef.value.validateField('File'); + } +}; + +const onVoucherFileRemove = (_file, _fileList) => { + // 文件被删除时,更新表单数据并触发验证 + voucherForm.File = null; + if (voucherFormRef.value) { + voucherFormRef.value.validateField('File'); + } }; const submitVoucher = async () => { if (!currentRow.value?.registrationId) return; if (!voucherFormRef.value) return; + + // 先清除可能的旧验证 + voucherFormRef.value.clearValidate(); + + // 执行完整表单验证 voucherFormRef.value.validate(async (valid) => { - if (!valid) return; + if (!valid) { + ElMessage.warning('请完善表单信息后再提交'); + return; + } + + // 二次验证支付金额 + if (!voucherForm.PayAmount || Number(voucherForm.PayAmount) <= 0) { + ElMessage.warning('请输入有效的支付金额'); + return; + } + + // 二次验证文件 + if (!voucherForm.File) { + ElMessage.warning('请上传凭证文件'); + return; + } + + // 二次验证支付时间 + if (!voucherForm.PayTime) { + ElMessage.warning('请选择支付时间'); + return; + } + voucherSubmitting.value = true; try { const payload = { File: voucherForm.File, PayAmount: voucherForm.PayAmount, PayTime: voucherForm.PayTime, - TransactionId: voucherForm.TransactionId || undefined, }; const { succeeded, data } = await usereventrecordVoucherPost(currentRow.value.registrationId, payload); if (succeeded) {