|
@@ -1,7 +1,6 @@
|
|
|
<!-- 区域选择弹窗 -->
|
|
<!-- 区域选择弹窗 -->
|
|
|
<template>
|
|
<template>
|
|
|
- <ele-modal form :width="1080" :bodyStyle="{ 'min-height': '400px' }" v-model="visible" :title="title"
|
|
|
|
|
- @open="handleOpen">
|
|
|
|
|
|
|
+ <ele-modal form :width="1080" :bodyStyle="{ 'min-height': '400px' }" v-model="visible" :title="title">
|
|
|
<div class="flex flex-col" v-loading="loading">
|
|
<div class="flex flex-col" v-loading="loading">
|
|
|
<div class="flex" v-for="dq in areaList" :key="dq.code">
|
|
<div class="flex" v-for="dq in areaList" :key="dq.code">
|
|
|
<el-checkbox :label="dq.name" :indeterminate="isIndeterminateShow(dq)" style="min-width: 100px"
|
|
<el-checkbox :label="dq.name" :indeterminate="isIndeterminateShow(dq)" style="min-width: 100px"
|
|
@@ -49,6 +48,7 @@
|
|
|
<script setup>
|
|
<script setup>
|
|
|
import { ref, reactive, nextTick, computed, defineEmits, defineExpose } from 'vue';
|
|
import { ref, reactive, nextTick, computed, defineEmits, defineExpose } from 'vue';
|
|
|
import { CaretBottom } from '@element-plus/icons-vue';
|
|
import { CaretBottom } from '@element-plus/icons-vue';
|
|
|
|
|
+import request from '@/utils/request';
|
|
|
|
|
|
|
|
const emit = defineEmits(['confirm']);
|
|
const emit = defineEmits(['confirm']);
|
|
|
const visible = defineModel({ type: Boolean });
|
|
const visible = defineModel({ type: Boolean });
|
|
@@ -57,80 +57,53 @@ const title = ref('选择配送区域');
|
|
|
const loading = ref(false);
|
|
const loading = ref(false);
|
|
|
const areaList = ref([]);
|
|
const areaList = ref([]);
|
|
|
|
|
|
|
|
-// Mock Data Generation
|
|
|
|
|
-const generateMockData = () => {
|
|
|
|
|
- const regions = {
|
|
|
|
|
- 'hd': ['上海', '江苏', '浙江', '安徽', '福建', '江西', '山东'],
|
|
|
|
|
- 'hb': ['北京', '天津', '河北', '山西', '内蒙古'],
|
|
|
|
|
- 'hz': ['河南', '湖北', '湖南'],
|
|
|
|
|
- 'hn': ['广东', '广西', '海南'],
|
|
|
|
|
- 'db': ['辽宁', '吉林', '黑龙江'],
|
|
|
|
|
- 'xb': ['陕西', '甘肃', '青海', '宁夏', '新疆'],
|
|
|
|
|
- 'xn': ['重庆', '四川', '贵州', '云南', '西藏'],
|
|
|
|
|
- 'gat': ['香港', '澳门', '台湾'],
|
|
|
|
|
- 'hw': ['海外']
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- const mockData = {};
|
|
|
|
|
- let idCounter = 1;
|
|
|
|
|
-
|
|
|
|
|
- for (const [code, provinces] of Object.entries(regions)) {
|
|
|
|
|
- mockData[code] = provinces.map(prov => ({
|
|
|
|
|
- id: idCounter++,
|
|
|
|
|
- district: prov,
|
|
|
|
|
- code: code, // Adding code for key if needed
|
|
|
|
|
- mySelected: 0,
|
|
|
|
|
- otherSelected: 0,
|
|
|
|
|
- childInfo: [] // For simplicity, no cities for now, or maybe just one '全境' city if needed, but let's assume province level for fee template mostly.
|
|
|
|
|
- // Wait, the original code uses childInfo for popover. Let's add dummy cities.
|
|
|
|
|
- }));
|
|
|
|
|
-
|
|
|
|
|
- // Add dummy cities for interaction testing
|
|
|
|
|
- mockData[code].forEach(prov => {
|
|
|
|
|
- prov.childInfo = [
|
|
|
|
|
- { id: idCounter++, district: prov.district + '市1', mySelected: 0, otherSelected: 0 },
|
|
|
|
|
- { id: idCounter++, district: prov.district + '市2', mySelected: 0, otherSelected: 0 }
|
|
|
|
|
- ];
|
|
|
|
|
- });
|
|
|
|
|
|
|
+// Fetch Province Info
|
|
|
|
|
+const getProvinceInfo = async () => {
|
|
|
|
|
+ loading.value = true;
|
|
|
|
|
+ try {
|
|
|
|
|
+ const res = await request.get('/shipping/templete/provinceInfo');
|
|
|
|
|
+ if (res.data.code === 200) {
|
|
|
|
|
+ return res.data.data || [];
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (error) {
|
|
|
|
|
+ console.error(error);
|
|
|
|
|
+ } finally {
|
|
|
|
|
+ loading.value = false;
|
|
|
}
|
|
}
|
|
|
- return mockData;
|
|
|
|
|
|
|
+ return [];
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
-// Define Regions
|
|
|
|
|
-const dqList = ref([
|
|
|
|
|
- { name: '华东', code: 'hd' },
|
|
|
|
|
- { name: '华北', code: 'hb' },
|
|
|
|
|
- { name: '华中', code: 'hz' },
|
|
|
|
|
- { name: '华南', code: 'hn' },
|
|
|
|
|
- { name: '东北', code: 'db' },
|
|
|
|
|
- { name: '西北', code: 'xb' },
|
|
|
|
|
- { name: '西南', code: 'xn' },
|
|
|
|
|
- { name: '港澳台', code: 'gat' },
|
|
|
|
|
- { name: '海外', code: 'hw' }
|
|
|
|
|
-]);
|
|
|
|
|
-
|
|
|
|
|
-const handleOpen = (existingSelection) => {
|
|
|
|
|
|
|
+const handleOpen = async (existingSelection) => {
|
|
|
visible.value = true;
|
|
visible.value = true;
|
|
|
loading.value = true;
|
|
loading.value = true;
|
|
|
|
|
|
|
|
- // Simulate API call
|
|
|
|
|
- setTimeout(() => {
|
|
|
|
|
- const data = generateMockData();
|
|
|
|
|
- areaList.value = [];
|
|
|
|
|
- dqList.value.forEach((item) => {
|
|
|
|
|
- const dqItem = { ...item, checked: false, children: data[item.code] || [] };
|
|
|
|
|
- areaList.value.push(dqItem);
|
|
|
|
|
|
|
+ const data = await getProvinceInfo();
|
|
|
|
|
+
|
|
|
|
|
+ // Transform API data to component structure
|
|
|
|
|
+ areaList.value = data.map(area => ({
|
|
|
|
|
+ name: area.areaCode,
|
|
|
|
|
+ code: area.areaCode,
|
|
|
|
|
+ children: (area.provinceInfo || []).map(prov => ({
|
|
|
|
|
+ id: prov.provinceId,
|
|
|
|
|
+ district: prov.provinceName,
|
|
|
|
|
+ mySelected: 0,
|
|
|
|
|
+ childInfo: [] // API only provides provinces, no cities
|
|
|
|
|
+ }))
|
|
|
|
|
+ }));
|
|
|
|
|
+
|
|
|
|
|
+ // Restore selection
|
|
|
|
|
+ if (existingSelection && Array.isArray(existingSelection)) {
|
|
|
|
|
+ const selectedIds = new Set(existingSelection.map(item => item.provinceId));
|
|
|
|
|
+ areaList.value.forEach(area => {
|
|
|
|
|
+ area.children.forEach(prov => {
|
|
|
|
|
+ if (selectedIds.has(prov.id)) {
|
|
|
|
|
+ prov.mySelected = 1;
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
});
|
|
});
|
|
|
-
|
|
|
|
|
- // Restore selection if passed (simplified restoration logic)
|
|
|
|
|
- // If existingSelection is passed, we would need to map it back to mySelected=1
|
|
|
|
|
- if (existingSelection && Array.isArray(existingSelection)) {
|
|
|
|
|
- // Logic to restore selection would go here
|
|
|
|
|
- // For now, let's just clear
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- loading.value = false;
|
|
|
|
|
- }, 300);
|
|
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ loading.value = false;
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
const handleCancel = () => {
|
|
const handleCancel = () => {
|
|
@@ -139,12 +112,11 @@ const handleCancel = () => {
|
|
|
|
|
|
|
|
// Computed Properties
|
|
// Computed Properties
|
|
|
const isPopoverDisabled = computed(() => (item) => {
|
|
const isPopoverDisabled = computed(() => (item) => {
|
|
|
- // Simplified: disabled if all children are 'otherSelected' (not applicable in this standalone version usually)
|
|
|
|
|
- return item.childInfo.length === 0;
|
|
|
|
|
|
|
+ return true; // Always disabled as no cities
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
const isShowAll = computed(() => (item) => {
|
|
const isShowAll = computed(() => (item) => {
|
|
|
- return item.childInfo.length > 0 && item.childInfo.every((i) => i.mySelected == 1);
|
|
|
|
|
|
|
+ return false; // No cities to show all
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
const isIndeterminateShow = computed(() => (dq) => {
|
|
const isIndeterminateShow = computed(() => (dq) => {
|
|
@@ -154,9 +126,7 @@ const isIndeterminateShow = computed(() => (dq) => {
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
const isIndeterCityShow = computed(() => (item, type) => {
|
|
const isIndeterCityShow = computed(() => (item, type) => {
|
|
|
- let len = item.childInfo.length;
|
|
|
|
|
- let length = item.childInfo.filter((i) => i[type] == 1).length;
|
|
|
|
|
- return length > 0 && length < len;
|
|
|
|
|
|
|
+ return false;
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
// Event Handlers
|
|
// Event Handlers
|
|
@@ -164,46 +134,38 @@ const handleDqChange = (value, dq) => {
|
|
|
const val = value ? 1 : 0;
|
|
const val = value ? 1 : 0;
|
|
|
dq.children.forEach((item) => {
|
|
dq.children.forEach((item) => {
|
|
|
item.mySelected = val;
|
|
item.mySelected = val;
|
|
|
- item.childInfo.forEach((i) => {
|
|
|
|
|
- i.mySelected = val;
|
|
|
|
|
- });
|
|
|
|
|
});
|
|
});
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
const handleParentChange = (value, item) => {
|
|
const handleParentChange = (value, item) => {
|
|
|
- const val = value ? 1 : 0;
|
|
|
|
|
- item.childInfo.forEach((i) => {
|
|
|
|
|
- i.mySelected = val;
|
|
|
|
|
- });
|
|
|
|
|
|
|
+ // value is boolean from checkbox
|
|
|
|
|
+ // item.mySelected is bound to v-model, so it updates automatically?
|
|
|
|
|
+ // Wait, v-model="item.mySelected" on checkbox updates it.
|
|
|
|
|
+ // But we also need to handle 'change' event if we want extra logic.
|
|
|
|
|
+ // The template uses: @change="(value) => handleParentChange(value, item)"
|
|
|
|
|
+ // and v-model="item.mySelected".
|
|
|
|
|
+ // Element Plus checkbox change emits the new value.
|
|
|
|
|
+ // We don't need to manually set item.mySelected if v-model is used,
|
|
|
|
|
+ // but the original code did manual updates for children.
|
|
|
|
|
+ // Since we have no children (cities), we might just rely on v-model.
|
|
|
|
|
+ // However, keeping the handler for consistency.
|
|
|
|
|
+ item.mySelected = value ? 1 : 0;
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
const handleChildChange = (value, item, child) => {
|
|
const handleChildChange = (value, item, child) => {
|
|
|
- let checked = item.childInfo.some((i) => i.mySelected == 1);
|
|
|
|
|
- item.mySelected = checked ? 1 : 0;
|
|
|
|
|
|
|
+ // No children
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
const handleSubmit = () => {
|
|
const handleSubmit = () => {
|
|
|
- // Collect selected regions
|
|
|
|
|
|
|
+ // Collect selected provinces
|
|
|
const selected = [];
|
|
const selected = [];
|
|
|
areaList.value.forEach(dq => {
|
|
areaList.value.forEach(dq => {
|
|
|
dq.children.forEach(prov => {
|
|
dq.children.forEach(prov => {
|
|
|
if (prov.mySelected === 1) {
|
|
if (prov.mySelected === 1) {
|
|
|
- // If all cities selected, just push province name
|
|
|
|
|
- if (isShowAll.value(prov)) {
|
|
|
|
|
- selected.push(prov.district);
|
|
|
|
|
- } else {
|
|
|
|
|
- // Else push selected cities
|
|
|
|
|
- const cities = prov.childInfo.filter(c => c.mySelected === 1).map(c => c.district);
|
|
|
|
|
- if (cities.length > 0) {
|
|
|
|
|
- selected.push(`${prov.district}(${cities.join(',')})`);
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- } else {
|
|
|
|
|
- // Check partial selection
|
|
|
|
|
- const cities = prov.childInfo.filter(c => c.mySelected === 1).map(c => c.district);
|
|
|
|
|
- if (cities.length > 0) {
|
|
|
|
|
- selected.push(`${prov.district}(${cities.join(',')})`);
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ selected.push({
|
|
|
|
|
+ provinceId: prov.id,
|
|
|
|
|
+ provinceName: prov.district
|
|
|
|
|
+ });
|
|
|
}
|
|
}
|
|
|
});
|
|
});
|
|
|
});
|
|
});
|