fix: improve commodity country selection

This commit is contained in:
zhx 2026-06-25 11:15:59 +08:00
parent 0083dbb1cf
commit 70c5e362c9
2 changed files with 106 additions and 13 deletions

View File

@ -21,7 +21,7 @@
<div class="flex-l">{{ regionName }}</div>
</el-form-item>
<el-form-item v-if="!isUpdate" label="支持国家" prop="payCountryIds">
<el-select v-model="form.payCountryIds" multiple filterable collapse-tags style="width:100%" placeholder="请选择支持国家">
<el-select v-model="form.payCountryIds" multiple filterable collapse-tags style="width:100%" placeholder="请选择支持国家" @change="handlePayCountryIdsChange">
<el-option
v-for="item in countryList"
:key="getPayCountryId(item)"
@ -157,7 +157,9 @@ export default {
associateLoading: false,
supportAmounts: [],
computedAmount: '',
amountUsd: ''
amountUsd: '',
lastPayCountryIds: [],
syncingPayCountryIds: false
}
},
computed: {
@ -212,6 +214,7 @@ export default {
if (!this.form.payCountryIds || this.form.payCountryIds.length === 0) {
this.$set(this.form, 'payCountryIds', this.form.payCountryId ? [this.form.payCountryId] : [])
}
this.syncPayCountryIdsBySameName(this.form.payCountryIds || [])
if (!this.form.awardContent && this.form.awardContent !== 0) {
this.$set(this.form, 'awardContent', '0')
}
@ -256,6 +259,82 @@ export default {
const country = this.getCountryBase(item)
return country.nationalFlag || country.icon || item.nationalFlag || item.countryNationalFlag || item.payCountryNationalFlag || item.icon || ''
},
handlePayCountryIdsChange(value) {
if (this.syncingPayCountryIds) {
return
}
const currentIds = this.normalizeCountryIds(value)
const lastIds = this.normalizeCountryIds(this.lastPayCountryIds)
const addedIds = currentIds.filter(id => !lastIds.includes(id))
const removedIds = lastIds.filter(id => !currentIds.includes(id))
let nextIds = currentIds.slice()
addedIds.forEach(id => {
nextIds = this.mergeCountryIds(nextIds, this.sameNameCountryIds(id))
})
removedIds.forEach(id => {
const removeIds = this.sameNameCountryIds(id)
nextIds = nextIds.filter(nextId => !removeIds.includes(String(nextId)))
})
this.syncPayCountryIdsBySameName(nextIds)
},
syncPayCountryIdsBySameName(value) {
const normalizedIds = this.normalizeCountryIds(value)
const expandedIds = normalizedIds.reduce((result, id) => {
return this.mergeCountryIds(result, this.sameNameCountryIds(id))
}, normalizedIds.slice())
const nextValues = this.countryIdValues(expandedIds)
this.lastPayCountryIds = this.normalizeCountryIds(nextValues)
if (this.sameCountryIdList(this.normalizeCountryIds(this.form.payCountryIds), this.lastPayCountryIds)) {
return
}
this.syncingPayCountryIds = true
this.$set(this.form, 'payCountryIds', nextValues)
this.$nextTick(() => {
this.syncingPayCountryIds = false
})
},
normalizeCountryIds(value) {
return (Array.isArray(value) ? value : []).map(item => String(item)).filter(Boolean)
},
mergeCountryIds(sourceIds, appendIds) {
const result = this.normalizeCountryIds(sourceIds)
appendIds.forEach(id => {
id = String(id)
if (id && !result.includes(id)) {
result.push(id)
}
})
return result
},
sameNameCountryIds(payCountryId) {
const selected = this.countryList.find(item => String(this.getPayCountryId(item)) === String(payCountryId))
if (!selected) {
return [String(payCountryId)]
}
const selectedName = this.countryNameKey(selected)
if (!selectedName) {
return [String(payCountryId)]
}
return this.countryList
.filter(item => this.countryNameKey(item) === selectedName)
.map(item => String(this.getPayCountryId(item)))
.filter(Boolean)
},
countryNameKey(item) {
return String(this.getCountryName(item) || '').trim().toLowerCase()
},
countryIdValues(countryIds) {
const normalizedIds = this.normalizeCountryIds(countryIds)
return normalizedIds.map(id => {
const option = this.countryList.find(item => String(this.getPayCountryId(item)) === id)
return option ? this.getPayCountryId(option) : id
})
},
sameCountryIdList(left, right) {
left = this.normalizeCountryIds(left)
right = this.normalizeCountryIds(right)
return left.length === right.length && left.every((id, index) => id === right[index])
},
changeAmount(val) {
if (!val || !validPositiveNumberPointTwo(val)) {
this.supportAmounts = []

View File

@ -34,6 +34,7 @@
style="width: 200px"
class="filter-item"
clearable
filterable
@change="changeCountry"
>
<el-option
@ -210,6 +211,7 @@ export default {
listLoading: false,
countryList: [],
allCountryList: [],
allCountryListLoadingPromise: null,
loadingCountry: false,
loading: false
}
@ -274,37 +276,46 @@ export default {
loadOpenCountry(regionId) {
const that = this
that.loadingCountry = true
const request = regionId ? listPayOpenCountryByRegionId(regionId) : that.loadAllOpenCountry()
const request = regionId ? that.loadRegionCountryList(regionId) : that.loadAllCountryList(true)
request.then(res => {
const countryList = that.normalizeList(res.body)
const countryList = that.normalizeList(res)
if (countryList.length > 0 || !regionId) {
that.loadingCountry = false
that.applyCountryList(countryList)
return
}
that.loadAllOpenCountry().then(fallbackRes => {
that.loadAllCountryList(true).then(fallbackList => {
that.loadingCountry = false
that.applyCountryList(that.normalizeList(fallbackRes.body))
that.applyCountryList(that.normalizeList(fallbackList))
}).catch(er => {
that.loadingCountry = false
console.error(er)
})
}).catch(er => {
console.error(er)
that.loadAllOpenCountry().then(fallbackRes => {
that.loadAllCountryList(true).then(fallbackList => {
that.loadingCountry = false
that.applyCountryList(that.normalizeList(fallbackRes.body))
that.applyCountryList(that.normalizeList(fallbackList))
}).catch(fallbackErr => {
that.loadingCountry = false
console.error(fallbackErr)
})
})
},
loadAllOpenCountry(cursor = 1, limit = 500) {
loadRegionCountryList(regionId) {
return listPayOpenCountryByRegionId(regionId).then(res => this.normalizeList(res.body))
},
loadAllOpenCountry(cursor = 1, limit = 200) {
return pagePayOpenCounty({ cursor, limit })
},
loadAllCountryList() {
const limit = 500
loadAllCountryList(force = false) {
if (!force && this.allCountryList.length > 0) {
return Promise.resolve(this.allCountryList)
}
if (!force && this.allCountryListLoadingPromise) {
return this.allCountryListLoadingPromise
}
const limit = 200
const loadPage = (cursor, countryList) => {
return this.loadAllOpenCountry(cursor, limit).then(res => {
const body = res.body || {}
@ -317,7 +328,10 @@ export default {
return this.allCountryList
})
}
return loadPage(1, [])
this.allCountryListLoadingPromise = loadPage(1, []).finally(() => {
this.allCountryListLoadingPromise = null
})
return this.allCountryListLoadingPromise
},
applyCountryList(countryList) {
this.countryList = countryList
@ -458,7 +472,7 @@ export default {
if (!payCountryId) {
return null
}
return this.countryList.find(item => String(this.getPayCountryId(item)) === String(payCountryId))
return this.countryList.concat(this.allCountryList).find(item => String(this.getPayCountryId(item)) === String(payCountryId))
},
getCommodityCountrySource(row) {
const payCountryId = row && row.payCountryId ? row.payCountryId : this.listQuery.payCountryId