💄 付款管理搜索栏改造为手写搜索区

- 与应收/应付明细等页面搜索样式统一(4列网格、查询/重置独占一行靠右、默认折叠一行4条件)
- 移除 avue 内置搜索配置与搜索专用列,搜索字段与后端参数保持不变
- 展开搜索后触发表格高度重算,分页保持在一屏内
This commit is contained in:
刘泉佳
2026-11-10 00:51:35 +08:00
parent 69782cecfc
commit 32cd42da92
2 changed files with 156 additions and 136 deletions
+7 -119
View File
@@ -1,14 +1,11 @@
/** /**
* 付款申请列表(avue-crud)配置 * 付款申请列表(avue-crud)配置
* ------------------------------------------------------------------ * ------------------------------------------------------------------
* 列表页与其它模块统一使用 avue-crud,头部 4 个按钮(刷新 / 列显隐 / 搜索显隐 / * 列表页与其它模块统一使用 avue-crud,头部按钮(刷新 / 列显隐 / 表格卡片切换)
* 表格卡片切换)由 avue-crud 自带,不做二次封装。 * 由 avue-crud 自带,不做二次封装。
* *
* 搜索项与表格列 label 不一致的(如表格列「收款方」/ 搜索项「客户名称」), * 搜索栏与应收/应付明细等页面统一为页面级手写搜索区(见 payment-application.vue),
* 单独定义一个 hide 的搜索列,并用 searchProp 映射到后端字段。 * 此处只保留表格列配置。
*
* ⚠️ avue 的 searchOrder 为降序排序,值越大越靠前(见 header-search2.js:
* `list.sort((a, b) => (b.searchOrder || 0) - (a.searchOrder || 0))`)。
*/ */
const textFormatter = (row, value) => const textFormatter = (row, value) =>
@@ -16,46 +13,10 @@ const textFormatter = (row, value) =>
const moneyFormatter = (row, value) => Number(value || 0).toFixed(2); const moneyFormatter = (row, value) => Number(value || 0).toFixed(2);
// 仅用于搜索、不在表格中出现的列 export const paymentApplicationOption = () => ({
const searchOnlyColumn = ({ label, prop, searchOrder, searchProp, dicData }) => {
const column = {
label,
prop,
search: true,
searchOrder,
searchPlaceholder: '请输入',
hide: true,
showColumn: false,
addDisplay: false,
editDisplay: false,
viewDisplay: false,
};
if (searchProp) column.searchProp = searchProp;
if (dicData) {
column.type = 'select';
column.searchPlaceholder = '请选择';
column.dicData = dicData;
}
return column;
};
export const paymentApplicationOption = ({
paymentTypeOptions = [],
approvalStatusOptions = [],
kingdeeStatusOptions = [],
} = {}) => ({
height: 'auto', height: 'auto',
calcHeight: 32, calcHeight: 32,
tip: false, tip: false,
searchBtnText: '查询',
emptyBtnText: '重置',
searchShow: true,
searchIcon: true,
searchLabelWidth: 88,
// 查询/重置紧跟首行 4 个条件(4×5 + 菜单 4 = 24),不再独占下一整行
searchMenuSpan: 4,
searchIndex: 4,
searchMenuPosition: 'right',
border: true, border: true,
index: true, index: true,
indexLabel: '序号', indexLabel: '序号',
@@ -73,84 +34,11 @@ export const paymentApplicationOption = ({
menuFixed: 'right', menuFixed: 'right',
dialogClickModal: false, dialogClickModal: false,
column: [ column: [
// ---------- 搜索项(前 4 项默认展示,其余折叠;searchOrder 越大越靠前) ----------
{
label: '单据号',
prop: 'paymentNo',
slot: true,
search: true,
searchSpan: 5,
searchOrder: 9,
searchPlaceholder: '请输入',
minWidth: 150,
},
{
label: '日期',
prop: 'applyDateRange',
type: 'daterange',
searchType: 'daterange',
search: true,
searchSpan: 5,
searchOrder: 8,
hide: true,
showColumn: false,
addDisplay: false,
editDisplay: false,
viewDisplay: false,
},
{
...searchOnlyColumn({
label: '客户名称',
prop: 'payeeNameSearch',
searchOrder: 7,
searchProp: 'payeeName',
}),
searchSpan: 5,
},
{
...searchOnlyColumn({
label: '项目名称',
prop: 'projectNameSearch',
searchOrder: 6,
searchProp: 'projectName',
}),
searchSpan: 5,
},
searchOnlyColumn({
label: '关联结算单',
prop: 'settlementNo',
searchOrder: 4,
}),
searchOnlyColumn({
label: '付款类型',
prop: 'paymentType',
searchOrder: 3,
dicData: paymentTypeOptions,
}),
searchOnlyColumn({
label: '审核状态',
prop: 'approvalStatus',
searchOrder: 2,
dicData: approvalStatusOptions,
}),
searchOnlyColumn({
label: '金蝶单据状态',
prop: 'kingdeeStatus',
searchOrder: 1,
dicData: kingdeeStatusOptions,
}),
// ---------- 表格列 ---------- // ---------- 表格列 ----------
{ label: '单据号', prop: 'paymentNo', slot: true, minWidth: 150 },
{ label: '付款类型', prop: 'paymentTypeName', minWidth: 110, formatter: textFormatter }, { label: '付款类型', prop: 'paymentTypeName', minWidth: 110, formatter: textFormatter },
{ label: '所属项目', prop: 'projectName', minWidth: 140, formatter: textFormatter }, { label: '所属项目', prop: 'projectName', minWidth: 140, formatter: textFormatter },
{ { label: '所属组织', prop: 'deptName', minWidth: 120, formatter: textFormatter },
label: '所属组织',
prop: 'deptName',
search: true,
searchOrder: 5,
searchslot: true,
minWidth: 120,
formatter: textFormatter,
},
{ label: '合同编号', prop: 'contractNo', minWidth: 130, formatter: textFormatter }, { label: '合同编号', prop: 'contractNo', minWidth: 130, formatter: textFormatter },
{ label: '合同名称', prop: 'contractName', minWidth: 140, formatter: textFormatter }, { label: '合同名称', prop: 'contractName', minWidth: 140, formatter: textFormatter },
{ label: '付款方', prop: 'payerName', minWidth: 130, formatter: textFormatter }, { label: '付款方', prop: 'payerName', minWidth: 130, formatter: textFormatter },
+149 -17
View File
@@ -1,13 +1,61 @@
<template> <template>
<basic-container class="payment-page"> <basic-container class="payment-page">
<section class="payment-search">
<el-form :model="searchForm" label-position="right" label-width="88px" @submit.prevent>
<div class="payment-search__grid">
<template v-for="field in visibleSearchFields" :key="field.prop">
<el-form-item :label="field.label">
<el-date-picker
v-if="field.type === 'daterange'"
v-model="searchForm[field.prop]"
type="daterange"
format="YYYY-MM-DD"
value-format="YYYY-MM-DD"
range-separator="~"
start-placeholder="年/月/日"
end-placeholder="年/月/日"
/>
<el-select
v-else-if="field.type === 'select'"
v-model="searchForm[field.prop]"
clearable
placeholder="请选择"
>
<el-option
v-for="item in field.options"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
<el-cascader
v-else-if="field.type === 'cascader'"
v-model="searchForm[field.prop]"
:options="organizationSearchTreeOptions"
:props="organizationCascaderProps"
filterable
clearable
placeholder="请选择 所属组织"
/>
<el-input v-else v-model="searchForm[field.prop]" clearable placeholder="请输入" />
</el-form-item>
</template>
<div class="payment-search__actions">
<el-button type="primary" @click="handleSearch">查询</el-button>
<el-button @click="handleReset">重置</el-button>
<el-button text :icon="searchExpanded ? ArrowUp : ArrowDown" @click="toggleSearch">
{{ searchExpanded ? '收起' : '展开' }}
</el-button>
</div>
</div>
</el-form>
</section>
<avue-crud <avue-crud
ref="crud" ref="crud"
:option="option" :option="option"
:table-loading="loading" :table-loading="loading"
:data="rows" :data="rows"
v-model:page="page" v-model:page="page"
@search-change="searchChange"
@search-reset="searchReset"
@selection-change="selectionChange" @selection-change="selectionChange"
@current-change="currentChange" @current-change="currentChange"
@size-change="sizeChange" @size-change="sizeChange"
@@ -174,6 +222,7 @@
</template> </template>
<script> <script>
import { ArrowDown, ArrowUp } from '@element-plus/icons-vue';
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
import * as api from '@/api/payment/paymentApplication'; import * as api from '@/api/payment/paymentApplication';
import { paymentApplicationOption } from '@/option/payment/paymentApplication'; import { paymentApplicationOption } from '@/option/payment/paymentApplication';
@@ -190,6 +239,8 @@ export default {
mixins: [organizationSearch], mixins: [organizationSearch],
data() { data() {
return { return {
ArrowDown,
ArrowUp,
rows: [], rows: [],
selection: [], selection: [],
loading: false, loading: false,
@@ -197,6 +248,9 @@ export default {
syncLoading: false, syncLoading: false,
resultSyncing: false, resultSyncing: false,
query: {}, query: {},
// 手写搜索区(与应收/应付明细同款):模型与展开状态
searchForm: {},
searchExpanded: false,
option: {}, option: {},
page: { page: {
currentPage: 1, currentPage: 1,
@@ -209,13 +263,37 @@ export default {
}, },
computed: { computed: {
...mapGetters(['permission']), ...mapGetters(['permission']),
// 搜索字段与应收/应付明细同结构;下拉选项沿用 api 常量
searchFields() {
return [
{ label: '单据号', prop: 'paymentNo', type: 'input' },
{ label: '日期', prop: 'applyDateRange', type: 'daterange' },
{ label: '客户名称', prop: 'payeeName', type: 'input' },
{ label: '项目名称', prop: 'projectName', type: 'input' },
{ label: '所属组织', prop: 'deptName', type: 'cascader' },
{ label: '关联结算单', prop: 'settlementNo', type: 'input' },
{ label: '付款类型', prop: 'paymentType', type: 'select', options: api.paymentTypeOptions },
{
label: '审核状态',
prop: 'approvalStatus',
type: 'select',
options: api.approvalStatusOptions,
},
{
label: '金蝶单据状态',
prop: 'kingdeeStatus',
type: 'select',
options: api.kingdeeStatusOptions,
},
];
},
// 默认折叠只展示一行 4 个条件
visibleSearchFields() {
return this.searchExpanded ? this.searchFields : this.searchFields.slice(0, 4);
},
}, },
created() { created() {
this.option = paymentApplicationOption({ this.option = paymentApplicationOption();
paymentTypeOptions: api.paymentTypeOptions,
approvalStatusOptions: api.approvalStatusOptions,
kingdeeStatusOptions: api.kingdeeStatusOptions,
});
this.loadOrganizationOptions(); this.loadOrganizationOptions();
}, },
mounted() { mounted() {
@@ -271,26 +349,30 @@ export default {
this.$refs.crud?.toggleSelection?.(); this.$refs.crud?.toggleSelection?.();
}); });
}, },
searchChange(params, done) { // 搜索提交:组织级联路径转名称、日期区间拆成起止参数(与原 avue searchChange 同规则)
// 所属组织级联返回 id 路径数组,转成部门名称给后端 buildSearchParams() {
const params = { ...this.searchForm };
this.normalizeOrganizationSearch(params, 'deptName'); this.normalizeOrganizationSearch(params, 'deptName');
// 日期区间拆成后端需要的起止字段
const range = params.applyDateRange || []; const range = params.applyDateRange || [];
delete params.applyDateRange; delete params.applyDateRange;
this.query = { return { ...params, applyStartDate: range[0] || '', applyEndDate: range[1] || '' };
...params, },
applyStartDate: range[0] || '', handleSearch() {
applyEndDate: range[1] || '', this.query = this.buildSearchParams();
};
this.page.currentPage = 1; this.page.currentPage = 1;
this.onLoad(this.page); this.onLoad(this.page);
done();
}, },
searchReset() { handleReset() {
this.searchForm = {};
this.query = {}; this.query = {};
this.page.currentPage = 1; this.page.currentPage = 1;
this.onLoad(this.page); this.onLoad(this.page);
}, },
toggleSearch() {
this.searchExpanded = !this.searchExpanded;
// 搜索区在 avue 外部,高度变化 avue 感知不到,手动触发表格高度重算,保证分页在一屏内
this.$nextTick(() => this.$refs.crud?.getTableHeight?.());
},
currentChange(currentPage) { currentChange(currentPage) {
this.page.currentPage = currentPage; this.page.currentPage = currentPage;
}, },
@@ -544,6 +626,56 @@ export default {
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
// 搜索区与应收/应付明细页(settlement-detail-page__search)同款样式
.payment-search {
margin-bottom: 8px;
padding: 12px 12px 4px;
background: #fff;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
:deep(.el-form-item__label) {
white-space: nowrap;
}
}
.payment-search__grid {
display: grid;
grid-template-columns: repeat(4, minmax(220px, 1fr));
gap: 8px 24px;
align-items: start;
:deep(.el-form-item) {
margin-bottom: 8px;
}
:deep(.el-input),
:deep(.el-select),
:deep(.el-cascader),
:deep(.el-date-editor) {
width: 100%;
}
}
.payment-search__actions {
grid-column: 1 / -1;
display: flex;
justify-content: flex-end;
gap: 8px;
margin-bottom: 8px;
}
@media screen and (max-width: 1200px) {
.payment-search__grid {
grid-template-columns: repeat(2, minmax(220px, 1fr));
}
}
@media screen and (max-width: 760px) {
.payment-search__grid {
grid-template-columns: 1fr;
}
}
.payment-page :deep(.el-table) { .payment-page :deep(.el-table) {
--el-table-border-color: #eff1f7; --el-table-border-color: #eff1f7;
} }