223 lines
4.5 KiB
Vue
223 lines
4.5 KiB
Vue
<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>
|