style(contract): 优化合同管理页面表单样式与布局

- 调整合同管理备注输入框行数和最大长度
- 细化合同变更页面表单项间距和对齐方式
- 统一弹窗表单项的底部间距样式,改为注释禁用
- 调整 port-terminal 和 region 组件的表单项底部间距
- 修改 vite 配置中 API 请求代理地址
- 优化凭证执行详情搜索表单列宽布局
- 在运单管理页面更新型号字段为非必填,调整变更记录内容格式化显示
- 引入并使用 formatRouteChangeContent 工具函数
- 统一明细按钮显示逻辑,草稿状态也显示详情按钮
- 新增路由变更相关工具函数与样式支持
This commit is contained in:
2026-10-14 12:44:56 +08:00
parent 6762cf7b83
commit 6de87ed4e2
26 changed files with 748 additions and 492 deletions
+4
View File
@@ -1,6 +1,7 @@
<template>
<basic-container class="bill-ledger-page">
<bill-ledger-search
v-if="searchVisible"
:query="query"
:loading="loading"
@search="handleSearch"
@@ -20,10 +21,12 @@
:rows="rows"
:loading="loading"
:page="page"
v-model:search-visible="searchVisible"
@add="openCreate"
@view="openView"
@edit="openEdit"
@delete="handleDelete"
@refresh="loadData"
@page-change="handlePageChange"
@size-change="handleSizeChange"
/>
@@ -124,6 +127,7 @@ export default {
return {
query: emptyQuery(),
counts: { all: 0, within30: 0, within90: 0, over90: 0 },
searchVisible: true,
rows: [],
loading: false,
page: { current: 1, size: 10, total: 0 },
+4
View File
@@ -1,6 +1,7 @@
<template>
<basic-container class="bill-payment-page">
<bill-payment-search
v-if="searchVisible"
:query="query"
:loading="loading"
@search="handleSearch"
@@ -11,6 +12,7 @@
:loading="loading"
:page="page"
:mk-enabled="mkEnabled"
v-model:search-visible="searchVisible"
@add="openCreate"
@view="openView"
@edit="openEdit"
@@ -20,6 +22,7 @@
@approve="handleApprove"
@return="handleReturn"
@void="handleVoid"
@refresh="loadTable"
@page-change="handlePageChange"
@size-change="handleSizeChange"
/>
@@ -47,6 +50,7 @@ export default {
data() {
return {
query: emptyQuery(),
searchVisible: true,
rows: [],
loading: false,
page: { current: 1, size: 10, total: 0 },
@@ -4,11 +4,19 @@
<el-button v-if="hasPermission('bill_ledger_add')" type="primary" @click="$emit('add')">
新增
</el-button>
<table-header-tools
:columns="columns"
v-model:visible-column-keys="visibleColumnKeys"
v-model:table-size="tableSize"
:search-visible="searchVisible"
@update:search-visible="$emit('update:searchVisible', $event)"
@refresh="$emit('refresh')"
/>
</div>
<el-table v-loading="loading" :data="rows" border>
<el-table v-loading="loading" :data="rows" :size="tableSize" border>
<el-table-column type="index" label="序号" width="64" fixed="left" align="center" />
<el-table-column
v-for="column in columns"
v-for="column in visibleColumns"
:key="column.prop"
v-bind="column"
align="center"
@@ -60,20 +68,30 @@
<script>
import { mapGetters } from 'vuex';
import { billLedgerTableColumns } from '@/option/payment/billLedger';
import TableHeaderTools from '@/components/table-header-tools/main.vue';
export default {
name: 'BillLedgerTable',
components: { TableHeaderTools },
props: {
rows: { type: Array, default: () => [] },
loading: { type: Boolean, default: false },
page: { type: Object, required: true },
searchVisible: { type: Boolean, default: true },
},
emits: ['add', 'view', 'edit', 'delete', 'page-change', 'size-change'],
emits: ['add', 'view', 'edit', 'delete', 'page-change', 'size-change', 'refresh', 'update:searchVisible'],
data() {
return { columns: billLedgerTableColumns };
return {
columns: billLedgerTableColumns,
visibleColumnKeys: billLedgerTableColumns.map(column => column.prop),
tableSize: 'default',
};
},
computed: {
...mapGetters(['permission']),
visibleColumns() {
return this.columns.filter(column => this.visibleColumnKeys.includes(column.prop));
},
},
methods: {
hasPermission(code) {
@@ -96,7 +114,7 @@ export default {
.bill-ledger-table__toolbar {
display: flex;
align-items: center;
justify-content: flex-start;
justify-content: space-between;
padding: 12px 0;
}
.bill-ledger-table__links {
@@ -4,11 +4,19 @@
<el-button v-if="hasPermission('bill_payment_add')" type="primary" @click="$emit('add')">
新增
</el-button>
<table-header-tools
:columns="columns"
v-model:visible-column-keys="visibleColumnKeys"
v-model:table-size="tableSize"
:search-visible="searchVisible"
@update:search-visible="$emit('update:searchVisible', $event)"
@refresh="$emit('refresh')"
/>
</div>
<el-table v-loading="loading" :data="rows" border>
<el-table v-loading="loading" :data="rows" :size="tableSize" border>
<el-table-column type="index" label="序号" width="64" fixed="left" align="center" />
<el-table-column
v-for="column in columns"
v-for="column in visibleColumns"
:key="column.prop"
v-bind="column"
align="center"
@@ -115,15 +123,18 @@
<script>
import { mapGetters } from 'vuex';
import { billPaymentTableColumns } from '@/option/payment/billPayment';
import TableHeaderTools from '@/components/table-header-tools/main.vue';
import { isAdministrator } from '@/utils/auth';
export default {
name: 'BillPaymentTable',
components: { TableHeaderTools },
props: {
rows: { type: Array, default: () => [] },
loading: { type: Boolean, default: false },
page: { type: Object, required: true },
mkEnabled: { type: Boolean, default: false },
searchVisible: { type: Boolean, default: true },
},
emits: [
'add',
@@ -137,12 +148,21 @@ export default {
'void',
'page-change',
'size-change',
'refresh',
'update:searchVisible',
],
data() {
return { columns: billPaymentTableColumns };
return {
columns: billPaymentTableColumns,
visibleColumnKeys: billPaymentTableColumns.map(column => column.prop),
tableSize: 'default',
};
},
computed: {
...mapGetters(['permission', 'userInfo']),
visibleColumns() {
return this.columns.filter(column => this.visibleColumnKeys.includes(column.prop));
},
isAdmin() {
return isAdministrator(this.userInfo);
},
@@ -173,7 +193,8 @@ export default {
}
.bill-payment-table__toolbar {
display: flex;
justify-content: flex-start;
align-items: center;
justify-content: space-between;
padding: 12px 0;
}
.bill-payment-table__links {
+25 -11
View File
@@ -1,6 +1,6 @@
<template>
<basic-container class="invoice-page">
<section class="invoice-page__search">
<section v-if="searchVisible" class="invoice-page__search">
<el-form :model="query" label-position="right" label-width="88px" @submit.prevent>
<div class="invoice-page__search-grid">
<el-form-item label="单据号">
@@ -78,18 +78,26 @@
>导出</el-button
>
</div>
<div class="invoice-page__toolbar-right">
<el-tooltip content="刷新" placement="top">
<el-button text :icon="Refresh" @click="loadTable" />
</el-tooltip>
</div>
<table-header-tools
:columns="columns"
v-model:visible-column-keys="visibleColumnKeys"
v-model:table-size="tableSize"
v-model:search-visible="searchVisible"
@refresh="loadTable"
/>
</div>
<el-table v-loading="loading" :data="rows" border @selection-change="selection = $event">
<el-table
v-loading="loading"
:data="rows"
:size="tableSize"
border
@selection-change="selection = $event"
>
<el-table-column type="selection" width="52" fixed="left" align="center" />
<el-table-column type="index" label="序号" width="64" fixed="left" align="center" />
<el-table-column
v-for="column in columns"
v-for="column in visibleColumns"
:key="column.prop"
v-bind="column"
align="center"
@@ -209,12 +217,13 @@
</template>
<script>
import { ArrowDown, ArrowUp, Refresh } from '@element-plus/icons-vue';
import { ArrowDown, ArrowUp } from '@element-plus/icons-vue';
import { mapGetters } from 'vuex';
import * as XLSX from 'xlsx';
import * as api from '@/api/payment/invoiceApplication';
import * as formalSettlementApi from '@/api/settlement/formalSettlement';
import { invoiceApplicationTableColumns } from '@/option/payment/invoiceApplication';
import TableHeaderTools from '@/components/table-header-tools/main.vue';
import organizationSearch from '@/mixins/organization-search';
import { getMKApprovalUrl } from '@/api/system/business-process';
import { loadMkEnabled, submitMkApprovalFlow } from '@/utils/mk-approval';
@@ -230,17 +239,20 @@ const emptyQuery = () => ({
export default {
name: 'InvoiceApplication',
components: { TableHeaderTools },
mixins: [organizationSearch],
data() {
return {
ArrowDown,
ArrowUp,
Refresh,
query: emptyQuery(),
searchExpanded: false,
searchVisible: true,
tableSize: 'default',
approvalStatusOptions: api.approvalStatusOptions,
kingdeeStatusOptions: api.kingdeeStatusOptions,
columns: invoiceApplicationTableColumns,
visibleColumnKeys: invoiceApplicationTableColumns.map(column => column.prop),
rows: [],
selection: [],
loading: false,
@@ -250,6 +262,9 @@ export default {
},
computed: {
...mapGetters(['permission']),
visibleColumns() {
return this.columns.filter(column => this.visibleColumnKeys.includes(column.prop));
},
},
mounted() {
this.loadOrganizationOptions();
@@ -477,7 +492,6 @@ export default {
padding: 12px 0;
}
.invoice-page__toolbar-left,
.invoice-page__toolbar-right,
.invoice-page__links {
display: flex;
align-items: center;
+25 -11
View File
@@ -1,6 +1,6 @@
<template>
<basic-container class="receipt-page">
<section class="receipt-page__search">
<section v-if="searchVisible" class="receipt-page__search">
<el-form :model="query" label-position="right" label-width="88px" @submit.prevent>
<div class="receipt-page__search-grid">
<el-form-item label="发票号码">
@@ -84,18 +84,26 @@
>导出</el-button
>
</div>
<div class="receipt-page__toolbar-right">
<el-tooltip content="刷新" placement="top">
<el-button text :icon="Refresh" @click="loadTable" />
</el-tooltip>
</div>
<table-header-tools
:columns="columns"
v-model:visible-column-keys="visibleColumnKeys"
v-model:table-size="tableSize"
v-model:search-visible="searchVisible"
@refresh="loadTable"
/>
</div>
<el-table v-loading="loading" :data="rows" border @selection-change="selection = $event">
<el-table
v-loading="loading"
:data="rows"
:size="tableSize"
border
@selection-change="selection = $event"
>
<el-table-column type="selection" width="52" fixed="left" align="center" />
<el-table-column type="index" label="序号" width="64" fixed="left" align="center" />
<el-table-column
v-for="column in columns"
v-for="column in visibleColumns"
:key="column.prop"
v-bind="column"
align="center"
@@ -202,11 +210,12 @@
</template>
<script>
import { ArrowDown, ArrowUp, Refresh } from '@element-plus/icons-vue';
import { ArrowDown, ArrowUp } from '@element-plus/icons-vue';
import { mapGetters } from 'vuex';
import * as XLSX from 'xlsx';
import * as api from '@/api/payment/invoiceReceipt';
import { invoiceReceiptTableColumns } from '@/option/payment/invoiceReceipt';
import TableHeaderTools from '@/components/table-header-tools/main.vue';
import organizationSearch from '@/mixins/organization-search';
import { getMKApprovalUrl } from '@/api/system/business-process';
import { loadMkEnabled, submitMkApprovalFlow } from '@/utils/mk-approval';
@@ -223,17 +232,20 @@ const emptyQuery = () => ({
export default {
name: 'InvoiceReceipt',
components: { TableHeaderTools },
mixins: [organizationSearch],
data() {
return {
ArrowDown,
ArrowUp,
Refresh,
query: emptyQuery(),
searchExpanded: false,
searchVisible: true,
tableSize: 'default',
approvalStatusOptions: api.approvalStatusOptions,
kingdeeStatusOptions: api.kingdeeStatusOptions,
columns: invoiceReceiptTableColumns,
visibleColumnKeys: invoiceReceiptTableColumns.map(column => column.prop),
rows: [],
selection: [],
loading: false,
@@ -243,6 +255,9 @@ export default {
},
computed: {
...mapGetters(['permission']),
visibleColumns() {
return this.columns.filter(column => this.visibleColumnKeys.includes(column.prop));
},
},
mounted() {
this.loadOrganizationOptions();
@@ -439,7 +454,6 @@ export default {
padding: 12px 0;
}
.receipt-page__toolbar-left,
.receipt-page__toolbar-right,
.receipt-page__links {
display: flex;
align-items: center;
+200 -347
View File
@@ -1,278 +1,177 @@
<template>
<basic-container class="payment-page">
<section class="payment-page__search">
<el-form :model="query" label-position="right" label-width="88px">
<div class="payment-page__search-grid">
<el-form-item label="单据号"
><el-input v-model="query.paymentNo" clearable
/></el-form-item>
<el-form-item label="日期"
><el-date-picker
v-model="query.applyDateRange"
type="daterange"
value-format="YYYY-MM-DD"
range-separator="~"
start-placeholder="年/月/日"
end-placeholder="年/月/日"
/></el-form-item>
<el-form-item label="客户名称"
><el-input v-model="query.payeeName" clearable
/></el-form-item>
<el-form-item label="项目名称"
><el-input v-model="query.projectName" clearable
/></el-form-item>
<template v-if="searchExpanded">
<el-form-item label="所属组织"
><el-cascader
v-model="query.deptPath"
:options="organizationTreeOptions"
:props="organizationCascaderProps"
filterable
clearable
style="width: 100%"
placeholder="请选择 所属组织"
@change="val => { query.deptName = findOrgById(val)?.rawLabel || '' }"
/></el-form-item>
<el-form-item label="关联结算单"
><el-input v-model="query.settlementNo" clearable
/></el-form-item>
<el-form-item label="付款类型"
><el-select v-model="query.paymentType" clearable
><el-option
v-for="item in paymentTypeOptions"
:key="item.value"
v-bind="item" /></el-select
></el-form-item>
<el-form-item label="审核状态"
><el-select v-model="query.approvalStatus" clearable
><el-option
v-for="item in approvalStatusOptions"
:key="item.value"
v-bind="item" /></el-select
></el-form-item>
<el-form-item label="金蝶单据状态"
><el-select v-model="query.kingdeeStatus" clearable
><el-option
v-for="item in kingdeeStatusOptions"
:key="item.value"
v-bind="item" /></el-select
></el-form-item>
</template>
</div>
<div class="payment-page__search-actions">
<el-button type="primary" @click="handleSearch">查询</el-button>
<el-button @click="resetSearch">重置</el-button>
<el-button text @click="searchExpanded = !searchExpanded"
><el-icon><component :is="searchExpanded ? ArrowUp : ArrowDown" /></el-icon
></el-button>
</div>
</el-form>
</section>
<section class="payment-page__table-panel">
<div class="payment-page__toolbar">
<div class="payment-page__toolbar-left">
<el-button
v-if="hasPermission('payment_application_add')"
type="primary"
@click="openCreate"
>新增付款申请</el-button
>
<el-button
v-if="hasPermission('payment_application_sync')"
type="primary"
plain
@click="handleSync"
>批量同步</el-button
>
<el-button
v-if="hasPermission('payment_application_add')"
type="primary"
plain
@click="openSettlementPayment"
>申请付尾款</el-button
>
<el-button
v-if="hasPermission('payment_application_add')"
type="primary"
plain
@click="openProjectAdvance"
>预付申请</el-button
>
<el-button
v-if="hasPermission('payment_application_export')"
type="primary"
plain
@click="handleExport"
>导出</el-button
>
</div>
<el-button text :icon="Refresh" @click="loadTable" />
</div>
<el-table v-loading="loading" :data="rows" border @selection-change="selection = $event">
<el-table-column type="selection" width="52" fixed="left" align="center" />
<el-table-column type="index" label="序号" width="64" fixed="left" align="center" />
<el-table-column
v-for="column in columns"
:key="column.prop"
v-bind="column"
align="center"
show-overflow-tooltip
<avue-crud
ref="crud"
:option="option"
:table-loading="loading"
:data="rows"
v-model:page="page"
@search-change="searchChange"
@search-reset="searchReset"
@selection-change="selectionChange"
@current-change="currentChange"
@size-change="sizeChange"
@refresh-change="refreshChange"
@on-load="onLoad"
>
<template #menu-left>
<el-button
v-if="hasPermission('payment_application_add')"
type="primary"
@click="openCreate"
>新增付款申请</el-button
>
<template #default="{ row }">
<el-link v-if="column.link" type="primary" @click="openView(row)">{{
row[column.prop]
}}</el-link>
<el-tag
v-else-if="column.status"
:type="statusType(row.approvalStatus)"
class="status-text"
>{{ row[column.prop] || '-' }}</el-tag
>
<span v-else-if="column.money">{{ formatMoney(row[column.prop]) }}</span>
<span v-else>{{ displayValue(row[column.prop]) }}</span>
</template>
</el-table-column>
<el-table-column label="操作" width="320" fixed="right" align="center">
<template #default="{ row }"
><div class="payment-page__links">
<el-link
v-if="hasPermission('payment_application_view')"
type="primary"
@click="openView(row)"
>查看</el-link
>
<el-link
v-if="
hasPermission('payment_application_edit') &&
['draft', 'returned'].includes(row.approvalStatus)
"
type="primary"
@click="openEdit(row)"
>编辑</el-link
>
<el-link
v-if="
hasPermission('payment_application_submit') &&
['draft', 'returned'].includes(row.approvalStatus)
"
type="primary"
@click="handleSubmit(row)"
>提交</el-link
>
<el-link
v-if="
mkEnabled &&
hasPermission('payment_application_approve') &&
['reviewing', 'approved'].includes(row.approvalStatus)
"
type="primary"
@click="handleMkAudit(row)"
>流程</el-link
>
<el-link
v-if="
!mkEnabled &&
hasPermission('payment_application_approve') &&
row.approvalStatus === 'reviewing'
"
type="primary"
@click="handleApprove(row)"
>通过</el-link
>
<el-link
v-if="
!mkEnabled &&
hasPermission('payment_application_approve') &&
row.approvalStatus === 'reviewing'
"
type="danger"
@click="handleReturn(row)"
>驳回</el-link
>
<el-link
v-if="
hasPermission('payment_application_void') && row.approvalStatus === 'approved'
"
type="danger"
@click="handleVoid(row)"
>作废</el-link
>
<el-link
v-if="hasPermission('payment_application_delete') && row.approvalStatus === 'draft'"
type="danger"
@click="handleDelete(row)"
>删除</el-link
>
</div></template
>
</el-table-column>
</el-table>
<div class="payment-page__pagination">
<el-pagination
v-model:current-page="page.current"
v-model:page-size="page.size"
:total="page.total"
:page-sizes="[10, 20, 50, 100]"
layout="total, sizes, prev, pager, next, jumper"
@current-change="loadTable"
@size-change="handleSizeChange"
/>
</div>
</section>
<el-button
v-if="hasPermission('payment_application_sync')"
type="primary"
plain
@click="handleSync"
>批量同步</el-button
>
<el-button
v-if="hasPermission('payment_application_add')"
type="primary"
plain
@click="openSettlementPayment"
>申请付尾款</el-button
>
<el-button
v-if="hasPermission('payment_application_add')"
type="primary"
plain
@click="openProjectAdvance"
>预付申请</el-button
>
<el-button
v-if="hasPermission('payment_application_export')"
type="primary"
plain
@click="handleExport"
>导出</el-button
>
</template>
<template #paymentNo="{ row }">
<el-link type="primary" @click="openView(row)">{{ row.paymentNo }}</el-link>
</template>
<template #approvalStatusName="{ row }">
<el-tag :type="statusType(row.approvalStatus)" class="status-text">{{
row.approvalStatusName || '-'
}}</el-tag>
</template>
<template #menu="{ row }">
<el-link
v-if="hasPermission('payment_application_view')"
type="primary"
@click="openView(row)"
>查看</el-link
>
<el-link
v-if="
hasPermission('payment_application_edit') &&
['draft', 'returned'].includes(row.approvalStatus)
"
type="primary"
@click="openEdit(row)"
>编辑</el-link
>
<el-link
v-if="
hasPermission('payment_application_submit') &&
['draft', 'returned'].includes(row.approvalStatus)
"
type="primary"
@click="handleSubmit(row)"
>提交</el-link
>
<el-link
v-if="
mkEnabled &&
hasPermission('payment_application_approve') &&
['reviewing', 'approved'].includes(row.approvalStatus)
"
type="primary"
@click="handleMkAudit(row)"
>流程</el-link
>
<el-link
v-if="
!mkEnabled &&
hasPermission('payment_application_approve') &&
row.approvalStatus === 'reviewing'
"
type="primary"
@click="handleApprove(row)"
>通过</el-link
>
<el-link
v-if="
!mkEnabled &&
hasPermission('payment_application_approve') &&
row.approvalStatus === 'reviewing'
"
type="danger"
@click="handleReturn(row)"
>驳回</el-link
>
<el-link
v-if="hasPermission('payment_application_void') && row.approvalStatus === 'approved'"
type="danger"
@click="handleVoid(row)"
>作废</el-link
>
<el-link
v-if="hasPermission('payment_application_delete') && row.approvalStatus === 'draft'"
type="danger"
@click="handleDelete(row)"
>删除</el-link
>
</template>
</avue-crud>
</basic-container>
</template>
<script>
import { ArrowDown, ArrowUp, Refresh } from '@element-plus/icons-vue';
import { mapGetters } from 'vuex';
import * as api from '@/api/payment/paymentApplication';
import { paymentApplicationTableColumns } from '@/option/payment/paymentApplication';
import { paymentApplicationOption } from '@/option/payment/paymentApplication';
import organizationSearch from '@/mixins/organization-search';
import { getMKApprovalUrl } from '@/api/system/business-process';
import { loadMkEnabled, submitMkApprovalFlow } from '@/utils/mk-approval';
const emptyQuery = () => ({
paymentNo: '',
applyDateRange: [],
payeeName: '',
projectName: '',
deptName: '',
deptPath: [],
settlementNo: '',
paymentType: '',
approvalStatus: '',
kingdeeStatus: '',
});
export default {
name: 'PaymentApplication',
mixins: [organizationSearch],
data() {
return {
ArrowDown,
ArrowUp,
Refresh,
query: emptyQuery(),
searchExpanded: false,
paymentTypeOptions: api.paymentTypeOptions,
approvalStatusOptions: api.approvalStatusOptions,
kingdeeStatusOptions: api.kingdeeStatusOptions,
columns: paymentApplicationTableColumns,
rows: [],
selection: [],
loading: false,
page: { current: 1, size: 10, total: 0 },
query: {},
option: {},
page: {
currentPage: 1,
pageSize: 10,
pageSizes: [10, 20, 50, 100],
total: 0,
},
mkEnabled: false,
};
},
computed: {
...mapGetters(['permission']),
visibleSearchFields() {
return this.searchExpanded ? this.columns : this.columns.slice(0, 4);
},
},
created() {
this.option = paymentApplicationOption({
paymentTypeOptions: api.paymentTypeOptions,
approvalStatusOptions: api.approvalStatusOptions,
kingdeeStatusOptions: api.kingdeeStatusOptions,
});
this.loadOrganizationOptions();
},
mounted() {
this.loadOrganizationOptions();
this.loadTable();
loadMkEnabled()
.then(enabled => {
this.mkEnabled = !!enabled;
@@ -289,39 +188,52 @@ export default {
const body = response?.data || response || {};
return body?.data || body;
},
buildParams() {
const params = { ...this.query };
onLoad(page) {
this.loading = true;
api
.getList(page.currentPage, page.pageSize, { ...this.query })
.then(res => {
const data = this.unwrapData(res);
this.rows = data.records || [];
this.page.total = Number(data.total || 0);
})
.finally(() => {
this.loading = false;
this.selection = [];
this.$refs.crud?.toggleSelection?.();
});
},
searchChange(params, done) {
// 所属组织级联返回 id 路径数组,转成部门名称给后端
this.normalizeOrganizationSearch(params, 'deptName');
// 日期区间拆成后端需要的起止字段
const range = params.applyDateRange || [];
delete params.applyDateRange;
if (range.length === 2) {
params.applyStartDate = range[0];
params.applyEndDate = range[1];
}
return params;
this.query = {
...params,
applyStartDate: range[0] || '',
applyEndDate: range[1] || '',
};
this.page.currentPage = 1;
this.onLoad(this.page);
done();
},
async loadTable() {
this.loading = true;
try {
const data = this.unwrapData(
await api.getList(this.page.current, this.page.size, this.buildParams())
);
this.rows = data.records || [];
this.page.total = data.total || 0;
} finally {
this.loading = false;
}
searchReset() {
this.query = {};
this.page.currentPage = 1;
this.onLoad(this.page);
},
handleSearch() {
this.page.current = 1;
this.loadTable();
currentChange(currentPage) {
this.page.currentPage = currentPage;
},
resetSearch() {
this.query = emptyQuery();
this.handleSearch();
sizeChange(pageSize) {
this.page.pageSize = pageSize;
},
handleSizeChange() {
this.page.current = 1;
this.loadTable();
refreshChange() {
this.onLoad(this.page);
},
selectionChange(list) {
this.selection = list;
},
openCreate() {
this.$router.push({ path: '/payment/payment-application/form', query: { mode: 'add' } });
@@ -361,7 +273,7 @@ export default {
await this.$confirm('确认删除该付款申请?', '提示', { type: 'warning' });
await api.remove(row.id);
this.$message.success('删除成功');
this.loadTable();
this.refreshChange();
},
async handleSubmit(row) {
const previousApprovalStatus = row.approvalStatus || '';
@@ -373,12 +285,12 @@ export default {
approvalStatus: previousApprovalStatus,
});
this.$message.success('提交成功');
this.loadTable();
this.refreshChange();
},
async handleApprove(row) {
await api.approve({ id: row.id });
this.$message.success('审批通过');
this.loadTable();
this.refreshChange();
},
handleMkAudit(row) {
if (!row?.id) {
@@ -402,18 +314,18 @@ export default {
const { value } = await this.$prompt('请输入驳回原因', '审批驳回');
await api.returnBill({ id: row.id, reason: value });
this.$message.success('已驳回');
this.loadTable();
this.refreshChange();
},
async handleVoid(row) {
const { value } = await this.$prompt('请输入作废原因', '作废付款申请');
await api.voidBill({ id: row.id, reason: value });
this.$message.success('作废成功');
this.loadTable();
this.refreshChange();
},
async handleSyncRow(row) {
const data = this.unwrapData(await api.syncKingdee(row.id));
this.$message.success(`已生成金蝶付款单:${data}`);
this.loadTable();
this.refreshChange();
},
async handleSync() {
const rows = this.selection.filter(row => row.approvalStatus === 'approved');
@@ -423,11 +335,16 @@ export default {
}
await api.syncKingdeeBatch(rows.map(row => row.id));
this.$message.success(`已同步${rows.length}条付款申请`);
this.loadTable();
this.refreshChange();
},
handleExport() {
const headers = this.columns.map(item => item.label);
const rows = this.rows.map(row => this.columns.map(item => row[item.prop] || ''));
const columns = this.option.column.filter(column => !column.hide && column.prop);
const headers = columns.map(item => item.label);
const rows = this.rows.map(row =>
columns.map(item =>
row[item.prop] === null || row[item.prop] === undefined ? '' : row[item.prop]
)
);
const csv = [headers, ...rows]
.map(item => item.map(value => `"${String(value).replaceAll('"', '""')}"`).join(','))
.join('\n');
@@ -444,65 +361,11 @@ export default {
''
);
},
displayValue(value) {
return value === null || value === undefined || value === '' ? '-' : value;
},
formatMoney(value) {
return Number(value || 0).toFixed(2);
},
},
};
</script>
<style scoped lang="scss">
.payment-page__search {
padding: 12px 12px 4px;
background: #fff;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
}
.payment-page__search-grid {
display: grid;
grid-template-columns: repeat(4, minmax(0, 1fr));
gap: 8px 24px;
}
.payment-page__search :deep(.el-form-item) {
margin-bottom: 8px;
}
.payment-page__search :deep(.el-input),
.payment-page__search :deep(.el-select),
.payment-page__search :deep(.el-date-editor) {
width: 100%;
}
.payment-page__search-actions {
display: flex;
justify-content: flex-end;
gap: 8px;
margin-bottom: 8px;
}
.payment-page__table-panel {
margin-top: 8px;
}
.payment-page__toolbar {
display: flex;
justify-content: space-between;
align-items: center;
padding: 12px 0;
}
.payment-page__toolbar-left {
display: flex;
gap: 8px;
}
.payment-page__links {
display: flex;
flex-wrap: wrap;
justify-content: center;
gap: 8px;
}
.payment-page__pagination {
display: flex;
justify-content: flex-end;
margin-top: 12px;
}
.payment-page :deep(.el-table) {
--el-table-border-color: #eff1f7;
}
@@ -512,14 +375,4 @@ export default {
:deep(.payment-page.basic-container .basic-container__card > .el-card__body) {
padding: 0;
}
@media (max-width: 1200px) {
.payment-page__search-grid {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
}
@media (max-width: 760px) {
.payment-page__search-grid {
grid-template-columns: 1fr;
}
}
</style>
+26 -4
View File
@@ -1,6 +1,6 @@
<template>
<basic-container class="claim-record-page">
<section-card class="claim-record-page__search">
<section-card v-if="searchVisible" class="claim-record-page__search">
<el-form :model="query" label-position="right" label-width="88px" @submit.prevent>
<div class="claim-record-page__search-grid">
<el-form-item label="认领通知单">
@@ -80,10 +80,19 @@
</section-card>
<section class="claim-record-page__table-panel">
<el-table v-loading="loading" :data="rows" border>
<div class="claim-record-page__toolbar">
<table-header-tools
:columns="columns"
v-model:visible-column-keys="visibleColumnKeys"
v-model:table-size="tableSize"
v-model:search-visible="searchVisible"
@refresh="loadTable"
/>
</div>
<el-table v-loading="loading" :data="rows" :size="tableSize" border>
<el-table-column type="index" label="序号" width="64" fixed="left" align="center" />
<el-table-column
v-for="column in columns"
v-for="column in visibleColumns"
:key="column.prop"
v-bind="column"
align="center"
@@ -138,6 +147,7 @@ import { mapGetters } from 'vuex';
import * as api from '@/api/payment/receiptClaimRecord';
import { receiptClaimRecordTableColumns } from '@/option/payment/receiptClaimRecord';
import SectionCard from '@/components/section-card/main.vue';
import TableHeaderTools from '@/components/table-header-tools/main.vue';
import { isAdministrator } from '@/utils/auth';
const emptyQuery = () => ({
@@ -156,16 +166,19 @@ const emptyQuery = () => ({
export default {
name: 'ReceiptClaimRecord',
components: { SectionCard },
components: { SectionCard, TableHeaderTools },
data() {
return {
ArrowDown,
ArrowUp,
query: emptyQuery(),
searchExpanded: false,
searchVisible: true,
tableSize: 'default',
claimStatusOptions: api.claimStatusOptions,
kingdeeBillStatusOptions: api.kingdeeBillStatusOptions,
columns: receiptClaimRecordTableColumns,
visibleColumnKeys: receiptClaimRecordTableColumns.map(column => column.prop),
rows: [],
loading: false,
page: { current: 1, size: 10, total: 0 },
@@ -173,6 +186,9 @@ export default {
},
computed: {
...mapGetters(['permission', 'userInfo']),
visibleColumns() {
return this.columns.filter(column => this.visibleColumnKeys.includes(column.prop));
},
isAdmin() {
return isAdministrator(this.userInfo);
},
@@ -279,6 +295,12 @@ export default {
.claim-record-page__table-panel {
margin-top: 8px;
}
.claim-record-page__toolbar {
display: flex;
justify-content: flex-end;
align-items: center;
padding: 12px 0;
}
.claim-record-page__pagination {
display: flex;
justify-content: flex-end;
+41 -19
View File
@@ -1,6 +1,6 @@
<template>
<basic-container class="receipt-flow-page">
<section class="receipt-flow-page__search">
<section v-if="searchVisible" class="receipt-flow-page__search">
<el-form :model="query" label-position="right" label-width="88px" @submit.prevent>
<div class="receipt-flow-page__search-grid">
<el-form-item label="认领通知单">
@@ -52,33 +52,43 @@
<section class="receipt-flow-page__table-panel">
<div class="receipt-flow-page__toolbar">
<el-button
v-if="hasPermission('receipt_flow_sync')"
type="primary"
:loading="syncing"
@click="handleSync"
>
手动同步流水
</el-button>
<el-button
v-if="hasPermission('receipt_flow_claim')"
type="primary"
:disabled="!selectedRows.length"
@click="openBatchClaim"
>
批量认领
</el-button>
<div class="receipt-flow-page__toolbar-left">
<el-button
v-if="hasPermission('receipt_flow_sync')"
type="primary"
:loading="syncing"
@click="handleSync"
>
手动同步流水
</el-button>
<el-button
v-if="hasPermission('receipt_flow_claim')"
type="primary"
:disabled="!selectedRows.length"
@click="openBatchClaim"
>
批量认领
</el-button>
</div>
<table-header-tools
:columns="columns"
v-model:visible-column-keys="visibleColumnKeys"
v-model:table-size="tableSize"
v-model:search-visible="searchVisible"
@refresh="loadTable"
/>
</div>
<el-table
v-loading="loading"
:data="rows"
:size="tableSize"
border
@selection-change="selectedRows = $event"
>
<el-table-column type="selection" width="52" align="center" />
<el-table-column type="index" label="序号" width="64" align="center" />
<el-table-column
v-for="column in columns"
v-for="column in visibleColumns"
:key="column.prop"
v-bind="column"
align="center"
@@ -193,6 +203,7 @@
import { mapGetters } from 'vuex';
import * as api from '@/api/payment/receiptFlow';
import { receiptFlowTableColumns } from '@/option/payment/receiptFlow';
import TableHeaderTools from '@/components/table-header-tools/main.vue';
import { isAdministrator } from '@/utils/auth';
const receiptFlowMockTemplates = [
@@ -265,11 +276,15 @@ const emptyQuery = () => ({
export default {
name: 'ReceiptFlow',
components: { TableHeaderTools },
data() {
return {
query: emptyQuery(),
claimStatusOptions: api.claimStatusOptions,
columns: receiptFlowTableColumns,
visibleColumnKeys: receiptFlowTableColumns.map(column => column.prop),
searchVisible: true,
tableSize: 'default',
rows: [],
selectedRows: [],
loading: false,
@@ -281,6 +296,9 @@ export default {
},
computed: {
...mapGetters(['permission', 'userInfo']),
visibleColumns() {
return this.columns.filter(column => this.visibleColumnKeys.includes(column.prop));
},
isAdmin() {
return isAdministrator(this.userInfo);
},
@@ -436,11 +454,15 @@ export default {
}
.receipt-flow-page__toolbar {
display: flex;
justify-content: flex-start;
justify-content: space-between;
align-items: center;
gap: 8px;
padding: 12px 0;
}
.receipt-flow-page__toolbar-left {
display: flex;
gap: 8px;
}
.receipt-flow-page__pagination {
display: flex;
justify-content: flex-end;