feat(shopExpressTemplateDetail): 支持省市两级多选配送区域
- 新增 model 字段 provinceIds 和 cityIds,兼容旧单值 provinceId 和 cityId - 引入 RegionMultiSelect 组件替代旧的单选级联选择器 - 编辑弹窗支持多选城市和省份,提交时转换为逗号分隔字符串 - 列表页配送区域列支持多选展示,超长文本截断并显示 tooltip - 新增 RegionMultiSelect 组件,实现省市两级树形多选穿梭弹窗 - 通过 computed 和 watch 同步组件选中状态和表单数据 - 更新相关类型定义和导入,确保编辑及展示逻辑正确 - 新增样式优化,提示默认配送全国规则说明
This commit is contained in:
+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