From fdeb869c386da95150a087bc22bcebc4e57d0f76 Mon Sep 17 00:00:00 2001
From: Tevin <tingquanren@163.com>
Date: Tue, 18 Mar 2025 18:16:32 +0800
Subject: [PATCH] 更新所有表单组件文档和头注释

---
 forms/chinaArea/CChinaArea.vue |  293 +++++++++++++++++++++++++++++++++++++++++++---------------
 1 files changed, 217 insertions(+), 76 deletions(-)

diff --git a/forms/chinaArea/CChinaArea.vue b/forms/chinaArea/CChinaArea.vue
index 5bfe017..faadcf5 100644
--- a/forms/chinaArea/CChinaArea.vue
+++ b/forms/chinaArea/CChinaArea.vue
@@ -1,11 +1,15 @@
 /**
- * CChinaArea
+ * CChinaArea - 表单项,中国地址三级联动
+ * 中国地区选择器组件,用于在表单中选择省市区地址
+ * 内置完整的中国行政区划数据,支持多级联动选择
+ * 支持自动通过地理定位获取省市区
  * @author Tevin
  */
 
 <template>
     <view class="c-china-area">
         <picker
+            class="c-china-area-picker"
             mode="multiSelector"
             :range="range"
             :value="current"
@@ -16,14 +20,14 @@
             <view @tap="evt=>handleOpen(evt)">
                 <AtInput
                     ref="input"
-                    :name="itemData.name"
-                    :title="itemData.label"
-                    :required="itemData.required"
-                    :error="itemData.error"
+                    :name="itemRes.name"
+                    :title="itemRes.label"
+                    :required="itemRes.required"
+                    :error="itemRes.error"
                     :placeholder="placeholder"
                     :value="selected"
                 >
-                    <view class="at-icon at-icon-chevron-right" />
+                    <AtIcon :value="loading ? 'loading':'chevron-right'" />
                 </AtInput>
             </view>
         </picker>
@@ -31,32 +35,45 @@
 </template>
 
 <script>
-import { AtInput } from 'taro-ui-vue';
-import ChinaLocations from './ChinaLocations';
+import Taro from '@tarojs/taro';
+import { AtInput, AtIcon } from 'taro-ui-vue';
+import { $locations } from '@components/forms/chinaArea/ChinaLocations';
 import './cChinaArea.scss';
-
-const { locationTree, getRegionNames } = ChinaLocations;
 
 export default {
     name: 'CChinaArea',
     components: {
         AtInput,
+        AtIcon,
     },
     props: {
+        // 表单数据资源(表单组件内部机制专用)
+        itemRes: Object,
+        // 是否自动通过地理定位获取省市区
+        autoGeo: {
+            type: Boolean,
+            default: false,
+        },
+        // 联动级别
+        level: {
+            type: Number,
+            default: 3,
+        },
+        // 占位提示
         placeholder: String,
-        itemData: Object,
     },
     data() {
         return {
-            range: [[], [], []],
-            current: [0, 0, 0],
+            loading: true,
+            range: [],
+            current: [],
         };
     },
     computed: {
         selected() {
-            const curVal = this.itemData.formData[this.itemData.name];
-            if (curVal && curVal.length === 3) {
-                return getRegionNames(curVal).join(' / ');
+            const curVal = this.itemRes.formData[this.itemRes.name];
+            if (curVal && (curVal.length === 3 || curVal.length === 4)) {
+                return curVal.join(' / ');
             } else {
                 return '';
             }
@@ -64,76 +81,200 @@
     },
     methods: {
         handleOpen(evt) {
-            if (evt.target.className.indexOf('at-input__title') >= 0) {
-                evt.stopPropagation();
-                evt.preventDefault();
-                return;
+            if (process.env.TARO_ENV === 'h5') {
+                if (evt && evt.target.className.indexOf('at-input__title') >= 0) {
+                    evt.stopPropagation();
+                    evt.preventDefault();
+                    return;
+                }
             }
-            const curVal = this.itemData.formData[this.itemData.name];
-            const range = [
-                locationTree,
-                locationTree[0].children,
-                locationTree[0].children[0].children,
-            ];
-            const current = [0, 0, 0];
-            // 有值
-            if (curVal && curVal.length > 0) {
-                // 省
-                if (curVal[0]) {
-                    const proviceIndex = locationTree.findIndex(
-                        (provice) => provice.code === curVal[0]
-                    );
-                    if (proviceIndex >= 0) {
-                        range[1] = locationTree[proviceIndex].children;
-                        range[2] = locationTree[proviceIndex].children[0].children;
-                        current[0] = proviceIndex;
-                        // 市
-                        if (curVal[1]) {
-                            const cityIndex = range[1].findIndex((city) => city.code === curVal[1]);
-                            if (cityIndex >= 0) {
-                                range[2] = range[1].children[cityIndex].children;
-                                current[1] = cityIndex;
-                            }
-                            // 区
-                            if (curVal[2]) {
-                                const areaIndex = range[2].findIndex(
-                                    (area) => area.code === curVal[2]
-                                );
-                                if (areaIndex >= 0) {
-                                    current[2] === areaIndex;
+            $locations.getLocationTree(this.level, locationTree => {
+                const curVal = this.itemRes.formData[this.itemRes.name];
+                const range2 = (locationTree[0] || {}).children || [];
+                const range3 = (range2[0] || {}).children || [];
+                const range = [locationTree, range2, range3];
+                const current = [0, 0, 0];
+                if (this.level === 4) {
+                    const range4 = (range3[0] || {}).children || [];
+                    range[3] = range4;
+                    current[3] = '';
+                }
+                // 有值
+                if (curVal && curVal.length > 0) {
+                    $locations.getRegionCodes(curVal, codes => {
+                        // 省
+                        if (codes[0]) {
+                            const proviceIndex = locationTree.findIndex(
+                                provice => provice.value === codes[0],
+                            );
+                            if (proviceIndex >= 0) {
+                                range[1] = locationTree[proviceIndex].children;
+                                range[2] =
+                                    locationTree[proviceIndex].children[0].children;
+                                current[0] = proviceIndex;
+                                // 市
+                                if (codes[1]) {
+                                    const cityIndex = range[1].findIndex(
+                                        city => city.value === codes[1],
+                                    );
+                                    if (cityIndex >= 0) {
+                                        range[2] = range[1][cityIndex].children;
+                                        current[1] = cityIndex;
+                                    }
+                                    // 区
+                                    if (codes[2]) {
+                                        const distIndex = range[2].findIndex(
+                                            dist => dist.value === codes[2],
+                                        );
+                                        if (distIndex >= 0) {
+                                            current[2] = distIndex;
+                                        }
+                                        // 街
+                                        if (this.level === 4) {
+                                            range[3] =
+                                                range[2][current[2]].children || [];
+                                            const streetIndex = range[3].findIndex(
+                                                street => street.value === codes[3],
+                                            );
+                                            if (streetIndex >= 0) {
+                                                current[3] = streetIndex;
+                                            }
+                                        }
+                                    }
                                 }
                             }
                         }
-                    }
+                    });
                 }
-            }
-            this.range = range;
-            this.current = current;
+                this.range = range;
+                setTimeout(() => {
+                    this.current = current;
+                }, 100);
+            });
         },
         updateColumns(roll) {
-            if (roll.column === 0) {
-                const cities = locationTree[roll.value].children;
-                this.range.splice(1, 2, cities, cities[0].children);
-                this.current = [roll.value, 0, 0];
-            } else if (roll.column === 1) {
-                const areas = locationTree[this.current[0]].children[roll.value].children;
-                this.range.splice(2, 1, areas);
-                this.current = [this.current[0], roll.value, 0];
-            } else if (roll.column === 3) {
-                this.current.splice(2, 1, roll.value);
-            }
+            $locations.getLocationTree(this.level, locationTree => {
+                // 第一列滚动
+                if (roll.column === 0) {
+                    const cities = locationTree[roll.value].children;
+                    this.range = [this.range[0], cities, cities[0].children];
+                    this.current = [roll.value, 0, 0];
+                    if (this.level === 4) {
+                        const range3 = (cities[0].children[0] || {}).children || [];
+                        this.range.splice(3, 1, range3);
+                        this.current.splice(3, 1, '');
+                    }
+                }
+                // 第二列滚动
+                else if (roll.column === 1) {
+                    const dists =
+                        locationTree[this.current[0]].children[roll.value].children;
+                    this.range = [this.range[0], this.range[1], dists];
+                    this.current = [this.current[0], roll.value, 0];
+                    if (this.level === 4) {
+                        const range3 = dists[0].children || [];
+                        this.range.splice(3, 1, range3);
+                        this.current.splice(3, 1, '');
+                    }
+                }
+                // 第三列滚动
+                else if (roll.column === 2) {
+                    this.current.splice(2, 1, roll.value);
+                    if (this.level === 4) {
+                        const streets =
+                            locationTree[this.current[0]].children[this.current[1]]
+                                .children[roll.value].children || [];
+                        this.range.splice(3, 1, streets);
+                        this.current.splice(3, 1, '');
+                    }
+                }
+                // 第四列滚动
+                else if (roll.column === 3) {
+                    this.current.splice(3, 1, roll.value);
+                }
+            });
         },
         handleChange(detail) {
-            const codes = [];
-            const provice = locationTree[detail[0]];
-            codes[0] = provice.value;
-            const city = provice.children[detail[1]];
-            codes[1] = city.value;
-            const area = city.children[detail[2]];
-            codes[2] = area.value;
-            this.itemData.onChange(codes);
+            $locations.getLocationTree(this.level, locationTree => {
+                const names = [];
+                const provice = locationTree[detail[0]];
+                names[0] = provice.label;
+                const city = provice.children[detail[1]] || {};
+                names[1] = city.label;
+                const dist = city.children[detail[2]] || {};
+                names[2] = dist.label;
+                if (this.level === 4) {
+                    const street = (dist.children || [])[detail[3]] || {};
+                    if (street.value) {
+                        names[3] = street.label;
+                    }
+                }
+                this.itemRes.onChange(names);
+            });
+        },
+        _getGeoLocation() {
+            this.loading = true;
+            Taro.getLocation({
+                type: 'wgs84',
+                success: res => {
+                    const latitude = res.latitude;
+                    const longitude = res.longitude;
+                    const myGeo = new BMap.Geocoder();
+                    // 根据坐标得到地址描述
+                    myGeo.getLocation(new BMap.Point(longitude, latitude), result => {
+                        if (!result) {
+                            this.locationLoading = false;
+                            return;
+                        }
+                        const address = result.addressComponents;
+                        const regions = [
+                            address.province.replace(/省|市|自治区|特别行政区/g, ''),
+                            address.city,
+                            address.district,
+                        ];
+                        if (this.level === 4) {
+                            regions.push(address.street);
+                        }
+                        $locations.getRegionCodes(regions, codes => {
+                            if (codes && codes.length > 0) {
+                                $locations.getRegionNames(codes, names => {
+                                    this.itemRes.onChange(names);
+                                });
+                            }
+                        });
+                        this.loading = false;
+                    });
+                },
+                cancel: res => (this.loading = false),
+                fail: err => (this.loading = false),
+            });
         },
     },
-    mounted() {},
+    mounted() {
+        $locations.onReady(() => {
+            this.loading = false;
+            this.handleOpen();
+            // 开启自动定位时,延迟 0.1 秒后发起定位
+            if (this.autoGeo) {
+                if (process.env.TARO_ENV === 'weapp') {
+                    setTimeout(() => {
+                        // TODO:小程序中定位
+                    }, 100);
+                } else if (process.env.TARO_ENV === 'h5') {
+                    if (typeof wx === 'undefined') {
+                        console.warn('无法进行地理位置定位,wx 不存在!');
+                        return;
+                    }
+                    wx.ready(() => {
+                        if (typeof BMap === 'undefined') {
+                            console.warn('无法进行地理位置定位,BMap 不存在!');
+                            return;
+                        }
+                        this._getGeoLocation();
+                    });
+                }
+            }
+        });
+    },
 };
 </script>
\ No newline at end of file

--
Gitblit v1.9.1