| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655 |
- <template>
- <div class="shipping-template-component">
- <el-card class="box-card">
- <!-- 头部 -->
- <template #header>
- <div class="card-header">
- <el-icon><Van /></el-icon>
- <span>{{ isEditMode ? '编辑运费模板' : '新建运费模板' }}</span>
- </div>
- </template>
- <el-form label-width="120px">
- <!-- 模板信息 -->
- <el-card shadow="never" class="mb-4">
- <template #header>
- <div class="card-sub-header">
- <span>模板信息</span>
- </div>
- </template>
-
- <el-row :gutter="20">
- <el-col :span="12">
- <el-form-item :rules="[{ required: true, message: '请输入模板名称', trigger: 'blur' }]" label="模板名称"
- prop="templateInfo.name">
- <el-input
- v-model="templateInfo.name"
- placeholder="例如:全国配送模板"
- />
- <div class="form-item-tip">给模板起一个容易识别的名称</div>
- </el-form-item>
- </el-col>
- <el-col :span="12">
- <el-form-item :rules="[{ required: true, message: '请选择计费方式', trigger: 'change' }]" label="计费方式"
- prop="templateInfo.calcMethod">
- <el-select
- v-model="templateInfo.calcMethod"
- @change="handleCalcMethodChange"
- style="width: 100%"
- placeholder="请选择计费方式"
- >
- <el-option label="按件数计算(标准化小商品如服饰)" value="piece" />
- <el-option label="按重量计算(重货如五金件)" value="weight" />
- <el-option label="按体积计算(轻抛货如泡沫箱、家具)" value="volume" />
- </el-select>
- <div class="form-item-tip">根据商品特性选择合适的计费方式</div>
- </el-form-item>
- </el-col>
- </el-row>
-
- <!-- 单位选择 -->
- <el-row :gutter="20" v-if="templateInfo.calcMethod !== 'piece'">
- <el-col :span="12">
- <el-form-item :rules="[{ required: true, message: '请选择计量单位', trigger: 'change' }]" label="计量单位"
- prop="templateInfo.unit">
- <el-select
- v-model="templateInfo.unit"
- @change="handleUnitChange"
- style="width: 100%"
- placeholder="请选择计量单位"
- >
- <el-option
- v-for="unit in getAvailableUnits()"
- :key="unit.value"
- :label="unit.label"
- :value="unit.value"
- />
- </el-select>
- <div class="form-item-tip">选择合适的计量单位便于计算运费</div>
- </el-form-item>
- </el-col>
- </el-row>
- </el-card>
- <!-- 默认区设置 -->
- <el-card shadow="never" class="mb-4">
- <template #header>
- <div class="flex justify-between items-center">
- <span>默认计费规则</span>
- <el-tag type="info">适用于未指定地区</el-tag>
- </div>
- </template>
- <el-alert
- class="mb-4"
- description="这是适用于全国大部分地区的运费计算规则,针对特定区域可以在下方设置特殊区域规则"
- show-icon
- title="默认计费规则说明"
- type="info"
- />
- <el-row :gutter="20">
- <el-col :span="8">
- <el-form-item :label="getFirstLabel()" :rules="[{ required: true, type: 'number', min: 0.001, message: getFirstLabel() + '必须大于0', trigger: 'blur' }]"
- prop="defaultRule.first">
- <div class="input-with-unit">
- <el-input-number
- v-model="defaultRule.first"
- :min="getMinFirstValue()"
- :step="getFirstStep()"
- controls-position="right"
- style="width: 100%"
- />
- <span class="unit-text">
- <span v-if="getCurrentDisplayUnit() === 'cm3'">
- cm<sup>3</sup>
- </span>
- <span v-else-if="getCurrentDisplayUnit() === 'm3'">
- m<sup>3</sup>
- </span>
- <span v-else>{{ getCurrentDisplayUnit() }}</span>
- </span>
- </div>
- </el-form-item>
- </el-col>
- <el-col :span="8">
- <el-form-item :label="getFirstPriceLabel()" :rules="[{ required: true, type: 'number', min: 0, message: getFirstPriceLabel() + '不能为负数', trigger: 'blur' }]"
- prop="defaultRule.firstPrice">
- <el-input-number
- v-model="defaultRule.firstPrice"
- :min="0"
- :step="0.01"
- controls-position="right"
- style="width: 100%"
- />
- <div class="form-item-tip">首{{ getCurrentDisplayUnit() }}的费用</div>
- </el-form-item>
- </el-col>
- <el-col :span="8">
- <el-form-item :label="getNextPriceLabel()" :rules="[{ required: true, type: 'number', min: 0, message: getNextPriceLabel() + '不能为负数', trigger: 'blur' }]"
- prop="defaultRule.nextPrice">
- <el-input-number
- v-model="defaultRule.nextPrice"
- :min="0"
- :step="0.01"
- controls-position="right"
- style="width: 100%"
- />
- <div class="form-item-tip">超出首{{ getCurrentDisplayUnit() }}后每增加一个单位的费用</div>
- </el-form-item>
- </el-col>
- </el-row>
- </el-card>
- <!-- 特殊区设置 -->
- <el-card shadow="never" class="mb-4">
- <template #header>
- <div class="flex justify-between items-center">
- <span>特殊区域设置</span>
- <el-button type="primary" @click="addSpecialArea" plain>
- <el-icon><Plus /></el-icon>添加特殊区
- </el-button>
- </div>
- </template>
- <el-alert
- class="mb-4"
- description="可以为某些偏远或特殊地区设置独立的运费规则,这些规则会覆盖默认规则"
- show-icon
- title="特殊区域设置说明"
- type="info"
- />
- <!-- 特殊区列表 -->
- <div
- v-for="(area, index) in specialAreas"
- :key="index"
- class="special-area mb-4 p-4 border rounded"
- >
- <el-button
- @click="removeSpecialArea(index)"
- type="danger"
- :icon="Close"
- circle
- size="small"
- class="float-right"
- />
-
- <el-row :gutter="20" class="mb-4">
- <el-col :span="12">
- <el-form-item :prop="'specialAreas.' + index + '.regions'" :rules="{ type: 'array', required: true, message: '请选择至少一个地区', trigger: 'change' }"
- label="选择地区">
- <div class="region-tags mb-2">
- <el-tag
- v-for="(region, regionIndex) in area.regions"
- :key="regionIndex"
- closable
- type="primary"
- class="mr-2 mb-2"
- @close="removeRegion(index, regionIndex)"
- >
- {{ formatRegionName(region) }}
- </el-tag>
- </div>
- <el-button @click="openRegionModal(index)" type="primary" link>
- <el-icon><Plus /></el-icon>添加地区
- </el-button>
- <div class="form-item-tip">点击添加地区,可选择省份、城市或区县</div>
- </el-form-item>
- </el-col>
- <el-col :span="12">
- <el-form-item :prop="'specialAreas.' + index + '.area_name'"
- :rules="{ required: true, message: '请输入区域名称', trigger: 'blur' }"
- label="区域名称">
- <el-input
- v-model="area.area_name"
- placeholder="例如:偏远地区"
- />
- <div class="form-item-tip">给这个特殊区域起一个名字,便于识别</div>
- </el-form-item>
- </el-col>
- </el-row>
- <!-- 特殊区域价格设置 -->
- <el-row :gutter="20">
- <el-col :span="8">
- <el-form-item :label="getFirstLabel()" :prop="'specialAreas.' + index + '.first'"
- :rules="{ required: true, type: 'number', min: 0.001, message: getFirstLabel() + '必须大于0', trigger: 'blur' }">
- <div class="input-with-unit">
- <el-input-number
- v-model="area.first"
- :min="getMinFirstValue()"
- :step="getFirstStep()"
- controls-position="right"
- style="width: 100%"
- />
- <span class="unit-text">
- <span v-if="getCurrentDisplayUnit() === 'cm3'">
- cm<sup>3</sup>
- </span>
- <span v-else-if="getCurrentDisplayUnit() === 'm3'">
- m<sup>3</sup>
- </span>
- <span v-else>{{ getCurrentDisplayUnit() }}</span>
- </span>
- </div>
- </el-form-item>
- </el-col>
- <el-col :span="8">
- <el-form-item :label="getFirstPriceLabel()" :prop="'specialAreas.' + index + '.firstPrice'"
- :rules="{ required: true, type: 'number', min: 0, message: getFirstPriceLabel() + '不能为负数', trigger: 'blur' }">
- <el-input-number
- v-model="area.firstPrice"
- :min="0"
- :step="0.01"
- controls-position="right"
- style="width: 100%"
- />
- <div class="form-item-tip">首{{ getCurrentDisplayUnit() }}的费用</div>
- </el-form-item>
- </el-col>
- <el-col :span="8">
- <el-form-item :label="getNextPriceLabel()" :prop="'specialAreas.' + index + '.nextPrice'"
- :rules="{ required: true, type: 'number', min: 0, message: getNextPriceLabel() + '不能为负数', trigger: 'blur' }">
- <el-input-number
- v-model="area.nextPrice"
- :min="0"
- :step="0.01"
- controls-position="right"
- style="width: 100%"
- />
- <div class="form-item-tip">超出首{{ getCurrentDisplayUnit() }}后每增加一个单位的费用</div>
- </el-form-item>
- </el-col>
- </el-row>
- </div>
- <el-empty v-if="specialAreas.length === 0" description="暂无特殊区域,请点击上方按钮添加"/>
- </el-card>
- <!-- 操作按钮 -->
- <div class="flex justify-end">
- <el-button @click="cancel">取消</el-button>
- <el-button :loading="props.loading" type="primary" @click="saveTemplate">
- <el-icon><DocumentAdd /></el-icon>{{ isEditMode ? '保存模板' : '创建模板' }}
- </el-button>
- </div>
- </el-form>
- </el-card>
- <!-- 地区选择对话框 -->
- <el-dialog
- v-model="showRegionModal"
- :before-close="closeRegionModal"
- title="选择地区"
- width="800px"
- >
- <el-alert
- class="mb-4"
- description="可以选择省份、城市或区县级别,系统会自动处理层级关系"
- show-icon
- title="地区选择说明"
- type="info"
- />
- <el-row :gutter="20">
- <el-col :span="6">
- <div class="region-selector-container">
- <div class="selector-header">
- <span>省份</span>
- <div>
- <el-button
- :disabled="!provinceList.length"
- link
- type="primary"
- @click="addAllProvinces"
- >
- 全部
- </el-button>
- <el-button
- :disabled="!selectedProvinces.length"
- link
- type="success"
- @click="addCurrentProvincesToSelected"
- >
- 添加
- </el-button>
- </div>
- </div>
- <el-scrollbar height="300px">
- <div
- v-for="province in provinceList"
- :key="province.code"
- :class="['region-item', { active: isProvinceSelected(province.code) || selectedProvinceCode === province.code }]"
- @click="selectProvince(province)"
- >
- <el-checkbox
- :model-value="isProvinceSelected(province.code)"
- @change="toggleProvinceSelection(province)"
- @click.stop
- />
- {{ province.name }}
- </div>
- </el-scrollbar>
- </div>
- </el-col>
- <el-col :span="6">
- <div class="region-selector-container">
- <div class="selector-header">
- <span>城市</span>
- <div>
- <el-button
- v-if="selectedProvince"
- :disabled="!cityList.length"
- link
- type="primary"
- @click="addAllCities"
- >
- 全部
- </el-button>
- <el-button
- :disabled="!selectedCities.length"
- link
- type="success"
- @click="addCurrentCitiesToSelected"
- >
- 添加
- </el-button>
- </div>
- </div>
- <el-scrollbar height="300px">
- <div
- v-for="city in cityList"
- :key="city.code"
- :class="['region-item', { active: isCitySelected(city.code) || selectedCityCode === city.code }]"
- @click="selectCity(city)"
- >
- <el-checkbox
- :disabled="isProvinceOfCitySelected(city)"
- :model-value="isCitySelected(city.code)"
- @change="toggleCitySelection(city)"
- @click.stop
- />
- {{ city.name }}
- </div>
- </el-scrollbar>
- </div>
- </el-col>
- <el-col :span="6">
- <div class="region-selector-container">
- <div class="selector-header">
- <span>区县</span>
- <div>
- <el-button
- v-if="selectedCity"
- :disabled="!areaList.length"
- link
- type="primary"
- @click="addAllAreas"
- >
- 全部
- </el-button>
- <el-button
- :disabled="!selectedAreas.length"
- link
- type="success"
- @click="addCurrentAreasToSelected"
- >
- 添加
- </el-button>
- </div>
- </div>
- <el-scrollbar height="300px">
- <div
- v-for="area in areaList"
- :key="area.code"
- :class="['region-item', { active: isAreaSelected(area.code) }]"
- @click="toggleAreaSelection(area)"
- >
- <el-checkbox
- :disabled="isHigherLevelRegionSelected(area)"
- :model-value="isAreaSelected(area.code)"
- @change="toggleAreaSelection(area)"
- @click.stop
- />
- {{ area.name }}
- </div>
- </el-scrollbar>
- </div>
- </el-col>
- <el-col :span="6">
- <div class="region-selector-container">
- <div class="selector-header">
- <span>已选择</span>
- <el-button
- :disabled="!selectedRegions.length"
- link
- type="danger"
- @click="clearSelectedRegions"
- >
- 清空
- </el-button>
- </div>
- <el-scrollbar height="300px">
- <div
- v-for="(region, index) in selectedRegions"
- :key="index"
- class="selected-region-item"
- >
- <span>{{ formatRegionName(region) }}</span>
- <el-icon @click.stop="removeSelectedRegion(index)">
- <Close/>
- </el-icon>
- </div>
- <div v-if="!selectedRegions.length" class="no-data">
- 暂无选择
- </div>
- </el-scrollbar>
- </div>
- </el-col>
- </el-row>
-
- <template #footer>
- <div class="dialog-footer">
- <el-button @click="closeRegionModal">取消</el-button>
- <el-button type="primary" @click="confirmRegions">确认选择</el-button>
- </div>
- </template>
- </el-dialog>
- </div>
- </template>
- <script setup lang="ts">
- import {computed, nextTick, onMounted, reactive, ref, watch} from 'vue'
- import {ElMessage, ElMessageBox} from 'element-plus'
- import {Close, DocumentAdd, Plus, Van} from '@element-plus/icons-vue'
- import {getAreas, getCities, getProvinces} from '../api/index.js'
- // 定义组件props
- const props = defineProps({
- // 模板数据,用于编辑模式
- templateData: {
- type: Object,
- default: null
- },
- // 加载状态
- loading: {
- type: Boolean,
- default: false
- }
- })
- // 定义组件事件
- const emit = defineEmits(['save', 'cancel'])
- // 判断是否为编辑模式
- const isEditMode = computed(() => {
- return props.templateData && props.templateData.templateInfo && props.templateData.templateInfo.id
- })
- // 省份数据
- const provinceData = ref<any[]>([])
- // 模板信息
- const templateInfo = reactive({
- id: null,
- name: '',
- calcMethod: 'piece', // piece, weight, volume
- unit: 'kg' // 默认单位为 kg
- })
- // 默认规则
- const defaultRule = reactive({
- first: 1,
- firstPrice: 10,
- nextPrice: 5
- })
- // 特殊区域列表
- const specialAreas = ref<any[]>([])
- // 地区选择模态框相关
- const showRegionModal = ref(false)
- const currentAreaIndex = ref(-1)
- // 按省市区选择相关
- const provinceList = ref<any[]>([]) // 省份列表
- const cityList = ref<any[]>([]) // 城市列表
- const areaList = ref<any[]>([]) // 区县列表
- const selectedProvince = ref<any>(null) // 已选择的省份
- const selectedProvinceCode = ref<string>('') // 已选择的省份编码
- const selectedCity = ref<any>(null) // 已选择的城市
- const selectedCityCode = ref<string>('') // 已选择的城市编码
- const selectedProvinces = ref<any[]>([]) // 已选择的省份列表
- const selectedCities = ref<any[]>([]) // 已选择的城市列表
- const selectedAreas = ref<any[]>([]) // 已选择的区县列表
- const selectedRegions = ref<any[]>([]) // 已选择的地区列表
- // 在组件挂载时加载省份数据
- onMounted(async () => {
- try {
- // 获取省份数据
- const res = await getProvinces()
- provinceData.value = res.data || []
- provinceList.value = res.data || []
- } catch (error) {
- console.error('加载省份数据失败:', error)
- // 不再使用硬编码的默认省份列表
- provinceData.value = []
- provinceList.value = []
- }
- })
- // 选择省份
- const selectProvince = async (province: any) => {
- selectedProvince.value = province
- selectedProvinceCode.value = province.code
- try {
- // 调用API获取城市列表
- const res = await getCities(province.code)
- cityList.value = res.data || []
- areaList.value = []
- selectedCity.value = null
- selectedCityCode.value = ''
- selectedCities.value = []
- selectedAreas.value = []
- } catch (error) {
- console.error('获取城市列表失败:', error)
- cityList.value = []
- areaList.value = []
- selectedCity.value = null
- selectedCityCode.value = ''
- selectedCities.value = []
- selectedAreas.value = []
- }
- }
- // 选择城市
- const selectCity = async (city: any) => {
- selectedCity.value = city
- selectedCityCode.value = city.code
- try {
- // 调用API获取区县列表
- const res = await getAreas(city.code)
- areaList.value = res.data || []
- selectedAreas.value = []
- } catch (error) {
- console.error('获取区县列表失败:', error)
- areaList.value = []
- selectedAreas.value = []
- }
- }
- // 切换城市选择
- const toggleCitySelection = (city: any) => {
- const index = selectedCities.value.findIndex((c: any) => c.city_id === city.code)
- if (index > -1) {
- // 取消选择
- selectedCities.value.splice(index, 1)
- // 同时取消该城市下所有区县的选择
- selectedAreas.value = selectedAreas.value.filter((area: any) => area.city_id !== city.city_id)
- } else {
- // 添加选择之前检查是否已选择了所属省份
- const isProvinceAlreadySelected = selectedProvinces.value.some(
- (province: any) => province.province_id === city.province_id
- )
- if (isProvinceAlreadySelected) {
- // 获取省份名称用于提示
- const province = selectedProvinces.value.find(
- (p: any) => p.province_id === city.province_id
- )
- const provinceName = province ? province.province_name : '该省份'
- ElMessage.warning(`您已选择了${provinceName},无需再单独选择其下属城市`)
- return
- }
- // 添加选择,直接存储完整的6个字段
- const province = provinceList.value.find((p: any) => p.code === city.province + '0000')
- const provinceName = province ? province.name : '未知省份'
- selectedCities.value.push({
- area_id: null,
- city_id: city.code,
- area_name: null,
- city_name: city.name,
- province_id: city.province + '0000',
- province_name: provinceName
- })
- }
- }
- // 切换区县选择
- const toggleAreaSelection = (area: any) => {
- const index = selectedAreas.value.findIndex((a: any) => a.area_id === area.code)
- if (index > -1) {
- // 取消选择
- selectedAreas.value.splice(index, 1)
- } else {
- // 添加选择之前检查是否已选择了所属城市或省份
- const isCityAlreadySelected = selectedCities.value.some(
- (city: any) => city.city_id === area.city_id
- )
- const isProvinceAlreadySelected = selectedProvinces.value.some(
- (province: any) => province.province_id === area.province_id
- )
- if (isCityAlreadySelected) {
- // 获取城市名称用于提示
- const city = selectedCities.value.find(
- (c: any) => c.city_id === area.city_id
- )
- const cityName = city ? city.city_name : '该城市'
- ElMessage.warning(`您已选择了${cityName},无需再单独选择其下属区县`)
- return
- }
- if (isProvinceAlreadySelected) {
- // 获取省份名称用于提示
- const province = selectedProvinces.value.find(
- (p: any) => p.province_id === area.province + '0000'
- )
- const provinceName = province ? province.province_name : '该省份'
- ElMessage.warning(`您已选择了${provinceName},无需再单独选择其下属区县`)
- return
- }
- // 添加选择,直接存储完整的6个字段
- const province = provinceList.value.find((p: any) => p.code === area.province + '0000')
- const provinceName = province ? province.name : '未知省份'
- const city = cityList.value.find((c: any) => c.code === area.province + area.city + '00')
- const cityName = city ? city.name : '未知城市'
-
- selectedAreas.value.push({
- area_id: area.code,
- city_id: area.province + area.city + '00',
- area_name: area.name,
- city_name: cityName,
- province_id: area.province + '0000',
- province_name: provinceName
- })
- }
- }
- // 切换省份选择
- const toggleProvinceSelection = (province: any) => {
- const index = selectedProvinces.value.findIndex((p: any) => p.province_id === province.code)
- if (index > -1) {
- // 取消选择
- selectedProvinces.value.splice(index, 1)
- // 同时取消该省份下所有城市和区县的选择
- selectedCities.value = selectedCities.value.filter((city: any) => city.province_id !== province.province_id)
- selectedAreas.value = selectedAreas.value.filter((area: any) => area.province_id !== province.province_id)
- } else {
- // 添加选择,直接存储完整的6个字段
- selectedProvinces.value.push({
- area_id: null,
- city_id: null,
- area_name: null,
- city_name: null,
- province_id: province.code,
- province_name: province.name
- })
- }
- }
- // 判断城市是否被选中
- const isCitySelected = (cityCode: string) => {
- return selectedCities.value.some((city: any) => city.city_id === cityCode)
- }
- // 判断区县是否被选中
- const isAreaSelected = (areaCode: string) => {
- return selectedAreas.value.some((area: any) => area.area_id === areaCode)
- }
- // 判断省份是否被选中
- const isProvinceSelected = (provinceCode: string) => {
- return selectedProvinces.value.some((province: any) => province.province_id === provinceCode)
- }
- // 判断城市的省份是否已经被选中
- const isProvinceOfCitySelected = (city: any) => {
- return selectedProvinces.value.some((province: any) => province.province_id === city.province_id)
- }
- // 判断区县的上级(城市或省份)是否已经被选中
- const isHigherLevelRegionSelected = (area: any) => {
- // 检查所属城市是否被选中
- const isCitySelected = selectedCities.value.some((city: any) => city.city_id === area.city_id)
- // 检查所属省份是否被选中
- const isProvinceSelected = selectedProvinces.value.some((province: any) => province.province_id === area.province_id)
- return isCitySelected || isProvinceSelected
- }
- // 添加所有城市
- const addAllCities = () => {
- // 过滤掉那些所属省份已经被选中的城市
- const citiesToAdd = cityList.value.filter((city: any) => !isProvinceOfCitySelected(city))
- selectedCities.value = citiesToAdd.map(city => {
- const province = provinceList.value.find((p: any) => p.code === city.province + '0000')
- const provinceName = province ? province.name : '未知省份'
- return {
- area_id: null,
- city_id: city.code,
- area_name: null,
- city_name: city.name,
- province_id: city.province + '0000',
- province_name: provinceName
- }
- })
- }
- // 添加所有区县
- const addAllAreas = () => {
- // 过滤掉那些所属城市或省份已经被选中的区县
- const areasToAdd = areaList.value.filter((area: any) => !isHigherLevelRegionSelected(area))
- selectedAreas.value = areasToAdd.map(area => {
- const province = provinceList.value.find((p: any) => p.code === area.province + '0000')
- const provinceName = province ? province.name : '未知省份'
- const city = cityList.value.find((c: any) => c.code === area.province + area.city + '00')
- const cityName = city ? city.name : '未知城市'
- return {
- area_id: area.code,
- city_id: area.province + area.city + '00',
- area_name: area.name,
- city_name: cityName,
- province_id: area.province + '0000',
- province_name: provinceName
- }
- })
- }
- // 添加所有省份
- const addAllProvinces = async () => {
- // 检查是否已选择了省份的子级(城市或区县)
- const hasCitySelected = selectedCities.value.some((city: any) => {
- return selectedProvinces.value.some((province: any) => province.province_id === city.province_id)
- })
- const hasAreaSelected = selectedAreas.value.some((area: any) => {
- return selectedProvinces.value.some((province: any) => province.province_id === area.province_id)
- })
- if (hasCitySelected || hasAreaSelected) {
- ElMessage.warning('您已选择了省份的子级区域,无法再添加全部省份')
- return
- }
- selectedProvinces.value = provinceList.value.map(province => ({
- area_id: null,
- city_id: null,
- area_name: null,
- city_name: null,
- province_id: province.code,
- province_name: province.name
- }))
- // 如果省份列表不为空,加载第一个省份的城市数据
- if (provinceList.value.length > 0) {
- const firstProvince = provinceList.value[0]
- selectedProvince.value = firstProvince
- selectedProvinceCode.value = firstProvince.code
- try {
- // 调用API获取城市列表
- const res = await getCities(firstProvince.code)
- cityList.value = res.data || []
- areaList.value = []
- selectedCity.value = null
- selectedCityCode.value = ''
- selectedCities.value = []
- selectedAreas.value = []
- } catch (error) {
- console.error('获取城市列表失败:', error)
- cityList.value = []
- areaList.value = []
- selectedCity.value = null
- selectedCityCode.value = ''
- selectedAreas.value = []
- }
- }
- }
- // 清空已选择的地区
- const clearSelectedRegions = () => {
- selectedRegions.value = []
- }
- // 移除已选择的地区
- const removeSelectedRegion = (index: number) => {
- selectedRegions.value.splice(index, 1)
- }
- // 格式化地区名称显示
- const formatRegionName = (region: any) => {
- if (!region.city_id && !region.area_id) {
- // 省级区域,只显示省份名称
- return region.province_name || ''
- } else if (region.city_id && !region.area_id) {
- // 市级区域,显示"河北省/石家庄市"格式
- return `${region.province_name || ''}/${region.city_name || ''}`
- } else if (region.city_id && region.area_id) {
- // 区县级区域,显示"河北省/石家庄市/长安区"格式
- return `${region.province_name || ''}/${region.city_name || ''}/${region.area_name || ''}`
- }
- return region.province_name || ''
- }
- // 打开地区选择模态框
- const openRegionModal = (areaIndex: number) => {
- currentAreaIndex.value = areaIndex
- showRegionModal.value = true
- // 初始化省市选择模式数据
- selectedProvince.value = null
- selectedProvinceCode.value = ''
- selectedCity.value = null
- selectedCityCode.value = ''
- cityList.value = []
- areaList.value = []
- selectedProvinces.value = []
- selectedCities.value = []
- selectedAreas.value = []
- // 从现有数据中恢复已选择的地区
- const regions = [...specialAreas.value[areaIndex].regions]
- selectedRegions.value = regions
- }
- // 关闭地区选择模态框
- const closeRegionModal = () => {
- showRegionModal.value = false
- currentAreaIndex.value = -1
- // 重置省市选择模式数据
- selectedProvince.value = null
- selectedProvinceCode.value = ''
- selectedCity.value = null
- selectedCityCode.value = ''
- cityList.value = []
- areaList.value = []
- selectedCities.value = []
- selectedAreas.value = []
- selectedRegions.value = []
- }
- // 确认选择地区
- const confirmRegions = () => {
- if (currentAreaIndex.value >= 0) {
- // 将当前所有选中的省份、城市、区县添加到已选择列表
- const currentRegions = []
- // 添加选中的省份
- for (const province of selectedProvinces.value) {
- currentRegions.push({
- area_id: province.area_id,
- city_id: province.city_id,
- area_name: province.area_name,
- city_name: province.city_name,
- province_id: province.province_id,
- province_name: province.province_name
- })
- }
- // 添加选中的城市(过滤掉所属省份已经被选中的城市)
- for (const city of selectedCities.value) {
- const isProvinceSelected = selectedProvinces.value.some(
- (province: any) => province.province_id === city.province_id
- )
- if (!isProvinceSelected) {
- currentRegions.push({
- area_id: city.area_id,
- city_id: city.city_id,
- area_name: city.area_name,
- city_name: city.city_name,
- province_id: city.province_id,
- province_name: city.province_name
- })
- }
- }
- // 添加选中的区县(过滤掉所属城市或省份已经被选中的区县)
- for (const area of selectedAreas.value) {
- const isCitySelected = selectedCities.value.some(
- (city: any) => city.city_id === area.city_id
- )
- const isProvinceSelected = selectedProvinces.value.some(
- (province: any) => province.province_id === area.province_id
- )
- if (!isCitySelected && !isProvinceSelected) {
- currentRegions.push({
- area_id: area.area_id,
- city_id: area.city_id,
- area_name: area.area_name,
- city_name: area.city_name,
- province_id: area.province_id,
- province_name: area.province_name
- })
- }
- }
- // 合并已存在的地区和新选择的地区
- const allRegions = [...selectedRegions.value, ...currentRegions]
- // 去重处理
- const uniqueRegions = allRegions.filter((region, index, self) =>
- index === self.findIndex(r =>
- r.province_id === region.province_id &&
- r.city_id === region.city_id &&
- r.area_id === region.area_id
- )
- )
- // 最后进行层级关系检查,确保不会同时存在父级和子级
- const filteredRegions = []
- for (const region of uniqueRegions) {
- let shouldAdd = true
- if (!region.city_id && !region.area_id) {
- // 省级区域,检查是否已存在其子级
- const hasChild = filteredRegions.some(r =>
- (r.province_id === region.province_id && (r.city_id || r.area_id))
- )
- shouldAdd = !hasChild
- } else if (region.city_id && !region.area_id) {
- // 市级区域,检查是否已存在父级或子级
- const hasParent = filteredRegions.some(r =>
- r.province_id === region.province_id && !r.city_id && !r.area_id
- )
- const hasChild = filteredRegions.some(r =>
- r.city_id === region.city_id && r.area_id
- )
- shouldAdd = !hasParent && !hasChild
- } else if (region.city_id && region.area_id) {
- // 区县级区域,检查是否已存在父级
- const hasParentProvince = filteredRegions.some(r =>
- r.province_id === region.province_id && !r.city_id && !r.area_id
- )
- const hasParentCity = filteredRegions.some(r =>
- r.province_id === region.province_id && r.city_id === region.city_id && !r.area_id
- )
- shouldAdd = !hasParentProvince && !hasParentCity
- }
- if (shouldAdd) {
- filteredRegions.push(region)
- }
- }
- specialAreas.value[currentAreaIndex.value].regions = filteredRegions
- }
- closeRegionModal()
- }
- // 监听传入的模板数据变化
- watch(() => props.templateData, (newVal) => {
- if (newVal) {
- // 填充表单数据用于编辑
- templateInfo.id = newVal.templateInfo?.id || null
- templateInfo.name = newVal.templateInfo?.name || ''
- templateInfo.calcMethod = newVal.templateInfo?.calcMethod || 'piece'
- templateInfo.unit = newVal.templateInfo?.unit || 'kg'
-
- if (newVal.defaultRule) {
- defaultRule.first = Number(newVal.defaultRule.first) || 1
- defaultRule.firstPrice = Number(newVal.defaultRule.firstPrice) || 0
- defaultRule.nextPrice = Number(newVal.defaultRule.nextPrice) || 0
- }
-
- if (Array.isArray(newVal.specialAreas)) {
- specialAreas.value = newVal.specialAreas.map((area: any) => {
- // 确保每个区域的字段都正确处理,特别是处理可能为 null 的字段
- const processedRegions = Array.isArray(area.regions)
- ? area.regions.map((region: any) => ({
- province_id: region.province_id || null,
- province_name: region.province_name || '',
- city_id: region.city_id || null,
- city_name: region.city_name || null,
- area_id: region.area_id || null,
- area_name: region.area_name || null
- })).filter((region: any) => region.province_id) // 过滤掉没有province_id的无效区域
- : [];
-
- return {
- area_name: area.area_name || area.name || '',
- regions: processedRegions,
- first: Number(area.first) || 1,
- firstPrice: Number(area.first_price || area.firstPrice) || 0,
- nextPrice: Number(area.next_price || area.nextPrice) || 0
- }
- })
- } else {
- specialAreas.value = []
- }
- } else {
- // 如果没有传入数据,重置表单
- // 为了避免引用错误,这里手动重置表单而不是调用resetForm函数
- templateInfo.id = null
- templateInfo.name = ''
- templateInfo.calcMethod = 'piece'
- templateInfo.unit = 'kg'
- defaultRule.first = 1
- defaultRule.firstPrice = 10
- defaultRule.nextPrice = 5
- specialAreas.value = []
- }
- }, { immediate: true })
- // 可用单位选项
- const unitOptions = {
- weight: [
- { label: '克(g)', value: 'g' },
- { label: '千克(kg)', value: 'kg' }
- ],
- volume: [
- { label: '立方厘米(cm³)', value: 'cm3' },
- { label: '立方米(m³)', value: 'm3' }
- ]
- }
- // 获取可用单位选项
- const getAvailableUnits = () => {
- if (templateInfo.calcMethod === 'weight') {
- return unitOptions.weight
- } else if (templateInfo.calcMethod === 'volume') {
- return unitOptions.volume
- }
- return []
- }
- // 获取当前显示的单位
- const getCurrentDisplayUnit = () => {
- // 如果是按件数计费,直接返回件
- if (templateInfo.calcMethod === 'piece') {
- return '件'
- }
-
- // 返回用户选择的具体单位
- return templateInfo.unit
- }
- // 获取首值标签
- const getFirstLabel = () => {
- switch (templateInfo.calcMethod) {
- case 'piece': return '首件'
- case 'weight': return '首重'
- case 'volume': return '首体积'
- default: return '首件'
- }
- }
- // 获取首价标签
- const getFirstPriceLabel = () => {
- switch (templateInfo.calcMethod) {
- case 'piece': return '首件费用(元)'
- case 'weight': return '首重费用(元)'
- case 'volume': return '首体积费用(元)'
- default: return '首件费用(元)'
- }
- }
- // 获取续价标签
- const getNextPriceLabel = () => {
- switch (templateInfo.calcMethod) {
- case 'piece': return '续件单价(元)'
- case 'weight': return '续重单价(元)'
- case 'volume': return '续体积单价(元)'
- default: return '续件单价(元)'
- }
- }
- // 获取首值的最小值
- const getMinFirstValue = () => {
- switch (templateInfo.calcMethod) {
- case 'piece': return 1
- case 'weight': return templateInfo.unit === 'g' ? 100 : 0.1
- case 'volume': return templateInfo.unit === 'cm3' ? 1000 : 0.001
- default: return 1
- }
- }
- // 获取首值的步长
- const getFirstStep = () => {
- switch (templateInfo.calcMethod) {
- case 'piece': return 1
- case 'weight': return templateInfo.unit === 'g' ? 100 : 0.1
- case 'volume': return templateInfo.unit === 'cm3' ? 1000 : 0.001
- default: return 1
- }
- }
- // 处理计费方式变更
- const handleCalcMethodChange = async () => {
- // 当计费方式改变时,更新所有规则的首值、步长和单位
- defaultRule.first = getMinFirstValue()
-
- // 更新所有特殊区域的首值
- specialAreas.value.forEach(area => {
- area.first = getMinFirstValue()
- })
-
- // 强制更新DOM以确保单位正确显示
- await nextTick()
- console.log('计费方式已更改为:', templateInfo.calcMethod)
- }
- // 处理单位变化
- const handleUnitChange = () => {
- // 更新默认规则的首值、步长
- defaultRule.first = getMinFirstValue()
-
- // 更新所有特殊区域的首值
- specialAreas.value.forEach(area => {
- area.first = getMinFirstValue()
- })
-
- console.log('单位已更改为:', templateInfo.unit)
- }
- // 添加特殊区域
- const addSpecialArea = () => {
- specialAreas.value.push({
- area_name: '',
- regions: [],
- first: getMinFirstValue(),
- firstPrice: 15,
- nextPrice: 8
- })
- }
- // 删除特殊区域
- const removeSpecialArea = (index: number) => {
- ElMessageBox.confirm('确定要删除这个特殊区域吗?', '提示', {
- type: 'warning'
- }).then(() => {
- specialAreas.value.splice(index, 1)
- }).catch(() => {
- // 取消删除
- })
- }
- // 删除地区
- const removeRegion = (areaIndex: number, regionIndex: number) => {
- specialAreas.value[areaIndex].regions.splice(regionIndex, 1)
- }
- // 保存模板
- const saveTemplate = () => {
- // 数据验证
- if (!templateInfo.name) {
- ElMessage.error('请输入模板名称')
- return
- }
-
- // 验证默认规则
- if (defaultRule.first <= 0) {
- ElMessage.error('默认规则' + getFirstLabel() + '必须大于0')
- return
- }
-
- if (defaultRule.firstPrice < 0) {
- ElMessage.error('默认规则' + getFirstPriceLabel() + '不能为负数')
- return
- }
-
- if (defaultRule.nextPrice < 0) {
- ElMessage.error('默认规则' + getNextPriceLabel() + '不能为负数')
- return
- }
-
- // 验证特殊区域
- for (let i = 0; i < specialAreas.value.length; i++) {
- const area = specialAreas.value[i]
- if (!area.area_name) {
- ElMessage.error(`第${i + 1}个特殊区域请输入区域名称`)
- return
- }
-
- if (area.regions.length === 0) {
- ElMessage.error(`第${i + 1}个特殊区域请选择地区`)
- return
- }
-
- if (area.first <= 0) {
- ElMessage.error(`第${i + 1}个特殊区域` + getFirstLabel() + '必须大于0')
- return
- }
-
- if (area.firstPrice < 0) {
- ElMessage.error(`第${i + 1}个特殊区域` + getFirstPriceLabel() + '不能为负数')
- return
- }
-
- if (area.nextPrice < 0) {
- ElMessage.error(`第${i + 1}个特殊区域` + getNextPriceLabel() + '不能为负数')
- return
- }
- }
- // 处理特殊区域数据,确保只包含有效的6字段结构
- const processedSpecialAreas = specialAreas.value.map(area => {
- // 过滤掉无效的区域数据并确保每个区域都有province_id
- const validRegions = area.regions
- .filter(region => region && region.province_id)
- .map(region => ({
- province_id: region.province_id,
- province_name: region.province_name || '',
- city_id: region.city_id || null,
- city_name: region.city_name || null,
- area_id: region.area_id || null,
- area_name: region.area_name || null
- }));
- return {
- area_name: area.area_name,
- first: area.first,
- firstPrice: area.firstPrice,
- nextPrice: area.nextPrice,
- regions: validRegions
- };
- });
-
- const templateData = {
- templateInfo: { ...templateInfo },
- defaultRule: { ...defaultRule },
- specialAreas: processedSpecialAreas
- }
-
- emit('save', templateData)
- const message = isEditMode.value ? '模板保存成功' : '模板创建成功'
- ElMessage.success(message)
- console.log('保存模板数据:', templateData)
- }
- // 取消操作
- const cancel = () => {
- ElMessageBox.confirm('确定要取消吗?未保存的数据将会丢失。', '提示', {
- type: 'warning'
- }).then(() => {
- emit('cancel')
- console.log('取消操作')
- }).catch(() => {
- // 取消操作
- })
- }
- // 重置表单
- const resetForm = () => {
- templateInfo.id = null
- templateInfo.name = ''
- templateInfo.calcMethod = 'piece'
- templateInfo.unit = 'kg'
- defaultRule.first = 1
- defaultRule.firstPrice = 10
- defaultRule.nextPrice = 5
- specialAreas.value = []
- }
- // 添加当前选中的省份到已选择列表
- const addCurrentProvincesToSelected = () => {
- const newRegions = [];
- // 添加选中的省份
- for (const province of selectedProvinces.value) {
- newRegions.push({
- area_id: province.area_id,
- city_id: province.city_id,
- area_name: province.area_name,
- city_name: province.city_name,
- province_id: province.province_id,
- province_name: province.province_name
- });
- }
- // 合并到已选择区域并去重
- const allRegions = [...selectedRegions.value, ...newRegions];
- const uniqueRegions = allRegions.filter((region, index, self) =>
- index === self.findIndex(r =>
- r.province_id === region.province_id &&
- r.city_id === region.city_id &&
- r.area_id === region.area_id
- )
- );
- // 检查添加省份时是否存在下级区域(已选择的城市或区县)
- const finalRegions = [];
- for (const region of uniqueRegions) {
- let shouldAdd = true;
- if (!region.city_id && !region.area_id) {
- // 对于省份,检查是否存在下级区域
- const hasChild = uniqueRegions.some(r =>
- (r.province_id === region.province_id && (r.city_id || r.area_id))
- );
- if (hasChild) {
- ElMessage.warning(`您已选择了${region.province_name}的下级区域,无法再添加该省份`);
- shouldAdd = false;
- }
- } else if (region.city_id && !region.area_id) {
- // 对于城市,检查是否存在上级省份或下级区县
- const hasParent = uniqueRegions.some(r =>
- r.province_id === region.province_id && !r.city_id && !r.area_id
- );
- const hasChild = uniqueRegions.some(r =>
- r.city_id === region.city_id && r.area_id
- );
- if (hasParent) {
- ElMessage.warning(`您已选择了${region.province_name}的上级省份,无法再添加该城市`);
- shouldAdd = false;
- }
- if (hasChild) {
- ElMessage.warning(`您已选择了${region.city_name}的下级区县,无法再添加该城市`);
- shouldAdd = false;
- }
- } else if (region.city_id && region.area_id) {
- // 对于区县,检查是否存在上级省份或城市
- const hasParentProvince = uniqueRegions.some(r =>
- r.province_id === region.province_id && !r.city_id && !r.area_id
- );
- const hasParentCity = uniqueRegions.some(r =>
- r.province_id === region.province_id && r.city_id === region.city_id && !r.area_id
- );
- if (hasParentProvince) {
- ElMessage.warning(`您已选择了${region.province_name}的上级省份,无法再添加该区县`);
- shouldAdd = false;
- }
- if (hasParentCity) {
- ElMessage.warning(`您已选择了${region.city_name}的上级城市,无法再添加该区县`);
- shouldAdd = false;
- }
- }
- if (shouldAdd) {
- finalRegions.push(region);
- }
- }
- selectedRegions.value = finalRegions;
- // 清空当前选中状态
- selectedProvinces.value = [];
- }
- // 添加当前选中的城市到已选择列表
- const addCurrentCitiesToSelected = () => {
- const newRegions = [];
- // 添加选中的城市
- for (const city of selectedCities.value) {
- newRegions.push({
- province_id: city.province_id,
- province_name: city.province_name,
- city_id: city.city_id,
- city_name: city.city_name,
- area_id: city.area_id,
- area_name: city.area_name
- });
- }
- // 合并到已选择区域并去重
- const allRegions = [...selectedRegions.value, ...newRegions];
- const uniqueRegions = allRegions.filter((region, index, self) =>
- index === self.findIndex(r =>
- r.province_id === region.province_id &&
- r.city_id === region.city_id &&
- r.area_id === region.area_id
- )
- );
- // 检查添加城市时是否存在上级或下级区域
- const finalRegions = [];
- for (const region of uniqueRegions) {
- let shouldAdd = true;
- if (!region.city_id && !region.area_id) {
- // 对于省份,检查是否存在下级区域
- const hasChild = uniqueRegions.some(r =>
- (r.province_id === region.province_id && (r.city_id || r.area_id))
- );
- if (hasChild) {
- ElMessage.warning(`您已选择了${region.province_name}的下级区域,无法再添加该省份`);
- shouldAdd = false;
- }
- } else if (region.city_id && !region.area_id) {
- // 对于城市,检查是否存在上级省份或下级区县
- const hasParent = uniqueRegions.some(r =>
- r.province_id === region.province_id && !r.city_id && !r.area_id
- );
- const hasChild = uniqueRegions.some(r =>
- r.city_id === region.city_id && r.area_id
- );
- if (hasParent) {
- ElMessage.warning(`您已选择了${region.province_name}的上级省份,无法再添加该城市`);
- shouldAdd = false;
- }
- if (hasChild) {
- ElMessage.warning(`您已选择了${region.city_name}的下级区县,无法再添加该城市`);
- shouldAdd = false;
- }
- } else if (region.city_id && region.area_id) {
- // 对于区县,检查是否存在上级省份或城市
- const hasParentProvince = uniqueRegions.some(r =>
- r.province_id === region.province_id && !r.city_id && !r.area_id
- );
- const hasParentCity = uniqueRegions.some(r =>
- r.province_id === region.province_id && r.city_id === region.city_id && !r.area_id
- );
- if (hasParentProvince) {
- ElMessage.warning(`您已选择了${region.province_name}的上级省份,无法再添加该区县`);
- shouldAdd = false;
- }
- if (hasParentCity) {
- ElMessage.warning(`您已选择了${region.city_name}的上级城市,无法再添加该区县`);
- shouldAdd = false;
- }
- }
- if (shouldAdd) {
- finalRegions.push(region);
- }
- }
- selectedRegions.value = finalRegions;
- // 清空当前选中状态
- selectedCities.value = [];
- }
- // 添加当前选中的区县到已选择列表
- const addCurrentAreasToSelected = () => {
- const newRegions = [];
- // 添加选中的区县
- for (const area of selectedAreas.value) {
- // 检查要添加的区县是否存在上级(已选择的省份或城市)
- const hasParentProvince = selectedProvinces.value.some(province => province.province_id === area.province_id);
- const hasParentCity = selectedCities.value.some(city => city.city_id === area.city_id);
- if (hasParentProvince) {
- ElMessage.warning(`您已选择了${area.name}的上级省份,无法再添加该区县`);
- continue; // 跳过这个区县,不添加
- }
- if (hasParentCity) {
- ElMessage.warning(`您已选择了${area.name}的上级城市,无法再添加该区县`);
- continue; // 跳过这个区县,不添加
- }
- newRegions.push({
- area_id: area.area_id,
- city_id: area.city_id,
- area_name: area.area_name,
- city_name: area.city_name,
- province_id: area.province_id,
- province_name: area.province_name
- });
- }
- // 合并到已选择区域并去重
- const allRegions = [...selectedRegions.value, ...newRegions];
- const uniqueRegions = allRegions.filter((region, index, self) =>
- index === self.findIndex(r =>
- r.province_id === region.province_id &&
- r.city_id === region.city_id &&
- r.area_id === region.area_id
- )
- );
- selectedRegions.value = uniqueRegions;
- // 清空当前选中状态
- selectedAreas.value = [];
- }
- </script>
- <style scoped lang="scss">
- .shipping-template-component {
- .card-header {
- font-size: 18px;
- font-weight: bold;
- color: #409eff;
- display: flex;
- align-items: center;
- gap: 8px;
- }
- .card-sub-header {
- font-size: 16px;
- font-weight: bold;
- }
- .special-area {
- border: 1px solid #dcdfe6;
- border-radius: 4px;
- transition: all 0.3s;
- &:hover {
- box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
- }
- }
- .region-tags {
- min-height: 32px;
- }
- .province-checkbox-group {
- max-height: 300px;
- overflow-y: auto;
- }
- .mb-4 {
- margin-bottom: 1rem;
- }
- :deep(.el-card__header) {
- padding: 12px 20px;
- border-bottom: 1px solid #ebeef5;
- }
- :deep(.el-form-item) {
- margin-bottom: 18px;
- }
- :deep(.el-form-item__label) {
- font-weight: normal;
- }
- .input-with-unit {
- display: flex;
- align-items: center;
- gap: 8px;
- .unit-text {
- white-space: nowrap;
- color: #606266;
- font-size: 14px;
- }
- }
- .form-item-tip {
- margin-top: 4px;
- font-size: 12px;
- color: #909399;
- line-height: 1.4;
- }
- .region-selector-container {
- border: 1px solid #dcdfe6;
- border-radius: 4px;
- height: 350px;
- display: flex;
- flex-direction: column;
- .selector-header {
- padding: 8px 12px;
- border-bottom: 1px solid #dcdfe6;
- display: flex;
- justify-content: space-between;
- align-items: center;
- font-weight: 500;
- }
- .region-item {
- padding: 8px 12px;
- cursor: pointer;
- display: flex;
- align-items: center;
- gap: 8px;
- &:hover {
- background-color: #f5f7fa;
- }
- &.active {
- background-color: #ecf5ff;
- color: #409eff;
- }
- }
- .selected-region-item {
- padding: 8px 12px;
- display: flex;
- justify-content: space-between;
- align-items: center;
- &:hover {
- background-color: #f5f7fa;
- }
- }
- .no-data {
- padding: 20px;
- text-align: center;
- color: #909399;
- }
- }
- .dialog-footer {
- text-align: right;
- }
- }
- </style>
|