From ea6ad9ddc3d5b33897e93276282245f7023836ff Mon Sep 17 00:00:00 2001 From: spring <2396852758@qq.com> Date: 星期四, 28 八月 2025 17:45:28 +0800 Subject: [PATCH] 大数据市场分析 --- src/views/invoiceCollaboration/components/InvoiceDialog.vue | 484 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 484 insertions(+), 0 deletions(-) diff --git a/src/views/invoiceCollaboration/components/InvoiceDialog.vue b/src/views/invoiceCollaboration/components/InvoiceDialog.vue new file mode 100644 index 0000000..3b8f2a6 --- /dev/null +++ b/src/views/invoiceCollaboration/components/InvoiceDialog.vue @@ -0,0 +1,484 @@ +<template> + <el-dialog + :model-value="dialogFormVisible" + @update:model-value="$emit('update:dialogFormVisible', $event)" + :title="title" + width="1200px" + :close-on-click-modal="false" + @close="handleClose" + > + <el-form + ref="formRef" + :model="formData" + :rules="rules" + label-width="120px" + class="invoice-form" + > + <!-- 璐拱鏂逛俊鎭� --> + <el-card class="buyer-card" shadow="never"> + <template #header> + <div class="card-header"> + <span>璐拱鏂逛俊鎭�</span> + </div> + </template> + + <el-row :gutter="20"> + <el-col :span="12"> + <el-form-item label="璐拱鏂瑰悕绉�" prop="buyerName"> + <el-input + v-model="formData.buyerName" + placeholder="璇疯緭鍏ヨ喘涔版柟鍚嶇О" + style="width: 100%" + /> + </el-form-item> + </el-col> + <el-col :span="12"> + <el-form-item label="绾崇◣浜鸿瘑鍒彿" prop="buyerTaxNo"> + <el-input + v-model="formData.buyerTaxNo" + placeholder="璇疯緭鍏ョ撼绋庝汉璇嗗埆鍙�" + style="width: 100%" + /> + </el-form-item> + </el-col> + </el-row> + + <el-row :gutter="20"> + <el-col :span="12"> + <el-form-item label="鍦板潃鐢佃瘽" prop="buyerAddress"> + <el-input + v-model="formData.buyerAddress" + placeholder="璇疯緭鍏ュ湴鍧�鐢佃瘽" + style="width: 100%" + /> + </el-form-item> + </el-col> + <el-col :span="12"> + <el-form-item label="寮�鎴疯鍙婅处鍙�" prop="buyerBankAccount"> + <el-input + v-model="formData.buyerBankAccount" + placeholder="璇疯緭鍏ュ紑鎴疯鍙婅处鍙�" + style="width: 100%" + /> + </el-form-item> + </el-col> + </el-row> + </el-card> + + <!-- 閿�鍞柟淇℃伅 --> + <el-card class="seller-card" shadow="never"> + <template #header> + <div class="card-header"> + <span>閿�鍞柟淇℃伅</span> + </div> + </template> + + <el-row :gutter="20"> + <el-col :span="12"> + <el-form-item label="閿�鍞柟鍚嶇О" prop="sellerName"> + <el-input + v-model="formData.sellerName" + placeholder="璇疯緭鍏ラ攢鍞柟鍚嶇О" + style="width: 100%" + /> + </el-form-item> + </el-col> + <el-col :span="12"> + <el-form-item label="绾崇◣浜鸿瘑鍒彿" prop="sellerTaxNo"> + <el-input + v-model="formData.sellerTaxNo" + placeholder="璇疯緭鍏ョ撼绋庝汉璇嗗埆鍙�" + style="width: 100%" + /> + </el-form-item> + </el-col> + </el-row> + + <el-row :gutter="20"> + <el-col :span="12"> + <el-form-item label="鍦板潃鐢佃瘽" prop="sellerAddress"> + <el-input + v-model="formData.sellerAddress" + placeholder="璇疯緭鍏ュ湴鍧�鐢佃瘽" + style="width: 100%" + /> + </el-form-item> + </el-col> + <el-col :span="12"> + <el-form-item label="寮�鎴疯鍙婅处鍙�" prop="sellerBankAccount"> + <el-input + v-model="formData.sellerBankAccount" + placeholder="璇疯緭鍏ュ紑鎴疯鍙婅处鍙�" + style="width: 100%" + /> + </el-form-item> + </el-col> + </el-row> + </el-card> + + <!-- 鍟嗗搧鏄庣粏 --> + <el-card class="items-card" shadow="never"> + <template #header> + <div class="card-header"> + <span>鍟嗗搧鏄庣粏</span> + <el-button type="primary" size="small" @click="addItem"> + 娣诲姞鍟嗗搧 + </el-button> + </div> + </template> + + <el-table :data="formData.items" border style="width: 100%"> + <el-table-column label="鍟嗗搧鍚嶇О" width="200"> + <template #default="scope"> + <el-input + v-model="scope.row.name" + placeholder="鍟嗗搧鍚嶇О" + style="width: 100%" + /> + </template> + </el-table-column> + <el-table-column label="瑙勬牸鍨嬪彿" width="150"> + <template #default="scope"> + <el-input + v-model="scope.row.specification" + placeholder="瑙勬牸鍨嬪彿" + style="width: 100%" + /> + </template> + </el-table-column> + <el-table-column label="鍗曚綅" width="100"> + <template #default="scope"> + <el-input + v-model="scope.row.unit" + placeholder="鍗曚綅" + style="width: 100%" + /> + </template> + </el-table-column> + <el-table-column label="鏁伴噺" width="120"> + <template #default="scope"> + <el-input + v-model.number="scope.row.quantity" + placeholder="鏁伴噺" + type="number" + @input="calculateItemAmount(scope.$index)" + style="width: 100%" + /> + </template> + </el-table-column> + <el-table-column label="鍗曚环" width="120"> + <template #default="scope"> + <el-input + v-model.number="scope.row.unitPrice" + placeholder="鍗曚环" + type="number" + @input="calculateItemAmount(scope.$index)" + style="width: 100%" + > + <template v-slot:suffix> + <span>鍏�</span> + </template> + </el-input> + </template> + </el-table-column> + <el-table-column label="閲戦" width="120"> + <template #default="scope"> + <span>{{ (scope.row.amount || 0).toFixed(2) }} 鍏�</span> + </template> + </el-table-column> + <el-table-column label="绋庣巼" width="120"> + <template #default="scope"> + <el-select + v-model="scope.row.taxRate" + placeholder="閫夋嫨绋庣巼" + @change="calculateItemAmount(scope.$index)" + style="width: 100%" + > + <el-option label="0%" value="0" /> + <el-option label="1%" value="0.01" /> + <el-option label="3%" value="0.03" /> + <el-option label="6%" value="0.06" /> + <el-option label="9%" value="0.09" /> + <el-option label="13%" value="0.13" /> + </el-select> + </template> + </el-table-column> + <el-table-column label="绋庨" width="120"> + <template #default="scope"> + <span>{{ (scope.row.taxAmount || 0).toFixed(2) }} 鍏�</span> + </template> + </el-table-column> + <el-table-column label="浠风◣鍚堣" width="120"> + <template #default="scope"> + <span>{{ (scope.row.totalAmount || 0).toFixed(2) }} 鍏�</span> + </template> + </el-table-column> + <el-table-column label="鎿嶄綔" width="80"> + <template #default="scope"> + <el-button + type="danger" + size="small" + @click="removeItem(scope.$index)" + > + 鍒犻櫎 + </el-button> + </template> + </el-table-column> + </el-table> + + <!-- 鍚堣淇℃伅 --> + <div class="summary-info"> + <el-row :gutter="20"> + <el-col :span="6"> + <span class="summary-label">閲戦鍚堣锛�</span> + <span class="summary-value">{{ totalAmount.toFixed(2) }} 鍏�</span> + </el-col> + <el-col :span="6"> + <span class="summary-label">绋庨鍚堣锛�</span> + <span class="summary-value">{{ totalTaxAmount.toFixed(2) }} 鍏�</span> + </el-col> + <el-col :span="6"> + <span class="summary-label">浠风◣鍚堣锛�</span> + <span class="summary-value">{{ totalTotalAmount.toFixed(2) }} 鍏�</span> + </el-col> + </el-row> + </div> + </el-card> + + <!-- 澶囨敞淇℃伅 --> + <el-form-item label="澶囨敞" prop="remark"> + <el-input + v-model="formData.remark" + type="textarea" + :rows="3" + placeholder="璇疯緭鍏ュ娉ㄤ俊鎭�" + /> + </el-form-item> + </el-form> + + <template #footer> + <div class="dialog-footer"> + <el-button @click="handleClose">鍙栨秷</el-button> + <el-button type="primary" @click="handleSubmit" :loading="submitLoading"> + 鎻愪氦 + </el-button> + </div> + </template> + </el-dialog> +</template> + +<script setup> +import { ref, reactive, watch, computed } from "vue"; +import { ElMessage } from "element-plus"; + +// Props +const props = defineProps({ + dialogFormVisible: { + type: Boolean, + default: false + }, + form: { + type: Object, + default: () => ({}) + }, + title: { + type: String, + default: "" + }, + isEdit: { + type: Boolean, + default: false + } +}); + +// Emits +const emit = defineEmits(['update:dialogFormVisible', 'update:form', 'submit', 'success']); + +// 鍝嶅簲寮忔暟鎹� +const formRef = ref(null); +const submitLoading = ref(false); + +// 琛ㄥ崟鏁版嵁 +const formData = reactive({ + buyerName: "", + buyerTaxNo: "", + buyerAddress: "", + buyerBankAccount: "", + sellerName: "鏈叕鍙�", + sellerTaxNo: "123456789012345678", + sellerAddress: "鍏徃鍦板潃", + sellerBankAccount: "閾惰璐︽埛", + items: [], + remark: "" +}); + +// 琛ㄥ崟楠岃瘉瑙勫垯 +const rules = { + buyerName: [ + { required: true, message: "璇疯緭鍏ヨ喘涔版柟鍚嶇О", trigger: "blur" } + ], + buyerTaxNo: [ + { required: true, message: "璇疯緭鍏ョ撼绋庝汉璇嗗埆鍙�", trigger: "blur" } + ], + items: [ + { + type: "array", + required: true, + message: "璇疯嚦灏戞坊鍔犱竴涓晢鍝�", + trigger: "change", + validator: (rule, value, callback) => { + if (!value || value.length === 0) { + callback(new Error("璇疯嚦灏戞坊鍔犱竴涓晢鍝�")); + } else { + callback(); + } + } + } + ] +}; + +// 璁$畻灞炴�� +const totalAmount = computed(() => { + return formData.items.reduce((sum, item) => sum + (item.amount || 0), 0); +}); + +const totalTaxAmount = computed(() => { + return formData.items.reduce((sum, item) => sum + (item.taxAmount || 0), 0); +}); + +const totalTotalAmount = computed(() => { + return formData.items.reduce((sum, item) => sum + (item.totalAmount || 0), 0); +}); + +// 鐩戝惉琛ㄥ崟鏁版嵁鍙樺寲 +watch(() => props.form, (newVal) => { + Object.assign(formData, newVal); + if (!formData.items || formData.items.length === 0) { + formData.items = []; + } +}, { deep: true, immediate: true }); + +// 娣诲姞鍟嗗搧 +const addItem = () => { + formData.items.push({ + name: "", + specification: "", + unit: "", + quantity: 0, + unitPrice: 0, + amount: 0, + taxRate: "0.13", + taxAmount: 0, + totalAmount: 0 + }); +}; + +// 鍒犻櫎鍟嗗搧 +const removeItem = (index) => { + formData.items.splice(index, 1); +}; + +// 璁$畻鍟嗗搧閲戦 +const calculateItemAmount = (index) => { + const item = formData.items[index]; + if (item.quantity && item.unitPrice) { + item.amount = item.quantity * item.unitPrice; + item.taxAmount = item.amount * parseFloat(item.taxRate); + item.totalAmount = item.amount + item.taxAmount; + } +}; + +// 鍏抽棴瀵硅瘽妗� +const handleClose = () => { + emit('update:dialogFormVisible', false); + formRef.value?.resetFields(); +}; + +// 鎻愪氦琛ㄥ崟 +const handleSubmit = async () => { + if (!formRef.value) return; + + try { + await formRef.value.validate(); + + // 楠岃瘉鍟嗗搧淇℃伅 + if (formData.items.length === 0) { + ElMessage.warning("璇疯嚦灏戞坊鍔犱竴涓晢鍝�"); + return; + } + + for (let item of formData.items) { + if (!item.name) { + ElMessage.warning("璇疯緭鍏ュ晢鍝佸悕绉�"); + return; + } + if (!item.quantity || item.quantity <= 0) { + ElMessage.warning("璇疯緭鍏ユ湁鏁堢殑鍟嗗搧鏁伴噺"); + return; + } + if (!item.unitPrice || item.unitPrice <= 0) { + ElMessage.warning("璇疯緭鍏ユ湁鏁堢殑鍟嗗搧鍗曚环"); + return; + } + } + + submitLoading.value = true; + + // 妯℃嫙鎻愪氦 + setTimeout(() => { + submitLoading.value = false; + ElMessage.success("鎻愪氦鎴愬姛"); + emit('submit', { ...formData }); + handleClose(); + }, 1000); + + } catch (error) { + console.error('琛ㄥ崟楠岃瘉澶辫触:', error); + } +}; +</script> + +<style scoped> +.invoice-form { + padding: 20px 0; +} + +.buyer-card, +.seller-card, +.items-card { + margin-bottom: 20px; +} + +.card-header { + display: flex; + justify-content: space-between; + align-items: center; + font-weight: bold; +} + +.summary-info { + margin-top: 15px; + padding: 15px; + background-color: #f5f7fa; + border-radius: 4px; +} + +.summary-label { + font-weight: bold; + margin-right: 10px; +} + +.summary-value { + color: #409eff; + font-size: 16px; + font-weight: bold; +} + +.dialog-footer { + text-align: right; +} + +.el-table { + margin-top: 10px; +} +</style> \ No newline at end of file -- Gitblit v1.9.3