From 92e38481fc2f68dcd540434c6428d790b470a84d Mon Sep 17 00:00:00 2001
From: spring <2396852758@qq.com>
Date: 星期四, 28 八月 2025 15:42:44 +0800
Subject: [PATCH] 发票协同

---
 src/views/invoiceCollaboration/components/InvoiceViewDialog.vue    |  291 +++++
 src/views/invoiceCollaboration/index.vue                           |  554 +++++++++++
 package.json                                                       |    1 
 src/views/invoiceCollaboration/components/TaxControlSyncDialog.vue |  362 +++++++
 src/views/invoiceCollaboration/components/BatchDownloadDialog.vue  |  704 ++++++++++++++
 src/views/invoiceCollaboration/components/InvoiceDialog.vue        |  484 +++++++++
 src/views/invoiceCollaboration/components/DownloadDialog.vue       |  580 +++++++++++
 7 files changed, 2,976 insertions(+), 0 deletions(-)

diff --git a/package.json b/package.json
index b241ca8..6d2877a 100644
--- a/package.json
+++ b/package.json
@@ -33,6 +33,7 @@
     "js-beautify": "1.14.11",
     "js-cookie": "3.0.5",
     "jsencrypt": "3.3.2",
+    "jszip": "^3.10.1",
     "nprogress": "0.2.0",
     "pinia": "2.1.7",
     "print-js": "^1.6.0",
diff --git a/src/views/invoiceCollaboration/components/BatchDownloadDialog.vue b/src/views/invoiceCollaboration/components/BatchDownloadDialog.vue
new file mode 100644
index 0000000..18e40a0
--- /dev/null
+++ b/src/views/invoiceCollaboration/components/BatchDownloadDialog.vue
@@ -0,0 +1,704 @@
+<template>
+  <el-dialog
+    :model-value="dialogVisible"
+    @update:model-value="$emit('update:dialogVisible', $event)"
+    title="鎵归噺涓嬭浇鍙戠エ"
+    width="800px"
+    :close-on-click-modal="false"
+    :close-on-press-escape="false"
+  >
+    <div class="batch-download-container">
+      <!-- 鍙戠エ鍒楄〃淇℃伅 -->
+      <el-card class="invoice-list" shadow="never">
+        <template #header>
+          <div class="card-header">
+            <span>寰呬笅杞藉彂绁ㄥ垪琛�</span>
+            <el-tag type="info" size="small" style="margin-left: 10px">
+              鍏� {{ invoices.length }} 寮犲彂绁�
+            </el-tag>
+          </div>
+        </template>
+        
+        <el-table :data="invoices" style="width: 100%" max-height="300">
+          <el-table-column prop="invoiceNo" label="鍙戠エ鍙风爜" width="120" />
+          <el-table-column prop="buyerName" label="璐拱鏂�" width="150" />
+          <el-table-column prop="amount" label="閲戦" width="100">
+            <template #default="scope">
+              楼{{ scope.row.amount.toFixed(2) }}
+            </template>
+          </el-table-column>
+          <el-table-column prop="status" label="鐘舵��" width="100">
+            <template #default="scope">
+              <el-tag :type="getStatusType(scope.row.status)" size="small">
+                {{ getStatusText(scope.row.status) }}
+              </el-tag>
+            </template>
+          </el-table-column>
+        </el-table>
+      </el-card>
+
+      <!-- 涓嬭浇閫夐」 -->
+      <el-card class="download-options" shadow="never">
+        <template #header>
+          <div class="card-header">涓嬭浇閫夐」</div>
+        </template>
+        
+        <el-form :model="downloadOptions" label-width="120px">
+                     <!-- 鏂囦欢鏍煎紡 -->
+           <el-form-item label="鏂囦欢鏍煎紡">
+             <el-radio-group v-model="downloadOptions.format">
+               <el-radio label="html">HTML鏍煎紡</el-radio>
+               <el-radio label="excel">Excel鏍煎紡</el-radio>
+               <el-radio label="zip">ZIP鍘嬬缉鍖�</el-radio>
+             </el-radio-group>
+           </el-form-item>
+
+          <!-- 涓嬭浇鍐呭 -->
+          <el-form-item label="涓嬭浇鍐呭">
+            <el-checkbox-group v-model="downloadOptions.content">
+              <el-checkbox label="invoice">鍙戠エ姝f湰</el-checkbox>
+              <el-checkbox label="details">鏄庣粏娓呭崟</el-checkbox>
+              <el-checkbox label="summary">姹囨�绘姤琛�</el-checkbox>
+            </el-checkbox-group>
+          </el-form-item>
+
+          <!-- 鏂囦欢鍛藉悕 -->
+          <el-form-item label="鏂囦欢鍛藉悕">
+            <el-select v-model="downloadOptions.naming" style="width: 100%">
+              <el-option label="鍙戠エ鍙风爜_璐拱鏂瑰悕绉�" value="invoice_buyer" />
+              <el-option label="鍙戠エ鍙风爜_鏃ユ湡" value="invoice_date" />
+              <el-option label="璐拱鏂瑰悕绉癬鏃ユ湡" value="buyer_date" />
+              <el-option label="鑷畾涔夊墠缂�" value="custom" />
+            </el-select>
+          </el-form-item>
+
+          <!-- 鑷畾涔夊墠缂� -->
+          <el-form-item v-if="downloadOptions.naming === 'custom'" label="鑷畾涔夊墠缂�">
+            <el-input v-model="downloadOptions.customPrefix" placeholder="璇疯緭鍏ユ枃浠跺墠缂�" />
+          </el-form-item>
+
+          <!-- 鍘嬬缉閫夐」 -->
+          <el-form-item label="鍘嬬缉閫夐」">
+            <el-checkbox v-model="downloadOptions.compress">鍚敤鍘嬬缉</el-checkbox>
+            <el-checkbox v-model="downloadOptions.password">璁剧疆瑙e帇瀵嗙爜</el-checkbox>
+          </el-form-item>
+
+          <!-- 瑙e帇瀵嗙爜 -->
+          <el-form-item v-if="downloadOptions.password" label="瑙e帇瀵嗙爜">
+            <el-input v-model="downloadOptions.extractPassword" placeholder="璇疯緭鍏ヨВ鍘嬪瘑鐮�" />
+          </el-form-item>
+        </el-form>
+      </el-card>
+
+      <!-- 涓嬭浇杩涘害 -->
+      <el-card v-if="downloading" class="download-progress" shadow="never">
+        <template #header>
+          <div class="card-header">涓嬭浇杩涘害</div>
+        </template>
+        
+        <div class="progress-content">
+          <el-progress 
+            :percentage="downloadProgress" 
+            :status="downloadProgress === 100 ? 'success' : ''"
+            :stroke-width="20"
+          />
+          <div class="progress-text">
+            {{ downloadProgress === 100 ? '涓嬭浇瀹屾垚' : `姝e湪涓嬭浇... ${downloadProgress}%` }}
+          </div>
+          <div class="progress-detail">
+            {{ downloadProgress === 100 ? '鎵�鏈夊彂绁ㄤ笅杞藉畬鎴�' : `宸蹭笅杞� ${downloadedCount} 寮狅紝鍓╀綑 ${invoices.length - downloadedCount} 寮燻 }}
+          </div>
+        </div>
+      </el-card>
+    </div>
+
+    <template #footer>
+      <div class="dialog-footer">
+        <el-button @click="handleClose" :disabled="downloading">鍙栨秷</el-button>
+        <el-button 
+          type="primary" 
+          @click="handleBatchDownload" 
+          :loading="downloading"
+          :disabled="!canDownload"
+        >
+          {{ downloading ? '涓嬭浇涓�...' : '寮�濮嬩笅杞�' }}
+        </el-button>
+      </div>
+    </template>
+  </el-dialog>
+</template>
+
+<script setup>
+import { ref, computed, watch } from 'vue';
+import { ElMessage } from 'element-plus';
+
+// 瀹氫箟props
+const props = defineProps({
+  dialogVisible: {
+    type: Boolean,
+    default: false
+  },
+  invoices: {
+    type: Array,
+    default: () => []
+  }
+});
+
+// 瀹氫箟emits
+const emit = defineEmits(['update:dialogVisible', 'success']);
+
+// 鍝嶅簲寮忔暟鎹�
+const downloading = ref(false);
+const downloadProgress = ref(0);
+const downloadedCount = ref(0);
+const downloadOptions = ref({
+  format: 'pdf',
+  content: ['invoice'],
+  naming: 'invoice_buyer',
+  customPrefix: '',
+  compress: true,
+  password: false,
+  extractPassword: ''
+});
+
+// 璁$畻灞炴��
+const canDownload = computed(() => {
+  return props.invoices.length > 0 && !downloading.value;
+});
+
+// 鐩戝惉鍣�
+watch(() => props.invoices, () => {
+  // 閲嶇疆涓嬭浇鐘舵��
+  downloading.value = false;
+  downloadProgress.value = 0;
+  downloadedCount.value = 0;
+}, { immediate: true });
+
+// 鑾峰彇鐘舵�佺被鍨�
+const getStatusType = (status) => {
+  const statusMap = {
+    'issued': 'success',
+    'pending': 'warning',
+    'cancelled': 'danger'
+  };
+  return statusMap[status] || 'info';
+};
+
+// 鑾峰彇鐘舵�佹枃鏈�
+const getStatusText = (status) => {
+  const statusMap = {
+    'issued': '宸插紑绁�',
+    'pending': '寰呭紑绁�',
+    'cancelled': '宸蹭綔搴�'
+  };
+  return statusMap[status] || '鏈煡';
+};
+
+// 鍏抽棴瀵硅瘽妗�
+const handleClose = () => {
+  if (!downloading.value) {
+    emit('update:dialogVisible', false);
+  }
+};
+
+// 鎵归噺涓嬭浇
+const handleBatchDownload = async () => {
+  if (downloading.value) return;
+  
+  try {
+    downloading.value = true;
+    downloadProgress.value = 0;
+    downloadedCount.value = 0;
+    
+    // 鎵归噺涓嬭浇杩囩▼
+    if (downloadOptions.format === 'zip') {
+      // ZIP鏍煎紡锛氱敓鎴愬崟涓帇缂╁寘
+      await generateZIPFile();
+      downloadProgress.value = 100;
+      downloadedCount.value = props.invoices.length;
+    } else {
+      // 鍏朵粬鏍煎紡锛氶�愪釜涓嬭浇鏂囦欢
+      const totalInvoices = props.invoices.length;
+      const progressStep = 100 / totalInvoices;
+      
+      for (let i = 0; i < totalInvoices; i++) {
+        // 鐢熸垚鍗曚釜鍙戠エ鏂囦欢
+        await generateInvoiceFile(props.invoices[i], i);
+        
+        downloadedCount.value++;
+        downloadProgress.value = Math.round((i + 1) * progressStep);
+        
+        // 鐭殏寤惰繜锛岄伩鍏嶆祻瑙堝櫒闃诲
+        await new Promise(resolve => setTimeout(resolve, 200));
+      }
+      
+      // 鐢熸垚姹囨�绘枃浠�
+      if (downloadOptions.content.includes('summary')) {
+        await generateSummaryFile();
+      }
+    }
+    
+    // 涓嬭浇瀹屾垚
+    ElMessage.success(`鎴愬姛涓嬭浇 ${totalInvoices} 寮犲彂绁╜);
+    emit('success');
+    
+  } catch (error) {
+    console.error('鎵归噺涓嬭浇澶辫触:', error);
+    ElMessage.error("鎵归噺涓嬭浇澶辫触锛岃閲嶈瘯");
+    downloading.value = false;
+    downloadProgress.value = 0;
+    downloadedCount.value = 0;
+  }
+};
+
+// 鐢熸垚鍗曚釜鍙戠エ鏂囦欢
+const generateInvoiceFile = async (invoice, index) => {
+  try {
+    let fileContent, fileName, mimeType;
+    
+         if (downloadOptions.format === 'html') {
+       fileContent = generateHTMLContent(invoice);
+       fileName = `${getFileName(invoice, index)}.html`;
+       mimeType = 'text/html';
+     } else if (downloadOptions.content.includes('details')) {
+       fileContent = generateExcelContent(invoice);
+       fileName = `${getFileName(invoice, index)}.csv`;
+       mimeType = 'text/csv';
+     } else if (downloadOptions.format === 'excel') {
+      fileContent = generateExcelContent(invoice);
+      fileName = `${getFileName(invoice, index)}.csv`;
+      mimeType = 'text/csv';
+    } else if (downloadOptions.format === 'zip') {
+      // ZIP鏍煎紡闇�瑕佺壒娈婂鐞嗭紝杩欓噷鍏堣烦杩�
+      return;
+    }
+
+    // 鍒涘缓Blob瀵硅薄
+    const blob = new Blob([fileContent], { type: mimeType });
+    
+    // 鍒涘缓涓嬭浇閾炬帴
+    const url = window.URL.createObjectURL(blob);
+    const link = document.createElement('a');
+    link.href = url;
+    link.download = fileName;
+    
+    // 瑙﹀彂涓嬭浇
+    document.body.appendChild(link);
+    link.click();
+    
+    // 娓呯悊
+    document.body.removeChild(link);
+    window.URL.revokeObjectURL(url);
+    
+  } catch (error) {
+    console.error(`鐢熸垚鍙戠エ鏂囦欢澶辫触: ${invoice.invoiceNo}`, error);
+  }
+};
+
+// 鐢熸垚ZIP鍘嬬缉鍖�
+const generateZIPFile = async () => {
+  try {
+    // 鍔ㄦ�佸鍏SZip搴�
+    const JSZip = await import('jszip');
+    const zip = new JSZip.default();
+    
+    // 娣诲姞鍙戠エ鏂囦欢鍒癦IP
+    props.invoices.forEach((invoice, index) => {
+      let fileContent, fileName;
+      
+             if (downloadOptions.content.includes('invoice')) {
+         if (downloadOptions.content.includes('details')) {
+           fileContent = generateExcelContent(invoice);
+           fileName = `${getFileName(invoice, index)}.csv`;
+         } else {
+           fileContent = generateHTMLContent(invoice);
+           fileName = `${getFileName(invoice, index)}.html`;
+         }
+         zip.file(fileName, fileContent);
+       }
+    });
+    
+    // 娣诲姞姹囨�绘枃浠�
+    if (downloadOptions.content.includes('summary')) {
+      const summaryContent = generateSummaryContent();
+      zip.file('鍙戠エ姹囨��.csv', summaryContent);
+    }
+    
+    // 鐢熸垚ZIP鏂囦欢
+    const zipBlob = await zip.generateAsync({ 
+      type: 'blob',
+      compression: downloadOptions.compress ? 'DEFLATE' : 'STORE'
+    });
+    
+    // 涓嬭浇ZIP鏂囦欢
+    const fileName = `鍙戠エ鎵归噺涓嬭浇_${new Date().toISOString().split('T')[0]}.zip`;
+    const url = window.URL.createObjectURL(zipBlob);
+    const link = document.createElement('a');
+    link.href = url;
+    link.download = fileName;
+    
+    document.body.appendChild(link);
+    link.click();
+    
+    document.body.removeChild(link);
+    window.URL.revokeObjectURL(url);
+    
+  } catch (error) {
+    console.error('鐢熸垚ZIP鏂囦欢澶辫触:', error);
+    ElMessage.error('ZIP鏂囦欢鐢熸垚澶辫触锛岃妫�鏌ユ槸鍚﹀畨瑁呬簡jszip搴�');
+  }
+};
+
+// 鐢熸垚姹囨�绘枃浠�
+const generateSummaryFile = async () => {
+  try {
+    const summaryContent = generateSummaryContent();
+    const fileName = `鍙戠エ姹囨�籣${new Date().toISOString().split('T')[0]}.csv`;
+    
+    const blob = new Blob([summaryContent], { type: 'text/csv;charset=utf-8;' });
+    const url = window.URL.createObjectURL(blob);
+    const link = document.createElement('a');
+    link.href = url;
+    link.download = fileName;
+    
+    document.body.appendChild(link);
+    link.click();
+    
+    document.body.removeChild(link);
+    window.URL.revokeObjectURL(url);
+    
+  } catch (error) {
+    console.error('鐢熸垚姹囨�绘枃浠跺け璐�:', error);
+  }
+};
+
+// 鑾峰彇鏂囦欢鍚�
+const getFileName = (invoice, index) => {
+  let fileName = '';
+  
+  if (downloadOptions.naming === 'invoice_buyer') {
+    fileName = `${invoice.invoiceNo}_${invoice.buyerName}`;
+  } else if (downloadOptions.naming === 'invoice_date') {
+    fileName = `${invoice.invoiceNo}_${invoice.invoiceDate}`;
+  } else if (downloadOptions.naming === 'buyer_date') {
+    fileName = `${invoice.buyerName}_${invoice.invoiceDate}`;
+  } else if (downloadOptions.naming === 'custom') {
+    fileName = `${downloadOptions.customPrefix || '鍙戠エ'}_${index + 1}`;
+  }
+  
+  // 娓呯悊鏂囦欢鍚嶄腑鐨勭壒娈婂瓧绗�
+  return fileName.replace(/[<>:"/\\|?*]/g, '_');
+};
+
+// 鐢熸垚HTML鍐呭
+const generateHTMLContent = (invoice) => {
+  const content = `<!DOCTYPE html>
+<html lang="zh-CN">
+<head>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title>鍙戠エ淇℃伅 - ${invoice.invoiceNo || 'N/A'}</title>
+    <style>
+        body {
+            font-family: 'Microsoft YaHei', Arial, sans-serif;
+            margin: 0;
+            padding: 20px;
+            background-color: #f5f5f5;
+        }
+        .invoice-container {
+            max-width: 800px;
+            margin: 0 auto;
+            background: white;
+            border-radius: 8px;
+            box-shadow: 0 2px 10px rgba(0,0,0,0.1);
+            overflow: hidden;
+        }
+        .invoice-header {
+            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
+            color: white;
+            padding: 30px;
+            text-align: center;
+        }
+        .invoice-header h1 {
+            margin: 0;
+            font-size: 28px;
+            font-weight: 300;
+        }
+        .invoice-header .subtitle {
+            margin-top: 10px;
+            opacity: 0.9;
+            font-size: 16px;
+        }
+        .invoice-content {
+            padding: 30px;
+        }
+        .info-section {
+            margin-bottom: 25px;
+        }
+        .info-section h3 {
+            color: #333;
+            border-bottom: 2px solid #667eea;
+            padding-bottom: 8px;
+            margin-bottom: 15px;
+        }
+        .info-grid {
+            display: grid;
+            grid-template-columns: 1fr 1fr;
+            gap: 15px;
+        }
+        .info-item {
+            display: flex;
+            align-items: center;
+            padding: 12px;
+            background: #f8f9fa;
+            border-radius: 6px;
+            border-left: 4px solid #667eea;
+        }
+        .info-label {
+            font-weight: bold;
+            color: #555;
+            min-width: 100px;
+        }
+        .info-value {
+            color: #333;
+            margin-left: 10px;
+        }
+        .amount-section {
+            background: #f8f9fa;
+            padding: 20px;
+            border-radius: 8px;
+            margin-top: 20px;
+        }
+        .amount-grid {
+            display: grid;
+            grid-template-columns: repeat(3, 1fr);
+            gap: 20px;
+        }
+        .amount-item {
+            text-align: center;
+            padding: 15px;
+            background: white;
+            border-radius: 6px;
+            box-shadow: 0 1px 3px rgba(0,0,0,0.1);
+        }
+        .amount-label {
+            font-size: 14px;
+            color: #666;
+            margin-bottom: 8px;
+        }
+        .amount-value {
+            font-size: 24px;
+            font-weight: bold;
+            color: #667eea;
+        }
+        .footer {
+            text-align: center;
+            padding: 20px;
+            color: #666;
+            border-top: 1px solid #eee;
+            margin-top: 20px;
+        }
+        @media print {
+            body { background: white; }
+            .invoice-container { box-shadow: none; }
+        }
+    </style>
+</head>
+<body>
+    <div class="invoice-container">
+        <div class="invoice-header">
+            <h1>鍙戠エ淇℃伅</h1>
+            <div class="subtitle">Invoice Information</div>
+        </div>
+        
+        <div class="invoice-content">
+            <div class="info-section">
+                <h3>鍩烘湰淇℃伅</h3>
+                <div class="info-grid">
+                    <div class="info-item">
+                        <span class="info-label">鍙戠エ鍙风爜:</span>
+                        <span class="info-value">${invoice.invoiceNo || 'N/A'}</span>
+                    </div>
+                    <div class="info-item">
+                        <span class="info-label">鍙戠エ浠g爜:</span>
+                        <span class="info-value">${invoice.invoiceCode || 'N/A'}</span>
+                    </div>
+                    <div class="info-item">
+                        <span class="info-label">寮�绁ㄦ棩鏈�:</span>
+                        <span class="info-value">${invoice.invoiceDate || 'N/A'}</span>
+                    </div>
+                    <div class="info-item">
+                        <span class="info-label">鐘舵��:</span>
+                        <span class="info-value">${getStatusText(invoice.status)}</span>
+                    </div>
+                </div>
+            </div>
+            
+            <div class="info-section">
+                <h3>璐拱鏂逛俊鎭�</h3>
+                <div class="info-grid">
+                    <div class="info-item">
+                        <span class="info-label">璐拱鏂瑰悕绉�:</span>
+                        <span class="info-value">${invoice.buyerName || 'N/A'}</span>
+                    </div>
+                    <div class="info-item">
+                        <span class="info-label">璐拱鏂圭◣鍙�:</span>
+                        <span class="info-value">${invoice.buyerTaxNo || 'N/A'}</span>
+                    </div>
+                    <div class="info-item">
+                        <span class="info-label">璐拱鏂瑰湴鍧�:</span>
+                        <span class="info-value">${invoice.buyerAddress || 'N/A'}</span>
+                    </div>
+                    <div class="info-item">
+                        <span class="info-label">閾惰璐︽埛:</span>
+                        <span class="info-value">${invoice.buyerBankAccount || 'N/A'}</span>
+                    </div>
+                </div>
+            </div>
+            
+            <div class="info-section">
+                <h3>閿�鍞柟淇℃伅</h3>
+                <div class="info-grid">
+                    <div class="info-item">
+                        <span class="info-label">閿�鍞柟鍚嶇О:</span>
+                        <span class="info-value">${invoice.sellerName || 'N/A'}</span>
+                    </div>
+                    <div class="info-item">
+                        <span class="info-label">閿�鍞柟绋庡彿:</span>
+                        <span class="info-value">${invoice.sellerTaxNo || 'N/A'}</span>
+                    </div>
+                    <div class="info-item">
+                        <span class="info-label">閿�鍞柟鍦板潃:</span>
+                        <span class="info-value">${invoice.sellerAddress || 'N/A'}</span>
+                    </div>
+                    <div class="info-item">
+                        <span class="info-label">閾惰璐︽埛:</span>
+                        <span class="info-value">${invoice.sellerBankAccount || 'N/A'}</span>
+                    </div>
+                </div>
+            </div>
+            
+            <div class="amount-section">
+                <h3>閲戦淇℃伅</h3>
+                <div class="amount-grid">
+                    <div class="amount-item">
+                        <div class="amount-label">閲戦</div>
+                        <div class="amount-value">楼${(invoice.amount || 0).toFixed(2)}</div>
+                    </div>
+                    <div class="info-item">
+                        <div class="amount-label">绋庨</div>
+                        <div class="amount-value">楼${(invoice.taxAmount || 0).toFixed(2)}</div>
+                    </div>
+                    <div class="amount-item">
+                        <div class="amount-label">浠风◣鍚堣</div>
+                        <div class="amount-value">楼${(invoice.totalAmount || 0).toFixed(2)}</div>
+                    </div>
+                </div>
+            </div>
+            
+            <div class="footer">
+                <p>鐢熸垚鏃堕棿: ${new Date().toLocaleString()}</p>
+                <p>姝ゆ枃浠剁敱绯荤粺鑷姩鐢熸垚</p>
+            </div>
+        </div>
+    </div>
+</body>
+</html>`;
+  
+  return content;
+};
+
+// 鐢熸垚Excel鍐呭
+const generateExcelContent = (invoice) => {
+  const content = `鍙戠エ淇℃伅
+鍙戠エ鍙风爜,${invoice.invoiceNo || 'N/A'}
+鍙戠エ浠g爜,${invoice.invoiceCode || 'N/A'}
+寮�绁ㄦ棩鏈�,${invoice.invoiceDate || 'N/A'}
+璐拱鏂瑰悕绉�,${invoice.buyerName || 'N/A'}
+閿�鍞柟鍚嶇О,${invoice.sellerName || 'N/A'}
+閲戦,${(invoice.amount || 0).toFixed(2)}
+绋庨,${(invoice.taxAmount || 0).toFixed(2)}
+浠风◣鍚堣,${(invoice.totalAmount || 0).toFixed(2)}
+鐘舵��,${getStatusText(invoice.status)}
+鍒涘缓鏃堕棿,${invoice.createTime || 'N/A'}`;
+  return content;
+};
+
+// 鐢熸垚姹囨�诲唴瀹�
+const generateSummaryContent = () => {
+  let content = '鍙戠エ姹囨�绘姤琛╘n';
+  content += '鍙戠エ鍙风爜,鍙戠エ浠g爜,寮�绁ㄦ棩鏈�,璐拱鏂瑰悕绉�,閿�鍞柟鍚嶇О,閲戦,绋庨,浠风◣鍚堣,鐘舵��,鍒涘缓鏃堕棿\n';
+  
+  props.invoices.forEach(invoice => {
+    content += `${invoice.invoiceNo || 'N/A'},${invoice.invoiceCode || 'N/A'},${invoice.invoiceDate || 'N/A'},${invoice.buyerName || 'N/A'},${invoice.sellerName || 'N/A'},${(invoice.amount || 0).toFixed(2)},${(invoice.taxAmount || 0).toFixed(2)},${(invoice.totalAmount || 0).toFixed(2)},${getStatusText(invoice.status)},${invoice.createTime || 'N/A'}\n`;
+  });
+  
+  // 娣诲姞鍚堣琛�
+  const totalAmount = props.invoices.reduce((sum, item) => sum + (item.amount || 0), 0);
+  const totalTaxAmount = props.invoices.reduce((sum, item) => sum + (item.taxAmount || 0), 0);
+  const totalSum = props.invoices.reduce((sum, item) => sum + (item.totalAmount || 0), 0);
+  
+  content += `鍚堣,,,,,${totalAmount.toFixed(2)},${totalTaxAmount.toFixed(2)},${totalSum.toFixed(2)},,`;
+  
+  return content;
+};
+</script>
+
+<style scoped>
+.batch-download-container {
+  padding: 0;
+}
+
+.invoice-list,
+.download-options,
+.download-progress {
+  margin-bottom: 20px;
+}
+
+.invoice-list:last-child,
+.download-options:last-child,
+.download-progress:last-child {
+  margin-bottom: 0;
+}
+
+.card-header {
+  font-weight: bold;
+  font-size: 16px;
+  display: flex;
+  align-items: center;
+}
+
+.progress-content {
+  padding: 20px 0;
+  text-align: center;
+}
+
+.progress-text {
+  margin-top: 15px;
+  font-size: 16px;
+  font-weight: bold;
+  color: #409eff;
+}
+
+.progress-detail {
+  margin-top: 10px;
+  color: #606266;
+  font-size: 14px;
+}
+
+.dialog-footer {
+  text-align: right;
+}
+
+.el-radio-group {
+  display: flex;
+  flex-direction: column;
+  gap: 10px;
+}
+
+.el-checkbox-group {
+  display: flex;
+  flex-direction: column;
+  gap: 10px;
+}
+</style>
diff --git a/src/views/invoiceCollaboration/components/DownloadDialog.vue b/src/views/invoiceCollaboration/components/DownloadDialog.vue
new file mode 100644
index 0000000..bd0ade3
--- /dev/null
+++ b/src/views/invoiceCollaboration/components/DownloadDialog.vue
@@ -0,0 +1,580 @@
+<template>
+  <el-dialog
+    :model-value="dialogVisible"
+    @update:model-value="$emit('update:dialogVisible', $event)"
+    title="涓嬭浇鍙戠エ"
+    width="600px"
+    :close-on-click-modal="false"
+  >
+    <div class="download-container">
+      <!-- 鍙戠エ淇℃伅 -->
+      <el-card class="invoice-info" shadow="never">
+        <template #header>
+          <div class="card-header">
+            <span>鍙戠エ淇℃伅</span>
+          </div>
+        </template>
+        
+        <el-descriptions :column="2" border>
+          <el-descriptions-item label="鍙戠エ鍙风爜">{{ invoice.invoiceNo || '-' }}</el-descriptions-item>
+          <el-descriptions-item label="鍙戠エ浠g爜">{{ invoice.invoiceCode || '-' }}</el-descriptions-item>
+          <el-descriptions-item label="寮�绁ㄦ棩鏈�">{{ invoice.invoiceDate || '-' }}</el-descriptions-item>
+          <el-descriptions-item label="璐拱鏂�">{{ invoice.buyerName || '-' }}</el-descriptions-item>
+          <el-descriptions-item label="閲戦">{{ (invoice.amount || 0).toFixed(2) }} 鍏�</el-descriptions-item>
+          <el-descriptions-item label="浠风◣鍚堣">{{ (invoice.totalAmount || 0).toFixed(2) }} 鍏�</el-descriptions-item>
+        </el-descriptions>
+      </el-card>
+
+      <!-- 涓嬭浇閫夐」 -->
+      <el-card class="download-options" shadow="never">
+        <template #header>
+          <div class="card-header">
+            <span>涓嬭浇閫夐」</span>
+          </div>
+        </template>
+        
+        <el-form :model="downloadOptions" label-width="120px">
+          <el-form-item label="鏂囦欢鏍煎紡">
+            <el-radio-group v-model="downloadOptions.format">
+              <el-radio label="pdf">PDF鏍煎紡</el-radio>
+              <el-radio label="excel">Excel鏍煎紡</el-radio>
+              <el-radio label="image">鍥剧墖鏍煎紡</el-radio>
+              <el-radio label="zip">ZIP鍘嬬缉鍖�</el-radio>
+            </el-radio-group>
+          </el-form-item>
+          
+          <el-form-item label="鍖呭惈鍐呭">
+            <el-checkbox-group v-model="downloadOptions.content">
+              <el-checkbox label="basic">鍩烘湰淇℃伅</el-checkbox>
+              <el-checkbox label="buyer">璐拱鏂逛俊鎭�</el-checkbox>
+              <el-checkbox label="seller">閿�鍞柟淇℃伅</el-checkbox>
+              <el-checkbox label="items">鍟嗗搧鏄庣粏</el-checkbox>
+              <el-checkbox label="summary">鍚堣淇℃伅</el-checkbox>
+            </el-checkbox-group>
+          </el-form-item>
+          
+          <el-form-item label="鏂囦欢鍛藉悕">
+            <el-input
+              v-model="downloadOptions.fileName"
+              placeholder="璇疯緭鍏ユ枃浠跺悕锛堜笉鍖呭惈鎵╁睍鍚嶏級"
+              style="width: 100%"
+            />
+          </el-form-item>
+          
+          <el-form-item label="姘村嵃璁剧疆">
+            <el-switch
+              v-model="downloadOptions.watermark"
+              active-text="娣诲姞姘村嵃"
+              inactive-text="鏃犳按鍗�"
+            />
+          </el-form-item>
+          
+          <el-form-item label="鍘嬬缉璁剧疆" v-if="downloadOptions.format === 'image'">
+            <el-select v-model="downloadOptions.compression" placeholder="閫夋嫨鍘嬬缉璐ㄩ噺" style="width: 100%">
+              <el-option label="楂樿川閲忥紙鏂囦欢杈冨ぇ锛�" value="high" />
+              <el-option label="涓瓑璐ㄩ噺" value="medium" />
+              <el-option label="浣庤川閲忥紙鏂囦欢杈冨皬锛�" value="low" />
+            </el-select>
+          </el-form-item>
+        </el-form>
+      </el-card>
+
+      <!-- 涓嬭浇杩涘害 -->
+      <el-card v-if="downloading" class="download-progress" shadow="never">
+        <template #header>
+          <div class="card-header">
+            <span>涓嬭浇杩涘害</span>
+          </div>
+        </template>
+        
+        <div class="progress-content">
+          <el-progress
+            :percentage="downloadProgress"
+            :status="downloadProgress === 100 ? 'success' : ''"
+            :stroke-width="20"
+          />
+          <div class="progress-text">
+            {{ downloadProgress === 100 ? '涓嬭浇瀹屾垚' : `姝e湪涓嬭浇... ${downloadProgress}%` }}
+          </div>
+          <div class="progress-detail" v-if="downloadProgress < 100">
+            <span>姝e湪鐢熸垚{{ getFormatText(downloadOptions.format) }}鏂囦欢...</span>
+          </div>
+        </div>
+      </el-card>
+    </div>
+
+    <template #footer>
+      <div class="dialog-footer">
+        <el-button @click="handleClose" :disabled="downloading">鍙栨秷</el-button>
+        <el-button 
+          type="primary" 
+          @click="handleDownload" 
+          :loading="downloading"
+          :disabled="!canDownload"
+        >
+          {{ downloading ? '涓嬭浇涓�...' : '寮�濮嬩笅杞�' }}
+        </el-button>
+      </div>
+    </template>
+  </el-dialog>
+</template>
+
+<script setup>
+import { ref, reactive, computed, watch } from "vue";
+import { ElMessage } from "element-plus";
+
+// Props
+const props = defineProps({
+  dialogVisible: {
+    type: Boolean,
+    default: false
+  },
+  invoice: {
+    type: Object,
+    default: () => ({})
+  }
+});
+
+// Emits
+const emit = defineEmits(['update:dialogVisible', 'success']);
+
+// 鍝嶅簲寮忔暟鎹�
+const downloading = ref(false);
+const downloadProgress = ref(0);
+
+// 涓嬭浇閫夐」
+const downloadOptions = reactive({
+  format: 'pdf',
+  content: ['basic', 'buyer', 'seller', 'items', 'summary'],
+  fileName: '',
+  watermark: true,
+  compression: 'medium'
+});
+
+// 璁$畻灞炴��
+const canDownload = computed(() => {
+  return downloadOptions.content.length > 0 && downloadOptions.fileName.trim() !== '';
+});
+
+// 鐩戝惉鍙戠エ鍙樺寲锛岃嚜鍔ㄨ缃枃浠跺悕
+watch(() => props.invoice, (newInvoice) => {
+  if (newInvoice && newInvoice.invoiceNo) {
+    downloadOptions.fileName = `${newInvoice.invoiceNo}_${newInvoice.invoiceDate}`;
+  }
+}, { immediate: true });
+
+// 鑾峰彇鏍煎紡鏂囨湰
+const getFormatText = (format) => {
+  const formatMap = {
+    pdf: 'PDF',
+    excel: 'Excel',
+    image: '鍥剧墖'
+  };
+  return formatMap[format] || format;
+};
+
+// 鍏抽棴瀵硅瘽妗�
+const handleClose = () => {
+  if (downloading.value) {
+    ElMessage.warning("涓嬭浇杩涜涓紝璇风瓑寰呭畬鎴�");
+    return;
+  }
+  emit('update:dialogVisible', false);
+  // 閲嶇疆鐘舵��
+  downloading.value = false;
+  downloadProgress.value = 0;
+};
+
+// 寮�濮嬩笅杞�
+const handleDownload = async () => {
+  if (!canDownload.value) {
+    ElMessage.warning("璇峰畬鍠勪笅杞介�夐」");
+    return;
+  }
+
+  downloading.value = true;
+  downloadProgress.value = 0;
+
+  try {
+    // 妯℃嫙涓嬭浇杩囩▼
+    const steps = [
+      { progress: 20, message: "姝e湪楠岃瘉鍙戠エ淇℃伅..." },
+      { progress: 40, message: "姝e湪鐢熸垚鏂囦欢鍐呭..." },
+      { progress: 60, message: "姝e湪搴旂敤鏍煎紡璁剧疆..." },
+      { progress: 80, message: "姝e湪鐢熸垚鏂囦欢..." },
+      { progress: 100, message: "涓嬭浇瀹屾垚" }
+    ];
+
+    for (let i = 0; i < steps.length; i++) {
+      const step = steps[i];
+      await new Promise(resolve => {
+        setTimeout(() => {
+          downloadProgress.value = step.progress;
+          resolve();
+        }, 800);
+      });
+    }
+
+    // 鐢熸垚鐪熷疄鐨勬枃浠跺苟涓嬭浇
+    await generateAndDownloadFile();
+
+  } catch (error) {
+    ElMessage.error("涓嬭浇澶辫触锛岃閲嶈瘯");
+    downloading.value = false;
+    downloadProgress.value = 0;
+  }
+};
+
+// 鐢熸垚骞朵笅杞芥枃浠�
+const generateAndDownloadFile = async () => {
+  try {
+    let fileContent, fileName, mimeType;
+    
+    if (downloadOptions.format === 'pdf') {
+      // 鐢熸垚PDF鍐呭锛堟ā鎷燂級
+      fileContent = generatePDFContent();
+      fileName = `${downloadOptions.fileName}.pdf`;
+      mimeType = 'application/pdf';
+    } else if (downloadOptions.format === 'excel') {
+      // 鐢熸垚Excel鍐呭锛圕SV鏍煎紡锛屽吋瀹规�ф洿濂斤級
+      fileContent = generateExcelContent();
+      fileName = `${downloadOptions.fileName}.csv`;
+      mimeType = 'text/csv';
+    } else if (downloadOptions.format === 'image') {
+      // 鐢熸垚鍥剧墖鍐呭锛圫VG鏍煎紡锛�
+      fileContent = generateImageContent();
+      fileName = `${downloadOptions.fileName}.svg`;
+      mimeType = 'image/svg+xml';
+    } else if (downloadOptions.format === 'zip') {
+      // 鐢熸垚ZIP鍘嬬缉鍖�
+      await generateZIPFile();
+      return; // ZIP涓嬭浇瀹屾垚鍚庣洿鎺ヨ繑鍥�
+    }
+
+    // 鍒涘缓Blob瀵硅薄
+    const blob = new Blob([fileContent], { type: mimeType });
+    
+    // 鍒涘缓涓嬭浇閾炬帴
+    const url = window.URL.createObjectURL(blob);
+    const link = document.createElement('a');
+    link.href = url;
+    link.download = fileName;
+    
+    // 瑙﹀彂涓嬭浇
+    document.body.appendChild(link);
+    link.click();
+    
+    // 娓呯悊
+    document.body.removeChild(link);
+    window.URL.revokeObjectURL(url);
+    
+    ElMessage.success(`鍙戠エ涓嬭浇鎴愬姛锛佹枃浠跺悕锛�${fileName}`);
+    emit('success');
+    
+    // 寤惰繜鍏抽棴瀵硅瘽妗�
+    setTimeout(() => {
+      handleClose();
+    }, 1500);
+
+  } catch (error) {
+    console.error('鏂囦欢鐢熸垚澶辫触:', error);
+    ElMessage.error("鏂囦欢鐢熸垚澶辫触锛岃閲嶈瘯");
+  }
+};
+
+// 鐢熸垚ZIP鍘嬬缉鍖�
+const generateZIPFile = async () => {
+  try {
+    // 鍔ㄦ�佸鍏SZip搴�
+    const JSZip = await import('jszip');
+    const zip = new JSZip.default();
+    
+    // 鏍规嵁閫夋嫨鐨勫唴瀹规坊鍔犳枃浠跺埌ZIP
+    if (downloadOptions.content.includes('basic')) {
+      const basicContent = generateBasicContent();
+      zip.file('鍩烘湰淇℃伅.csv', basicContent);
+    }
+    
+    if (downloadOptions.content.includes('buyer')) {
+      const buyerContent = generateBuyerContent();
+      zip.file('璐拱鏂逛俊鎭�.csv', buyerContent);
+    }
+    
+    if (downloadOptions.content.includes('seller')) {
+      const sellerContent = generateSellerContent();
+      zip.file('閿�鍞柟淇℃伅.csv', sellerContent);
+    }
+    
+    if (downloadOptions.content.includes('items')) {
+      const itemsContent = generateItemsContent();
+      zip.file('鍟嗗搧鏄庣粏.csv', itemsContent);
+    }
+    
+    if (downloadOptions.content.includes('summary')) {
+      const summaryContent = generateSummaryContent();
+      zip.file('鍚堣淇℃伅.csv', summaryContent);
+    }
+    
+    // 鐢熸垚ZIP鏂囦欢
+    const zipBlob = await zip.generateAsync({ 
+      type: 'blob',
+      compression: 'DEFLATE'
+    });
+    
+    // 涓嬭浇ZIP鏂囦欢
+    const fileName = `${downloadOptions.fileName}.zip`;
+    const url = window.URL.createObjectURL(zipBlob);
+    const link = document.createElement('a');
+    link.href = url;
+    link.download = fileName;
+    
+    document.body.appendChild(link);
+    link.click();
+    
+    document.body.removeChild(link);
+    window.URL.revokeObjectURL(url);
+    
+    ElMessage.success(`鍙戠エ涓嬭浇鎴愬姛锛佹枃浠跺悕锛�${fileName}`);
+    emit('success');
+    
+    // 寤惰繜鍏抽棴瀵硅瘽妗�
+    setTimeout(() => {
+      handleClose();
+    }, 1500);
+    
+  } catch (error) {
+    console.error('ZIP鏂囦欢鐢熸垚澶辫触:', error);
+    ElMessage.error('ZIP鏂囦欢鐢熸垚澶辫触锛岃妫�鏌ユ槸鍚﹀畨瑁呬簡jszip搴�');
+  }
+};
+
+// 鐢熸垚PDF鍐呭锛堟ā鎷燂級
+const generatePDFContent = () => {
+  const invoice = props.invoice;
+  const content = `
+%PDF-1.4
+1 0 obj
+<<
+/Type /Catalog
+/Pages 2 0 R
+>>
+endobj
+
+2 0 obj
+<<
+/Type /Pages
+/Kids [3 0 R]
+/Count 1
+>>
+endobj
+
+3 0 obj
+<<
+/Type /Page
+/Parent 2 0 R
+/MediaBox [0 0 612 792]
+/Contents 4 0 R
+>>
+endobj
+
+4 0 obj
+<<
+/Length 200
+>>
+stream
+BT
+/F1 12 Tf
+72 720 Td
+(鍙戠エ鍙风爜: ${invoice.invoiceNo || 'N/A'}) Tj
+0 -20 Td
+(寮�绁ㄦ棩鏈�: ${invoice.invoiceDate || 'N/A'}) Tj
+0 -20 Td
+(璐拱鏂�: ${invoice.buyerName || 'N/A'}) Tj
+0 -20 Td
+(閲戦: ${(invoice.amount || 0).toFixed(2)} 鍏�) Tj
+0 -20 Td
+(浠风◣鍚堣: ${(invoice.totalAmount || 0).toFixed(2)} 鍏�) Tj
+ET
+endstream
+endobj
+
+xref
+0 5
+0000000000 65535 f 
+0000000009 00000 n 
+0000000058 00000 n 
+0000000115 00000 n 
+0000000204 00000 n 
+trailer
+<<
+/Size 5
+/Root 1 0 R
+>>
+startxref
+295
+%%EOF
+  `;
+  return content;
+};
+
+// 鐢熸垚Excel鍐呭锛圕SV鏍煎紡锛�
+const generateExcelContent = () => {
+  const invoice = props.invoice;
+  const content = `鍙戠エ淇℃伅
+鍙戠エ鍙风爜,${invoice.invoiceNo || 'N/A'}
+鍙戠エ浠g爜,${invoice.invoiceCode || 'N/A'}
+寮�绁ㄦ棩鏈�,${invoice.invoiceDate || 'N/A'}
+璐拱鏂瑰悕绉�,${invoice.buyerName || 'N/A'}
+閿�鍞柟鍚嶇О,${invoice.sellerName || 'N/A'}
+閲戦,${(invoice.amount || 0).toFixed(2)}
+绋庨,${(invoice.taxAmount || 0).toFixed(2)}
+浠风◣鍚堣,${(invoice.totalAmount || 0).toFixed(2)}
+鐘舵��,${getStatusText(invoice.status)}
+鍒涘缓鏃堕棿,${invoice.createTime || 'N/A'}`;
+  return content;
+};
+
+// 鐢熸垚鍥剧墖鍐呭锛圫VG鏍煎紡锛�
+const generateImageContent = () => {
+  const invoice = props.invoice;
+  const content = `<?xml version="1.0" encoding="UTF-8"?>
+<svg width="600" height="400" xmlns="http://www.w3.org/2000/svg">
+  <rect width="600" height="400" fill="white" stroke="black" stroke-width="2"/>
+  <text x="20" y="40" font-family="Arial" font-size="24" fill="black">鍙戠エ</text>
+  <text x="20" y="80" font-family="Arial" font-size="16" fill="black">鍙戠エ鍙风爜: ${invoice.invoiceNo || 'N/A'}</text>
+  <text x="20" y="110" font-family="Arial" font-size="16" fill="black">寮�绁ㄦ棩鏈�: ${invoice.invoiceDate || 'N/A'}</text>
+  <text x="20" y="140" font-family="Arial" font-size="16" fill="black">璐拱鏂�: ${invoice.buyerName || 'N/A'}</text>
+  <text x="20" y="170" font-family="Arial" font-size="16" fill="black">閲戦: ${(invoice.amount || 0).toFixed(2)} 鍏�</text>
+  <text x="20" y="200" font-family="Arial" font-size="16" fill="black">浠风◣鍚堣: ${(invoice.totalAmount || 0).toFixed(2)} 鍏�</text>
+  <text x="20" y="230" font-family="Arial" font-size="16" fill="black">鐘舵��: ${getStatusText(invoice.status)}</text>
+</svg>`;
+  return content;
+};
+
+// 鑾峰彇鐘舵�佹枃鏈�
+const getStatusText = (status) => {
+  const statusMap = {
+    'draft': '鑽夌',
+    'pending': '寰呭紑绁�',
+    'issuing': '寮�绁ㄤ腑',
+    'issued': '宸插紑绁�',
+    'failed': '寮�绁ㄥけ璐�',
+    'cancelled': '宸蹭綔搴�'
+  };
+  return statusMap[status] || status;
+};
+
+// 鐢熸垚鍩烘湰淇℃伅鍐呭
+const generateBasicContent = () => {
+  const invoice = props.invoice;
+  return `鍩烘湰淇℃伅
+鍙戠エ鍙风爜,${invoice.invoiceNo || 'N/A'}
+鍙戠エ浠g爜,${invoice.invoiceCode || 'N/A'}
+寮�绁ㄦ棩鏈�,${invoice.invoiceDate || 'N/A'}
+鐘舵��,${getStatusText(invoice.status)}
+鍒涘缓鏃堕棿,${invoice.createTime || 'N/A'}`;
+};
+
+// 鐢熸垚璐拱鏂逛俊鎭唴瀹�
+const generateBuyerContent = () => {
+  const invoice = props.invoice;
+  return `璐拱鏂逛俊鎭�
+璐拱鏂瑰悕绉�,${invoice.buyerName || 'N/A'}
+璐拱鏂圭◣鍙�,${invoice.buyerTaxNo || 'N/A'}
+璐拱鏂瑰湴鍧�,${invoice.buyerAddress || 'N/A'}
+璐拱鏂归摱琛岃处鎴�,${invoice.buyerBankAccount || 'N/A'}`;
+};
+
+// 鐢熸垚閿�鍞柟淇℃伅鍐呭
+const generateSellerContent = () => {
+  const invoice = props.invoice;
+  return `閿�鍞柟淇℃伅
+閿�鍞柟鍚嶇О,${invoice.sellerName || 'N/A'}
+閿�鍞柟绋庡彿,${invoice.sellerTaxNo || 'N/A'}
+閿�鍞柟鍦板潃,${invoice.sellerAddress || 'N/A'}
+閿�鍞柟閾惰璐︽埛,${invoice.sellerBankAccount || 'N/A'}`;
+};
+
+// 鐢熸垚鍟嗗搧鏄庣粏鍐呭
+const generateItemsContent = () => {
+  const invoice = props.invoice;
+  if (!invoice.items || invoice.items.length === 0) {
+    return `鍟嗗搧鏄庣粏
+鏆傛棤鍟嗗搧鏄庣粏淇℃伅`;
+  }
+  
+  let content = '鍟嗗搧鏄庣粏\n鍟嗗搧鍚嶇О,瑙勬牸鍨嬪彿,鏁伴噺,鍗曚环,閲戦,绋庣巼,绋庨,浠风◣鍚堣\n';
+  invoice.items.forEach(item => {
+    content += `${item.name || 'N/A'},${item.spec || 'N/A'},${item.quantity || 0},${(item.price || 0).toFixed(2)},${(item.amount || 0).toFixed(2)},${(item.taxRate || 0).toFixed(2)}%,${(item.taxAmount || 0).toFixed(2)},${(item.totalAmount || 0).toFixed(2)}\n`;
+  });
+  
+  return content;
+};
+
+// 鐢熸垚鍚堣淇℃伅鍐呭
+const generateSummaryContent = () => {
+  const invoice = props.invoice;
+  return `鍚堣淇℃伅
+閲戦鍚堣,${(invoice.amount || 0).toFixed(2)} 鍏�
+绋庨鍚堣,${(invoice.taxAmount || 0).toFixed(2)} 鍏�
+浠风◣鍚堣,${(invoice.totalAmount || 0).toFixed(2)} 鍏�
+澶囨敞,${invoice.remark || 'N/A'}`;
+};
+</script>
+
+<style scoped>
+.download-container {
+  padding: 0;
+}
+
+.invoice-info,
+.download-options,
+.download-progress {
+  margin-bottom: 20px;
+}
+
+.invoice-info:last-child,
+.download-options:last-child,
+.download-progress:last-child {
+  margin-bottom: 0;
+}
+
+.card-header {
+  font-weight: bold;
+  font-size: 16px;
+}
+
+.progress-content {
+  padding: 20px 0;
+  text-align: center;
+}
+
+.progress-text {
+  margin-top: 15px;
+  font-size: 16px;
+  font-weight: bold;
+  color: #409eff;
+}
+
+.progress-detail {
+  margin-top: 10px;
+  color: #606266;
+  font-size: 14px;
+}
+
+.dialog-footer {
+  text-align: right;
+}
+
+.el-checkbox-group {
+  display: flex;
+  flex-direction: column;
+  gap: 10px;
+}
+
+.el-radio-group {
+  display: flex;
+  flex-direction: column;
+  gap: 10px;
+}
+</style>
\ No newline at end of file
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
diff --git a/src/views/invoiceCollaboration/components/InvoiceViewDialog.vue b/src/views/invoiceCollaboration/components/InvoiceViewDialog.vue
new file mode 100644
index 0000000..72e7091
--- /dev/null
+++ b/src/views/invoiceCollaboration/components/InvoiceViewDialog.vue
@@ -0,0 +1,291 @@
+<template>
+  <el-dialog
+    :model-value="dialogViewVisible"
+    @update:model-value="$emit('update:dialogViewVisible', $event)"
+    :title="title"
+    width="1000px"
+    :close-on-click-modal="false"
+  >
+    <div class="invoice-view">
+      <!-- 鍩烘湰淇℃伅 -->
+      <el-card class="basic-info" shadow="never">
+        <template #header>
+          <div class="card-header">
+            <span>鍩烘湰淇℃伅</span>
+          </div>
+        </template>
+        
+        <el-descriptions :column="2" border>
+          <el-descriptions-item label="鍙戠エ鍙风爜">{{ form.invoiceNo || '-' }}</el-descriptions-item>
+          <el-descriptions-item label="鍙戠エ浠g爜">{{ form.invoiceCode || '-' }}</el-descriptions-item>
+          <el-descriptions-item label="寮�绁ㄦ棩鏈�">{{ form.invoiceDate || '-' }}</el-descriptions-item>
+          <el-descriptions-item label="寮�绁ㄧ姸鎬�">
+            <el-tag :type="getStatusType(form.status)">
+              {{ getStatusText(form.status) }}
+            </el-tag>
+          </el-descriptions-item>
+          <el-descriptions-item label="绋庢帶骞冲彴鐘舵��">
+            <el-tag :type="getTaxControlStatusType(form.taxControlStatus)">
+              {{ getTaxControlStatusText(form.taxControlStatus) }}
+            </el-tag>
+          </el-descriptions-item>
+          <el-descriptions-item label="鍒涘缓鏃堕棿">{{ form.createTime || '-' }}</el-descriptions-item>
+        </el-descriptions>
+      </el-card>
+
+      <!-- 璐拱鏂逛俊鎭� -->
+      <el-card class="buyer-info" shadow="never">
+        <template #header>
+          <div class="card-header">
+            <span>璐拱鏂逛俊鎭�</span>
+          </div>
+        </template>
+        
+        <el-descriptions :column="2" border>
+          <el-descriptions-item label="璐拱鏂瑰悕绉�">{{ form.buyerName || '-' }}</el-descriptions-item>
+          <el-descriptions-item label="绾崇◣浜鸿瘑鍒彿">{{ form.buyerTaxNo || '-' }}</el-descriptions-item>
+          <el-descriptions-item label="鍦板潃鐢佃瘽">{{ form.buyerAddress || '-' }}</el-descriptions-item>
+          <el-descriptions-item label="寮�鎴疯鍙婅处鍙�">{{ form.buyerBankAccount || '-' }}</el-descriptions-item>
+        </el-descriptions>
+      </el-card>
+
+      <!-- 閿�鍞柟淇℃伅 -->
+      <el-card class="seller-info" shadow="never">
+        <template #header>
+          <div class="card-header">
+            <span>閿�鍞柟淇℃伅</span>
+          </div>
+        </template>
+        
+        <el-descriptions :column="2" border>
+          <el-descriptions-item label="閿�鍞柟鍚嶇О">{{ form.sellerName || '-' }}</el-descriptions-item>
+          <el-descriptions-item label="绾崇◣浜鸿瘑鍒彿">{{ form.sellerTaxNo || '-' }}</el-descriptions-item>
+          <el-descriptions-item label="鍦板潃鐢佃瘽">{{ form.sellerAddress || '-' }}</el-descriptions-item>
+          <el-descriptions-item label="寮�鎴疯鍙婅处鍙�">{{ form.sellerBankAccount || '-' }}</el-descriptions-item>
+        </el-descriptions>
+      </el-card>
+
+      <!-- 鍟嗗搧鏄庣粏 -->
+      <el-card class="items-info" shadow="never">
+        <template #header>
+          <div class="card-header">
+            <span>鍟嗗搧鏄庣粏</span>
+          </div>
+        </template>
+        
+        <el-table :data="form.items || []" border style="width: 100%">
+          <el-table-column label="鍟嗗搧鍚嶇О" prop="name" width="200" />
+          <el-table-column label="瑙勬牸鍨嬪彿" prop="specification" width="150" />
+          <el-table-column label="鍗曚綅" prop="unit" width="100" />
+          <el-table-column label="鏁伴噺" prop="quantity" width="100" />
+          <el-table-column label="鍗曚环" prop="unitPrice" width="120">
+            <template #default="scope">
+              {{ scope.row.unitPrice }} 鍏�
+            </template>
+          </el-table-column>
+          <el-table-column label="閲戦" prop="amount" width="120">
+            <template #default="scope">
+              {{ (scope.row.amount || 0).toFixed(2) }} 鍏�
+            </template>
+          </el-table-column>
+          <el-table-column label="绋庣巼" prop="taxRate" width="100">
+            <template #default="scope">
+              {{ (parseFloat(scope.row.taxRate || 0) * 100).toFixed(0) }}%
+            </template>
+          </el-table-column>
+          <el-table-column label="绋庨" prop="taxAmount" width="120">
+            <template #default="scope">
+              {{ (scope.row.taxAmount || 0).toFixed(2) }} 鍏�
+            </template>
+          </el-table-column>
+          <el-table-column label="浠风◣鍚堣" prop="totalAmount" width="120">
+            <template #default="scope">
+              {{ (scope.row.totalAmount || 0).toFixed(2) }} 鍏�
+            </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">{{ getTotalAmount().toFixed(2) }} 鍏�</span>
+            </el-col>
+            <el-col :span="6">
+              <span class="summary-label">绋庨鍚堣锛�</span>
+              <span class="summary-value">{{ getTotalTaxAmount().toFixed(2) }} 鍏�</span>
+            </el-col>
+            <el-col :span="6">
+              <span class="summary-label">浠风◣鍚堣锛�</span>
+              <span class="summary-value">{{ getTotalTotalAmount().toFixed(2) }} 鍏�</span>
+            </el-col>
+          </el-row>
+        </div>
+      </el-card>
+
+      <!-- 澶囨敞淇℃伅 -->
+      <el-card class="remark-info" shadow="never">
+        <template #header>
+          <div class="card-header">
+            <span>澶囨敞淇℃伅</span>
+          </div>
+        </template>
+        
+        <div class="remark-content">
+          {{ form.remark || '鏃�' }}
+        </div>
+      </el-card>
+    </div>
+
+    <template #footer>
+      <div class="dialog-footer">
+        <el-button @click="handleClose">鍏抽棴</el-button>
+      </div>
+    </template>
+  </el-dialog>
+</template>
+
+<script setup>
+import { computed } from "vue";
+
+// Props
+const props = defineProps({
+  dialogViewVisible: {
+    type: Boolean,
+    default: false
+  },
+  form: {
+    type: Object,
+    default: () => ({})
+  },
+  title: {
+    type: String,
+    default: ""
+  }
+});
+
+// Emits
+const emit = defineEmits(['update:dialogViewVisible']);
+
+// 鑾峰彇鐘舵�佺被鍨�
+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 getTotalAmount = () => {
+  return (props.form.items || []).reduce((sum, item) => sum + (item.amount || 0), 0);
+};
+
+// 璁$畻鎬荤◣棰�
+const getTotalTaxAmount = () => {
+  return (props.form.items || []).reduce((sum, item) => sum + (item.taxAmount || 0), 0);
+};
+
+// 璁$畻鎬讳环绋庡悎璁�
+const getTotalTotalAmount = () => {
+  return (props.form.items || []).reduce((sum, item) => sum + (item.totalAmount || 0), 0);
+};
+
+// 鍏抽棴瀵硅瘽妗�
+const handleClose = () => {
+  emit('update:dialogViewVisible', false);
+};
+</script>
+
+<style scoped>
+.invoice-view {
+  padding: 20px 0;
+}
+
+.basic-info,
+.buyer-info,
+.seller-info,
+.items-info,
+.remark-info {
+  margin-bottom: 20px;
+}
+
+.card-header {
+  font-weight: bold;
+  font-size: 16px;
+}
+
+.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;
+}
+
+.remark-content {
+  padding: 15px;
+  background-color: #f5f7fa;
+  border-radius: 4px;
+  min-height: 60px;
+  line-height: 1.6;
+}
+
+.dialog-footer {
+  text-align: right;
+}
+
+.el-table {
+  margin-top: 10px;
+}
+</style>
diff --git a/src/views/invoiceCollaboration/components/TaxControlSyncDialog.vue b/src/views/invoiceCollaboration/components/TaxControlSyncDialog.vue
new file mode 100644
index 0000000..19bcfcd
--- /dev/null
+++ b/src/views/invoiceCollaboration/components/TaxControlSyncDialog.vue
@@ -0,0 +1,362 @@
+<template>
+  <el-dialog
+    :model-value="dialogSyncVisible"
+    @update:model-value="$emit('update:dialogSyncVisible', $event)"
+    title="绋庢帶骞冲彴鍚屾"
+    width="800px"
+    :close-on-click-modal="false"
+  >
+    <div class="sync-container">
+      <!-- 鍚屾鐘舵�� -->
+      <el-card class="sync-status" shadow="never">
+        <template #header>
+          <div class="card-header">
+            <span>鍚屾鐘舵��</span>
+          </div>
+        </template>
+        
+        <div class="status-content">
+          <el-row :gutter="20">
+            <el-col :span="8">
+              <div class="status-item">
+                <div class="status-icon success">
+                  <el-icon><Check /></el-icon>
+                </div>
+                <div class="status-text">
+                  <div class="status-title">宸插悓姝�</div>
+                  <div class="status-count">{{ syncedCount }}</div>
+                </div>
+              </div>
+            </el-col>
+            <el-col :span="8">
+              <div class="status-item">
+                <div class="status-icon warning">
+                  <el-icon><Clock /></el-icon>
+                </div>
+                <div class="status-text">
+                  <div class="status-title">寰呭悓姝�</div>
+                  <div class="status-count">{{ pendingCount }}</div>
+                </div>
+              </div>
+            </el-col>
+            <el-col :span="8">
+              <div class="status-item">
+                <div class="status-icon danger">
+                  <el-icon><Close /></el-icon>
+                </div>
+                <div class="status-text">
+                  <div class="status-title">鍚屾澶辫触</div>
+                  <div class="status-count">{{ failedCount }}</div>
+                </div>
+              </div>
+            </el-col>
+          </el-row>
+        </div>
+      </el-card>
+
+      <!-- 鍚屾閰嶇疆 -->
+      <el-card class="sync-config" shadow="never">
+        <template #header>
+          <div class="card-header">
+            <span>鍚屾閰嶇疆</span>
+          </div>
+        </template>
+        
+        <el-form :model="syncConfig" label-width="120px">
+          <el-form-item label="绋庢帶骞冲彴鍦板潃">
+            <el-input
+              v-model="syncConfig.taxControlUrl"
+              placeholder="璇疯緭鍏ョ◣鎺у钩鍙板湴鍧�"
+              style="width: 100%"
+            />
+          </el-form-item>
+          <el-form-item label="鍚屾棰戠巼">
+            <el-select
+              v-model="syncConfig.syncFrequency"
+              placeholder="璇烽�夋嫨鍚屾棰戠巼"
+              style="width: 100%"
+            >
+              <el-option label="瀹炴椂鍚屾" value="realtime" />
+              <el-option label="姣忓皬鏃跺悓姝�" value="hourly" />
+              <el-option label="姣忓ぉ鍚屾" value="daily" />
+              <el-option label="鎵嬪姩鍚屾" value="manual" />
+            </el-select>
+          </el-form-item>
+          <el-form-item label="鑷姩閲嶈瘯">
+            <el-switch
+              v-model="syncConfig.autoRetry"
+              active-text="寮�鍚�"
+              inactive-text="鍏抽棴"
+            />
+          </el-form-item>
+          <el-form-item label="閲嶈瘯娆℃暟" v-if="syncConfig.autoRetry">
+            <el-input-number
+              v-model="syncConfig.retryCount"
+              :min="1"
+              :max="10"
+              style="width: 100%"
+            />
+          </el-form-item>
+        </el-form>
+      </el-card>
+
+      <!-- 鍚屾鏃ュ織 -->
+      <el-card class="sync-log" shadow="never">
+        <template #header>
+          <div class="card-header">
+            <span>鍚屾鏃ュ織</span>
+            <el-button type="primary" size="small" @click="refreshLog">
+              鍒锋柊鏃ュ織
+            </el-button>
+          </div>
+        </template>
+        
+        <el-table :data="syncLogs" border style="width: 100%" max-height="300">
+          <el-table-column label="鏃堕棿" prop="time" width="160" />
+          <el-table-column label="鎿嶄綔" prop="action" width="120" />
+          <el-table-column label="鐘舵��" prop="status" width="100">
+            <template #default="scope">
+              <el-tag :type="getLogStatusType(scope.row.status)">
+                {{ getLogStatusText(scope.row.status) }}
+              </el-tag>
+            </template>
+          </el-table-column>
+          <el-table-column label="璇︽儏" prop="detail" show-overflow-tooltip />
+        </el-table>
+      </el-card>
+    </div>
+
+    <template #footer>
+      <div class="dialog-footer">
+        <el-button @click="handleClose">鍙栨秷</el-button>
+        <el-button type="primary" @click="handleSync" :loading="syncLoading">
+          寮�濮嬪悓姝�
+        </el-button>
+      </div>
+    </template>
+  </el-dialog>
+</template>
+
+<script setup>
+import { ref, reactive, onMounted } from "vue";
+import { ElMessage } from "element-plus";
+import { Check, Clock, Close } from "@element-plus/icons-vue";
+
+// Props
+const props = defineProps({
+  dialogSyncVisible: {
+    type: Boolean,
+    default: false
+  }
+});
+
+// Emits
+const emit = defineEmits(['update:dialogSyncVisible', 'success']);
+
+// 鍝嶅簲寮忔暟鎹�
+const syncLoading = ref(false);
+const syncedCount = ref(15);
+const pendingCount = ref(8);
+const failedCount = ref(2);
+
+// 鍚屾閰嶇疆
+const syncConfig = reactive({
+  taxControlUrl: "https://tax-control.example.com/api",
+  syncFrequency: "manual",
+  autoRetry: true,
+  retryCount: 3
+});
+
+// 鍚屾鏃ュ織
+const syncLogs = ref([
+  {
+    time: "2024-12-01 15:30:00",
+    action: "鍙戠エ鍚屾",
+    status: "success",
+    detail: "鎴愬姛鍚屾15寮犲彂绁ㄥ埌绋庢帶骞冲彴"
+  },
+  {
+    time: "2024-12-01 15:25:00",
+    action: "鍙戠エ鍚屾",
+    status: "success",
+    detail: "鎴愬姛鍚屾8寮犲彂绁ㄥ埌绋庢帶骞冲彴"
+  },
+  {
+    time: "2024-12-01 15:20:00",
+    action: "鍙戠エ鍚屾",
+    status: "failed",
+    detail: "鍚屾澶辫触锛氱綉缁滆繛鎺ヨ秴鏃�"
+  },
+  {
+    time: "2024-12-01 15:15:00",
+    action: "鍙戠エ鍚屾",
+    status: "success",
+    detail: "鎴愬姛鍚屾12寮犲彂绁ㄥ埌绋庢帶骞冲彴"
+  }
+]);
+
+// 鑾峰彇鏃ュ織鐘舵�佺被鍨�
+const getLogStatusType = (status) => {
+  const statusMap = {
+    success: "success",
+    failed: "danger",
+    pending: "warning"
+  };
+  return statusMap[status] || "";
+};
+
+// 鑾峰彇鏃ュ織鐘舵�佹枃鏈�
+const getLogStatusText = (status) => {
+  const statusMap = {
+    success: "鎴愬姛",
+    failed: "澶辫触",
+    pending: "杩涜涓�"
+  };
+  return statusMap[status] || status;
+};
+
+// 鍒锋柊鏃ュ織
+const refreshLog = () => {
+  ElMessage.success("鏃ュ織宸插埛鏂�");
+};
+
+// 寮�濮嬪悓姝�
+const handleSync = async () => {
+  if (!syncConfig.taxControlUrl) {
+    ElMessage.warning("璇峰厛閰嶇疆绋庢帶骞冲彴鍦板潃");
+    return;
+  }
+
+  syncLoading.value = true;
+
+  try {
+    // 妯℃嫙鍚屾杩囩▼
+    await new Promise(resolve => setTimeout(resolve, 2000));
+
+    // 鏇存柊鍚屾鐘舵��
+    const newSynced = Math.min(pendingCount.value, 5);
+    syncedCount.value += newSynced;
+    pendingCount.value -= newSynced;
+
+    // 娣诲姞鍚屾鏃ュ織
+    syncLogs.value.unshift({
+      time: new Date().toLocaleString(),
+      action: "鍙戠エ鍚屾",
+      status: "success",
+      detail: `鎴愬姛鍚屾${newSynced}寮犲彂绁ㄥ埌绋庢帶骞冲彴`
+    });
+
+    ElMessage.success("鍚屾瀹屾垚");
+    emit('success');
+  } catch (error) {
+    ElMessage.error("鍚屾澶辫触");
+    failedCount.value++;
+    
+    // 娣诲姞澶辫触鏃ュ織
+    syncLogs.value.unshift({
+      time: new Date().toLocaleString(),
+      action: "鍙戠エ鍚屾",
+      status: "failed",
+      detail: "鍚屾澶辫触锛氱郴缁熼敊璇�"
+    });
+  } finally {
+    syncLoading.value = false;
+  }
+};
+
+// 鍏抽棴瀵硅瘽妗�
+const handleClose = () => {
+  emit('update:dialogSyncVisible', false);
+};
+
+// 缁勪欢鎸傝浇鏃跺垵濮嬪寲鏁版嵁
+onMounted(() => {
+  // 鍙互鍦ㄨ繖閲屽姞杞藉垵濮嬫暟鎹�
+});
+</script>
+
+<style scoped>
+.sync-container {
+  padding: 0;
+}
+
+.sync-status,
+.sync-config,
+.sync-log {
+  margin-bottom: 20px;
+}
+
+.sync-status:last-child,
+.sync-config:last-child,
+.sync-log:last-child {
+  margin-bottom: 0;
+}
+
+.card-header {
+  font-weight: bold;
+  font-size: 16px;
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+}
+
+.status-content {
+  padding: 20px 0;
+}
+
+.status-item {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  padding: 20px;
+  text-align: center;
+}
+
+.status-icon {
+  width: 60px;
+  height: 60px;
+  border-radius: 50%;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  margin-right: 15px;
+  font-size: 24px;
+  color: white;
+}
+
+.status-icon.success {
+  background-color: #67c23a;
+}
+
+.status-icon.warning {
+  background-color: #e6a23c;
+}
+
+.status-icon.danger {
+  background-color: #f56c6c;
+}
+
+.status-text {
+  text-align: left;
+}
+
+.status-title {
+  font-size: 14px;
+  color: #606266;
+  margin-bottom: 5px;
+}
+
+.status-count {
+  font-size: 24px;
+  font-weight: bold;
+  color: #303133;
+}
+
+.dialog-footer {
+  text-align: right;
+}
+
+.el-table {
+  margin-top: 10px;
+}
+</style>
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