feat(shopExpressTemplateDetail): 支持省市两级多选配送区域
- 新增 model 字段 provinceIds 和 cityIds,兼容旧单值 provinceId 和 cityId - 引入 RegionMultiSelect 组件替代旧的单选级联选择器 - 编辑弹窗支持多选城市和省份,提交时转换为逗号分隔字符串 - 列表页配送区域列支持多选展示,超长文本截断并显示 tooltip - 新增 RegionMultiSelect 组件,实现省市两级树形多选穿梭弹窗 - 通过 computed 和 watch 同步组件选中状态和表单数据 - 更新相关类型定义和导入,确保编辑及展示逻辑正确 - 新增样式优化,提示默认配送全国规则说明
This commit is contained in:
@@ -0,0 +1,28 @@
|
||||
# 2026-08-11 工作记录
|
||||
|
||||
## 运费模板配送地区改为「省+市两级多选穿梭弹窗」
|
||||
|
||||
### 需求背景
|
||||
客户要求运费模板的配送地区选择改成仿截图的双栏穿梭弹窗(左侧候选 + 右侧已选),
|
||||
选择粒度从原「省+市单选(级联)」升级为「多条规则覆盖多城市」,并保留「不选=全国」规则。
|
||||
|
||||
### 改动清单(纯前端,后端字段由用户确认可改)
|
||||
1. **新建组件** `src/components/RegionMultiSelect/index.vue`
|
||||
- 树形可展开:省级可展开看市级;省级"选择"=选该省全部市,市级可单独选。
|
||||
- 左栏搜索(按省/市名过滤)、右栏已选列表(单项是"省/市"+取消)。
|
||||
- 底部:全部选择 / 取消 / 确认。
|
||||
- `v-model:value` 绑定已选**城市ID数组**;额外 emit `update:provinceIds`(由城市推导的省份ID数组)。
|
||||
- 复用 `src/components/RegionsSelect/load-data.ts` 的 getRegionsData()(public/json/regions-data.json,取省+市两级,丢弃区级)。
|
||||
2. **model** `src/api/shop/shopExpressTemplateDetail/model/index.ts`
|
||||
- 新增 `provinceIds?: string`(逗号分隔)、`cityIds?: string`(逗号分隔);保留旧 `provinceId/cityId` 兼容历史数据。
|
||||
3. **编辑弹窗** `src/views/shop/shopExpressTemplateDetail/components/shopExpressTemplateDetailEdit.vue`
|
||||
- 移除 `RegionsSelect type="provinceCity"`,改用 `RegionMultiSelect`。
|
||||
- 打开时从 `record.cityIds`(兼容旧 `cityId`)回填;保存时数组→逗号串提交 `cityIds/provinceIds`。
|
||||
4. **列表页** `src/views/shop/shopExpressTemplateDetail/index.vue`
|
||||
- "配送地区"列 customRender 改为遍历 `cityIds` 多值反查 regionMap;超22字截断+tooltip;旧单值数据兼容。
|
||||
- 新增 `h` 函数 import。
|
||||
|
||||
### 待办 / 风险
|
||||
- **后端需同步改造**:表加 `province_ids` / `city_ids`(varchar 逗号分隔),接口 add/update 接收这两个字段。前端已按此约定提交,后端未改则数据落不了库。
|
||||
- antd 为 v4,`var(--ant-color-border)` 在暗色下可能回退浅灰(边框略浅,不影响功能);如要完美暗色适配可后续改 less 变量。
|
||||
- 构建验证(vite build)已触发,待结果确认无编译错误。
|
||||
@@ -55,3 +55,11 @@
|
||||
- 一键上下架、批量上下架均通过 `updateShopGoods({ ...record, status })` 直接改 status 实现(不额外用 isShow 字段)。
|
||||
- 列表 tag 仍显示:0=已上架、1=待上架、2=待审核、3=审核不通过。
|
||||
|
||||
### 运费模板配送地区多选(2026-08-11 已实现前端)
|
||||
- 需求:配送地区选择从「省+市单选级联」升级为「省+市两级多选穿梭弹窗」(仿客户截图双栏:左候选/右已选)。
|
||||
- 前端组件:`src/components/RegionMultiSelect/index.vue`(树形可展开,省级"选择"=选该省全部市,市级可单独选;@update:value 城市ID数组 + @update:provinceIds 省份ID数组)。
|
||||
- 数据字段:model 新增 `provinceIds` / `cityIds`(逗号分隔字符串);保留旧 `provinceId`/`cityId` 兼容(编辑回显时旧单值会自动补进 cityIds)。
|
||||
- 列表多值展示:`index.vue` customRender 遍历 `cityIds` 反查 regionMap,超 22 字截断 + tooltip。
|
||||
- ⚠️ 后端待改:`shop_express_template_detail` 表加 `province_ids`/`city_ids`(varchar 逗号分隔),add/update 接口接收这两个字段;前端已按此约定提交,后端未改前数据落不了库。
|
||||
- 注:与"不发货地区(黑名单) regionMode/regionIds"是不同需求,勿混淆。
|
||||
|
||||
|
||||
@@ -12,10 +12,14 @@ export interface ShopExpressTemplateDetail {
|
||||
templateId?: number;
|
||||
/** 计费方式: true=按件, false=按重量 */
|
||||
type?: boolean;
|
||||
/** 省份ID */
|
||||
/** 省份ID(旧单值字段,兼容历史数据) */
|
||||
provinceId?: number;
|
||||
/** 城市ID */
|
||||
/** 城市ID(旧单值字段,兼容历史数据) */
|
||||
cityId?: number;
|
||||
/** 省份IDs(逗号分隔,多选配送区域) */
|
||||
provinceIds?: string;
|
||||
/** 城市IDs(逗号分隔,多选配送区域) */
|
||||
cityIds?: string;
|
||||
/** 首件数量/重量 */
|
||||
firstNum?: string;
|
||||
/** 首件价格 */
|
||||
|
||||
@@ -0,0 +1,375 @@
|
||||
<!-- 省+市两级多选穿梭弹窗 -->
|
||||
<template>
|
||||
<div class="region-multi-select">
|
||||
<!-- 触发区 -->
|
||||
<div class="rms-trigger">
|
||||
<a-button class="rms-trigger-btn" @click="openModal">
|
||||
{{ triggerText }}
|
||||
</a-button>
|
||||
<span v-if="modelValue.length" class="rms-summary">
|
||||
已选 {{ modelValue.length }} 个城市
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<!-- 弹窗 -->
|
||||
<a-modal
|
||||
v-model:visible="visible"
|
||||
title="区域选择"
|
||||
width="760px"
|
||||
:mask-closable="false"
|
||||
@cancel="handleCancel"
|
||||
>
|
||||
<div class="rms-body">
|
||||
<!-- 左侧候选 -->
|
||||
<div class="rms-panel">
|
||||
<a-input-search
|
||||
v-model:value="keyword"
|
||||
placeholder="输入地区关键字"
|
||||
allow-clear
|
||||
class="rms-search"
|
||||
/>
|
||||
<div class="rms-scroll">
|
||||
<div
|
||||
v-for="p in filteredProvinces"
|
||||
:key="p.value"
|
||||
class="rms-province"
|
||||
>
|
||||
<div class="rms-province-row">
|
||||
<span class="rms-expand" @click="toggleExpand(p.value)">
|
||||
{{ isExpanded(p.value) ? '▾' : '▸' }}
|
||||
</span>
|
||||
<span class="rms-label" @click="toggleExpand(p.value)">
|
||||
{{ p.label }}
|
||||
</span>
|
||||
<a-button
|
||||
type="link"
|
||||
size="small"
|
||||
:disabled="isProvinceSelected(p)"
|
||||
@click="selectProvince(p)"
|
||||
>
|
||||
{{ isProvinceSelected(p) ? '已选' : '选择' }}
|
||||
</a-button>
|
||||
</div>
|
||||
<div v-if="isExpanded(p.value)" class="rms-city-list">
|
||||
<div
|
||||
v-for="c in p.cities"
|
||||
:key="c.value"
|
||||
class="rms-city-row"
|
||||
>
|
||||
<span class="rms-label">{{ c.label }}</span>
|
||||
<a-button
|
||||
type="link"
|
||||
size="small"
|
||||
:disabled="isCitySelected(c.value)"
|
||||
@click="toggleCity(c.value)"
|
||||
>
|
||||
{{ isCitySelected(c.value) ? '已选' : '选择' }}
|
||||
</a-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 右侧已选 -->
|
||||
<div class="rms-panel">
|
||||
<div class="rms-selected-title">
|
||||
已选择 ({{ selectedCities.length }})
|
||||
</div>
|
||||
<div class="rms-scroll">
|
||||
<div
|
||||
v-for="item in selectedList"
|
||||
:key="item.cityValue"
|
||||
class="rms-selected-item"
|
||||
>
|
||||
<span class="rms-selected-label">
|
||||
{{ item.provinceLabel }} / {{ item.cityLabel }}
|
||||
</span>
|
||||
<a-button
|
||||
type="link"
|
||||
size="small"
|
||||
danger
|
||||
@click="removeCity(item.cityValue)"
|
||||
>
|
||||
取消
|
||||
</a-button>
|
||||
</div>
|
||||
<a-empty
|
||||
v-if="!selectedCities.length"
|
||||
:image="simpleImage"
|
||||
description="暂未选择"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<template #footer>
|
||||
<a-button @click="selectAll">全部选择</a-button>
|
||||
<span class="rms-footer-spacer"></span>
|
||||
<a-button @click="handleCancel">取消</a-button>
|
||||
<a-button type="primary" @click="handleConfirm">确认</a-button>
|
||||
</template>
|
||||
</a-modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, computed, watch } from 'vue';
|
||||
import { Empty } from 'ant-design-vue';
|
||||
import { getRegionsData } from '@/components/RegionsSelect/load-data';
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
/** 已选城市ID数组(逗号分隔的行政区码) */
|
||||
value?: string[];
|
||||
placeholder?: string;
|
||||
}>(),
|
||||
{ value: () => [], placeholder: '选择配送地区' }
|
||||
);
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'update:value', value: string[]): void;
|
||||
(e: 'update:provinceIds', value: string[]): void;
|
||||
}>();
|
||||
|
||||
const simpleImage = Empty.PRESENTED_IMAGE_SIMPLE;
|
||||
|
||||
const visible = ref(false);
|
||||
const keyword = ref('');
|
||||
const expandedSet = ref<Set<string>>(new Set());
|
||||
const selectedSet = ref<Set<string>>(new Set());
|
||||
|
||||
interface CityItem {
|
||||
value: string;
|
||||
label: string;
|
||||
}
|
||||
interface ProvinceItem {
|
||||
value: string;
|
||||
label: string;
|
||||
cities: CityItem[];
|
||||
}
|
||||
|
||||
const provinceList = ref<ProvinceItem[]>([]);
|
||||
const cityToProvince = ref<Record<string, string>>({});
|
||||
const labelMap = ref<Record<string, string>>({});
|
||||
|
||||
// 加载省+市两级数据(丢弃区级)
|
||||
getRegionsData().then((data) => {
|
||||
const list: ProvinceItem[] = [];
|
||||
const c2p: Record<string, string> = {};
|
||||
const lm: Record<string, string> = {};
|
||||
(data ?? []).forEach((p) => {
|
||||
lm[p.value] = p.label;
|
||||
const cities: CityItem[] = (p.children ?? []).map((c) => {
|
||||
c2p[c.value] = p.value;
|
||||
lm[c.value] = c.label;
|
||||
return { value: c.value, label: c.label };
|
||||
});
|
||||
list.push({ value: p.value, label: p.label, cities });
|
||||
});
|
||||
provinceList.value = list;
|
||||
cityToProvince.value = c2p;
|
||||
labelMap.value = lm;
|
||||
});
|
||||
|
||||
const modelValue = computed(() => props.value ?? []);
|
||||
|
||||
const triggerText = computed(() =>
|
||||
modelValue.value.length
|
||||
? `已选 ${modelValue.value.length} 个城市`
|
||||
: props.placeholder
|
||||
);
|
||||
|
||||
const isExpanded = (v: string) => expandedSet.value.has(v);
|
||||
const toggleExpand = (v: string) => {
|
||||
const s = new Set(expandedSet.value);
|
||||
if (s.has(v)) {
|
||||
s.delete(v);
|
||||
} else {
|
||||
s.add(v);
|
||||
}
|
||||
expandedSet.value = s;
|
||||
};
|
||||
|
||||
const isCitySelected = (v: string) => selectedSet.value.has(v);
|
||||
const isProvinceSelected = (p: ProvinceItem) =>
|
||||
p.cities.length > 0 && p.cities.every((c) => selectedSet.value.has(c.value));
|
||||
|
||||
const filteredProvinces = computed(() => {
|
||||
const kw = keyword.value.trim();
|
||||
if (!kw) {
|
||||
return provinceList.value;
|
||||
}
|
||||
return provinceList.value
|
||||
.map((p) => {
|
||||
const matchProvince = p.label.includes(kw);
|
||||
if (matchProvince) {
|
||||
return p;
|
||||
}
|
||||
const cities = p.cities.filter((c) => c.label.includes(kw));
|
||||
if (cities.length) {
|
||||
return { ...p, cities };
|
||||
}
|
||||
return null;
|
||||
})
|
||||
.filter(Boolean) as ProvinceItem[];
|
||||
});
|
||||
|
||||
const selectedCities = computed(() => Array.from(selectedSet.value));
|
||||
|
||||
const selectedList = computed(() =>
|
||||
selectedCities.value.map((cv) => ({
|
||||
cityValue: cv,
|
||||
cityLabel: labelMap.value[cv] || cv,
|
||||
provinceValue: cityToProvince.value[cv],
|
||||
provinceLabel: labelMap.value[cityToProvince.value[cv]] || ''
|
||||
}))
|
||||
);
|
||||
|
||||
const derivedProvinceIds = computed(() => {
|
||||
const set = new Set<string>();
|
||||
selectedSet.value.forEach((cv) => {
|
||||
const pv = cityToProvince.value[cv];
|
||||
if (pv) {
|
||||
set.add(pv);
|
||||
}
|
||||
});
|
||||
return Array.from(set);
|
||||
});
|
||||
|
||||
const selectProvince = (p: ProvinceItem) => {
|
||||
const s = new Set(selectedSet.value);
|
||||
p.cities.forEach((c) => s.add(c.value));
|
||||
selectedSet.value = s;
|
||||
};
|
||||
|
||||
const toggleCity = (cv: string) => {
|
||||
const s = new Set(selectedSet.value);
|
||||
if (s.has(cv)) {
|
||||
s.delete(cv);
|
||||
} else {
|
||||
s.add(cv);
|
||||
}
|
||||
selectedSet.value = s;
|
||||
};
|
||||
|
||||
const removeCity = (cv: string) => {
|
||||
const s = new Set(selectedSet.value);
|
||||
s.delete(cv);
|
||||
selectedSet.value = s;
|
||||
};
|
||||
|
||||
const selectAll = () => {
|
||||
const s = new Set<string>();
|
||||
provinceList.value.forEach((p) =>
|
||||
p.cities.forEach((c) => s.add(c.value))
|
||||
);
|
||||
selectedSet.value = s;
|
||||
};
|
||||
|
||||
const openModal = () => {
|
||||
selectedSet.value = new Set(modelValue.value);
|
||||
keyword.value = '';
|
||||
visible.value = true;
|
||||
};
|
||||
|
||||
const handleConfirm = () => {
|
||||
emit('update:value', selectedCities.value);
|
||||
emit('update:provinceIds', derivedProvinceIds.value);
|
||||
visible.value = false;
|
||||
};
|
||||
|
||||
const handleCancel = () => {
|
||||
visible.value = false;
|
||||
};
|
||||
|
||||
// 外部清空时同步内部选中态
|
||||
watch(
|
||||
() => props.value,
|
||||
(v) => {
|
||||
if (!visible.value) {
|
||||
selectedSet.value = new Set(v ?? []);
|
||||
}
|
||||
}
|
||||
);
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.region-multi-select {
|
||||
width: 100%;
|
||||
}
|
||||
.rms-trigger {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
}
|
||||
.rms-trigger-btn {
|
||||
flex: 1;
|
||||
text-align: left;
|
||||
}
|
||||
.rms-summary {
|
||||
color: var(--ant-color-text-secondary, #999);
|
||||
font-size: 12px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.rms-body {
|
||||
display: flex;
|
||||
gap: 16px;
|
||||
height: 420px;
|
||||
}
|
||||
.rms-panel {
|
||||
flex: 1;
|
||||
border: 1px solid var(--ant-color-border, #f0f0f0);
|
||||
border-radius: 6px;
|
||||
padding: 12px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
}
|
||||
.rms-search {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
.rms-scroll {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
}
|
||||
.rms-province-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 4px 0;
|
||||
}
|
||||
.rms-expand {
|
||||
width: 20px;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
color: var(--ant-color-text-secondary, #999);
|
||||
}
|
||||
.rms-label {
|
||||
flex: 1;
|
||||
cursor: default;
|
||||
}
|
||||
.rms-city-list {
|
||||
padding-left: 24px;
|
||||
}
|
||||
.rms-city-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 2px 0;
|
||||
}
|
||||
.rms-selected-title {
|
||||
font-weight: 600;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
.rms-selected-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 4px 0;
|
||||
border-bottom: 1px dashed var(--ant-color-border, #f5f5f5);
|
||||
}
|
||||
.rms-selected-label {
|
||||
flex: 1;
|
||||
}
|
||||
.rms-footer-spacer {
|
||||
flex: 1;
|
||||
}
|
||||
</style>
|
||||
+55
-28
@@ -20,13 +20,13 @@
|
||||
styleResponsive ? { md: 19, sm: 19, xs: 24 } : { flex: '1' }
|
||||
"
|
||||
>
|
||||
<a-form-item label="配送地区" name="regions">
|
||||
<RegionsSelect
|
||||
v-model:value="regions"
|
||||
type="provinceCity"
|
||||
:show-search="true"
|
||||
placeholder="请选择配送省份/城市(不选则默认全国)"
|
||||
<a-form-item label="配送地区">
|
||||
<RegionMultiSelect
|
||||
:value="cityIds"
|
||||
@update:value="onCityIdsChange"
|
||||
@update:provinceIds="onProvinceIdsChange"
|
||||
/>
|
||||
<div class="rms-tip">不选则默认全国</div>
|
||||
</a-form-item>
|
||||
<a-form-item :label="templateType ? '首件数量' : '首重重量'" name="firstNum">
|
||||
<a-input-number
|
||||
@@ -94,7 +94,7 @@
|
||||
import {
|
||||
ShopExpressTemplateDetail
|
||||
} from '@/api/shop/shopExpressTemplateDetail/model';
|
||||
import RegionsSelect from '@/components/RegionsSelect/index.vue';
|
||||
import RegionMultiSelect from '@/components/RegionMultiSelect/index.vue';
|
||||
import { useThemeStore } from '@/store/modules/theme';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { FormInstance } from 'ant-design-vue/es/form';
|
||||
@@ -128,8 +128,10 @@
|
||||
const maxable = ref(true);
|
||||
// 表单实例
|
||||
const formRef = ref<FormInstance | null>(null);
|
||||
// 级联选择器选中值(字符串ID数组)
|
||||
const regions = ref<string[]>([]);
|
||||
// 已选城市ID数组
|
||||
const cityIds = ref<string[]>([]);
|
||||
// 已选省份ID数组(由城市推导,随城市变化同步)
|
||||
const provinceIds = ref<string[]>([]);
|
||||
|
||||
// 表单数据
|
||||
const form = reactive<ShopExpressTemplateDetail>({
|
||||
@@ -138,6 +140,8 @@
|
||||
type: true,
|
||||
provinceId: undefined,
|
||||
cityId: undefined,
|
||||
provinceIds: undefined,
|
||||
cityIds: undefined,
|
||||
firstNum: undefined,
|
||||
firstAmount: undefined,
|
||||
extraAmount: undefined,
|
||||
@@ -186,16 +190,17 @@
|
||||
|
||||
const { resetFields } = useForm(form, rules);
|
||||
|
||||
/* 级联选择器值变化时,同步到 form.provinceId / form.cityId */
|
||||
watch(regions, (val) => {
|
||||
if (val && val.length > 0) {
|
||||
form.provinceId = Number(val[0]);
|
||||
form.cityId = val.length > 1 ? Number(val[1]) : undefined;
|
||||
} else {
|
||||
form.provinceId = undefined;
|
||||
form.cityId = undefined;
|
||||
}
|
||||
});
|
||||
/* 城市选中变化,同步到 form.cityIds */
|
||||
const onCityIdsChange = (val: string[]) => {
|
||||
cityIds.value = val;
|
||||
form.cityIds = val.length ? val.join(',') : undefined;
|
||||
};
|
||||
|
||||
/* 省份选中变化(由组件根据已选城市推导),同步到 form.provinceIds */
|
||||
const onProvinceIdsChange = (val: string[]) => {
|
||||
provinceIds.value = val;
|
||||
form.provinceIds = val.length ? val.join(',') : undefined;
|
||||
};
|
||||
|
||||
/* 保存编辑 */
|
||||
const save = () => {
|
||||
@@ -210,6 +215,13 @@
|
||||
// 确保templateId和type从父级继承
|
||||
formData.templateId = props.templateId;
|
||||
formData.type = props.templateType ?? true;
|
||||
// 多选配送区域(逗号分隔,空则默认全国)
|
||||
formData.cityIds = cityIds.value.length
|
||||
? cityIds.value.join(',')
|
||||
: undefined;
|
||||
formData.provinceIds = provinceIds.value.length
|
||||
? provinceIds.value.join(',')
|
||||
: undefined;
|
||||
const saveOrUpdate = isUpdate.value
|
||||
? updateShopExpressTemplateDetail
|
||||
: addShopExpressTemplateDetail;
|
||||
@@ -240,21 +252,36 @@
|
||||
form.templateId = props.templateId;
|
||||
form.type = props.templateType ?? true;
|
||||
}
|
||||
// 回显级联选择器
|
||||
if (form.provinceId) {
|
||||
const arr = [String(form.provinceId)];
|
||||
if (form.cityId) {
|
||||
arr.push(String(form.cityId));
|
||||
}
|
||||
regions.value = arr;
|
||||
// 回显多选配送区域
|
||||
if (form.cityIds) {
|
||||
cityIds.value = form.cityIds.split(',').filter(Boolean);
|
||||
} else if (form.cityId) {
|
||||
// 兼容旧单值数据
|
||||
cityIds.value = [String(form.cityId)];
|
||||
} else {
|
||||
regions.value = [];
|
||||
cityIds.value = [];
|
||||
}
|
||||
if (form.provinceIds) {
|
||||
provinceIds.value = form.provinceIds.split(',').filter(Boolean);
|
||||
} else if (form.provinceId) {
|
||||
provinceIds.value = [String(form.provinceId)];
|
||||
} else {
|
||||
provinceIds.value = [];
|
||||
}
|
||||
} else {
|
||||
resetFields();
|
||||
regions.value = [];
|
||||
cityIds.value = [];
|
||||
provinceIds.value = [];
|
||||
}
|
||||
},
|
||||
{ immediate: true }
|
||||
);
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.rms-tip {
|
||||
margin-top: 4px;
|
||||
color: var(--ant-color-text-secondary, #999);
|
||||
font-size: 12px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -51,7 +51,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { createVNode, ref, computed, onMounted } from 'vue';
|
||||
import { createVNode, ref, computed, onMounted, h } from 'vue';
|
||||
import { useRoute } from 'vue-router';
|
||||
import { message, Modal } from 'ant-design-vue';
|
||||
import { ExclamationCircleOutlined } from '@ant-design/icons-vue';
|
||||
@@ -128,6 +128,26 @@
|
||||
align: 'center',
|
||||
width: 150,
|
||||
customRender: ({ record }) => {
|
||||
// 多选配送区域(cityIds 逗号分隔)
|
||||
const cityIds = (record.cityIds || '')
|
||||
.split(',')
|
||||
.filter(Boolean);
|
||||
if (cityIds.length) {
|
||||
const names = cityIds.map(
|
||||
(id: string) => regionMap.value[id] || id
|
||||
);
|
||||
const text = names.join('、');
|
||||
// 过长截断并支持 tooltip 悬浮查看全部
|
||||
if (text.length > 22) {
|
||||
return h(
|
||||
'span',
|
||||
{ title: text },
|
||||
text.slice(0, 22) + '…'
|
||||
);
|
||||
}
|
||||
return text;
|
||||
}
|
||||
// 兼容旧单值数据
|
||||
const province = record.provinceId
|
||||
? regionMap.value[String(record.provinceId)]
|
||||
: '';
|
||||
|
||||
Reference in New Issue
Block a user