guzhi/web/src/views/transaction/invoice/InvoiceModal.vue
2025-11-13 17:51:49 +08:00

223 lines
4.5 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<script setup>
import { ref, watch } from 'vue'
import { NModal, NCard, NForm, NFormItem, NInput, NButton, NUpload, NSpace, NText } from 'naive-ui'
const props = defineProps({
visible: {
type: Boolean,
default: false,
},
invoiceData: {
type: Object,
default: () => ({}),
},
mode: {
type: String,
default: 'invoice', // 'invoice' 或 'view'
},
})
const emit = defineEmits(['update:visible', 'confirm'])
const formRef = ref(null)
const formData = ref({
email: '',
content: '',
attachments: [],
})
const fileList = ref([])
// 监听弹窗打开,初始化数据
watch(
() => props.visible,
(val) => {
if (val) {
formData.value = {
email: props.invoiceData?.email || '',
content: '',
attachments: [],
}
fileList.value = []
}
}
)
// 关闭弹窗
const handleClose = () => {
emit('update:visible', false)
}
// 确认操作
const handleConfirm = () => {
formRef.value?.validate((errors) => {
if (!errors) {
emit('confirm', {
...formData.value,
id: props.invoiceData?.id,
})
}
})
}
// 文件上传前的处理
const beforeUpload = (data) => {
const { file } = data
const isImage = file.type.startsWith('image/')
const isPdf = file.type === 'application/pdf'
if (!isImage && !isPdf) {
$message.error('只能上传图片或PDF文件')
return false
}
const isLt10M = file.size / 1024 / 1024 < 10
if (!isLt10M) {
$message.error('文件大小不能超过10MB')
return false
}
return true
}
// 文件上传变化
const handleUploadChange = ({ fileList: newFileList }) => {
fileList.value = newFileList
formData.value.attachments = newFileList.map(file => file.id || file.name)
}
// 移除文件
const handleRemove = ({ file }) => {
const index = fileList.value.findIndex(item => item.id === file.id)
if (index > -1) {
fileList.value.splice(index, 1)
}
return true
}
const rules = {
email: [
{
required: true,
message: '请输入发送邮箱',
trigger: ['input', 'blur'],
},
{
type: 'email',
message: '请输入正确的邮箱格式',
trigger: ['input', 'blur'],
},
],
}
const modalTitle = props.mode === 'invoice' ? '开票' : '查看发票'
</script>
<template>
<NModal
:show="visible"
:mask-closable="false"
preset="card"
:title="modalTitle"
class="invoice-modal"
style="width: 600px"
@update:show="handleClose"
>
<NForm
ref="formRef"
:model="formData"
:rules="rules"
label-placement="left"
label-width="100"
>
<NFormItem label="发送邮箱" path="email">
<NInput
v-model:value="formData.email"
placeholder="请输入邮箱地址"
clearable
/>
</NFormItem>
<NFormItem label="文案">
<NInput
v-model:value="formData.content"
type="textarea"
placeholder="请输入文案内容"
:rows="4"
clearable
/>
</NFormItem>
<NFormItem label="发票附件">
<div style="width: 100%">
<NUpload
v-model:file-list="fileList"
multiple
:max="2"
list-type="image-card"
:before-upload="beforeUpload"
@change="handleUploadChange"
@remove="handleRemove"
>
<div class="upload-trigger">
<div class="upload-icon">+</div>
</div>
</NUpload>
</div>
</NFormItem>
<NFormItem>
<div style="width: 100%; text-align: left; padding-left: 100px">
<NText depth="3" style="font-size: 12px; color: #ff9800">
ps最多上传两张
</NText>
</div>
</NFormItem>
</NForm>
<template #footer>
<div style="display: flex; justify-content: flex-end; gap: 12px">
<NButton @click="handleClose">取消</NButton>
<NButton type="primary" @click="handleConfirm">上传并通知</NButton>
</div>
</template>
</NModal>
</template>
<style scoped>
.invoice-modal {
max-width: 90vw;
}
.upload-trigger {
width: 100px;
height: 100px;
border: 2px dashed #d9d9d9;
border-radius: 4px;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
transition: all 0.3s;
}
.upload-trigger:hover {
border-color: #40a9ff;
}
.upload-icon {
font-size: 32px;
color: #d9d9d9;
}
:deep(.n-upload-file-list) {
display: flex;
gap: 8px;
}
:deep(.n-upload-trigger) {
width: 100px;
height: 100px;
}
</style>