增加订单复选搜索

This commit is contained in:
wuweihua
2026-10-22 17:40:57 +08:00
parent 23236ec141
commit 4ec28de073
5 changed files with 144 additions and 19 deletions
@@ -3415,7 +3415,7 @@ public class PrcPriceSetServiceImpl implements IPrcPriceSetService
}
PrcPriceSetVersion effect = null;
PrcPriceSetVersion pending = null;
PrcPriceSetVersion best = null;
List<PrcPriceSetVersion> ranked = new ArrayList<PrcPriceSetVersion>();
for (PrcPriceSetVersion v : list)
{
if (v == null || v.getPsvId() == null)
@@ -3434,15 +3434,58 @@ public class PrcPriceSetServiceImpl implements IPrcPriceSetService
{
pending = v;
}
if (best == null || (v.getVersionSeq() != null && best.getVersionSeq() != null
&& v.getVersionSeq().intValue() > best.getVersionSeq().intValue())
|| (best.getVersionSeq() == null && v.getVersionSeq() != null))
}
if (effect != null)
{
ranked.add(effect);
}
if (pending != null && (effect == null || !pending.getPsvId().equals(effect.getPsvId())))
{
ranked.add(pending);
}
list.stream()
.filter(v -> v != null && v.getPsvId() != null)
.filter(v -> excludePsvId == null || !excludePsvId.equals(v.getPsvId()))
.sorted((a, b) -> {
int sa = a.getVersionSeq() == null ? 0 : a.getVersionSeq().intValue();
int sb = b.getVersionSeq() == null ? 0 : b.getVersionSeq().intValue();
return Integer.compare(sb, sa);
})
.forEach(v -> {
boolean exists = false;
for (PrcPriceSetVersion r : ranked)
{
if (r.getPsvId().equals(v.getPsvId()))
{
exists = true;
break;
}
}
if (!exists)
{
ranked.add(v);
}
});
for (PrcPriceSetVersion cand : ranked)
{
if (versionHasSetProducts(cand.getPsvId()))
{
best = v;
return cand.getPsvId();
}
}
PrcPriceSetVersion pick = effect != null ? effect : (pending != null ? pending : best);
return pick == null ? null : pick.getPsvId();
return ranked.isEmpty() ? null : ranked.get(0).getPsvId();
}
private boolean versionHasSetProducts(Long psvId)
{
if (psvId == null)
{
return false;
}
PrcPriceSetProduct pq = new PrcPriceSetProduct();
pq.setPsvId(psvId);
List<PrcPriceSetProduct> products = setProductMapper.selectPrcPriceSetProductList(pq);
return products != null && !products.isEmpty();
}
/**
+59 -2
View File
@@ -79,6 +79,32 @@
remote-search
/>
</template>
<template #search-billingFailStatuses="{ model }">
<el-select
v-model="model.billingFailStatuses"
multiple
filterable
clearable
collapse-tags
collapse-tags-tooltip
placeholder="请选择"
style="width: 100%"
>
<template #header>
<el-checkbox
:model-value="isAllBillingFailSelected(model)"
:indeterminate="isBillingFailIndeterminate(model)"
@change="(checked) => toggleAllBillingFail(model, checked)"
>全选</el-checkbox>
</template>
<el-option
v-for="opt in billingFailStatusOptions"
:key="opt.value"
:label="opt.label"
:value="opt.value"
/>
</el-select>
</template>
<template #col-product="{ row }">
{{ row.productName || '-' }} ({{ row.productCode || '-' }})
</template>
@@ -158,7 +184,8 @@ const tableHeight = ref(480)
let tableResizeObserver = null
const defaultParams = {
orderStatuses: [3, 4, 5, 6, 7, 8, 11]
orderStatuses: [3, 4, 5, 6, 7, 8, 11],
billingFailStatuses: []
}
const columns = [
@@ -227,6 +254,29 @@ const billingFailStatusOptions = [
{ label: '未知失败', value: 22 }
]
const billingFailAllValues = computed(() => billingFailStatusOptions.map(o => o.value))
function selectedBillingFailStatuses(model) {
return Array.isArray(model?.billingFailStatuses) ? model.billingFailStatuses : []
}
function isAllBillingFailSelected(model) {
const selected = selectedBillingFailStatuses(model)
const all = billingFailAllValues.value
return all.length > 0 && selected.length === all.length
}
function isBillingFailIndeterminate(model) {
const selected = selectedBillingFailStatuses(model)
const all = billingFailAllValues.value
return selected.length > 0 && selected.length < all.length
}
function toggleAllBillingFail(model, checked) {
if (!model) return
model.billingFailStatuses = checked ? [...billingFailAllValues.value] : []
}
const searchColumns = [
{ label: '单号', prop: 'orderIdentifiers', placeholder: '订单号/运单号/转单号' },
{ label: '客户', prop: 'customerCodes', placeholder: '客户名称/客户代码/对外代码' },
@@ -268,7 +318,14 @@ const searchColumns = [
prop: 'billingFailStatuses',
component: 'select',
options: billingFailStatusOptions,
placeholder: '请选择'
placeholder: '请选择',
props: {
multiple: true,
filterable: true,
clearable: true,
collapseTags: true,
collapseTagsTooltip: true
}
}
]
@@ -391,7 +391,9 @@ async function loadLatestPriorVersionDraft() {
const res = await getPriceSet(props.priceSetId)
const data = res.data || {}
const versions = data.versions || []
const prior = pickLatestPriorVersion(versions, props.psvId || resolvedPsvId.value)
// Only exclude the draft being edited. Do NOT use resolvedPsvId — it may
// point at EFFECT after resolvePsvId() and wrongly skip the real prior.
const prior = pickLatestPriorVersion(versions, props.psvId)
if (!prior || prior.psvId == null) return false
const products = (prior.products || [])
.filter(p => p && p.productCode)
+17 -5
View File
@@ -377,19 +377,31 @@ function onPriceBuildModeUpdate(mode) {
}).catch(() => {})
})
} else if (mode === 'IMPORT') {
nextTick(() => {
nextTick(async () => {
// newVersion/copy: wait until loadExisting fills priceSetId
const qid = route.query.priceSetId
if (!form.priceSetId && qid) {
for (let i = 0; i < 50 && !form.priceSetId; i++) {
await new Promise(r => setTimeout(r, 100))
}
}
const loader = detailsRef.value && detailsRef.value.loadLatestPriorVersionDraft
if (!loader) {
proxy.$modal.msgSuccess("请导入 Excel 建价")
return
}
loader().then(ok => {
if (!form.priceSetId) {
proxy.$modal.msgSuccess("新建套餐无历史版本可带出,请直接导入 Excel 建价")
return
}
try {
const ok = await loader()
proxy.$modal.msgSuccess(ok
? "已带出上一版全部产品,导入 Excel 按产品+国家覆盖或新增"
: "暂无上一版产品,请导入 Excel 建价")
}).catch(() => {
: "未找到含产品的上一版,请导入 Excel 建价")
} catch (e) {
proxy.$modal.msgSuccess("请导入 Excel 建价")
})
}
})
}
}
@@ -108,9 +108,14 @@ export function nextVersionNo(versions) {
return 'V' + (max + 1)
}
function versionHasProducts(v) {
return !!(v && (v.products || []).some(p => p && p.productCode))
}
/**
* Latest prior version for Excel build-price preload (exclude current draft).
* Prefer EFFECT, then PENDING, then highest versionSeq.
* Prefer EFFECT / PENDING / highest versionSeq that actually has products,
* so an empty EFFECT does not hide an older version that still has data.
*/
export function pickLatestPriorVersion(versions, excludePsvId) {
const list = (versions || []).filter(v => {
@@ -119,11 +124,17 @@ export function pickLatestPriorVersion(versions, excludePsvId) {
return true
})
if (!list.length) return null
const ranked = []
const effect = list.find(v => String(v.status) === VER_STATUS.EFFECT)
if (effect) return effect
if (effect) ranked.push(effect)
const pending = list.find(v => String(v.status) === VER_STATUS.PENDING)
if (pending) return pending
return list.slice().sort((a, b) => (Number(b.versionSeq) || 0) - (Number(a.versionSeq) || 0))[0]
if (pending && (!effect || String(pending.psvId) !== String(effect.psvId))) ranked.push(pending)
const bySeq = list.slice().sort((a, b) => (Number(b.versionSeq) || 0) - (Number(a.versionSeq) || 0))
bySeq.forEach(v => {
if (!ranked.some(x => String(x.psvId) === String(v.psvId))) ranked.push(v)
})
const withProducts = ranked.find(versionHasProducts)
return withProducts || ranked[0] || null
}
/** Package status label */