diff --git a/app/api/v1/app_invoices/app_invoices.py b/app/api/v1/app_invoices/app_invoices.py index a696baa..e644370 100644 --- a/app/api/v1/app_invoices/app_invoices.py +++ b/app/api/v1/app_invoices/app_invoices.py @@ -116,6 +116,14 @@ async def create_with_receipt(payload: AppCreateInvoiceWithReceipt, current_user wechat=getattr(current_user, "alias", None), ) inv = await invoice_controller.create(inv_data) + if payload.receipt_urls: + receipts = [] + for url in payload.receipt_urls: + receipt = await invoice_controller.create_receipt(inv.id, PaymentReceiptCreate(url=url, note=payload.note)) + detail = await invoice_controller.get_receipt_by_id(receipt.id) + if detail: + receipts.append(detail) + return Success(data={"invoice_id": inv.id, "receipts": receipts}, msg="创建并上传成功") if payload.receipt_url: receipt = await invoice_controller.create_receipt(inv.id, PaymentReceiptCreate(url=payload.receipt_url, note=payload.note)) detail = await invoice_controller.get_receipt_by_id(receipt.id) diff --git a/app/schemas/invoice.py b/app/schemas/invoice.py index 2367bdc..bc02a28 100644 --- a/app/schemas/invoice.py +++ b/app/schemas/invoice.py @@ -134,6 +134,7 @@ class AppCreateInvoiceWithReceipt(BaseModel): # 兼容前端索引字段:"0"→normal,"1"→special invoiceTypeIndex: Optional[str] = None receipt_url: Optional[str] = Field(None, max_length=512) + receipt_urls: Optional[List[str]] = None note: Optional[str] = Field(None, max_length=256) @field_validator('ticket_type', mode='before') @@ -153,6 +154,21 @@ class AppCreateInvoiceWithReceipt(BaseModel): return s or None return v + @field_validator('receipt_urls', mode='before') + @classmethod + def _clean_receipt_urls(cls, v): + if v is None: + return v + if isinstance(v, str): + v = [v] + if isinstance(v, list): + cleaned = [] + for item in v: + if isinstance(item, str) and item.strip(): + cleaned.append(item.strip()) + return cleaned or None + return None + @model_validator(mode='after') def _coerce_invoice_type(self): if not self.invoice_type and self.invoiceTypeIndex is not None: diff --git a/web1/src/views/user-center/components/CorporateTransfer.vue b/web1/src/views/user-center/components/CorporateTransfer.vue index 0d0bb5a..4e8bdf8 100644 --- a/web1/src/views/user-center/components/CorporateTransfer.vue +++ b/web1/src/views/user-center/components/CorporateTransfer.vue @@ -144,13 +144,15 @@ >
@@ -158,7 +160,7 @@
@@ -256,9 +258,8 @@ const actionUrl = 'https://value.cdcee.net/api/v1/upload/file' const currentStep = ref(1) // 文件上传相关 -const fileInput = ref(null) -const uploadedFile = ref(null) -const uploadedFileUrl = ref('') +const fileList = ref([]) +const uploadedFiles = ref([]) // 表单选择相关 @@ -297,39 +298,43 @@ const message = useMessage() // 计算表单是否有效 const isFormValid = computed(() => { - console.log('isFormValid check:', { - uploadedFile: uploadedFile.value, - invoiceHeader: formModel.invoiceHeader, - invoiceType: formModel.invoiceType - }) return ( - !!uploadedFile.value && + uploadedFiles.value.length > 0 && !!formModel.invoiceHeader && !!formModel.invoiceType ) }) -const handleUploadFinish = (file) => { - console.log('handleUploadFinish called:', file) - console.log('response:', file.event?.target?.response) +const handleUploadFinish = ({ file, event }) => { try { - let response = JSON.parse(file.event.target.response) - console.log('parsed response:', response) - uploadedFile.value = response.data.url - console.log('uploadedFile.value set to:', uploadedFile.value) + const response = JSON.parse(event?.target?.response || '{}') + const fileUrl = response.data?.url + if (fileUrl) { + file.url = fileUrl + file.name = response.data.filename || file.name + file.status = 'finished' + if (!uploadedFiles.value.includes(fileUrl)) { + uploadedFiles.value.push(fileUrl) + } + message.success('上传成功') + return file + } + message.error(response.message || '上传失败') } catch (error) { console.error('Error parsing upload response:', error) + message.error('上传失败,请重试') } } -const deleteUpload = () => { - uploadedFile.value = '' + +const handleRemove = ({ file }) => { + uploadedFiles.value = uploadedFiles.value.filter((url) => url !== file?.url) } const beforeUpload = (data) => { const file = data.file.file - const isLt10M = file.size / 1024 / 1024 < 10 - if (!isLt10M) { - message.error('图片大小不能超过10MB,请重新上传') + const isLt20M = file.size / 1024 / 1024 <= 20 + if (!isLt20M) { + message.error('图片大小不能超过20MB,请重新上传') return false } return true @@ -346,7 +351,7 @@ function handleUploadSubmit() { header_id: formModel.invoiceHeader, ticket_type: 'electronic', invoice_type: formModel.invoiceType, - receipt_url: uploadedFile.value, + receipt_urls: uploadedFiles.value, }) currentStep.value = 3 } @@ -501,7 +506,8 @@ defineExpose({ .form-tip { font-size: 12px; color: #c0c4cc; - margin-top: 8px; + line-height: 18px; + margin: 12px 0 8px; } .select-wrapper {