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/index.vue | 554 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 554 insertions(+), 0 deletions(-) diff --git a/src/views/invoiceCollaboration/index.vue b/src/views/invoiceCollaboration/index.vue new file mode 100644 index 0000000..b44ee92 --- /dev/null +++ b/src/views/invoiceCollaboration/index.vue @@ -0,0 +1,554 @@ +<template> + <div class="app-container"> + <!-- 鎼滅储琛ㄥ崟 --> + <el-form :inline="true" :model="queryParams" class="search-form"> + <el-form-item label="鍙戠エ鍙风爜"> + <el-input + v-model="queryParams.invoiceNo" + placeholder="璇疯緭鍏ュ彂绁ㄥ彿鐮�" + clearable + :style="{ width: '200px' }" + /> + </el-form-item> + <el-form-item label="寮�绁ㄧ姸鎬�"> + <el-select + v-model="queryParams.status" + placeholder="璇烽�夋嫨寮�绁ㄧ姸鎬�" + clearable + :style="{ width: '150px' }" + > + <el-option + :label="item.label" + v-for="item in statusList" + :key="item.value" + :value="item.value" + /> + </el-select> + </el-form-item> + <el-form-item label="寮�绁ㄦ棩鏈�"> + <el-date-picker + v-model="queryParams.dateRange" + type="daterange" + range-separator="鑷�" + start-placeholder="寮�濮嬫棩鏈�" + end-placeholder="缁撴潫鏃ユ湡" + format="YYYY-MM-DD" + value-format="YYYY-MM-DD" + :style="{ width: '240px' }" + /> + </el-form-item> + <el-form-item> + <el-button type="primary" @click="handleQuery">鏌ヨ</el-button> + <el-button @click="resetQuery">閲嶇疆</el-button> + </el-form-item> + </el-form> + + <el-card> + <!-- 鎿嶄綔鎸夐挳鍖� --> + <el-row :gutter="24" class="table-toolbar" justify="space-between"> + <el-button type="primary" :icon="Plus" @click="handleAdd"> + 鏂板鍙戠エ + </el-button> + <el-button type="success" :icon="Refresh" @click="handleSyncTaxControl"> + 鍚屾绋庢帶骞冲彴 + </el-button> + <el-button type="warning" :icon="Download" @click="handleBatchDownload"> + 鎵归噺涓嬭浇 + </el-button> + <el-button type="danger" :icon="Delete" @click="handleBatchDelete" :disabled="selectedIds.length === 0"> + 鎵归噺鍒犻櫎 + </el-button> + </el-row> + + <!-- 琛ㄦ牸缁勪欢 --> + <el-table + v-loading="loading" + :data="tableData" + @selection-change="handleSelectionChange" + border + style="width: 100%" + > + <el-table-column type="selection" width="55" /> + <el-table-column label="鍙戠エ鍙风爜" prop="invoiceNo" width="180" /> + <el-table-column label="鍙戠エ浠g爜" prop="invoiceCode" width="150" /> + <el-table-column label="寮�绁ㄦ棩鏈�" prop="invoiceDate" width="120" /> + <el-table-column label="璐拱鏂瑰悕绉�" prop="buyerName" width="200" show-overflow-tooltip /> + <el-table-column label="閿�鍞柟鍚嶇О" prop="sellerName" width="200" show-overflow-tooltip /> + <el-table-column label="閲戦" prop="amount" width="120"> + <template #default="scope"> + {{ scope.row.amount }} 鍏� + </template> + </el-table-column> + <el-table-column label="绋庨" prop="taxAmount" width="120"> + <template #default="scope"> + {{ scope.row.taxAmount }} 鍏� + </template> + </el-table-column> + <el-table-column label="浠风◣鍚堣" prop="totalAmount" width="120"> + <template #default="scope"> + {{ scope.row.totalAmount }} 鍏� + </template> + </el-table-column> + <el-table-column label="寮�绁ㄧ姸鎬�" prop="status" width="100"> + <template #default="scope"> + <el-tag :type="getStatusType(scope.row.status)"> + {{ getStatusText(scope.row.status) }} + </el-tag> + </template> + </el-table-column> + <el-table-column label="绋庢帶骞冲彴鐘舵��" prop="taxControlStatus" width="120"> + <template #default="scope"> + <el-tag :type="getTaxControlStatusType(scope.row.taxControlStatus)"> + {{ getTaxControlStatusText(scope.row.taxControlStatus) }} + </el-tag> + </template> + </el-table-column> + <el-table-column label="鍒涘缓鏃堕棿" prop="createTime" width="160" /> + <el-table-column label="鎿嶄綔" width="250" fixed="right"> + <template #default="scope"> + <el-button + size="small" + type="primary" + @click="handleView(scope.row)" + > + 鏌ョ湅 + </el-button> + <el-button + size="small" + type="success" + @click="handleDownload(scope.row)" + v-if="scope.row.status === 'issued'" + > + 涓嬭浇 + </el-button> + <el-button + size="small" + type="warning" + @click="handleEdit(scope.row)" + v-if="scope.row.status === 'draft'" + > + 缂栬緫 + </el-button> + <el-button + size="small" + type="danger" + @click="handleDelete(scope.row)" + v-if="scope.row.status === 'draft'" + > + 鍒犻櫎 + </el-button> + </template> + </el-table-column> + </el-table> + + <!-- 鍒嗛〉缁勪欢 --> + <pagination + v-if="total > 0" + :page="current" + :limit="pageSize" + :total="total" + @pagination="handlePagination" + :layout="'total, prev, pager, next, jumper'" + /> + </el-card> + + <!-- 鏂板/缂栬緫瀵硅瘽妗� --> + <InvoiceDialog + v-model:dialogFormVisible="dialogFormVisible" + v-model:form="form" + :title="title" + :is-edit="isEdit" + @submit="handleSubmit" + @success="handleSuccess" + ref="invoiceDialog" + /> + + <!-- 鏌ョ湅璇︽儏瀵硅瘽妗� --> + <InvoiceViewDialog + v-model:dialogViewVisible="dialogViewVisible" + :form="viewForm" + title="鍙戠エ璇︽儏" + /> + + <!-- 绋庢帶骞冲彴鍚屾瀵硅瘽妗� --> + <TaxControlSyncDialog + v-model:dialogSyncVisible="dialogSyncVisible" + @success="handleSyncSuccess" + /> + + <!-- 鍗曚釜鍙戠エ涓嬭浇瀵硅瘽妗� --> + <DownloadDialog + v-model:dialogVisible="downloadDialogVisible" + :invoice="currentDownloadInvoice" + @success="handleDownloadSuccess" + /> + + <!-- 鎵归噺涓嬭浇瀵硅瘽妗� --> + <BatchDownloadDialog + v-model:dialogVisible="batchDownloadDialogVisible" + :invoices="batchDownloadInvoices" + @success="handleBatchDownloadSuccess" + /> + </div> +</template> + +<script setup> +import { ref, reactive, onMounted } from "vue"; +import { ElMessage, ElMessageBox } from "element-plus"; +import { Plus, Edit, Delete, Refresh, Download, View } from "@element-plus/icons-vue"; +import Pagination from "@/components/Pagination"; +import InvoiceDialog from "./components/InvoiceDialog.vue"; +import InvoiceViewDialog from "./components/InvoiceViewDialog.vue"; +import TaxControlSyncDialog from "./components/TaxControlSyncDialog.vue"; +import DownloadDialog from "./components/DownloadDialog.vue"; +import BatchDownloadDialog from "./components/BatchDownloadDialog.vue"; + +// 鍝嶅簲寮忔暟鎹� +const loading = ref(false); +const tableData = ref([]); +const selectedIds = ref([]); +const current = ref(1); +const pageSize = ref(10); +const total = ref(0); +const dialogFormVisible = ref(false); +const dialogViewVisible = ref(false); +const dialogSyncVisible = ref(false); +const downloadDialogVisible = ref(false); +const batchDownloadDialogVisible = ref(false); +const isEdit = ref(false); +const title = ref(""); +const form = ref({}); +const viewForm = ref({}); +const currentDownloadInvoice = ref({}); +const batchDownloadInvoices = ref([]); + +// 鏌ヨ鍙傛暟 +const queryParams = reactive({ + invoiceNo: "", + status: "", + dateRange: [] +}); + +// 鐘舵�佸垪琛� +const statusList = ref([ + { value: "draft", label: "鑽夌" }, + { value: "pending", label: "寰呭紑绁�" }, + { value: "issuing", label: "寮�绁ㄤ腑" }, + { value: "issued", label: "宸插紑绁�" }, + { value: "failed", label: "寮�绁ㄥけ璐�" }, + { value: "cancelled", label: "宸蹭綔搴�" } +]); + +// 妯℃嫙鏁版嵁 +const mockData = [ + { + id: "1", + invoiceNo: "FP20241201001", + invoiceCode: "123456789", + invoiceDate: "2024-12-01", + buyerName: "瀹㈡埛A鍏徃", + sellerName: "鏈叕鍙�", + amount: 10000.00, + taxAmount: 1300.00, + totalAmount: 11300.00, + status: "issued", + taxControlStatus: "synced", + createTime: "2024-12-01 10:00:00" + }, + { + id: "2", + invoiceNo: "FP20241201002", + invoiceCode: "123456790", + invoiceDate: "2024-12-01", + buyerName: "瀹㈡埛B鍏徃", + sellerName: "鏈叕鍙�", + amount: 5000.00, + taxAmount: 650.00, + totalAmount: 5650.00, + status: "pending", + taxControlStatus: "pending", + createTime: "2024-12-01 14:30:00" + } +]; + +// 鑾峰彇鐘舵�佺被鍨� +const getStatusType = (status) => { + const statusMap = { + draft: "", + pending: "warning", + issuing: "warning", + issued: "success", + failed: "danger", + cancelled: "info" + }; + return statusMap[status] || ""; +}; + +// 鑾峰彇鐘舵�佹枃鏈� +const getStatusText = (status) => { + const statusMap = { + draft: "鑽夌", + pending: "寰呭紑绁�", + issuing: "寮�绁ㄤ腑", + issued: "宸插紑绁�", + failed: "寮�绁ㄥけ璐�", + cancelled: "宸蹭綔搴�" + }; + return statusMap[status] || status; +}; + +// 鑾峰彇绋庢帶骞冲彴鐘舵�佺被鍨� +const getTaxControlStatusType = (status) => { + const statusMap = { + pending: "warning", + syncing: "warning", + synced: "success", + failed: "danger" + }; + return statusMap[status] || ""; +}; + +// 鑾峰彇绋庢帶骞冲彴鐘舵�佹枃鏈� +const getTaxControlStatusText = (status) => { + const statusMap = { + pending: "寰呭悓姝�", + syncing: "鍚屾涓�", + synced: "宸插悓姝�", + failed: "鍚屾澶辫触" + }; + return statusMap[status] || status; +}; + +// 鏌ヨ +const handleQuery = () => { + current.value = 1; + loadData(); +}; + +// 閲嶇疆鏌ヨ +const resetQuery = () => { + Object.assign(queryParams, { + invoiceNo: "", + status: "", + dateRange: [] + }); + handleQuery(); +}; + +// 鍔犺浇鏁版嵁 +const loadData = () => { + loading.value = true; + // 妯℃嫙API璋冪敤 + setTimeout(() => { + tableData.value = mockData; + total.value = mockData.length; + loading.value = false; + }, 500); +}; + +// 鍒嗛〉澶勭悊 +const handlePagination = (pagination) => { + current.value = pagination.page; + pageSize.value = pagination.limit; + loadData(); +}; + +// 閫夋嫨鍙樺寲 +const handleSelectionChange = (selection) => { + selectedIds.value = selection.map(item => item.id); +}; + +// 鏂板 +const handleAdd = () => { + isEdit.value = false; + title.value = "鏂板鍙戠エ"; + form.value = { + buyerName: "", + buyerTaxNo: "", + buyerAddress: "", + buyerBankAccount: "", + sellerName: "鏈叕鍙�", + sellerTaxNo: "123456789012345678", + sellerAddress: "鍏徃鍦板潃", + sellerBankAccount: "閾惰璐︽埛", + items: [], + remark: "" + }; + dialogFormVisible.value = true; +}; + +// 缂栬緫 +const handleEdit = (row) => { + isEdit.value = true; + title.value = "缂栬緫鍙戠エ"; + form.value = { ...row }; + dialogFormVisible.value = true; +}; + +// 鏌ョ湅 +const handleView = (row) => { + viewForm.value = { ...row }; + dialogViewVisible.value = true; +}; + +// 鍒犻櫎 +const handleDelete = (row) => { + ElMessageBox.confirm( + `纭畾瑕佸垹闄ゅ彂绁� ${row.invoiceNo} 鍚楋紵`, + "鎻愮ず", + { + confirmButtonText: "纭畾", + cancelButtonText: "鍙栨秷", + type: "warning" + } + ).then(() => { + // 妯℃嫙鍒犻櫎 + const index = tableData.value.findIndex(item => item.id === row.id); + if (index > -1) { + tableData.value.splice(index, 1); + total.value--; + ElMessage.success("鍒犻櫎鎴愬姛"); + } + }); +}; + +// 鎵归噺鍒犻櫎 +const handleBatchDelete = () => { + if (selectedIds.value.length === 0) { + ElMessage.warning("璇烽�夋嫨瑕佸垹闄ょ殑璁板綍"); + return; + } + + ElMessageBox.confirm( + `纭畾瑕佸垹闄ら�変腑鐨� ${selectedIds.value.length} 鏉¤褰曞悧锛焋, + "鎻愮ず", + { + confirmButtonText: "纭畾", + cancelButtonText: "鍙栨秷", + type: "warning" + } + ).then(() => { + // 妯℃嫙鎵归噺鍒犻櫎 + tableData.value = tableData.value.filter(item => !selectedIds.value.includes(item.id)); + total.value = tableData.value.length; + selectedIds.value = []; + ElMessage.success("鎵归噺鍒犻櫎鎴愬姛"); + }); +}; + +// 涓嬭浇鍙戠エ +const handleDownload = (row) => { + if (row.status !== 'issued') { + ElMessage.warning("鍙湁宸插紑绁ㄧ殑鍙戠エ鎵嶈兘涓嬭浇"); + return; + } + + // 鏄剧ず涓嬭浇閫夐」瀵硅瘽妗� + downloadDialogVisible.value = true; + currentDownloadInvoice.value = row; +}; + +// 鎵归噺涓嬭浇 +const handleBatchDownload = () => { + if (selectedIds.value.length === 0) { + ElMessage.warning("璇烽�夋嫨瑕佷笅杞界殑璁板綍"); + return; + } + + // 妫�鏌ラ�変腑鐨勫彂绁ㄧ姸鎬� + const selectedInvoices = tableData.value.filter(item => selectedIds.value.includes(item.id)); + const issuedInvoices = selectedInvoices.filter(item => item.status === 'issued'); + + if (issuedInvoices.length === 0) { + ElMessage.warning("閫変腑鐨勫彂绁ㄤ腑娌℃湁宸插紑绁ㄧ殑鍙戠エ"); + return; + } + + if (issuedInvoices.length < selectedInvoices.length) { + ElMessage.warning(`閫変腑鐨�${selectedInvoices.length}寮犲彂绁ㄤ腑锛屽彧鏈�${issuedInvoices.length}寮犲凡寮�绁紝灏嗗彧涓嬭浇宸插紑绁ㄧ殑鍙戠エ`); + } + + // 鏄剧ず鎵归噺涓嬭浇閫夐」瀵硅瘽妗� + batchDownloadDialogVisible.value = true; + batchDownloadInvoices.value = issuedInvoices; +}; + +// 鍚屾绋庢帶骞冲彴 +const handleSyncTaxControl = () => { + dialogSyncVisible.value = true; +}; + +// 鎻愪氦琛ㄥ崟 +const handleSubmit = (formData) => { + if (isEdit.value) { + // 缂栬緫 + const index = tableData.value.findIndex(item => item.id === formData.id); + if (index > -1) { + tableData.value[index] = { ...formData }; + ElMessage.success("缂栬緫鎴愬姛"); + } + } else { + // 鏂板 + const newItem = { + id: Date.now().toString(), + invoiceNo: `FP${Date.now()}`, + invoiceCode: "123456789", + invoiceDate: new Date().toISOString().split('T')[0], + buyerName: formData.buyerName, + sellerName: formData.sellerName, + amount: formData.items.reduce((sum, item) => sum + (item.amount || 0), 0), + taxAmount: formData.items.reduce((sum, item) => sum + (item.taxAmount || 0), 0), + totalAmount: formData.items.reduce((sum, item) => sum + (item.totalAmount || 0), 0), + status: "draft", + taxControlStatus: "pending", + createTime: new Date().toLocaleString() + }; + tableData.value.unshift(newItem); + total.value++; + ElMessage.success("鏂板鎴愬姛"); + } + dialogFormVisible.value = false; +}; + +// 琛ㄥ崟鎴愬姛鍥炶皟 +const handleSuccess = () => { + loadData(); +}; + +// 鍚屾鎴愬姛鍥炶皟 +const handleSyncSuccess = () => { + loadData(); + ElMessage.success("绋庢帶骞冲彴鍚屾鎴愬姛"); +}; + +// 鍗曚釜涓嬭浇鎴愬姛鍥炶皟 +const handleDownloadSuccess = () => { + downloadDialogVisible.value = false; + ElMessage.success("鍙戠エ涓嬭浇鎴愬姛"); +}; + +// 鎵归噺涓嬭浇鎴愬姛鍥炶皟 +const handleBatchDownloadSuccess = () => { + batchDownloadDialogVisible.value = false; + ElMessage.success("鎵归噺涓嬭浇鎴愬姛"); +}; + +// 椤甸潰鍔犺浇 +onMounted(() => { + loadData(); +}); +</script> + +<style scoped> +.search-form { + margin-bottom: 20px; +} + +.table-toolbar { + margin-bottom: 20px; +} + +.el-card { + margin-bottom: 20px; +} +</style> \ No newline at end of file -- Gitblit v1.9.3