Prechádzať zdrojové kódy

feat(订单地址): 添加地区级联选择器组件并集成到地址表单

yz 1 mesiac pred
rodič
commit
722d48229e

+ 159 - 0
src/components/region-cascader/index.vue

@@ -0,0 +1,159 @@
+<template>
+  <el-cascader
+    ref="cascader"
+    v-model="selectedValues"
+    :options="options"
+    :props="cascaderProps"
+    :placeholder="placeholder"
+    :clearable="clearable"
+    :disabled="disabled"
+    :size="size"
+    @change="handleChange"
+    @expand-change="handleExpandChange"
+    filterable
+  />
+</template>
+
+<script>
+import { getLazyTree } from '@/api/base/region'
+
+export default {
+  name: 'RegionCascader',
+  props: {
+    value: {
+      type: [String, Array],
+      default: ''
+    },
+    placeholder: {
+      type: String,
+      default: '请选择省/市/区'
+    },
+    clearable: {
+      type: Boolean,
+      default: true
+    },
+    disabled: {
+      type: Boolean,
+      default: false
+    },
+    size: {
+      type: String,
+      default: 'small'
+    }
+  },
+  data() {
+    return {
+      options: [],
+      selectedValues: [],
+      cascaderProps: {
+        value: 'value',
+        label: 'title',
+        children: 'children',
+        lazy: true,
+        lazyLoad: this.lazyLoad,
+        checkStrictly: false
+      }
+    }
+  },
+  watch: {
+    value: {
+      handler(newVal) {
+        if (newVal && typeof newVal === 'string') {
+          this.selectedValues = []
+        } else if (Array.isArray(newVal)) {
+          this.selectedValues = [...newVal]
+        } else {
+          this.selectedValues = []
+        }
+      },
+      immediate: true
+    }
+  },
+  async mounted() {
+    await this.loadProvinces()
+  },
+  methods: {
+    async loadProvinces() {
+      try {
+        const res = await getLazyTree('00')
+        if (res.data.success) {
+          this.options = res.data.data.map(item => ({
+            ...item,
+            leaf: false
+          }))
+        }
+      } catch (error) {
+        console.error('加载省级数据失败:', error)
+        this.$message.error('加载省级数据失败')
+      }
+    },
+
+    async lazyLoad(node, resolve) {
+      const { level, value } = node
+      
+      try {
+        // 如果是第三级(区级),直接返回空数组,不再加载子级
+        if (level >= 3) {
+          resolve([])
+          return
+        }
+
+        const res = await getLazyTree(value)
+        if (res.data.success) {
+          const children = res.data.data.map(item => ({
+            ...item,
+            leaf: level >= 2 // 市级的子级(区级)设为叶子节点
+          }))
+          resolve(children)
+        } else {
+          resolve([])
+        }
+      } catch (error) {
+        console.error('加载子级数据失败:', error)
+        resolve([])
+      }
+    },
+
+    /**
+     * 选择改变事件
+     * @param {Array} values - 选中的值数组
+     */
+    handleChange(values) {
+      this.selectedValues = values || []
+      
+      // 获取选中的节点信息
+    //   const selectedNodes = this.$refs.cascader?.getCheckedNodes() || []
+      const selectedNodes = this.$refs.cascader ? this.$refs.cascader.getCheckedNodes() : []
+
+      let regionName = ''
+      let regionCode = ''
+      
+      if (values && values.length > 0) {
+        // 获取选中的节点信息
+        const selectedNodes = this.$refs.cascader.getCheckedNodes()
+        if (selectedNodes.length > 0) {
+          const node = selectedNodes[0]
+          regionName = node.pathLabels.join(' ')
+          regionCode = values[values.length - 1]
+        }
+      }
+
+      // 直接返回regionName作为组件的值,这样avue-crud可以正确验证
+      this.$emit('input', regionName)
+      this.$emit('change', {
+        values,
+        regionName,
+        regionCode
+      })
+    },
+
+    /**
+     * 展开改变事件
+     * @param {Array} activeValues - 当前展开的值
+     */
+    handleExpandChange(activeValues) {
+      this.$emit('expand-change', activeValues)
+    }
+  }
+}
+</script>

+ 53 - 2
src/views/order/address/index.vue

@@ -44,6 +44,15 @@
           {{ row.isActive === 1 ? '启用' : '禁用' }}
         </el-tag>
       </template>
+
+      <!-- 地区选择器插槽 -->
+      <template slot="regionNameForm" slot-scope="{value, column}">
+        <region-cascader
+          v-model="form.regionName"
+          @change="handleRegionChange"
+          :placeholder="column.placeholder || '请选择省/市/区'"
+        />
+      </template>
     </avue-crud>
   </basic-container>
 </template>
@@ -51,6 +60,7 @@
 <script>
 import { getList, add, update, remove, getDetail } from '@/api/order/address'
 import { mapGetters } from 'vuex'
+import RegionCascader from '@/components/region-cascader'
 
 /**
  * 客户地址查询参数
@@ -104,6 +114,10 @@ import { mapGetters } from 'vuex'
 
 export default {
   name: 'OrderAddress',
+  components: {
+    RegionCascader
+  },
+  // 在data中添加regionCascaderValue
   data() {
     return {
       /**
@@ -125,6 +139,12 @@ export default {
       loading: true,
       
       /**
+       * 地区级联选择器的值
+       * @type {Array}
+       */
+      regionCascaderValue: [],
+      
+      /**
        * 分页信息
        * @type {{pageSize: number, currentPage: number, total: number}}
        */
@@ -219,11 +239,12 @@ export default {
             prop: 'regionName',
             search: true,
             width: 150,
+            formSlot: true, // 启用表单插槽
             rules: [
               {
                 required: true,
-                message: '请输入地区名称',
-                trigger: 'blur'
+                message: '请选择地区',
+                trigger: 'change'
               }
             ]
           },
@@ -374,6 +395,26 @@ export default {
   },
   methods: {
     /**
+     * 地区选择改变事件
+     * @param {Object} data - 选择的地区数据
+     */
+    handleRegionChange(data) {
+      const { values, regionName, regionCode } = data
+      
+      // 直接设置表单字段值
+      this.form.regionName = regionName
+      // this.form.regionCode = regionCode
+      this.regionCascaderValue = values
+      
+      // 手动触发表单验证
+      this.$nextTick(() => {
+        if (this.$refs.crud && this.$refs.crud.$refs.dialogForm) {
+          this.$refs.crud.$refs.dialogForm.validateField('regionName')
+        }
+      })
+    },
+
+    /**
      * 新增前的回调
      * @param {Function} done - 完成回调
      * @param {string} type - 操作类型
@@ -384,9 +425,19 @@ export default {
         try {
           const res = await getDetail(this.form.id)
           this.form = res.data.data
+          
+          // 如果有地区数据,需要解析并设置级联选择器的值
+          if (this.form.regionCode) {
+            // 这里可能需要根据regionCode反向解析出完整的省市区路径
+            // 暂时清空,让用户重新选择
+            this.regionCascaderValue = []
+          }
         } catch (error) {
           window.console.log(error)
         }
+      } else {
+        // 新增时清空地区选择
+        this.regionCascaderValue = []
       }
       done()
     },