mirror of
				https://gitee.com/hhyykk/ipms-sjy-ui.git
				synced 2025-10-30 01:38:44 +08:00 
			
		
		
		
	运费模板性能优化。区域选择使用懒加载
This commit is contained in:
		| @@ -1,8 +1,16 @@ | |||||||
| import request from '@/config/axios' | import request from '@/config/axios' | ||||||
|  |  | ||||||
| // 获得地区树 | // 获得地区树 | ||||||
| export const getAreaTree = async (id: number) => { | export const getAreaTree = async () => { | ||||||
|   return await request.get({ url: '/system/area/tree?id=' + id }) |   return await request.get({ url: '/system/area/tree' }) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export const getChildrenArea = async (id: number) => { | ||||||
|  |   return await request.get({ url: '/system/area/getChildrenArea?id=' + id }) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export const getAreaListByIds = async (data) => { | ||||||
|  |   return await request.post({ url: '/system/area/list', data }) | ||||||
| } | } | ||||||
|  |  | ||||||
| // 获得 IP 对应的地区名 | // 获得 IP 对应的地区名 | ||||||
|   | |||||||
| @@ -194,3 +194,17 @@ export const convertToInteger = (num: number | string | undefined): number => { | |||||||
|   // TODO 分转元后还有小数则四舍五入 |   // TODO 分转元后还有小数则四舍五入 | ||||||
|   return Math.round(parsedNumber * 100) |   return Math.round(parsedNumber * 100) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * 元转分 | ||||||
|  |  */ | ||||||
|  | export const yuanToFen = (amount: string | number): number => { | ||||||
|  |   return Math.round(Number(amount) * 100) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * 分转元 | ||||||
|  |  */ | ||||||
|  | export const fenToYuan = (amount: string | number): number => { | ||||||
|  |   return Number((Number(amount) / 100).toFixed(2)) | ||||||
|  | } | ||||||
|   | |||||||
| @@ -11,7 +11,8 @@ const DEFAULT_CONFIG: TreeHelperConfig = { | |||||||
| export const defaultProps = { | export const defaultProps = { | ||||||
|   children: 'children', |   children: 'children', | ||||||
|   label: 'name', |   label: 'name', | ||||||
|   value: 'id' |   value: 'id', | ||||||
|  |   isLeaf: 'leaf' | ||||||
| } | } | ||||||
|  |  | ||||||
| const getConfig = (config: Partial<TreeHelperConfig>) => Object.assign({}, DEFAULT_CONFIG, config) | const getConfig = (config: Partial<TreeHelperConfig>) => Object.assign({}, DEFAULT_CONFIG, config) | ||||||
|   | |||||||
| @@ -21,16 +21,18 @@ | |||||||
|         <el-table border style="width: 100%" :data="formData.templateCharge"> |         <el-table border style="width: 100%" :data="formData.templateCharge"> | ||||||
|           <el-table-column align="center" label="区域"> |           <el-table-column align="center" label="区域"> | ||||||
|             <template #default="{ row }"> |             <template #default="{ row }"> | ||||||
|               <!--   @芋艿 TODO 数据多,性能有问题 , 如何解决 --> |               <!--   区域数据太多,用赖加载方式,要不然性能有问题 --> | ||||||
|               <el-tree-select |               <el-tree-select | ||||||
|                 v-model="row.areaId" |                 v-model="row.areaId" | ||||||
|                 :data="areaList" |                 lazy | ||||||
|  |                 :load="loadChargeArea" | ||||||
|                 :props="defaultProps" |                 :props="defaultProps" | ||||||
|                 node-key="id" |                 node-key="id" | ||||||
|                 check-strictly |                 check-strictly | ||||||
|                 show-checkbox |                 show-checkbox | ||||||
|                 check-on-click-node |                 check-on-click-node | ||||||
|                 :render-after-expand="false" |                 :render-after-expand="false" | ||||||
|  |                 :cache-data="areaCache" | ||||||
|               /> |               /> | ||||||
|             </template> |             </template> | ||||||
|           </el-table-column> |           </el-table-column> | ||||||
| @@ -39,7 +41,6 @@ | |||||||
|               <el-input-number v-model="row.startCount" :min="1" /> |               <el-input-number v-model="row.startCount" :min="1" /> | ||||||
|             </template> |             </template> | ||||||
|           </el-table-column> |           </el-table-column> | ||||||
|           <!--   TODO 元转换 分       --> |  | ||||||
|           <el-table-column label="运费(元)" prop="startPrice"> |           <el-table-column label="运费(元)" prop="startPrice"> | ||||||
|             <template #default="{ row }"> |             <template #default="{ row }"> | ||||||
|               <el-input-number v-model="row.startPrice" :min="1" /> |               <el-input-number v-model="row.startPrice" :min="1" /> | ||||||
| @@ -73,16 +74,18 @@ | |||||||
|         <el-table border style="width: 100%" :data="formData.templateFree"> |         <el-table border style="width: 100%" :data="formData.templateFree"> | ||||||
|           <el-table-column label="区域"> |           <el-table-column label="区域"> | ||||||
|             <template #default="{ row }"> |             <template #default="{ row }"> | ||||||
|               <!--   @芋艿 TODO 数据多,性能有问题 , 如何解决 --> |               <!--   区域数据太多,用赖加载方式,要不然性能有问题 --> | ||||||
|               <el-tree-select |               <el-tree-select | ||||||
|                 v-model="row.areaId" |                 v-model="row.areaId" | ||||||
|                 :data="areaList" |                 lazy | ||||||
|  |                 :load="loadFreeArea" | ||||||
|                 :props="defaultProps" |                 :props="defaultProps" | ||||||
|                 node-key="id" |                 node-key="id" | ||||||
|                 check-strictly |                 check-strictly | ||||||
|                 show-checkbox |                 show-checkbox | ||||||
|                 check-on-click-node |                 check-on-click-node | ||||||
|                 :render-after-expand="false" |                 :render-after-expand="false" | ||||||
|  |                 :cache-data="areaCache" | ||||||
|               /> |               /> | ||||||
|             </template> |             </template> | ||||||
|           </el-table-column> |           </el-table-column> | ||||||
| @@ -121,7 +124,9 @@ | |||||||
| <script setup lang="ts"> | <script setup lang="ts"> | ||||||
| import * as DeliveryExpressTemplateApi from '@/api/mall/trade/delivery/expressTemplate' | import * as DeliveryExpressTemplateApi from '@/api/mall/trade/delivery/expressTemplate' | ||||||
| import { defaultProps } from '@/utils/tree' | import { defaultProps } from '@/utils/tree' | ||||||
| import { getAreaTree } from '@/api/system/area' | import { yuanToFen, fenToYuan } from '@/utils' | ||||||
|  | import { getChildrenArea, getAreaListByIds } from '@/api/system/area' | ||||||
|  | import { cloneDeep } from 'lodash-es' | ||||||
| const { t } = useI18n() // 国际化 | const { t } = useI18n() // 国际化 | ||||||
| const message = useMessage() // 消息弹窗 | const message = useMessage() // 消息弹窗 | ||||||
|  |  | ||||||
| @@ -137,6 +142,7 @@ const formData = ref({ | |||||||
|   templateCharge: [], |   templateCharge: [], | ||||||
|   templateFree: [] |   templateFree: [] | ||||||
| }) | }) | ||||||
|  | const columnTitleMap = new Map() | ||||||
| const columnTitle = ref({ | const columnTitle = ref({ | ||||||
|   startCountTitle: '首件', |   startCountTitle: '首件', | ||||||
|   extraCountTitle: '续件', |   extraCountTitle: '续件', | ||||||
| @@ -148,7 +154,8 @@ const formRules = reactive({ | |||||||
|   sort: [{ required: true, message: '分类排序不能为空', trigger: 'blur' }] |   sort: [{ required: true, message: '分类排序不能为空', trigger: 'blur' }] | ||||||
| }) | }) | ||||||
| const formRef = ref() // 表单 Ref | const formRef = ref() // 表单 Ref | ||||||
| const areaList = ref([]) //区域数据 | const areaCache = ref([]) //由于区域节点懒加载,已选区域节点需要缓存展示 | ||||||
|  | // let areaTree: any[] | ||||||
| /** 打开弹窗 */ | /** 打开弹窗 */ | ||||||
| const open = async (type: string, id?: number) => { | const open = async (type: string, id?: number) => { | ||||||
|   dialogVisible.value = true |   dialogVisible.value = true | ||||||
| @@ -160,6 +167,26 @@ const open = async (type: string, id?: number) => { | |||||||
|     if (id) { |     if (id) { | ||||||
|       formLoading.value = true |       formLoading.value = true | ||||||
|       formData.value = await DeliveryExpressTemplateApi.getDeliveryExpressTemplate(id) |       formData.value = await DeliveryExpressTemplateApi.getDeliveryExpressTemplate(id) | ||||||
|  |       columnTitle.value = columnTitleMap.get(formData.value.chargeMode) | ||||||
|  |       //已选的区域节点 | ||||||
|  |       const areaIds = [] | ||||||
|  |       formData.value.templateCharge.forEach((item) => { | ||||||
|  |         //不等于全国的节点 | ||||||
|  |         if (item.areaId !== 1) { | ||||||
|  |           areaIds.push(item.areaId) | ||||||
|  |         } | ||||||
|  |         //前端价格以元展示 | ||||||
|  |         item.startPrice = fenToYuan(item.startPrice) | ||||||
|  |         item.extraPrice = fenToYuan(item.extraPrice) | ||||||
|  |       }) | ||||||
|  |       formData.value.templateFree.forEach((item) => { | ||||||
|  |         if (item.areaId !== 1 && !areaIds.includes(item.areaId)) { | ||||||
|  |           areaIds.push(item.areaId) | ||||||
|  |         } | ||||||
|  |         item.freePrice = fenToYuan(item.freePrice) | ||||||
|  |       }) | ||||||
|  |       //区域节点,懒加载方式。 已选节点需要缓存展示 | ||||||
|  |       areaCache.value = await getAreaListByIds(areaIds) | ||||||
|     } |     } | ||||||
|   } finally { |   } finally { | ||||||
|     formLoading.value = false |     formLoading.value = false | ||||||
| @@ -178,6 +205,14 @@ const submitForm = async () => { | |||||||
|   formLoading.value = true |   formLoading.value = true | ||||||
|   try { |   try { | ||||||
|     const data = formData.value as DeliveryExpressTemplateApi.DeliveryExpressTemplateVO |     const data = formData.value as DeliveryExpressTemplateApi.DeliveryExpressTemplateVO | ||||||
|  |     data.templateCharge.forEach((item) => { | ||||||
|  |       //前端价格以元展示,提交到后端。用分计算 | ||||||
|  |       item.startPrice = yuanToFen(item.startPrice) | ||||||
|  |       item.extraPrice = yuanToFen(item.extraPrice) | ||||||
|  |     }) | ||||||
|  |     data.templateFree.forEach((item) => { | ||||||
|  |       item.freePrice = yuanToFen(item.freePrice) | ||||||
|  |     }) | ||||||
|     if (formType.value === 'create') { |     if (formType.value === 'create') { | ||||||
|       await DeliveryExpressTemplateApi.createDeliveryExpressTemplate(data) |       await DeliveryExpressTemplateApi.createDeliveryExpressTemplate(data) | ||||||
|       message.success(t('common.createSuccess')) |       message.success(t('common.createSuccess')) | ||||||
| @@ -210,46 +245,102 @@ const resetForm = () => { | |||||||
|     templateFree: [], |     templateFree: [], | ||||||
|     sort: 0 |     sort: 0 | ||||||
|   } |   } | ||||||
|   columnTitle.value = { |   columnTitle.value = columnTitleMap.get(1) | ||||||
|     startCountTitle: '首件', |  | ||||||
|     extraCountTitle: '续件', |  | ||||||
|     freeCountTitle: '包邮件数' |  | ||||||
|   } |  | ||||||
|   formRef.value?.resetFields() |   formRef.value?.resetFields() | ||||||
| } | } | ||||||
| /** 配送计费方法改变 */ | /** 配送计费方法改变 */ | ||||||
| const changeChargeMode = (chargeMod: number) => { | const changeChargeMode = (chargeMode: number) => { | ||||||
|   if (chargeMod === 1) { |   columnTitle.value = columnTitleMap.get(chargeMode) | ||||||
|     columnTitle.value = { | } | ||||||
|       startCountTitle: '首件', | const defaultArea = [{ id: 1, name: '全国', disabled: false }] | ||||||
|       extraCountTitle: '续件', |  | ||||||
|       freeCountTitle: '包邮件数' | /** 初始化数据 */ | ||||||
|  | const initData = async () => { | ||||||
|  |   // TODO 从服务端全量加载数据, 后面看懒加载是不是可以从前端获取数据。 目前从后端获取数据 | ||||||
|  |   // formLoading.value = true | ||||||
|  |   // try { | ||||||
|  |   //   const data = await getAreaTree() | ||||||
|  |   //   areaTree = data | ||||||
|  |   //   console.log('areaTree', areaTree) | ||||||
|  |   // } finally { | ||||||
|  |   //   formLoading.value = false | ||||||
|  |   // } | ||||||
|  |   //表头标题和计费方式的映射 | ||||||
|  |   columnTitleMap.set(1, { | ||||||
|  |     startCountTitle: '首件', | ||||||
|  |     extraCountTitle: '续件', | ||||||
|  |     freeCountTitle: '包邮件数' | ||||||
|  |   }) | ||||||
|  |   columnTitleMap.set(2, { | ||||||
|  |     startCountTitle: '首件重量(kg)', | ||||||
|  |     extraCountTitle: '续件重量(kg)', | ||||||
|  |     freeCountTitle: '包邮重量(kg)' | ||||||
|  |   }) | ||||||
|  |   columnTitleMap.set(3, { | ||||||
|  |     startCountTitle: '首件体积(m³)', | ||||||
|  |     extraCountTitle: '续件体积(m³)', | ||||||
|  |     freeCountTitle: '包邮体积(m³)' | ||||||
|  |   }) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /** 懒加载运费区域树 */ | ||||||
|  | const loadChargeArea = async (node, resolve) => { | ||||||
|  |   const areaIds = [] | ||||||
|  |   formData.value.templateCharge.forEach((item) => { | ||||||
|  |     if (item.areaId) { | ||||||
|  |       areaIds.push(item.areaId) | ||||||
|     } |     } | ||||||
|   } |   }) | ||||||
|   if (chargeMod === 2) { |   if (node.isLeaf) return resolve([]) | ||||||
|     columnTitle.value = { |   const length = node.data.length | ||||||
|       startCountTitle: '首件重量(kg)', |   if (length === 0) { | ||||||
|       extraCountTitle: '续件重量(kg)', |     const data = cloneDeep(defaultArea) | ||||||
|       freeCountTitle: '包邮重量(kg)' |     const item = data[0] | ||||||
|     } |     if (areaIds.includes(item.id)) { | ||||||
|   } |       item.disabled = true | ||||||
|   if (chargeMod === 3) { |  | ||||||
|     columnTitle.value = { |  | ||||||
|       startCountTitle: '首件体积(m³)', |  | ||||||
|       extraCountTitle: '续件体积(m³)', |  | ||||||
|       freeCountTitle: '包邮体积(m³)' |  | ||||||
|     } |     } | ||||||
|  |     resolve(data) | ||||||
|  |   } else { | ||||||
|  |     const id = node.data.id | ||||||
|  |     const data = await getChildrenArea(id) | ||||||
|  |     data.forEach((item) => { | ||||||
|  |       if (areaIds.includes(item.id)) { | ||||||
|  |         item.disabled = true | ||||||
|  |       } | ||||||
|  |     }) | ||||||
|  |     resolve(data) | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
| /** 初始化区域数据 */ | /** 懒加载包邮区域树 */ | ||||||
| const initAreaData = async () => { | const loadFreeArea = async (node, resolve) => { | ||||||
|   formLoading.value = true |   if (node.isLeaf) return resolve([]) | ||||||
|   try { |   //已经选择的区域id | ||||||
|     const data = await getAreaTree(1) |   const areaIds = [] | ||||||
|     areaList.value = data |   formData.value.templateFree.forEach((item) => { | ||||||
|   } finally { |     if (item.areaId) { | ||||||
|     formLoading.value = false |       areaIds.push(item.areaId) | ||||||
|  |     } | ||||||
|  |   }) | ||||||
|  |   const length = node.data.length | ||||||
|  |   if (length === 0) { | ||||||
|  |     // 为空,从全国开始选择。全国 id == 1 | ||||||
|  |     const data = cloneDeep(defaultArea) | ||||||
|  |     const item = data[0] | ||||||
|  |     if (areaIds.includes(item.id)) { | ||||||
|  |       item.disabled = true | ||||||
|  |     } | ||||||
|  |     resolve(data) | ||||||
|  |   } else { | ||||||
|  |     const id = node.data.id | ||||||
|  |     const data = await getChildrenArea(id) | ||||||
|  |     //已选区域需要禁止再次选择 | ||||||
|  |     data.forEach((item) => { | ||||||
|  |       if (areaIds.includes(item.id)) { | ||||||
|  |         item.disabled = true | ||||||
|  |       } | ||||||
|  |     }) | ||||||
|  |     resolve(data) | ||||||
|   } |   } | ||||||
| } | } | ||||||
| /** 添加计费区域 */ | /** 添加计费区域 */ | ||||||
| @@ -285,6 +376,6 @@ const deleteFreeArea = (index) => { | |||||||
|  |  | ||||||
| /** 初始化 **/ | /** 初始化 **/ | ||||||
| onMounted(() => { | onMounted(() => { | ||||||
|   initAreaData() |   initData() | ||||||
| }) | }) | ||||||
| </script> | </script> | ||||||
|   | |||||||
| @@ -57,8 +57,7 @@ const list = ref([]) | |||||||
|  * 获得数据列表 |  * 获得数据列表 | ||||||
|  */ |  */ | ||||||
| const getList = async () => { | const getList = async () => { | ||||||
|   // id == 1 中国 |   list.value = await AreaApi.getAreaTree() | ||||||
|   list.value = await AreaApi.getAreaTree(1) |  | ||||||
| } | } | ||||||
|  |  | ||||||
| /** 添加/修改操作 */ | /** 添加/修改操作 */ | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 jason
					jason