merged widget products selected&points product sales classification

This commit is contained in:
maqian
2026-05-21 10:21:16 +08:00
parent 33f718fe54
commit efed0f527e
5 changed files with 251 additions and 101 deletions

View File

@@ -191,6 +191,8 @@ export default {
}
const formData = Object.assign(defaultParams, queryParams)
return {
type: 'pickerGoodsItem',
defaultVal: [],
formData,
salesStatus: SALES_STATUS,
list: [],
@@ -206,7 +208,9 @@ export default {
},
categoryList: [],
multiple: this.value?.multiple ?? true,
localSelection: []
localSelection: [],
rowKey: this.value?.rowKey || 'item_id',
restoringSelection: false
}
},
computed: {
@@ -285,8 +289,8 @@ export default {
},
created() {
this.$options.config.title = this.$t('3157a2d5.43d1e2')
this.localSelection = cloneDeep(this.value.data) || []
this.rowKey = this.value?.rowKey || 'item_id'
this.localSelection = this.normalizeSelectionList(this.value.data)
this.syncLocalValFromSelection()
},
mounted() {
this.getGoodsBranchList()
@@ -316,16 +320,53 @@ export default {
}
return params
},
rowId(row) {
if (!row) return ''
const id = row[this.rowKey] ?? row.item_id ?? row.itemId
return id != null && id !== '' ? String(id) : ''
},
normalizeSelectionList(list) {
if (!Array.isArray(list)) return []
const map = new Map()
list.forEach((item) => {
if (item == null) return
if (typeof item === 'string' || typeof item === 'number') {
const id = String(item)
map.set(id, { item_id: id, itemId: id })
return
}
const id = this.rowId(item)
if (id) {
map.set(id, {
...item,
item_id: item.item_id ?? item.itemId ?? id,
itemId: item.itemId ?? item.item_id ?? id
})
}
})
return Array.from(map.values())
},
syncLocalValFromSelection() {
this.localVal = { data: this.localSelection }
},
dedupeSelectionList(list) {
return this.normalizeSelectionList(list)
},
afterSearch(response) {
const { list } = response.data.data
if (this.localSelection.length > 0) {
const { finderTable } = this.$refs.finder.$refs
const ids = this.localSelection.map((m) => m[this.rowKey])
const selectRows = list.filter((item) => ids.includes(item[this.rowKey]))
setTimeout(() => {
finderTable.$refs.finderTable.setSelection(selectRows)
const idSet = new Set(this.localSelection.map((m) => this.rowId(m)).filter(Boolean))
if (!idSet.size) return
const selectRows = list.filter((item) => idSet.has(this.rowId(item)))
const finderTable = this.$refs.finder?.$refs?.finderTable?.$refs?.finderTable
if (!finderTable || !selectRows.length) return
this.restoringSelection = true
this.$nextTick(() => {
const sidSet = new Set((finderTable.selection || []).map((m) => this.rowId(m)))
finderTable.setSelection(selectRows.filter((f) => !sidSet.has(this.rowId(f))))
this.$nextTick(() => {
this.restoringSelection = false
})
}
})
},
onReset() {
this.$refs.finder.refresh(true)
@@ -334,24 +375,30 @@ export default {
this.$refs.finder.initData(true)
},
onSelect(selection, row) {
if (this.restoringSelection) return
if (!this.multiple) {
const { finderTable } = this.$refs.finder.$refs
finderTable.clearSelection()
this.localSelection = [row]
this.localSelection = row ? [row] : []
this.$nextTick(() => {
finderTable.$refs.finderTable.setSelection(selection.length > 0 ? [row] : [])
})
} else {
const isAdd = selection.includes(row)
const idx = this.localSelection.findIndex((f) => f[this.rowKey] === row[this.rowKey])
const rowKeyVal = this.rowId(row)
const idx = this.localSelection.findIndex((f) => this.rowId(f) === rowKeyVal)
if (isAdd && idx === -1) {
this.localSelection.push(row)
} else if (!isAdd && idx !== -1) {
if (isAdd) {
if (idx === -1) {
this.localSelection.push(row)
} else {
this.localSelection.splice(idx, 1, row)
}
} else if (idx !== -1) {
this.localSelection.splice(idx, 1)
}
}
this.localSelection = this.localSelection.filter((item) => item.itemId)
this.localSelection = this.dedupeSelectionList(this.localSelection)
this.updateVal(this.localSelection)
},
/**
@@ -360,31 +407,27 @@ export default {
* @param list 当前页勾选数据 如果localSelection存在未来页数据 那么页码切换的时候 list中也会有
*/
async handleSelectAll(list) {
if (this.restoringSelection) return
const { finderTable } = this.$refs.finder.$refs
const currentPageData = finderTable.$refs.finderTable.list
const currentPageDataIds = currentPageData.map((m) => m[this.rowKey])
const currentPageIdSet = new Set(currentPageData.map((m) => this.rowId(m)).filter(Boolean))
// 获取当前页面已选中的数据
const currentPageSelectList = list.filter((item) =>
currentPageDataIds.includes(item[this.rowKey])
)
const currentPageSelectList = list.filter((item) => currentPageIdSet.has(this.rowId(item)))
// 先移除当前页的所有选中项
this.localSelection = this.localSelection.filter(
(item) => !currentPageDataIds.includes(item[this.rowKey])
(item) => !currentPageIdSet.has(this.rowId(item))
)
// 如果有选中项,则添加到 localSelection
if (currentPageSelectList.length > 0) {
this.localSelection.push(...currentPageData)
this.localSelection.push(...currentPageSelectList)
}
this.localSelection = this.dedupeSelectionList(this.localSelection)
this.updateVal(this.localSelection)
// 更新表格选中状态
this.$nextTick(() => {
if (currentPageSelectList.length > 0) {
finderTable.$refs.finderTable.setSelection(currentPageData)
finderTable.$refs.finderTable.setSelection(currentPageSelectList)
} else {
finderTable.$refs.finderTable.clearSelection()
}

View File

@@ -42,7 +42,8 @@ export default {
goods: (args) => fn({ value: { ...args }, type: 'pickerGoods', width: '1110px' }, parent),
goodsList: (args) =>
fn({ value: { ...args }, type: 'pickerGoodsList', width: '1110px' }, parent),
goodsitem: (args) => fn({ value: { ...args }, type: 'pickerGoodsItem' }, parent),
goodsitem: (args) =>
fn({ value: { ...(args || {}), type: 'pickerGoodsItem' }, type: 'pickerGoodsItem' }, parent),
goodsSku: (args) => fn({ value: { ...args }, type: 'pickerGoodsSku' }, parent),
goodsParams: (args) => fn({ value: { ...args }, type: 'pickerGoodsParams' }, parent),
supplier: (args) => fn({ value: { ...args }, type: 'pickerSupplier' }, parent),

View File

@@ -131,15 +131,13 @@
</el-col> -->
<el-col :xs="24" :sm="12" :md="12">
<el-form-item :label="$t('4b43f5ef.728f47')" label-width="110px">
<treeselect
<el-cascader
v-model="form.item_category"
:no-children-text="$t('4b43f5ef.6ef104')"
:no-options-text="$t('4b43f5ef.4b327e')"
:no-results-text="$t('4b43f5ef.f46047')"
:options="categoryList"
:show-count="true"
:multiple="true"
:disable-branch-nodes="true"
clearable
filterable
:props="cascaderProps"
:options="saleCategoryList"
style="width: 100%"
/>
</el-form-item>
</el-col>
@@ -854,7 +852,6 @@
<script>
import store from '@/store'
import { mapGetters } from 'vuex'
import Treeselect from '@riophae/vue-treeselect'
import draggable from 'vuedraggable'
import { getItemsDetail, createItems, updateItems } from '@/api/pointsmall'
import { getGoodsAttr, getCategory, getCategoryInfo } from '@/api/goods'
@@ -865,8 +862,6 @@ import richTextEditor from '@/components/function/richTextEditor'
import imgBox from '@/components/element/imgBox'
import district from '@/common/district.json'
import { getOrigincountry } from '@/api/crossborder'
import { transformTree } from '@/utils'
export default {
beforeRouteLeave(to, from, next) {
if (this.$refs['decorateRef'].dialogVisible) {
@@ -877,14 +872,19 @@ export default {
},
components: {
videoPicker,
Treeselect,
draggable,
richTextEditor,
imgBox
},
inject: ['refresh'],
data() {
const cascaderProps = {
multiple: true,
value: 'value',
children: 'children'
}
return {
cascaderProps,
// 跨境设置
origincountry: [], // 产地国
itemVideo: {},
@@ -916,7 +916,7 @@ export default {
{ title: '4b43f5ef.fe94ed', value: 'online' },
{ title: '4b43f5ef.30bee6', value: 'mix' }
],
categoryList: [],
saleCategoryList: [],
brandList: [],
content: [],
dragIssuesOptions: {
@@ -1372,8 +1372,15 @@ export default {
}
this.form.spec_images = JSON.stringify(this.specImages)
this.form.spec_items = JSON.stringify(formSkuItem)
const itemCategory = this.form.item_category || []
const submitForm = {
...this.form,
item_category: itemCategory.map((item) =>
item && item.length ? item[item.length - 1] : item
)
}
if (this.form.item_id && !this.is_new) {
updateItems(this.form.item_id, this.form)
updateItems(this.form.item_id, submitForm)
.then((response) => {
this.$message({
message: this.$t('4b43f5ef.55aa63'),
@@ -1391,7 +1398,7 @@ export default {
this.submitLoading = false
})
} else {
createItems(this.form)
createItems(submitForm)
.then((response) => {
this.$message({
message: this.$t('4b43f5ef.3fdaea'),
@@ -1812,13 +1819,25 @@ export default {
})
getCategory({ is_show: false }).then((response) => {
this.categoryList = transformTree(response.data.data, {
id: 'category_id',
label: 'category_name',
children: 'children'
})
if (this.$route.params.itemId) {
this.form.item_category = this.form.item_category_temp
const res = response.data.data
function _deepCategory(cate, temp) {
cate.forEach((item) => {
const _temp = {
label: item.category_name,
value: item.category_id
}
if (item.children) {
_temp.children = []
_deepCategory(item.children, _temp.children)
}
temp.push(_temp)
})
}
const saleCategoryList = []
_deepCategory(res, saleCategoryList)
this.saleCategoryList = saleCategoryList
if (this.$route.params.itemId && this.form.item_category_temp) {
this.form.item_category = this.deepSalesCategory(this.form.item_category_temp)
delete this.form.item_category_temp
}
})
@@ -1830,6 +1849,32 @@ export default {
// this.form.is_profit = false
// }
// },
deepSalesCategory(value) {
const { saleCategoryList } = this
function findPathById(tree, id, path) {
if (typeof path === 'undefined') {
path = []
}
for (let i = 0; i < tree.length; i++) {
const tempPath = [...path]
tempPath.push(tree[i].value)
if (tree[i].value == id) {
return tempPath
}
if (tree[i].children) {
const result = findPathById(tree[i].children, id, tempPath)
if (result) {
return result
}
}
}
}
const list = []
value.forEach((v) => {
list.push(findPathById(saleCategoryList, v))
})
return list
},
// select值变化
paramsChange(e) {
const params = this.params
@@ -1867,11 +1912,14 @@ export default {
}
</script>
<style lang="scss">
.vue-treeselect__placeholder {
line-height: 40px;
.el-cascader {
width: 100%;
.el-input {
width: 100%;
max-width: initial;
}
}
</style>
<style lang="scss">
.fallback-class {
width: 118px;
height: 118px;

View File

@@ -323,8 +323,14 @@
style="width: 500px"
:placeholder="$t('8312e7f7.708c9d')"
clearable
filterable
:options="categoryList"
:props="{ value: 'category_id', label: 'category_name', checkStrictly: true }"
:props="{
value: 'category_id',
label: 'category_name',
multiple: true,
children: 'children'
}"
/>
<span slot="footer" class="dialog-footer">
<el-button @click="addCategorydialogVisible = false">{{
@@ -687,27 +693,30 @@ export default {
})
},
changeCategory() {
if (this.item_id.length) {
if (!this.category_id) {
this.$message({
type: 'error',
message: this.$t('8312e7f7.e4e928')
})
return false
}
this.addCategorydialogVisible = false
setItemsCategory({ category_id: this.category_id, item_id: this.item_id }).then(
(response) => {
this.getGoodsList()
this.category_id = []
}
)
} else {
if (!this.item_id.length) {
this.$message({
type: 'error',
message: this.$t('8312e7f7.ace302')
})
return
}
if (!this.category_id || !this.category_id.length) {
this.$message({
type: 'error',
message: this.$t('8312e7f7.e4e928')
})
return
}
const _category_id = this.category_id.map((item) => item[item.length - 1])
this.addCategorydialogVisible = false
setItemsCategory({ category_id: _category_id, item_id: this.item_id }).then(() => {
this.getGoodsList()
this.category_id = []
this.$message({
type: 'success',
message: this.$t('8312e7f7.33130f')
})
})
},
addItems() {
// 添加商品
@@ -725,6 +734,7 @@ export default {
},
addCategory() {
if (this.item_id.length) {
this.category_id = []
this.addCategorydialogVisible = true
} else {
this.$message({

View File

@@ -128,11 +128,11 @@ export default {
return this.localValue ? this.localValue.split(',') : []
},
itemsDisplayText() {
const count = this.localValue?.info?.length
const count = this.getSelectedItemCount(this.localValue)
return count > 0 ? this.$t('40718fc5.e1a5c2', { count }) : this.$t('40718fc5.c5c5f2')
},
pointGoodsDisplayText() {
const count = this.localValue?.info?.length
const count = this.getSelectedItemCount(this.localValue)
return count > 0 ? this.$t('40718fc5.e1a5c2', { count }) : this.$t('46e04a5c.5d71c6')
}
},
@@ -144,33 +144,71 @@ export default {
this.minPrice = Number(min) || 0
this.maxPrice = Number(max) || 0
} else if (newVal === 'items') {
if (this.value?.info?.type === 'group_id') {
this.localValue = cloneDeep(this.value)
} else {
this.localValue = {
id: this.value?.id,
info: {
length: this.value?.id ? this.value?.id?.split(',')?.length : 0,
type: ''
}
}
}
this.syncItemsLocalValue(this.value)
} else if (newVal === 'pointsmall_items') {
this.localValue = {
id: this.value?.id || '',
info: {
length: this.value?.id ? this.value.id.split(',').length : 0,
type: 'pointsmall_items'
}
}
this.syncPointGoodsLocalValue(this.value)
} else {
this.localValue = cloneDeep(this.value)
}
},
immediate: true
},
value: {
handler(val) {
if (this.type === 'items') {
this.syncItemsLocalValue(val)
} else if (this.type === 'pointsmall_items') {
this.syncPointGoodsLocalValue(val)
} else if (this.type === 'price' && val?.id) {
const [min, max] = String(val.id).split(',')
this.minPrice = Number(min) || 0
this.maxPrice = Number(max) || 0
} else if (val) {
this.localValue = cloneDeep(val)
}
},
deep: true
}
},
methods: {
getSelectedItemCount(data) {
if (!data) return 0
if (typeof data.info?.length === 'number') return data.info.length
if (Array.isArray(data.info?.length)) return data.info.length
if (!data.id) return 0
return String(data.id).split(',').filter(Boolean).length
},
syncItemsLocalValue(val) {
const id = (val?.id || '').trim()
const ids = id ? id.split(',').filter(Boolean) : []
const type = val?.info?.type === 'group_id' || ids.length ? 'group_id' : ''
this.localValue = {
id,
info: {
length: ids.length,
type
}
}
},
syncPointGoodsLocalValue(val) {
const id = (val?.id || '').trim()
const ids = id ? id.split(',').filter(Boolean) : []
this.localValue = {
id,
info: {
length: ids.length,
type: 'point'
}
}
},
buildPickerDataFromIds(idStr) {
if (!idStr) return []
return idStr
.split(',')
.map((s) => s.trim())
.filter(Boolean)
.map((id) => ({ item_id: id, itemId: id }))
},
// 选择管理分类
async handleSelectMainCategory(v) {
const { data } = await this.$picker.category({
@@ -209,20 +247,25 @@ export default {
},
// 选择指定商品(使用 goodsitem 弹窗goodsCheck 在 plugin 中未注册)
async handleSelectGoods() {
const idStr = this.localValue?.info?.type === 'group_id' ? this.localValue?.id || '' : ''
const list = idStr ? idStr.split(',').map((id) => ({ item_id: id, itemId: id })) : []
const idStr = (this.localValue?.id || this.value?.id || '').trim()
const result = await this.$picker.goodsitem({
isPointGoods: false,
multiple: true,
rowKey: 'item_id',
data: list,
data: this.buildPickerDataFromIds(idStr),
regionauth_id: this.$route.query.regionauth_id,
distributor_id: this.$route.query.distributor_id,
distributor_name: this.$route.query.distributor_name
})
if (!result || !result.data) return
const selected = result.data || []
const ids = selected.map((item) => item.item_id || item.itemId).filter(Boolean)
const ids = [
...new Set(
(result.data || [])
.map((item) => item.item_id ?? item.itemId)
.filter((id) => id != null && id !== '')
.map(String)
)
]
const data = ids.join(',')
const length = ids.length
this.localValue = {
@@ -236,20 +279,25 @@ export default {
},
// 选择积分商品
async handleSelectPointGoods() {
const idStr = this.localValue?.info?.type === 'point' ? this.localValue?.id || '' : ''
const list = idStr ? idStr.split(',').map((id) => ({ item_id: id, itemId: id })) : []
const idStr = (this.localValue?.id || this.value?.id || '').trim()
const result = await this.$picker.goodsitem({
isPointGoods: true,
multiple: true,
rowKey: 'item_id',
data: list,
data: this.buildPickerDataFromIds(idStr),
regionauth_id: this.$route.query.regionauth_id,
distributor_id: this.$route.query.distributor_id,
distributor_name: this.$route.query.distributor_name
})
if (!result || !result.data) return
const selected = result.data || []
const ids = selected.map((item) => item.item_id || item.itemId).filter(Boolean)
const ids = [
...new Set(
(result.data || [])
.map((item) => item.item_id ?? item.itemId)
.filter((id) => id != null && id !== '')
.map(String)
)
]
const data = ids.join(',')
const length = ids.length
this.localValue = {