From 61c4c3f45e4257e2e7662f033e2719e62366c632 Mon Sep 17 00:00:00 2001
From: wlzboy <66905212@qq.com>
Date: 星期二, 31 三月 2026 23:02:22 +0800
Subject: [PATCH] feat: 优化申请发票,还可以修改发票信息

---
 ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysInvoiceServiceImpl.java         |   84 ++++
 app/pages/mine/invoice/edit.vue                                                             |  262 +++++++++++++++
 app/pages/mine/invoice/detail.vue                                                           |  314 ++++++++++++++++++
 app/pages/mine/invoice/index.vue                                                            |   18 
 app/pages.json                                                                              |   10 
 ruoyi-system/src/main/resources/mapper/system/LegacyInvoiceMapper.xml                       |   21 +
 ruoyi-system/src/main/java/com/ruoyi/system/service/ISysInvoiceService.java                 |    6 
 ruoyi-system/src/main/java/com/ruoyi/system/service/impl/LegacyTransferSyncServiceImpl.java |  122 ++++---
 ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysInvoiceController.java         |   78 ++++
 app/api/invoice.js                                                                          |   26 +
 ruoyi-system/src/main/java/com/ruoyi/system/mapper/LegacyInvoiceMapper.java                 |    7 
 ruoyi-system/src/main/java/com/ruoyi/system/mapper/LegacyTransferSyncMapper.java            |    9 
 ruoyi-system/src/main/resources/mapper/system/LegacyTransferSyncMapper.xml                  |   18 
 13 files changed, 907 insertions(+), 68 deletions(-)

diff --git a/app/api/invoice.js b/app/api/invoice.js
index 410749e..048fa0b 100644
--- a/app/api/invoice.js
+++ b/app/api/invoice.js
@@ -34,3 +34,29 @@
     method: 'get'
   })
 }
+
+// 鏇存柊鍙戠エ鐢宠锛堝緟瀹℃牳/宸查┏鍥炵姸鎬佸彲缂栬緫锛�
+export function updateInvoice(data) {
+  return request({
+    url: '/system/invoice',
+    method: 'put',
+    data: data
+  })
+}
+
+// App绔敤鎴风紪杈戣嚜宸辩殑鍙戠エ锛堜笓鐢ㄦ帴鍙o紝瀹夊叏鏍¢獙锛�
+export function myEditInvoice(data) {
+  return request({
+    url: '/system/invoice/myEdit',
+    method: 'put',
+    data: data
+  })
+}
+
+// App绔煡鐪嬪彂绁ㄨ鎯咃紙涓撶敤鎺ュ彛锛屼粎鍙煡鐪嬭嚜宸辩殑锛�
+export function myInvoiceDetail(invoiceId) {
+  return request({
+    url: `/system/invoice/myDetail/${invoiceId}`,
+    method: 'get'
+  })
+}
diff --git a/app/pages.json b/app/pages.json
index e6b4e4e..9b67872 100644
--- a/app/pages.json
+++ b/app/pages.json
@@ -120,6 +120,16 @@
     "style": {
       "navigationBarTitleText": "鐢宠鍙戠エ"
     }
+  }, {
+    "path": "pages/mine/invoice/edit",
+    "style": {
+      "navigationBarTitleText": "缂栬緫鍙戠エ鐢宠"
+    }
+  }, {
+    "path": "pages/mine/invoice/detail",
+    "style": {
+      "navigationBarTitleText": "鍙戠エ璇︽儏"
+    }
   }],
   "subPackages": [{
     "root": "pagesTask",
diff --git a/app/pages/mine/invoice/detail.vue b/app/pages/mine/invoice/detail.vue
new file mode 100644
index 0000000..452ed0c
--- /dev/null
+++ b/app/pages/mine/invoice/detail.vue
@@ -0,0 +1,314 @@
+<template>
+  <view class="invoice-detail-container">
+    <view v-if="loading" class="loading-box">
+      <text class="text-gray">鍔犺浇涓�...</text>
+    </view>
+
+    <block v-else-if="info">
+      <!-- 鐘舵�佹í骞� -->
+      <view class="status-banner" :class="statusBannerClass">
+        <text class="status-icon">{{ statusIcon }}</text>
+        <text class="status-text">{{ statusLabel }}</text>
+      </view>
+
+      <!-- 椹冲洖鍘熷洜 -->
+      <view v-if="info.status === 2 && info.auditRemarks" class="reject-reason">
+        <text class="reject-label">椹冲洖鍘熷洜锛�</text>
+        <text class="reject-content">{{ info.auditRemarks }}</text>
+      </view>
+
+      <!-- 鍩烘湰淇℃伅 -->
+      <view class="section-card">
+        <view class="section-title">鐢宠淇℃伅</view>
+        <view class="detail-row">
+          <text class="d-label">鏈嶅姟鍗曞彿</text>
+          <text class="d-value">{{ info.serviceCode || info.legacyServiceOrderId || '鈥�' }}</text>
+        </view>
+        <view class="detail-row">
+          <text class="d-label">寮�绁ㄧ被鍨�</text>
+          <text class="d-value">{{ info.invoiceType == 2 ? '浼佷笟' : '涓汉' }}</text>
+        </view>
+        <view class="detail-row">
+          <text class="d-label">鍙戠エ鎶ご</text>
+          <text class="d-value">{{ info.invoiceName || '鈥�' }}</text>
+        </view>
+        <view class="detail-row">
+          <text class="d-label">鐢宠閲戦</text>
+          <text class="d-value text-price">锟{ info.invoiceMoney ? Number(info.invoiceMoney).toFixed(2) : '0.00' }}</text>
+        </view>
+        <view class="detail-row" v-if="info.invoiceRemarks">
+          <text class="d-label">鍙戠エ澶囨敞</text>
+          <text class="d-value">{{ info.invoiceRemarks }}</text>
+        </view>
+        <view class="detail-row">
+          <text class="d-label">鐢宠鏃堕棿</text>
+          <text class="d-value">{{ formatTime(info.applyTime) }}</text>
+        </view>
+      </view>
+
+      <!-- 浼佷笟淇℃伅 -->
+      <view class="section-card" v-if="info.invoiceType == 2">
+        <view class="section-title">浼佷笟淇℃伅</view>
+        <view class="detail-row" v-if="info.companyAddress">
+          <text class="d-label">娉ㄥ唽鍦板潃</text>
+          <text class="d-value">{{ info.companyAddress }}</text>
+        </view>
+        <view class="detail-row" v-if="info.companyBank">
+          <text class="d-label">寮�鎴烽摱琛�</text>
+          <text class="d-value">{{ info.companyBank }}</text>
+        </view>
+        <view class="detail-row" v-if="info.companyBankNo">
+          <text class="d-label">閾惰甯愬彿</text>
+          <text class="d-value">{{ info.companyBankNo }}</text>
+        </view>
+      </view>
+
+      <!-- 閭瘎淇℃伅 -->
+      <view class="section-card" v-if="info.zipCode || info.mailAddress || info.contactName || info.contactPhone">
+        <view class="section-title">閭瘎淇℃伅</view>
+        <view class="detail-row" v-if="info.zipCode">
+          <text class="d-label">閭紪</text>
+          <text class="d-value">{{ info.zipCode }}</text>
+        </view>
+        <view class="detail-row" v-if="info.mailAddress">
+          <text class="d-label">閭瘎鍦板潃</text>
+          <text class="d-value">{{ info.mailAddress }}</text>
+        </view>
+        <view class="detail-row" v-if="info.contactName">
+          <text class="d-label">鑱旂郴浜�</text>
+          <text class="d-value">{{ info.contactName }}</text>
+        </view>
+        <view class="detail-row" v-if="info.contactPhone">
+          <text class="d-label">鑱旂郴鐢佃瘽</text>
+          <text class="d-value">{{ info.contactPhone }}</text>
+        </view>
+      </view>
+
+      <!-- 瀹℃牳/鍙戠エ淇℃伅 -->
+      <view class="section-card" v-if="info.status === 1">
+        <view class="section-title">鍙戠エ淇℃伅</view>
+        <view class="detail-row" v-if="info.invoiceNo">
+          <text class="d-label">鍙戠エ缂栧彿</text>
+          <text class="d-value">{{ info.invoiceNo }}</text>
+        </view>
+        <view class="detail-row" v-if="info.auditTime">
+          <text class="d-label">瀹℃牳鏃堕棿</text>
+          <text class="d-value">{{ formatTime(info.auditTime) }}</text>
+        </view>
+      </view>
+
+      <!-- 鎿嶄綔鎸夐挳 -->
+      <view class="action-area">
+        <button v-if="info.invoiceUrl" class="cu-btn block bg-green lg margin-bottom-sm" @click="handleDownload">
+          鏌ョ湅鍙戠エ
+        </button>
+        <button v-if="info.status === 0 || info.status === 2" class="cu-btn block bg-blue lg" @click="handleEdit">
+          缂栬緫鐢宠
+        </button>
+      </view>
+    </block>
+
+    <view v-else class="empty-box">
+      <text class="text-gray">鏆傛棤鏁版嵁</text>
+    </view>
+  </view>
+</template>
+
+<script>
+import { myInvoiceDetail } from "@/api/invoice"
+import config from '@/config.js'
+
+export default {
+  data() {
+    return {
+      loading: true,
+      info: null,
+      invoiceId: null
+    }
+  },
+  computed: {
+    statusLabel() {
+      const map = { 0: '寰呭鏍�', 1: '宸查�氳繃', 2: '宸查┏鍥�' }
+      return this.info ? (map[this.info.status] || '鏈煡') : ''
+    },
+    statusBannerClass() {
+      if (!this.info) return ''
+      const map = { 0: 'banner-pending', 1: 'banner-passed', 2: 'banner-rejected' }
+      return map[this.info.status] || ''
+    },
+    statusIcon() {
+      if (!this.info) return ''
+      const map = { 0: '鈴�', 1: '鉁�', 2: '鉂�' }
+      return map[this.info.status] || ''
+    }
+  },
+  onLoad(options) {
+    if (options && options.invoiceId) {
+      this.invoiceId = Number(options.invoiceId)
+      this.loadDetail()
+    } else {
+      this.loading = false
+    }
+  },
+  methods: {
+    loadDetail() {
+      this.loading = true
+      myInvoiceDetail(this.invoiceId).then(res => {
+        this.info = res.data
+      }).catch(err => {
+        console.error('鍔犺浇鍙戠エ璇︽儏澶辫触:', err)
+        this.$modal.msgError('鍔犺浇澶辫触锛岃杩斿洖閲嶈瘯')
+      }).finally(() => {
+        this.loading = false
+      })
+    },
+    formatTime(time) {
+      if (!time) return '鈥�'
+      const date = new Date(time)
+      const y = date.getFullYear()
+      const m = String(date.getMonth() + 1).padStart(2, '0')
+      const d = String(date.getDate()).padStart(2, '0')
+      const h = String(date.getHours()).padStart(2, '0')
+      const min = String(date.getMinutes()).padStart(2, '0')
+      return `${y}-${m}-${d} ${h}:${min}`
+    },
+    handleEdit() {
+      const invoiceInfo = encodeURIComponent(JSON.stringify(this.info))
+      this.$tab.navigateTo(`/pages/mine/invoice/edit?invoiceInfo=${invoiceInfo}`)
+    },
+    handleDownload() {
+      const url = this.info.invoiceUrl
+      if (!url) return
+      let fullUrl = url.startsWith('http') ? url : config.baseUrl + url
+      const fileExt = fullUrl.match(/\.(\w+)$/)?.[1]?.toLowerCase()
+
+      // #ifdef H5
+      window.open(fullUrl)
+      // #endif
+
+      // #ifndef H5
+      const imageExts = ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp']
+      if (imageExts.includes(fileExt)) {
+        uni.previewImage({ urls: [fullUrl], current: fullUrl })
+        return
+      }
+      uni.showLoading({ title: '涓嬭浇涓�...', mask: true })
+      uni.downloadFile({
+        url: fullUrl,
+        success: (res) => {
+          uni.hideLoading()
+          if (res.statusCode === 200) {
+            uni.openDocument({
+              filePath: res.tempFilePath,
+              showMenu: true,
+              fail: (err) => {
+                uni.showModal({ title: '鎻愮ず', content: `鏃犳硶鎵撳紑鏂囦欢: ${err.errMsg || '鏈煡閿欒'}`, showCancel: false })
+              }
+            })
+          } else {
+            this.$modal.msgError(`涓嬭浇澶辫触锛岀姸鎬佺爜: ${res.statusCode}`)
+          }
+        },
+        fail: (err) => {
+          uni.hideLoading()
+          this.$modal.msgError(`涓嬭浇澶辫触: ${err.errMsg || '鏈煡閿欒'}`)
+        }
+      })
+      // #endif
+    }
+  }
+}
+</script>
+
+<style lang="scss">
+.invoice-detail-container {
+  min-height: 100vh;
+  background-color: #f5f6fa;
+  padding-bottom: 60rpx;
+
+  .loading-box, .empty-box {
+    padding: 120rpx;
+    text-align: center;
+  }
+
+  // 鐘舵�佹í骞�
+  .status-banner {
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    padding: 36rpx 0;
+    gap: 16rpx;
+
+    .status-icon { font-size: 44rpx; }
+    .status-text { font-size: 36rpx; font-weight: bold; }
+
+    &.banner-pending { background: #fff8e1; .status-text { color: #e6a817; } }
+    &.banner-passed  { background: #e8f5e9; .status-text { color: #4caf50; } }
+    &.banner-rejected{ background: #fdecea; .status-text { color: #f44336; } }
+  }
+
+  // 椹冲洖鍘熷洜
+  .reject-reason {
+    margin: 0 24rpx 16rpx;
+    padding: 24rpx;
+    background: #fdecea;
+    border-radius: 12rpx;
+    border-left: 6rpx solid #f44336;
+
+    .reject-label { font-size: 26rpx; color: #f44336; font-weight: bold; }
+    .reject-content { font-size: 26rpx; color: #d32f2f; display: block; margin-top: 8rpx; }
+  }
+
+  // 淇℃伅鍗$墖
+  .section-card {
+    margin: 16rpx 24rpx;
+    background: #fff;
+    border-radius: 16rpx;
+    padding: 0 30rpx;
+    box-shadow: 0 2rpx 12rpx rgba(0,0,0,0.06);
+
+    .section-title {
+      font-size: 28rpx;
+      font-weight: bold;
+      color: #333;
+      padding: 28rpx 0 20rpx;
+      border-bottom: 1rpx solid #f0f0f0;
+      margin-bottom: 4rpx;
+    }
+
+    .detail-row {
+      display: flex;
+      align-items: flex-start;
+      padding: 22rpx 0;
+      border-bottom: 1rpx solid #f8f8f8;
+
+      &:last-child { border-bottom: none; }
+
+      .d-label {
+        font-size: 26rpx;
+        color: #999;
+        min-width: 160rpx;
+        flex-shrink: 0;
+      }
+
+      .d-value {
+        font-size: 26rpx;
+        color: #333;
+        flex: 1;
+        word-break: break-all;
+
+        &.text-price {
+          color: #f44336;
+          font-weight: bold;
+          font-size: 30rpx;
+        }
+      }
+    }
+  }
+
+  // 鎿嶄綔鍖�
+  .action-area {
+    margin: 30rpx 24rpx 0;
+  }
+}
+</style>
diff --git a/app/pages/mine/invoice/edit.vue b/app/pages/mine/invoice/edit.vue
new file mode 100644
index 0000000..1a864bb
--- /dev/null
+++ b/app/pages/mine/invoice/edit.vue
@@ -0,0 +1,262 @@
+<template>
+  <view class="invoice-apply-container bg-white">
+    <form>
+      <!-- 鍏宠仈浠诲姟锛堝彧璇诲睍绀猴紝涓嶅彲鏇存敼锛� -->
+      <view class="selected-task" v-if="form.serviceOrderId">
+        <view class="label">鍏宠仈浠诲姟</view>
+        <view class="task-card">
+          <view class="card-header">
+            <text class="service-code">{{ taskDisplay }}</text>
+          </view>
+          <view class="task-info-detail" v-if="invoiceInfo.legacyServiceOrderId">
+            <view class="info-row">
+              <text class="info-label">鏈嶅姟鍗曞彿:</text>
+              <text class="info-value">{{ invoiceInfo.legacyServiceOrderId }}</text>
+            </view>
+          </view>
+        </view>
+      </view>
+
+      <view class="cu-form-group">
+        <view class="title">寮�绁ㄧ被鍨�</view>
+        <radio-group class="flex" @change="handleTypeChange">
+          <view class="margin-right-sm">
+            <radio value="1" :checked="form.invoiceType == 1"></radio><text class="margin-left-xs">涓汉</text>
+          </view>
+          <view>
+            <radio value="2" :checked="form.invoiceType == 2"></radio><text class="margin-left-xs">浼佷笟</text>
+          </view>
+        </radio-group>
+      </view>
+
+      <view class="cu-form-group">
+        <view class="title required">鍙戠エ鎶ご</view>
+        <input placeholder="璇疯緭鍏ュ彂绁ㄦ姮澶�" v-model="form.invoiceName" />
+      </view>
+
+      <view class="cu-form-group">
+        <view class="title required">鍙戠エ閲戦</view>
+        <input
+          type="digit"
+          placeholder="璇疯緭鍏ラ噾棰�"
+          v-model="form.invoiceMoney"
+          @blur="validateMoney"
+        />
+      </view>
+
+      <view class="cu-form-group align-start">
+        <view class="title">鍙戠エ澶囨敞</view>
+        <textarea maxlength="-1" v-model="form.invoiceRemarks" placeholder="璇疯緭鍏ュ娉ㄤ俊鎭�"></textarea>
+      </view>
+
+      <block v-if="form.invoiceType == 2">
+        <view class="cu-form-group">
+          <view class="title">娉ㄥ唽鍦板潃</view>
+          <input placeholder="璇疯緭鍏ヤ紒涓氭敞鍐屽湴鍧�" v-model="form.companyAddress" />
+        </view>
+        <view class="cu-form-group">
+          <view class="title">寮�鎴烽摱琛�</view>
+          <input placeholder="璇疯緭鍏ヤ紒涓氬紑鎴烽摱琛�" v-model="form.companyBank" />
+        </view>
+        <view class="cu-form-group">
+          <view class="title">閾惰甯愬彿</view>
+          <input placeholder="璇疯緭鍏ヤ紒涓氶摱琛屽笎鍙�" v-model="form.companyBankNo" />
+        </view>
+      </block>
+
+      <view class="cu-form-group margin-top-sm">
+        <view class="title">閭紪</view>
+        <input placeholder="璇疯緭鍏ラ偖缂�" v-model="form.zipCode" />
+      </view>
+
+      <view class="cu-form-group">
+        <view class="title">閭瘎鍦板潃</view>
+        <input placeholder="璇疯緭鍏ラ偖瀵勫湴鍧�" v-model="form.mailAddress" />
+      </view>
+
+      <view class="cu-form-group">
+        <view class="title">鑱旂郴浜�</view>
+        <input placeholder="璇疯緭鍏ヨ仈绯讳汉" v-model="form.contactName" />
+      </view>
+
+      <view class="cu-form-group">
+        <view class="title">鑱旂郴鐢佃瘽</view>
+        <input placeholder="璇疯緭鍏ヨ仈绯荤數璇�" v-model="form.contactPhone" />
+      </view>
+
+      <view class="padding flex flex-direction">
+        <button class="cu-btn bg-blue lg" @click="submit">淇濆瓨淇敼</button>
+      </view>
+    </form>
+  </view>
+</template>
+
+<script>
+import { myEditInvoice, myInvoiceDetail } from "@/api/invoice"
+
+export default {
+  data() {
+    return {
+      invoiceInfo: {},   // 鍘熷鍙戠エ淇℃伅锛堝彧璇婚儴鍒嗭級
+      form: {
+        invoiceId: null,
+        serviceOrderId: null,
+        legacyServiceOrderId: null,
+        invoiceType: 1,
+        invoiceName: '',
+        invoiceMoney: '',
+        invoiceRemarks: '',
+        companyAddress: '',
+        companyBank: '',
+        companyBankNo: '',
+        zipCode: '',
+        mailAddress: '',
+        contactName: '',
+        contactPhone: ''
+      }
+    }
+  },
+  computed: {
+    taskDisplay() {
+      return this.invoiceInfo.serviceCode || this.invoiceInfo.legacyServiceOrderId || '鈥�'
+    }
+  },
+  onLoad(options) {
+    if (options && options.invoiceInfo) {
+      try {
+        const info = JSON.parse(decodeURIComponent(options.invoiceInfo))
+        this.invoiceInfo = info
+        this.fillForm(info)
+      } catch (e) {
+        console.error('瑙f瀽鍙戠エ淇℃伅澶辫触:', e)
+        this.$modal.msgError('鍙傛暟瑙f瀽澶辫触锛岃杩斿洖閲嶈瘯')
+      }
+    }
+  },
+  methods: {
+    fillForm(info) {
+      this.form.invoiceId        = info.invoiceId
+      this.form.serviceOrderId   = info.serviceOrderId
+      this.form.legacyServiceOrderId = info.legacyServiceOrderId
+      this.form.invoiceType      = info.invoiceType || 1
+      this.form.invoiceName      = info.invoiceName || ''
+      this.form.invoiceMoney     = info.invoiceMoney != null ? String(info.invoiceMoney) : ''
+      this.form.invoiceRemarks   = info.invoiceRemarks || ''
+      this.form.companyAddress   = info.companyAddress || ''
+      this.form.companyBank      = info.companyBank || ''
+      this.form.companyBankNo    = info.companyBankNo || ''
+      this.form.zipCode          = info.zipCode || ''
+      this.form.mailAddress      = info.mailAddress || ''
+      this.form.contactName      = info.contactName || ''
+      this.form.contactPhone     = info.contactPhone || ''
+    },
+    handleTypeChange(e) {
+      this.form.invoiceType = e.detail.value
+    },
+    validateMoney() {
+      if (!this.form.invoiceMoney) return
+      const money = parseFloat(this.form.invoiceMoney)
+      if (isNaN(money) || money <= 0) {
+        this.$modal.msgError('璇疯緭鍏ユ湁鏁堢殑閲戦')
+        this.form.invoiceMoney = ''
+      }
+    },
+    submit() {
+      if (!this.form.invoiceName) {
+        this.$modal.msgError('璇疯緭鍏ュ彂绁ㄦ姮澶�')
+        return
+      }
+      if (!this.form.invoiceMoney) {
+        this.$modal.msgError('璇疯緭鍏ュ彂绁ㄩ噾棰�')
+        return
+      }
+      const money = parseFloat(this.form.invoiceMoney)
+      if (isNaN(money) || money <= 0) {
+        this.$modal.msgError('璇疯緭鍏ユ湁鏁堢殑閲戦')
+        return
+      }
+
+      myEditInvoice(this.form).then(() => {
+        this.$modal.msgSuccess('淇敼鎴愬姛')
+        setTimeout(() => {
+          uni.navigateBack()
+        }, 1200)
+      }).catch(err => {
+        console.error('鏇存柊鍙戠エ澶辫触:', err)
+        this.$modal.msgError('淇濆瓨澶辫触锛岃閲嶈瘯')
+      })
+    }
+  }
+}
+</script>
+
+<style lang="scss">
+.invoice-apply-container {
+  min-height: 100vh;
+  padding-bottom: 50rpx;
+
+  .cu-form-group .title {
+    min-width: calc(4em + 15px);
+
+    &.required::before {
+      content: '*';
+      color: #f56c6c;
+      margin-right: 4rpx;
+      font-weight: bold;
+    }
+  }
+
+  .selected-task {
+    margin: 20rpx 30rpx;
+
+    .label {
+      font-size: 28rpx;
+      color: #666;
+      margin-bottom: 10rpx;
+    }
+
+    .task-card {
+      padding: 20rpx;
+      background: #e8f5e9;
+      border-radius: 8rpx;
+      border: 2rpx solid #4caf50;
+
+      .card-header {
+        display: flex;
+        justify-content: space-between;
+        align-items: center;
+      }
+
+      .service-code {
+        font-size: 32rpx;
+        font-weight: bold;
+        color: #2e7d32;
+      }
+
+      .task-info-detail {
+        margin-top: 16rpx;
+
+        .info-row {
+          display: flex;
+          margin-bottom: 12rpx;
+          line-height: 1.6;
+
+          .info-label {
+            font-size: 26rpx;
+            color: #666;
+            min-width: 140rpx;
+            flex-shrink: 0;
+          }
+
+          .info-value {
+            font-size: 26rpx;
+            color: #333;
+            flex: 1;
+            word-break: break-all;
+          }
+        }
+      }
+    }
+  }
+}
+</style>
diff --git a/app/pages/mine/invoice/index.vue b/app/pages/mine/invoice/index.vue
index d6b6018..31895e4 100644
--- a/app/pages/mine/invoice/index.vue
+++ b/app/pages/mine/invoice/index.vue
@@ -57,7 +57,7 @@
       </view>
       
       <!-- 鍙戠エ鍒楄〃 -->
-      <view v-for="(item, index) in list" :key="index" class="invoice-item bg-white margin-sm padding-sm radius shadow">
+      <view v-for="(item, index) in list" :key="index" class="invoice-item bg-white margin-sm padding-sm radius shadow" @click="handleDetail(item)">
         <view class="flex justify-between border-bottom padding-bottom-xs margin-bottom-xs">
           <text class="text-bold">鏈嶅姟鍗曞彿: {{ item.serviceCode || item.legacyServiceOrderId || '鏈煡' }}</text>
           <text :class="item.status === 0 ? 'text-orange' : item.status === 1 ? 'text-green' : item.status === 2 ? 'text-red' : 'text-gray'">{{ item.status === 0 ? '寰呭鏍�' : item.status === 1 ? '宸查�氳繃' : item.status === 2 ? '宸查┏鍥�' : '鏈煡' }}</text>
@@ -79,8 +79,9 @@
           <text class="value">{{ item.invoiceNo }}</text>
         </view>
         
-        <view class="action-bar margin-top-sm flex justify-end" v-if="item.invoiceUrl">
-          <button class="cu-btn sm bg-green" @click="handleDownload" :data-url="item.invoiceUrl">鏌ョ湅鍙戠エ</button>
+        <view class="action-bar margin-top-sm flex justify-end">
+          <button v-if="item.invoiceUrl" class="cu-btn sm bg-green margin-right-xs" @click.stop="handleDownload" :data-url="item.invoiceUrl">鏌ョ湅鍙戠エ</button>
+          <button v-if="item.status === 0 || item.status === 2" class="cu-btn sm bg-blue" @click.stop="handleEdit(item)">缂栬緫</button>
         </view>
         <view v-if="item.status === 2 && item.auditRemarks" class="margin-top-xs padding-xs bg-gray radius">
           <text class="text-sm text-red">椹冲洖鍘熷洜: {{ item.auditRemarks }}</text>
@@ -165,6 +166,13 @@
     },
     handleApply() {
       this.$tab.navigateTo('/pages/mine/invoice/apply')
+    },
+    handleDetail(item) {
+      this.$tab.navigateTo(`/pages/mine/invoice/detail?invoiceId=${item.invoiceId}`)
+    },
+    handleEdit(item) {
+      const invoiceInfo = encodeURIComponent(JSON.stringify(item))
+      this.$tab.navigateTo(`/pages/mine/invoice/edit?invoiceInfo=${invoiceInfo}`)
     },
     handleDownload(e) {
       const url = e.currentTarget.dataset.url
@@ -378,6 +386,10 @@
   }
   
   .invoice-item {
+    cursor: pointer;
+    transition: box-shadow 0.2s;
+    &:active { opacity: 0.85; }
+    
     .border-bottom {
       border-bottom: 1rpx solid #eee;
     }
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysInvoiceController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysInvoiceController.java
index 088027a..9db2197 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysInvoiceController.java
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysInvoiceController.java
@@ -4,6 +4,10 @@
 import java.util.Map;
 import java.util.HashMap;
 import javax.servlet.http.HttpServletResponse;
+
+import com.ruoyi.common.utils.LongUtil;
+import com.ruoyi.system.domain.SysTaskEmergency;
+import com.ruoyi.system.service.ISysTaskEmergencyService;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.web.bind.annotation.GetMapping;
@@ -16,6 +20,8 @@
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 import com.ruoyi.common.annotation.Log;
 import com.ruoyi.common.core.controller.BaseController;
 import com.ruoyi.common.core.domain.AjaxResult;
@@ -38,11 +44,17 @@
 @RequestMapping("/system/invoice")
 public class SysInvoiceController extends BaseController
 {
+    private static final Logger log = LoggerFactory.getLogger(SysInvoiceController.class);
+
     @Autowired
     private ISysInvoiceService sysInvoiceService;
     
     @Autowired
     private ISysDeptService sysDeptService;
+
+
+    @Autowired
+    private ISysTaskEmergencyService sysTaskEmergencyService;
 
     /**
      * 鏌ヨ鍙戠エ鐢宠鍒楄〃
@@ -182,6 +194,72 @@
     }
 
     /**
+     * App绔煡鐪嬫垜鐨勬煇鏉″彂绁ㄨ鎯咃紙鏃犻渶鍚庡彴鏉冮檺锛屼絾鍙兘鏌ョ湅鑷繁鐨勫彂绁級
+     */
+    @GetMapping("/myDetail/{invoiceId}")
+    public AjaxResult myDetail(@PathVariable("invoiceId") Long invoiceId)
+    {
+        Long currentUserId = SecurityUtils.getUserId();
+        SysInvoice invoice = sysInvoiceService.selectSysInvoiceByInvoiceId(invoiceId);
+        if (invoice == null) {
+            return AjaxResult.error("鍙戠エ涓嶅瓨鍦�");
+        }
+        if (!currentUserId.equals(invoice.getApplyUserId())) {
+            return AjaxResult.error("鏃犳潈闄愭煡鐪嬭鍙戠エ");
+        }
+        return AjaxResult.success(invoice);
+    }
+
+    /**
+     * App绔敤鎴风紪杈戣嚜宸辩殑鍙戠エ鐢宠锛堜粎寰呭鏍�/宸查┏鍥炲彲缂栬緫锛屼笉鍙洿鏀瑰叧鑱斾换鍔★級
+     */
+    @Log(title = "鍙戠エ鐢宠鑷姪淇敼", businessType = BusinessType.UPDATE)
+    @PutMapping("/myEdit")
+    public AjaxResult myEdit(@RequestBody SysInvoice sysInvoice)
+    {
+        Long currentUserId = SecurityUtils.getUserId();
+        if (sysInvoice.getInvoiceId() == null) {
+            return AjaxResult.error("鍙戠エID涓嶈兘涓虹┖");
+        }
+        SysInvoice exist = sysInvoiceService.selectSysInvoiceByInvoiceId(sysInvoice.getInvoiceId());
+        if (exist == null) {
+            return AjaxResult.error("鍙戠エ涓嶅瓨鍦�");
+        }
+        if (!currentUserId.equals(exist.getApplyUserId())) {
+            return AjaxResult.error("鏃犳潈闄愪慨鏀硅鍙戠エ");
+        }
+        if (exist.getStatus() != 0 && exist.getStatus() != 2) {
+            return AjaxResult.error("鍙湁寰呭鏍告垨宸查┏鍥炵殑鍙戠エ鍙互淇敼");
+        }
+        Long taskId = exist.getServiceOrderId();
+        Long legacyServiceOrdId = exist.getLegacyServiceOrderId();
+        if(LongUtil.isNotEmpty(taskId) && LongUtil.isEmpty(legacyServiceOrdId)){
+           SysTaskEmergency taskEmergency= sysTaskEmergencyService.selectSysTaskEmergencyByTaskId(taskId);
+           if(taskEmergency!=null){
+               legacyServiceOrdId=taskEmergency.getLegacyServiceOrdId();
+           }
+
+        }
+        // 淇濇寔鍏宠仈浠诲姟淇℃伅涓嶅彉锛屽彧鏇存柊鍙戠エ鍐呭瀛楁
+        sysInvoice.setServiceOrderId(exist.getServiceOrderId());
+        sysInvoice.setLegacyServiceOrderId(legacyServiceOrdId);
+        sysInvoice.setApplyUserId(exist.getApplyUserId());
+        sysInvoice.setApplyTime(exist.getApplyTime());
+        sysInvoice.setStatus(0); // 閲嶆柊缃负寰呭鏍�
+        int rows = sysInvoiceService.updateSysInvoice(sysInvoice);
+
+        if (rows > 0) {
+            // 寮傛鍚屾鍒版棫绯荤粺锛屽け璐ヤ笉褰卞搷涓绘祦绋�
+            try {
+                sysInvoiceService.syncUpdateToLegacySystem(sysInvoice.getInvoiceId());
+            } catch (Exception e) {
+                log.warn("鍙戠エ缂栬緫鍚屾鏃х郴缁熷け璐ワ紝涓嶅奖鍝嶄繚瀛樼粨鏋�: {}", e.getMessage());
+            }
+        }
+        return toAjax(rows);
+    }
+
+    /**
      * 鑾峰彇鍙敵璇峰彂绁ㄧ殑浠诲姟鍒楄〃
      * @param searchKeyword 鎼滅储鍏抽敭璇嶏紙鏀寔taskCode銆乻erviceCode銆乴egacyServiceOrdNo锛�
      * @param serviceOrdClass 鍒嗗叕鍙镐唬鐮侊紙鍙�夛紝榛樿浣跨敤鐢ㄦ埛鎵�灞炲垎鍏徃锛�
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/LegacyInvoiceMapper.java b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/LegacyInvoiceMapper.java
index de782d9..6fa6aa6 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/LegacyInvoiceMapper.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/LegacyInvoiceMapper.java
@@ -34,4 +34,11 @@
      * @return
      */
     public List<Map<String, Object>> selectLegacyInvoiceByServiceOrderId(Long serviceOrderId);
+
+    /**
+     * 鏇存柊鏃х郴缁熷彂绁ㄨ褰曪紙缂栬緫鍚屾鏃朵娇鐢級
+     * @param params
+     * @return
+     */
+    public int updateLegacyInvoice(Map<String, Object> params);
 }
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/LegacyTransferSyncMapper.java b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/LegacyTransferSyncMapper.java
index f42635d..2c3fcf0 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/LegacyTransferSyncMapper.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/LegacyTransferSyncMapper.java
@@ -18,12 +18,15 @@
 public interface LegacyTransferSyncMapper {
     
     /**
-     * 鏌ヨ鎸囧畾鏃ユ湡鑼冨洿鐨勮浆杩愬崟鏁版嵁
-     * 
+     * 鏌ヨ鎸囧畾鏃ユ湡鑼冨洿鐨勮浆杩愬崟鏁版嵁锛圞eyset娓告爣鍒嗛〉锛岃蛋涓婚敭绱㈠紩锛�
+     *
      * @param startDate 寮�濮嬫棩鏈�
+     * @param endDate   缁撴潫鏃ユ湡
+     * @param lastId    涓婁竴椤垫渶鍚庝竴鏉$殑 ServiceOrdID锛岄娆′紶 0
+     * @param pageSize  姣忛〉鏉℃暟
      * @return 杞繍鍗曟暟鎹垪琛�
      */
-    List<Map<String, Object>> selectTransferOrders(@Param("startDate") String startDate, @Param("endDate") String endDate);
+    List<Map<String, Object>> selectTransferOrders(@Param("startDate") String startDate, @Param("endDate") String endDate, @Param("lastId") long lastId, @Param("pageSize") int pageSize);
     
     /**ServiceOrdNo
      * 鏍规嵁鏈嶅姟鍗旾D鍜岃皟搴﹀崟ID鏌ヨ杞繍鍗曟暟鎹�
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysInvoiceService.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysInvoiceService.java
index 5e0b1da..7f7cc9a 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysInvoiceService.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysInvoiceService.java
@@ -76,6 +76,12 @@
     public int syncToLegacySystem(Long invoiceId);
 
     /**
+     * 缂栬緫鍚庡悓姝ユ洿鏂板埌鏃х郴缁燂紙鏈塴egacyInvoiceId鍒橴PDATE锛屾棤鍒欓噸鏂癐NSERT锛�
+     * @param invoiceId 鏂扮郴缁熷彂绁↖D
+     */
+    public void syncUpdateToLegacySystem(Long invoiceId);
+
+    /**
      * 浠庢棫绯荤粺鍚屾鐘舵��
      */
     public void syncStatusFromLegacySystem();
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/LegacyTransferSyncServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/LegacyTransferSyncServiceImpl.java
index 247bbc3..78d9033 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/LegacyTransferSyncServiceImpl.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/LegacyTransferSyncServiceImpl.java
@@ -90,63 +90,79 @@
             String startDateStr = DateUtils.parseDateToStr("yyyy-MM-dd", startDate);
             String endDateStr = DateUtils.parseDateToStr("yyyy-MM-dd", new Date());
             
-            // 浠嶴QL Server鏌ヨ杞繍鍗曟暟鎹�
-            List<Map<String, Object>> transferOrders = legacyTransferSyncMapper.selectTransferOrders(startDateStr, endDateStr);
-            
-            if (transferOrders == null || transferOrders.isEmpty()) {
-                log.info("鏈煡璇㈠埌{}澶╁墠鐨勮浆杩愬崟鏁版嵁", daysAgo);
-                return 0;
-            }
-            
-//            log.info("鏌ヨ鍒皗}鏉¤浆杩愬崟鏁版嵁锛屽紑濮嬪悓姝�...", transferOrders.size());
-            
+            // Keyset娓告爣鍒嗛〉浠� SQL Server 鎷夊彇杞繍鍗曟暟鎹紝姣忛〉 10 鏉★紝璧颁富閿储寮曞交搴曡閬胯秴鏃�
+            final int PAGE_SIZE = 10;
+            long lastId = 0L;   // 娓告爣锛氳褰曚笂涓�椤垫渶鍚庝竴鏉$殑 ServiceOrdID锛岄娆′紶 0
             int successCount = 0;
-            int totalCount = transferOrders.size();
-            int processedCount = 0;
-            
-            for (Map<String, Object> order : transferOrders) {
-                processedCount++;
-                try {
-                    Long serviceOrdID = MapValueUtils.getLongValue(order, "ServiceOrdID");
-                    Long dispatchOrdID = MapValueUtils.getLongValue(order, "DispatchOrdID");
-                    
-                    // 妫�鏌ュ弬鏁版湁鏁堟��
-                    if (serviceOrdID==null || serviceOrdID<=0) {
-                        log.warn("绗瑊}鏉℃暟鎹湇鍔″崟ID涓虹┖锛岃烦杩囧鐞�", processedCount);
-                        continue;
-                    }
-                    
-//                    log.debug("姝e湪澶勭悊绗瑊}/{}鏉¤浆杩愬崟: ServiceOrdID={}, DispatchOrdID={}",
-//                             processedCount, totalCount, serviceOrdID, dispatchOrdID);
-                    
-                    // 妫�鏌ユ槸鍚﹀凡鍚屾
-                    if (isTransferOrderSynced(serviceOrdID, dispatchOrdID)) {
-//                        log.debug("杞繍鍗曞凡鍚屾锛岃烦杩�: ServiceOrdID={}, DispatchOrdID={}", serviceOrdID, dispatchOrdID);
-                        //杩涜鏇存柊鎿嶄綔
-                        updateTransferOrder(serviceOrdID, dispatchOrdID, order);
-                        continue;
-                    }
-                    
-                    // 鍚屾鍗曚釜杞繍鍗�
-                    boolean success = syncSingleTransferOrder(serviceOrdID, dispatchOrdID, order);
-                    if (success) {
-                        successCount++;
-                    }
-                    
-                    // 鎺у埗鍚屾棰戠巼锛岄伩鍏嶈姹傝繃蹇�
-                    Thread.sleep(100);
-                } catch (InterruptedException ie) {
-                    log.warn("鍚屾浠诲姟琚腑鏂�");
-                    Thread.currentThread().interrupt();
+
+            while (true) {
+                List<Map<String, Object>> transferOrders = legacyTransferSyncMapper.selectTransferOrders(startDateStr, endDateStr, lastId, PAGE_SIZE);
+
+                if (transferOrders == null || transferOrders.isEmpty()) {
                     break;
-                } catch (Exception e) {
-                    log.error("鍚屾鍗曚釜杞繍鍗曞け璐�: ServiceOrdID={}, DispatchOrdID={}", 
-                             MapValueUtils.getStringValue(order, "ServiceOrdID"), 
-                             MapValueUtils.getStringValue(order, "DispatchOrdID"), e);
+                }
+
+                int totalCount = transferOrders.size();
+                int processedCount = 0;
+
+                for (Map<String, Object> order : transferOrders) {
+                    processedCount++;
+                    try {
+                        Long serviceOrdID = MapValueUtils.getLongValue(order, "ServiceOrdID");
+                        Long dispatchOrdID = MapValueUtils.getLongValue(order, "DispatchOrdID");
+
+                        // 妫�鏌ュ弬鏁版湁鏁堟��
+                        if (serviceOrdID == null || serviceOrdID <= 0) {
+                            log.warn("绗瑊}鏉℃暟鎹湇鍔″崟ID涓虹┖锛岃烦杩囧鐞�", processedCount);
+                            continue;
+                        }
+
+//                        log.debug("姝e湪澶勭悊绗瑊}/{}鏉¤浆杩愬崟: ServiceOrdID={}, DispatchOrdID={}",
+//                                 processedCount, totalCount, serviceOrdID, dispatchOrdID);
+
+                        // 妫�鏌ユ槸鍚﹀凡鍚屾
+                        if (isTransferOrderSynced(serviceOrdID, dispatchOrdID)) {
+//                            log.debug("杞繍鍗曞凡鍚屾锛岃烦杩�: ServiceOrdID={}, DispatchOrdID={}", serviceOrdID, dispatchOrdID);
+                            //杩涜鏇存柊鎿嶄綔
+                            updateTransferOrder(serviceOrdID, dispatchOrdID, order);
+                            continue;
+                        }
+
+                        // 鍚屾鍗曚釜杞繍鍗�
+                        boolean success = syncSingleTransferOrder(serviceOrdID, dispatchOrdID, order);
+                        if (success) {
+                            successCount++;
+                        }
+
+                        // 鎺у埗鍚屾棰戠巼锛岄伩鍏嶈姹傝繃蹇�
+                        Thread.sleep(100);
+                    } catch (InterruptedException ie) {
+                        log.warn("鍚屾浠诲姟琚腑鏂�");
+                        Thread.currentThread().interrupt();
+                        break;
+                    } catch (Exception e) {
+                        log.error("鍚屾鍗曚釜杞繍鍗曞け璐�: ServiceOrdID={}, DispatchOrdID={}",
+                                MapValueUtils.getStringValue(order, "ServiceOrdID"),
+                                MapValueUtils.getStringValue(order, "DispatchOrdID"), e);
+                    }
+                }
+
+                // 鏇存柊娓告爣涓烘湰椤垫渶鍚庝竴鏉$殑 ServiceOrdID
+                Map<String, Object> lastOrder = transferOrders.get(transferOrders.size() - 1);
+                Long lastServiceOrdID = MapValueUtils.getLongValue(lastOrder, "ServiceOrdID");
+                if (lastServiceOrdID != null && lastServiceOrdID > 0) {
+                    lastId = lastServiceOrdID;
+                } else {
+                    break;
+                }
+
+                // 鏈〉鏈弧涓�椤碉紝璇存槑宸叉棤鏇村鏁版嵁
+                if (totalCount < PAGE_SIZE) {
+                    break;
                 }
             }
-            
-//            log.info("鍚屾瀹屾垚锛屽叡澶勭悊{}鏉¤浆杩愬崟锛屾垚鍔熷悓姝}鏉¤浆杩愬崟鏁版嵁", totalCount, successCount);
+
+//            log.info("鍚屾瀹屾垚锛屾垚鍔熷悓姝}鏉¤浆杩愬崟鏁版嵁", successCount);
             return successCount;
             
         } catch (Exception e) {
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysInvoiceServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysInvoiceServiceImpl.java
index ee2c483..d655552 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysInvoiceServiceImpl.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysInvoiceServiceImpl.java
@@ -4,6 +4,10 @@
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+
+import com.ruoyi.common.utils.LongUtil;
+import com.ruoyi.system.domain.SysTaskEmergency;
+import com.ruoyi.system.mapper.SysTaskEmergencyMapper;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -37,6 +41,9 @@
     
     @Autowired
     private SysUserMapper sysUserMapper;
+
+    @Autowired
+    private SysTaskEmergencyMapper sysTaskEmergencyMapper;
 
     /**
      * 鏌ヨ鍙戠エ鐢宠
@@ -83,6 +90,16 @@
     @Override
     public int insertSysInvoice(SysInvoice sysInvoice)
     {
+        Long taskId = sysInvoice.getServiceOrderId();
+        Long legacyServiceOrdId = sysInvoice.getLegacyServiceOrderId();
+        if(LongUtil.isNotEmpty(taskId) && LongUtil.isEmpty(legacyServiceOrdId)){
+            SysTaskEmergency taskEmergency= sysTaskEmergencyMapper.selectSysTaskEmergencyByTaskId(taskId);
+            if(taskEmergency!=null){
+                legacyServiceOrdId=taskEmergency.getLegacyServiceOrdId();
+            }
+
+        }
+        sysInvoice.setLegacyServiceOrderId(legacyServiceOrdId);
         sysInvoice.setApplyTime(DateUtils.getNowDate());
         sysInvoice.setStatus(0); // 寰呭鏍�
         sysInvoice.setSyncStatus(0); // 鏈悓姝�
@@ -191,6 +208,73 @@
     }
 
     /**
+     * 缂栬緫鍚庡悓姝ユ洿鏂板埌鏃х郴缁�
+     * - 宸叉湁 legacyInvoiceId锛氱洿鎺� UPDATE 鏃х郴缁熻褰�
+     * - 鏃� legacyInvoiceId锛堝巻鍙插悓姝ュけ璐ワ級锛氶噸鏂� INSERT
+     */
+    @Override
+    public void syncUpdateToLegacySystem(Long invoiceId) {
+        SysInvoice invoice = sysInvoiceMapper.selectSysInvoiceByInvoiceId(invoiceId);
+        if (invoice == null) return;
+
+        Map<String, Object> params = new HashMap<>();
+        params.put("InvoiceType",         invoice.getInvoiceType());
+        params.put("InvoiceName",         invoice.getInvoiceName());
+        params.put("InvoiceMakeout",      invoice.getInvoiceRemarks());
+        params.put("InvoiceCompanyPhone", invoice.getContactPhone());
+        params.put("InvoiceCompanyID",    "");
+        params.put("InvoiceCompanyAdd",   invoice.getCompanyAddress());
+        params.put("InvoiceCompanyBank",  invoice.getCompanyBank());
+        params.put("InvoiceCompanyBankNo",invoice.getCompanyBankNo());
+        params.put("InvoiceZipCode",      invoice.getZipCode());
+        params.put("Invoice_strAdd",      invoice.getMailAddress());
+        params.put("Invoice_strName",     invoice.getContactName());
+        params.put("Invoice_strPhone",    invoice.getContactPhone());
+        params.put("Invoice_strEmail",    invoice.getContactEmail());
+        params.put("ServiceOrderIDPK",   invoice.getLegacyServiceOrderId());
+        params.put("InvoiceMoney",        invoice.getInvoiceMoney());
+
+        Integer oaUserId = 0;
+        if (invoice.getApplyUserId() != null) {
+            SysUser user = sysUserMapper.selectUserById(invoice.getApplyUserId());
+            if (user != null && user.getOaUserId() != null) {
+                oaUserId = user.getOaUserId();
+            }
+        }
+        params.put("ApplyOAID", oaUserId);
+
+        try {
+            if (invoice.getLegacyInvoiceId() != null && invoice.getLegacyInvoiceId() > 0) {
+                // 鏃х郴缁熷凡鏈夎褰曪紝UPDATE
+                params.put("InvoiceID", invoice.getLegacyInvoiceId());
+                int rows = legacyInvoiceMapper.updateLegacyInvoice(params);
+                if (rows > 0) {
+                    invoice.setSyncStatus(1);
+                    sysInvoiceMapper.updateSysInvoice(invoice);
+                    log.info("鍙戠エ缂栬緫鍚屾鏃х郴缁熸垚鍔�(UPDATE), invoiceId={}, legacyId={}", invoiceId, invoice.getLegacyInvoiceId());
+                }
+            } else {
+                // 鏃х郴缁熸棤璁板綍锛岄噸鏂� INSERT
+                params.put("ServiceOrderIDPK", invoice.getLegacyServiceOrderId());
+                int rows = legacyInvoiceMapper.insertLegacyInvoice(params);
+                if (rows > 0) {
+                    Object legacyId = params.get("InvoiceID");
+                    if (legacyId != null) {
+                        invoice.setLegacyInvoiceId(Integer.valueOf(legacyId.toString()));
+                    }
+                    invoice.setSyncStatus(1);
+                    sysInvoiceMapper.updateSysInvoice(invoice);
+                    log.info("鍙戠エ缂栬緫鍚屾鏃х郴缁熸垚鍔�(INSERT), invoiceId={}", invoiceId);
+                }
+            }
+        } catch (Exception e) {
+            log.error("鍙戠エ缂栬緫鍚屾鏃х郴缁熷紓甯�, invoiceId={}: {}", invoiceId, e.getMessage());
+            invoice.setSyncStatus(2);
+            sysInvoiceMapper.updateSysInvoice(invoice);
+        }
+    }
+
+    /**
      * 浠庢棫绯荤粺鍚屾鍙戠エ鐘舵�佸彉鍖�
      */
     @Override
diff --git a/ruoyi-system/src/main/resources/mapper/system/LegacyInvoiceMapper.xml b/ruoyi-system/src/main/resources/mapper/system/LegacyInvoiceMapper.xml
index b36a98b..a7352d1 100644
--- a/ruoyi-system/src/main/resources/mapper/system/LegacyInvoiceMapper.xml
+++ b/ruoyi-system/src/main/resources/mapper/system/LegacyInvoiceMapper.xml
@@ -31,4 +31,25 @@
     <select id="selectLegacyInvoiceByServiceOrderId" parameterType="Long" resultType="Map">
         SELECT * FROM InvoiceData WHERE ServiceOrderIDPK = #{serviceOrderId}
     </select>
+
+    <!-- 缂栬緫鏃舵洿鏂版棫绯荤粺鍙戠エ璁板綍 -->
+    <update id="updateLegacyInvoice" parameterType="Map">
+        UPDATE InvoiceData SET
+            ServiceOrderIDPK   = #{ServiceOrderIDPK},
+            InvoiceType        = #{InvoiceType},
+            InvoiceName        = #{InvoiceName},
+            InvoiceMakeout     = #{InvoiceMakeout},
+            InvoiceCompanyPhone= #{InvoiceCompanyPhone},
+            InvoiceCompanyAdd  = #{InvoiceCompanyAdd},
+            InvoiceCompanyBank = #{InvoiceCompanyBank},
+            InvoiceCompanyBankNo = #{InvoiceCompanyBankNo},
+            InvoiceZipCode     = #{InvoiceZipCode},
+            Invoice_strAdd     = #{Invoice_strAdd},
+            Invoice_strName    = #{Invoice_strName},
+            Invoice_strPhone   = #{Invoice_strPhone},
+            Invoice_strEmail   = #{Invoice_strEmail},
+            InvoiceMoney       = #{InvoiceMoney},
+            AuditStatus        = 0
+        WHERE InvoiceID = #{InvoiceID}
+    </update>
 </mapper>
diff --git a/ruoyi-system/src/main/resources/mapper/system/LegacyTransferSyncMapper.xml b/ruoyi-system/src/main/resources/mapper/system/LegacyTransferSyncMapper.xml
index ce3ae5c..bbe6068 100644
--- a/ruoyi-system/src/main/resources/mapper/system/LegacyTransferSyncMapper.xml
+++ b/ruoyi-system/src/main/resources/mapper/system/LegacyTransferSyncMapper.xml
@@ -59,9 +59,9 @@
         <result property="EntourageState" column="EntourageState" />
     </resultMap>
     
-    <!-- 鏌ヨ鎸囧畾鏃ユ湡鑼冨洿鐨勮浆杩愬崟鏁版嵁 -->
+    <!-- 鏌ヨ鎸囧畾鏃ユ湡鑼冨洿鐨勮浆杩愬崟鏁版嵁锛圞eyset娓告爣鍒嗛〉锛岃蛋涓婚敭绱㈠紩锛屽交搴曡閬胯秴鏃讹級 -->
     <select id="selectTransferOrders" resultMap="TransferOrderResult">
-        SELECT 
+        SELECT TOP (${pageSize})
             a.ServiceOrdID,
             a.Old_ServiceOrdID_TXT,
             a.ServiceOrdNo,
@@ -102,15 +102,15 @@
             a.ServiceOrdPtServices,
             a.ServiceOrdPtInServices,
             a.ServiceOrdPtName,
-            b.DispatchOrdState,            
             b.DispatchOrdNo,
-            b.DispatchOrdClass,
-            a.ServiceOrdClass  
-        FROM ServiceOrder as a 
-        left JOIN DispatchOrd b on a.ServiceOrdID = b.ServiceOrdIDDt
+            b.DispatchOrdClass
+        FROM ServiceOrder AS a
+        LEFT JOIN DispatchOrd b ON a.ServiceOrdID = b.ServiceOrdIDDt
         WHERE a.ServiceOrdState &lt;= 3
-            AND a.ServiceOrd_CC_Time > #{startDate} and a.ServiceOrd_CC_Time &lt; #{endDate}
-            
+            AND a.ServiceOrd_CC_Time > #{startDate}
+            AND a.ServiceOrd_CC_Time &lt; #{endDate}
+            AND a.ServiceOrdID > #{lastId}
+        ORDER BY a.ServiceOrdID
     </select>
     
     <!-- 鏍规嵁鏈嶅姟鍗旾D鍜岃皟搴﹀崟ID鏌ヨ杞繍鍗曟暟鎹� -->

--
Gitblit v1.9.1