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