修改更新欠费状态功能

This commit is contained in:
wuweihua
2026-09-23 15:53:12 +08:00
parent 8522201248
commit c62433c09e
9 changed files with 253 additions and 18 deletions
+9
View File
@@ -104,3 +104,12 @@ export function deleteIncomeBillFee(feeId) {
method: 'delete'
})
}
/** 计费列表:批量更新订单额度欠费状态(校验可用额度) */
export function updateCreditArrears(billIds) {
return request({
url: '/price/billing/bill/creditArrears',
method: 'put',
data: billIds
})
}
@@ -159,7 +159,9 @@ const props = defineProps({
// schema 项配置
item: { type: Object, required: true },
// 字典映射表(来自父级 BasicForm)
dictMap: { type: Object, default: () => ({}) }
dictMap: { type: Object, default: () => ({}) },
// 拉伸模式(固定每行 N 项的栅格布局):忽略 item.width,控件填满单元格
stretch: { type: Boolean, default: false }
})
const comp = computed(() => props.item.component || 'input')
@@ -167,8 +169,11 @@ const placeholder = computed(() => props.item.placeholder)
const valueKey = computed(() => props.item.valueKey || 'value')
const labelKey = computed(() => props.item.labelKey || 'label')
// 控件宽度样式
const controlStyle = computed(() => (props.item.width ? { width: props.item.width } : null))
// 控件宽度样式(stretch 模式下填满单元格)
const controlStyle = computed(() => {
if (props.stretch) return { width: '100%' }
return props.item.width ? { width: props.item.width } : null
})
// 选项:静态 options 优先,其次字典
const options = computed(() => {
+29 -2
View File
@@ -8,7 +8,7 @@
:label-position="labelPosition"
:disabled="disabled"
:size="size"
:class="['basic-form', { 'basic-form--grid': !inline }]"
:class="['basic-form', { 'basic-form--grid': !inline, 'basic-form--perrow': inline && perRow > 0 }]"
>
<!-- 行内布局:直接平铺 -->
<template v-if="inline">
@@ -17,10 +17,11 @@
:label="item.label"
:prop="item.prop"
:label-width="item.labelWidth"
:style="perRow > 0 && item.colSpan > 1 ? { gridColumn: 'span ' + item.colSpan } : undefined"
v-bind="item.formItemProps"
>
<slot :name="`form-${item.prop}`" :model="modelValue" :item="item">
<form-control :model="modelValue" :item="item" :dict-map="dictMap" />
<form-control :model="modelValue" :item="item" :dict-map="dictMap" :stretch="perRow > 0" />
</slot>
</el-form-item>
</template>
@@ -81,6 +82,7 @@
* valueKey: 'value', // 选项值字段(默认 value)
* labelKey: 'label', // 选项标签字段(默认 label)
* span: 12, // 栅格占位(grid 布局,默认 24)
* colSpan: 2, // 占据的列数(行内 perRow 栅格模式,默认 1)
* width: '200px', // 控件宽度
* show: true, // 是否显示
* disabled: false,
@@ -117,6 +119,11 @@ const props = defineProps({
type: Boolean,
default: false
},
// 行内布局下固定每行项数(>0 时启用栅格模式,控件拉伸填满单元格;0 表示自动流式换行)
perRow: {
type: Number,
default: 0
},
// 标签宽度
labelWidth: {
type: [String, Number],
@@ -239,6 +246,26 @@ defineExpose({
margin-bottom: 18px;
}
/* 行内固定每行 N 项:CSS 栅格,多余项自动换行 */
.basic-form--perrow {
display: grid;
grid-template-columns: repeat(v-bind(perRow), minmax(0, 1fr));
column-gap: 16px;
row-gap: 2px;
}
.basic-form--perrow :deep(.el-form-item) {
display: flex;
margin-right: 0;
}
.basic-form--perrow :deep(.el-form-item__content) {
flex: 1;
min-width: 0;
}
/* 操作区居中时独占整行 */
.basic-form--perrow .basic-form-action--center {
grid-column: 1 / -1;
}
/* 操作区居中:占满整行、内容水平居中(搜索按钮换行后居中显示的场景) */
.basic-form .basic-form-action--center {
width: 100%;
@@ -9,6 +9,7 @@
:rules="searchRules"
:label-width="searchLabelWidth"
:action-align="searchActionAlign"
:per-row="searchPerRow"
:size="size"
inline
v-show="showSearch"
@@ -184,6 +185,11 @@ const props = defineProps({
type: String,
default: 'left'
},
// 搜索区固定每行项数(>0 时启用栅格布局,多余项自动换行;0 为流式换行)
searchPerRow: {
type: Number,
default: 0
},
// 列表加载函数:(params) => Promise<{rows, total}> | {rows, total}
query: {
type: Function,
+55 -13
View File
@@ -6,6 +6,7 @@
:search-columns="searchColumns"
:query="queryList"
search-action-align="center"
:search-per-row="4"
row-key="billId"
>
<template #search-orderNos="{ model }">
@@ -66,6 +67,18 @@
<template #col-payTotal="{ row }">
<span class="payable">{{ formatMoney(row.payTotal) }}</span>
</template>
<template #toolbar="{ selection, ids }">
<el-col :span="1.5">
<el-button
type="warning"
plain
icon="Refresh"
:disabled="!selection.length"
v-hasPermi="['price:billing:arrearsUpdate']"
@click="handleUpdateArrears(ids, selection)"
>更新欠费状态</el-button>
</el-col>
</template>
<template #col-action="{ row }">
<el-button link type="primary" icon="View" @click="handleView(row)">查看</el-button>
</template>
@@ -76,7 +89,8 @@
</template>
<script setup name="BillingBill">
import { listBill, getBill, listOrderNoOptions, listTrackingNoOptions, listTransferNoOptions } from '@/api/price/billing'
import { listBill, getBill, listOrderNoOptions, listTrackingNoOptions, listTransferNoOptions, updateCreditArrears } from '@/api/price/billing'
import { ElMessage, ElMessageBox } from 'element-plus'
import { useProducts } from '@/components/ProductSelect/useProducts'
import BillDetail from './components/BillDetail.vue'
@@ -132,18 +146,53 @@ const columns = [
{ label: '操作', prop: 'action', align: 'center', width: 90, fixed: 'right', slot: 'action', showInToolbar: false }
]
const arrearsStatusOptions = [
{ label: '正常', value: 'NORMAL' },
{ label: '欠费', value: 'ARREARS' }
]
const searchColumns = [
{ label: '订单号', prop: 'orderNos', placeholder: '订单号' },
{ label: '运单号', prop: 'trackingNos', placeholder: '运单号' },
{ label: '转单号', prop: 'transferNos', placeholder: '转单号' },
{ label: '客户', prop: 'customerCodes', placeholder: '客户代码' },
{ label: '产品代码', prop: 'productCodes', placeholder: '产品代码' }
{ label: '产品代码', prop: 'productCodes', placeholder: '产品代码' },
{
label: '额度欠费',
prop: 'creditArrearsStatus',
component: 'select',
options: arrearsStatusOptions,
placeholder: '请选择',
props: { clearable: true }
}
]
function queryList(params) {
return listBill(params)
}
function handleUpdateArrears(ids, selection) {
const billIds = (ids && ids.length)
? ids
: (selection || []).map(row => row.billId).filter(Boolean)
if (!billIds.length) {
ElMessage.warning('请勾选要更新的订单')
return
}
const arrearsCount = (selection || []).filter(row => row.creditArrearsStatus === 'ARREARS').length
ElMessageBox.confirm(
'确认将勾选的 ' + billIds.length + ' 条订单更新欠费状态为正常?将逐单校验可用额度,校验不通过的不会更新' +
(arrearsCount < billIds.length ? '(当前勾选中欠费 ' + arrearsCount + ' 条)' : '') + '。',
'更新欠费状态',
{ type: 'warning' }
).then(() => {
return updateCreditArrears(billIds)
}).then(res => {
ElMessage.success(res.msg || '更新完成')
tableRef.value?.refresh?.()
}).catch(() => {})
}
function handleView(row) {
title.value = '计费详情'
open.value = true
@@ -217,17 +266,10 @@ function creditArrearsTagType(status) {
font-variant-numeric: tabular-nums;
}
/* 搜索栏铺满整行:搜索项 flex 等分拉伸,控件占满所在项 */
.billing-bill :deep(.basic-form.el-form--inline) {
display: flex;
flex-wrap: wrap;
}
.billing-bill :deep(.basic-form.el-form--inline > .el-form-item:not(.basic-form-action--center)) {
flex: 1 1 0;
margin-right: 12px;
}
.billing-bill :deep(.basic-form.el-form--inline .el-form-item .el-select),
.billing-bill :deep(.basic-form.el-form--inline .el-form-item .el-input) {
/* 搜索栏走 BasicTable search-per-row=4 的栅格布局(固定 4 项一行,多余换行),
这里只补齐插槽渲染的控件宽度,不再覆盖 BasicForm 的布局 */
.billing-bill :deep(.basic-form .el-form-item .el-select),
.billing-bill :deep(.basic-form .el-form-item .el-input) {
width: 100%;
}
</style>