feat(web-admin): allow ProductSelector to restrict by product ids

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
zlwuandCursor committed 2026-08-30 11:00:05 +08:00
1 parent f18442be2e
commit bbab39e6b7
1 file changed
+59 -2
@@ -21,7 +21,12 @@
@search="handleQuickSearch"
@clear="handleQuickSearchClear"
/>
<el-button class="btn-main" type="primary" @click="handleAddProduct">
<el-button
v-if="!isRestrictedMode"
class="btn-main"
type="primary"
@click="handleAddProduct"
>
<el-icon><Plus /></el-icon>新增
</el-button>
<el-button
@@ -166,7 +171,7 @@
</ListTable>
<ListPagination
v-show="total > 0"
v-show="total > 0 && !isRestrictedMode"
:total="total"
v-model:page="queryParams.pageNum"
v-model:limit="queryParams.pageSize"
@@ -225,6 +230,7 @@
import PlProductNameHazardCell from '@/components/business/pl-product-name-hazard-cell/index.vue'
import {
fetchCategoryTree,
fetchProductDetail,
fetchProductList,
type ProductAliasItem,
type ProductBrandItem
@@ -258,6 +264,8 @@
const props = defineProps<{
visible: boolean
supplierId?: string | number
/** 非空时仅展示这些产品(按 id 拉详情,避免分页漏选) */
allowedProductIds?: string[]
}>()
const emit = defineEmits<{
@@ -271,12 +279,20 @@
const formDialogVisible = ref(false)
const formProductId = ref<string | null>(null)
const pendingSelectId = ref<string | null>(null)
/** 限制模式下打开弹窗后「无产品」提示只打一次 */
let emptyAllowedWarnedOnOpen = false
const normalizedAllowedIds = computed(() =>
(props.allowedProductIds || []).map((id) => String(id).trim()).filter(Boolean)
)
const isRestrictedMode = computed(() => normalizedAllowedIds.value.length > 0)
watch(
() => props.visible,
(val) => {
dialogVisible.value = val
if (val) {
emptyAllowedWarnedOnOpen = false
quickSearchKeyword.value = ''
queryParams.value.pageNum = 1
getList()
@@ -316,9 +332,50 @@
return names.length ? names.join('、') : '-'
}
function matchesQuickKeyword(product: ProductVO, keyword: string) {
const kw = keyword.toLowerCase()
const name = String(product.productName || '').toLowerCase()
const model = String(product.model || '').toLowerCase()
return name.includes(kw) || model.includes(kw)
}
/** 按允许的产品 id 并行拉详情,避免分页目录漏选 */
const getRestrictedList = async () => {
const ids = normalizedAllowedIds.value
const results = await Promise.all(
ids.map(async (id) => {
try {
const res: any = await fetchProductDetail({ id })
const data = res?.data ?? res
return data?.id != null ? (data as ProductVO) : null
} catch {
return null
}
})
)
const fetched = results.filter((p): p is ProductVO => p != null)
if (!fetched.length && !emptyAllowedWarnedOnOpen) {
emptyAllowedWarnedOnOpen = true
ElMessage.warning('所选合同暂无产品明细')
}
const keyword = quickSearchKeyword.value?.trim()
const list = keyword ? fetched.filter((p) => matchesQuickKeyword(p, keyword)) : fetched
productList.value = list
total.value = list.length
if (categoryTree.value.length > 0) {
resolveCategoryNames()
}
await nextTick()
await selectPendingRow()
}
const getList = async () => {
loading.value = true
try {
if (isRestrictedMode.value) {
await getRestrictedList()
return
}
const keyword = quickSearchKeyword.value?.trim()
const res = await fetchProductList({
page: queryParams.value.pageNum,