From 56bc142d33106db9f226abe39f60d0059d702338 Mon Sep 17 00:00:00 2001
From: rk <94314517@qq.com>
Date: 星期五, 10 四月 2026 20:04:38 +0800
Subject: [PATCH] Merge remote-tracking branch 'origin/master'

---
 admin/src/components/business/OperaCityPriceRuleWindow.vue |  349 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 349 insertions(+), 0 deletions(-)

diff --git a/admin/src/components/business/OperaCityPriceRuleWindow.vue b/admin/src/components/business/OperaCityPriceRuleWindow.vue
new file mode 100644
index 0000000..8e40ff5
--- /dev/null
+++ b/admin/src/components/business/OperaCityPriceRuleWindow.vue
@@ -0,0 +1,349 @@
+<template>
+  <GlobalWindow
+    :title="title"
+    :visible.sync="visible"
+    width="60%"
+  >
+    <el-tabs v-model="activeTab">
+      <el-tab-pane label="灏卞湴瀵勫瓨" name="local">
+        <div class="price-tip">鏍规嵁琛屾潕灏哄浠ュ強瀛樻斁澶╂暟鏀惰垂锛堜笉瓒充竴澶╂寜涓�澶╄浠凤級</div>
+        <div class="price-items">
+          <div class="price-item" v-for="(item, index) in jiudiTableData" :key="index">
+            <span class="price-label">鍏朵腑{{item.categoryName}}姣忓ぉ鏀惰垂</span>
+            <el-input style="width: 200px;" v-model="item.unitPrice" type="number" placeholder="璇疯緭鍏�"></el-input>
+            <span class="price-unit">鍏�</span>
+          </div>
+        </div>
+      </el-tab-pane>
+      <el-tab-pane label="寮傚湴瀵勫瓨" name="remote">
+        <div class="remote-config-title">寮傚湴瀵勯�侀厤缃�</div>
+        <div class="remote-header">
+          <span class="remote-tip">鏍规嵁琛屾潕灏哄銆侀厤閫侀噷绋嬪強閰嶉�佷环鏍兼敹鍙栬垂鐢紙涓嶈冻1鍏噷鎸�1鍏噷璁′环锛�</span>
+        </div>
+        <el-table :data="remoteTableData" border stripe>
+          <el-table-column prop="categoryName" label="琛屾潕灏哄"></el-table-column>
+          <el-table-column label="璧烽�侀噷绋�(鍏噷)">
+            <template slot-scope="{row}">
+              <el-input v-model="row.startDistance" type="number" placeholder="璇疯緭鍏�"></el-input>
+            </template>
+          </el-table-column>
+          <el-table-column label="璧烽�佷环鏍�(鍏�)">
+            <template slot-scope="{row}">
+              <el-input v-model="row.startPrice" type="number" placeholder="璇疯緭鍏�"></el-input>
+            </template>
+          </el-table-column>
+          <el-table-column label="缁�侀噷绋�(鍏噷)">
+            <template slot-scope="{row}">
+              <el-input v-model="row.extraDistance" type="number" placeholder="璇疯緭鍏�"></el-input>
+            </template>
+          </el-table-column>
+          <el-table-column label="缁�佷环鏍�(鍏�)">
+            <template slot-scope="{row}">
+              <el-input v-model="row.extraPrice" type="number" placeholder="璇疯緭鍏�"></el-input>
+            </template>
+          </el-table-column>
+        </el-table>
+      </el-tab-pane>
+      <el-tab-pane label="棰勮鏃舵晥" name="time">
+        <div class="remote-config-title">棰勮鏃舵晥瑙勫垯</div>
+        <div class="remote-header">
+          <span class="remote-tip">鏍规嵁閰嶉�侀噷绋嬮璁¢厤閫佹椂闀垮苟灞曠ず鍦ㄥ皬绋嬪簭涓嬪崟椤甸潰</span>
+        </div>
+        <el-table :data="timeTableData" border stripe>
+          <el-table-column label="璧烽�侀噷绋�(鍏噷)">
+            <template slot-scope="{row}">
+              <el-input v-model="row.startDistance" type="number" placeholder="璇疯緭鍏�"></el-input>
+            </template>
+          </el-table-column>
+          <el-table-column label="璧烽�佹椂闀�(灏忔椂)">
+            <template slot-scope="{row}">
+              <el-input v-model="row.startTime" type="number" placeholder="璇疯緭鍏�"></el-input>
+            </template>
+          </el-table-column>
+          <el-table-column label="缁�侀噷绋�(鍏噷)">
+            <template slot-scope="{row}">
+              <el-input v-model="row.continueDistance" type="number" placeholder="璇疯緭鍏�"></el-input>
+            </template>
+          </el-table-column>
+          <el-table-column label="缁�佹椂闀�(灏忔椂)">
+            <template slot-scope="{row}">
+              <el-input v-model="row.continueTime" type="number" placeholder="璇疯緭鍏�"></el-input>
+            </template>
+          </el-table-column>
+        </el-table>
+      </el-tab-pane>
+      <el-tab-pane label="闂ㄥ簵娉ㄥ唽鎶奸噾" name="deposit">
+        <div class="price-tip">鏍规嵁鎵�鍦ㄥ煄甯備互鍙婃敞鍐岀被鍨嬩笉鍚岋紝骞冲彴鏀跺彇涓嶅悓鏁伴鎶奸噾銆傛娂閲戜細鍦ㄩ棬搴楅��缃戝悗绾夸笅鍘熼閫�杩橈紙闂ㄥ簵绾夸笂寰俊鏀粯鐨勬娂閲戝洜寰俊瀹樻柟瑕佹眰鍏锋湁鏃舵晥鎬э級</div>
+        <div class="price-items">
+          <div class="price-item" v-for="(item, index) in storeDepositData" :key="index">
+            <span class="price-label">鍏朵腑{{item.fieldTypeName}}鏀跺彇鎶奸噾</span>
+            <el-input style="width: 200px;" v-model="item.depositAmount" type="number" placeholder="璇疯緭鍏�"></el-input>
+            <span class="price-unit">鍏�</span>
+          </div>
+        </div>
+      </el-tab-pane>
+      <el-tab-pane label="鍒嗘垚姣斾緥" name="share">
+        <div class="price-tip">鏍规嵁璁㈠崟涓笉鍚岃繍钀ヨ鑹茶�岀嫭绔嬮厤缃笉鍚屽垎鎴愭瘮渚�</div>
+        <div class="price-items">
+          <div class="price-item" v-for="(item, index) in shareTableData" :key="index">
+            <span class="price-label">{{item.fieldType === 4 ? '鍦ㄨ鍗曚腑浣滀负閰嶉�佸憳鏃讹紝' : '鍏朵腑闂ㄥ簵绫诲瀷涓�'}}{{item.fieldTypeName}}鍒嗘垚姣斾緥涓�</span>
+            <el-input style="width: 100px;" v-model="item.ratio" type="number" placeholder="璇疯緭鍏�"></el-input>
+            <span class="price-unit">%</span>
+          </div>
+        </div>
+      </el-tab-pane>
+    </el-tabs>
+    <div slot="footer" class="dialog-footer">
+      <el-button @click="visible = false">鍙栨秷</el-button>
+      <el-button type="primary" @click="confirm" :loading="isWorking">纭畾</el-button>
+    </div>
+  </GlobalWindow>
+</template>
+
+<script>
+import BaseOpera from '@/components/base/BaseOpera'
+import GlobalWindow from '@/components/common/GlobalWindow'
+import {
+  localStorage,
+  remoteDelivery,
+  estimatedDelivery,
+  storeDeposit,
+  revenueShare,
+  batchSave,
+  batchSaveRemoteDelivery,
+  batchSaveEstimatedDelivery,
+  batchSaveStoreDeposit,
+  batchSaveRevenueShare
+} from '@/api/business/pricingRule'
+export default {
+  name: 'OperaCityPriceRuleWindow',
+  extends: BaseOpera,
+  components: { GlobalWindow },
+  data () {
+    return {
+      activeTab: 'local',
+
+      jiudiTableData: [],
+      remoteTableData: [],
+      timeTableData: [],
+      storeDepositData: [],
+      shareTableData: [],
+
+      form: {
+        cityId: null
+      }
+    }
+  },
+  created () {
+    this.config({
+      api: '/business/pricingRule',
+      'field.id': 'id'
+    })
+  },
+  methods: {
+    open (title, target) {
+      this.title = title
+      this.visible = true
+      this.activeTab = 'local'
+      this.jiudiTableData = []
+      this.remoteTableData = []
+      this.timeTableData = []
+      this.storeDepositData = []
+      this.shareTableData = []
+      this.form = {
+        cityId: target
+      }
+      this.fetchPriceRule()
+      this.fetchRemoteDelivery()
+      this.fetchEstimatedDelivery()
+      this.fetchStoreDeposit()
+      this.fetchRevenueShare()
+    },
+    // 鏌ヨ灏卞湴瀛樺彇瑙勫垯鍒楄〃
+    fetchPriceRule () {
+      localStorage(this.form.cityId)
+        .then(data => {
+          this.jiudiTableData = data
+        })
+        .catch(e => {
+          this.$tip.apiFailed(e)
+        })
+    },
+    // 鏌ヨ寮傚湴瀵勯�佽鍒欏垪琛�
+    fetchRemoteDelivery () {
+      remoteDelivery(this.form.cityId)
+        .then(data => {
+          this.remoteTableData = data
+        })
+        .catch(e => {
+          this.$tip.apiFailed(e)
+        })
+    },
+    // 鏌ヨ寮傚湴瀵勯�佽鍒欏垪琛�
+    fetchEstimatedDelivery () {
+      estimatedDelivery(this.form.cityId)
+        .then(data => {
+          this.timeTableData = [
+            data
+          ]
+        })
+        .catch(e => {
+          this.$tip.apiFailed(e)
+        })
+    },
+    // 鏌ヨ闂ㄥ簵娉ㄥ唽鎶奸噾瑙勫垯鍒楄〃
+    fetchStoreDeposit () {
+      storeDeposit(this.form.cityId)
+        .then(data => {
+          this.storeDepositData = data
+        })
+        .catch(e => {
+          this.$tip.apiFailed(e)
+        })
+    },
+    // 鏌ヨ鍒嗘垚姣斾緥瑙勫垯鍒楄〃
+    fetchRevenueShare () {
+      revenueShare(this.form.cityId)
+        .then(data => {
+          this.shareTableData = data
+        })
+        .catch(e => {
+          this.$tip.apiFailed(e)
+        })
+    },
+    // 淇濆瓨鎵�鏈夎鍒�
+    confirm () {
+      if (!this.validateLocalStorage()) return
+      if (!this.validateRemoteDelivery()) return
+      if (!this.validateEstimatedDelivery()) return
+      if (!this.validateStoreDeposit()) return
+      if (!this.validateRevenueShare()) return
+
+      this.isWorking = true
+      Promise.all([
+        batchSave({ cityId: this.form.cityId, items: this.jiudiTableData }),
+        batchSaveRemoteDelivery({ cityId: this.form.cityId, items: this.remoteTableData }),
+        batchSaveEstimatedDelivery({ cityId: this.form.cityId, ...this.timeTableData[0] }),
+        batchSaveStoreDeposit({ cityId: this.form.cityId, items: this.storeDepositData }),
+        batchSaveRevenueShare({ cityId: this.form.cityId, items: this.shareTableData })
+      ])
+        .then(() => {
+          this.visible = false
+          this.$tip.apiSuccess('淇濆瓨鎴愬姛')
+          this.$emit('success')
+        })
+        .catch(e => {
+          this.$tip.apiFailed(e)
+        })
+        .finally(() => {
+          this.isWorking = false
+        })
+    },
+    // 鏍¢獙灏卞湴瀵勫瓨
+    validateLocalStorage () {
+      for (const item of this.jiudiTableData) {
+        if (item.unitPrice === null || item.unitPrice === undefined || item.unitPrice === '') {
+          this.$message.error('璇峰~鍐欐墍鏈夊氨鍦板瘎瀛樼殑鏀惰垂閲戦')
+          return false
+        }
+      }
+      return true
+    },
+    // 鏍¢獙寮傚湴瀵勫瓨
+    validateRemoteDelivery () {
+      for (const item of this.remoteTableData) {
+        if (item.startDistance === null || item.startDistance === undefined || item.startDistance === '' ||
+            item.startPrice === null || item.startPrice === undefined || item.startPrice === '' ||
+            item.extraDistance === null || item.extraDistance === undefined || item.extraDistance === '' ||
+            item.extraPrice === null || item.extraPrice === undefined || item.extraPrice === '') {
+          this.$message.error('璇峰~鍐欐墍鏈夊紓鍦板瘎閫佺殑閰嶇疆淇℃伅')
+          return false
+        }
+      }
+      return true
+    },
+    // 鏍¢獙棰勮鏃舵晥
+    validateEstimatedDelivery () {
+      const item = this.timeTableData[0]
+      if (!item || item.startDistance === null || item.startDistance === undefined || item.startDistance === '' ||
+          item.startTime === null || item.startTime === undefined || item.startTime === '' ||
+          item.continueDistance === null || item.continueDistance === undefined || item.continueDistance === '' ||
+          item.continueTime === null || item.continueTime === undefined || item.continueTime === '') {
+        this.$message.error('璇峰~鍐欓璁℃椂鏁堢殑鎵�鏈夐厤缃俊鎭�')
+        return false
+      }
+      return true
+    },
+    // 鏍¢獙闂ㄥ簵娉ㄥ唽鎶奸噾
+    validateStoreDeposit () {
+      for (const item of this.storeDepositData) {
+        if (item.depositAmount === null || item.depositAmount === undefined || item.depositAmount === '') {
+          this.$message.error('璇峰~鍐欐墍鏈夐棬搴楁敞鍐屾娂閲戠殑閲戦')
+          return false
+        }
+      }
+      return true
+    },
+    // 鏍¢獙鍒嗘垚姣斾緥
+    validateRevenueShare () {
+      for (const item of this.shareTableData) {
+        if (item.ratio === null || item.ratio === undefined || item.ratio === '') {
+          this.$message.error('璇峰~鍐欐墍鏈夊垎鎴愭瘮渚�')
+          return false
+        }
+      }
+      return true
+    }
+  }
+}
+</script>
+
+<style scoped>
+.price-tip {
+  margin-bottom: 20px;
+  color: #666;
+  font-size: 14px;
+}
+.price-items {
+  display: flex;
+  flex-direction: column;
+  gap: 16px;
+}
+.price-item {
+  display: flex;
+  align-items: center;
+  gap: 10px;
+}
+.price-label {
+  flex-shrink: 0;
+  font-weight: 500;
+}
+.price-unit {
+  color: #666;
+  white-space: nowrap;
+}
+.dialog-footer {
+  text-align: right;
+  padding: 0 20px;
+  box-sizing: border-box;
+  border-top: 1px solid #eee;
+}
+.remote-config-title {
+  font-weight: bold;
+  margin-bottom: 15px;
+}
+.remote-header {
+  display: flex;
+  align-items: center;
+  gap: 15px;
+  margin-bottom: 15px;
+}
+.remote-tip {
+  color: #666;
+  font-size: 14px;
+}
+.remote-pagination {
+  margin-top: 15px;
+  text-align: right;
+}
+</style>
\ No newline at end of file

--
Gitblit v1.9.3