⚡ 优化表格工具栏、附件文件名展示与合同金额两位小数

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-10-13 12:44:40 +08:00
parent bc7755a160
commit 6955784e93
31 changed files with 967 additions and 344 deletions
@@ -306,13 +306,15 @@
class-name="is-ellipsis-link"
>
<template #default="{ row }">
<el-link
:disabled="!getAttachmentUrl(row)"
type="primary"
@click="previewAttachment(row)"
>
{{ row.originalName || row.name || '-' }}
</el-link>
<span
class="attachment-file-name"
:class="{ 'is-disabled': !getAttachmentUrl(row) }"
role="button"
tabindex="0"
@click="getAttachmentUrl(row) && previewAttachment(row)"
@keydown.enter="getAttachmentUrl(row) && previewAttachment(row)"
@keydown.space.prevent="getAttachmentUrl(row) && previewAttachment(row)"
>{{ row.originalName || row.name || '-' }}</span>
</template>
</el-table-column>
<el-table-column prop="uploadUserName" label="上传人" min-width="120" align="center">
@@ -39,16 +39,20 @@
>导出</el-button
>
</div>
<div class="fs-table-panel__toolbar-right">
<el-tooltip content="刷新" placement="top">
<el-button :icon="Refresh" text @click="$emit('refresh')" />
</el-tooltip>
</div>
<settlement-table-tools
:columns="columnSettingOptions"
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
ref="tableRef"
v-loading="loading"
:data="rows"
:size="tableSize"
border
highlight-current-row
@current-change="handleCurrentChange"
@@ -57,7 +61,7 @@
<el-table-column type="index" label="序号" width="64" fixed="left" align="center" />
<el-table-column type="selection" width="52" 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"
@@ -119,15 +123,16 @@
</template>
<script>
import { Refresh } from '@element-plus/icons-vue';
import {
invoiceStatusName,
kingdeeSyncStatusOptions,
paymentStatusOptions,
} from '@/option/settlement/formalSettlementSearch';
import SettlementTableTools from './settlement-table-tools.vue';
export default {
name: 'FormalSettlementTablePanel',
components: { SettlementTableTools },
props: {
rows: { type: Array, default: () => [] },
columns: { type: Array, default: () => [] },
@@ -135,6 +140,7 @@ export default {
page: { type: Object, required: true },
hasPermission: { type: Function, required: true },
mkEnabled: { type: Boolean, default: false },
searchVisible: { type: Boolean, default: true },
},
emits: [
'create',
@@ -146,14 +152,47 @@ export default {
'page-change',
'action',
'update:selection',
'update:searchVisible',
],
data() {
return {
Refresh,
selection: [],
tableSize: 'default',
visibleColumnKeys: [],
knownColumnProps: [],
};
},
computed: {
columnSettingOptions() {
return this.columns.map(column => ({
prop: column.prop,
label: column.label,
}));
},
visibleColumns() {
if (!this.visibleColumnKeys.length) return this.columns;
return this.columns.filter(column => this.visibleColumnKeys.includes(column.prop));
},
},
watch: {
columns: {
immediate: true,
handler(columns) {
const props = columns.map(column => column.prop);
if (!this.visibleColumnKeys.length) {
this.visibleColumnKeys = props;
this.knownColumnProps = props;
return;
}
const visible = new Set(this.visibleColumnKeys);
const known = new Set(this.knownColumnProps || []);
props.forEach(prop => {
if (!known.has(prop)) visible.add(prop);
});
this.knownColumnProps = props;
this.visibleColumnKeys = props.filter(prop => visible.has(prop));
},
},
rows() {
this.selection = [];
this.$refs.tableRef?.clearSelection();
@@ -245,11 +284,6 @@ export default {
align-items: center;
padding: 12px 0;
}
.fs-table-panel__toolbar-right {
display: flex;
align-items: center;
gap: 8px;
}
.fs-table-panel__links {
display: flex;
flex-wrap: wrap;
@@ -361,9 +361,14 @@
class-name="is-ellipsis-link"
>
<template #default="{ row }">
<el-link type="primary" @click="previewAttachment(row)">
{{ attachmentName(row) }}
</el-link>
<span
class="attachment-file-name"
role="button"
tabindex="0"
@click="previewAttachment(row)"
@keydown.enter="previewAttachment(row)"
@keydown.space.prevent="previewAttachment(row)"
>{{ attachmentName(row) }}</span>
</template>
</el-table-column>
<el-table-column label="附件描述" min-width="220">
@@ -200,9 +200,14 @@
class-name="is-ellipsis-link"
>
<template #default="{ row }">
<el-link type="primary" @click="previewAttachment(row)">
{{ attachmentName(row) }}
</el-link>
<span
class="attachment-file-name"
role="button"
tabindex="0"
@click="previewAttachment(row)"
@keydown.enter="previewAttachment(row)"
@keydown.space.prevent="previewAttachment(row)"
>{{ attachmentName(row) }}</span>
</template>
</el-table-column>
<el-table-column label="附件描述" min-width="240">
@@ -0,0 +1,13 @@
<template>
<table-header-tools v-bind="$attrs" />
</template>
<script>
import TableHeaderTools from '@/components/table-header-tools/main.vue';
export default {
name: 'SettlementTableTools',
components: { TableHeaderTools },
inheritAttrs: false,
};
</script>
@@ -10,22 +10,26 @@
>
<el-button type="primary" plain @click="$emit('export')">导出</el-button>
</div>
<div class="tr-table-panel__toolbar-right">
<el-tooltip content="刷新" placement="top">
<el-button :icon="Refresh" text @click="$emit('refresh')" />
</el-tooltip>
</div>
<settlement-table-tools
:columns="columnSettingOptions"
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"
:size="tableSize"
border
@selection-change="handleSelectionChange"
>
<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"
@@ -73,24 +77,68 @@
</template>
<script>
import { Refresh } from '@element-plus/icons-vue';
import SettlementTableTools from './settlement-table-tools.vue';
export default {
name: 'TransportReconciliationTablePanel',
components: { SettlementTableTools },
props: {
rows: { type: Array, default: () => [] },
columns: { type: Array, default: () => [] },
loading: { type: Boolean, default: false },
page: { type: Object, required: true },
hasPermission: { type: Function, required: true },
searchVisible: { type: Boolean, default: true },
},
emits: ['create', 'export', 'refresh', 'page-change', 'update:selection', 'action'],
emits: [
'create',
'export',
'refresh',
'page-change',
'update:selection',
'action',
'update:searchVisible',
],
data() {
return {
Refresh,
selection: [],
tableSize: 'default',
visibleColumnKeys: [],
knownColumnProps: [],
};
},
computed: {
columnSettingOptions() {
return this.columns.map(column => ({
prop: column.prop,
label: column.label,
}));
},
visibleColumns() {
if (!this.visibleColumnKeys.length) return this.columns;
return this.columns.filter(column => this.visibleColumnKeys.includes(column.prop));
},
},
watch: {
columns: {
immediate: true,
handler(columns) {
const props = columns.map(column => column.prop);
if (!this.visibleColumnKeys.length) {
this.visibleColumnKeys = props;
this.knownColumnProps = props;
return;
}
const visible = new Set(this.visibleColumnKeys);
const known = new Set(this.knownColumnProps || []);
props.forEach(prop => {
if (!known.has(prop)) visible.add(prop);
});
this.knownColumnProps = props;
this.visibleColumnKeys = props.filter(prop => visible.has(prop));
},
},
},
methods: {
handleSelectionChange(value) {
this.selection = value;
@@ -127,11 +175,6 @@ export default {
align-items: center;
padding: 12px 0;
}
.tr-table-panel__toolbar-right {
display: flex;
align-items: center;
gap: 8px;
}
.tr-table-panel__links {
display: flex;
flex-wrap: wrap;
+4 -1
View File
@@ -1,6 +1,6 @@
<template>
<basic-container class="formal-page">
<section class="formal-page__search">
<section v-show="searchVisible" class="formal-page__search">
<el-form :model="query" label-position="right" label-width="88px" @submit.prevent>
<div class="formal-page__search-grid">
<el-form-item v-for="field in visibleSearchFields" :key="field.prop" :label="field.label">
@@ -65,6 +65,7 @@
:page="page"
:has-permission="hasPermissionFn"
:mk-enabled="mkEnabled"
v-model:search-visible="searchVisible"
@create="openCreate"
@payment="openPaymentDialog"
@sync="handleSync"
@@ -84,6 +85,7 @@
:page="page"
:has-permission="hasPermissionFn"
:mk-enabled="mkEnabled"
v-model:search-visible="searchVisible"
@create="openCreate"
@payment="openPaymentDialog"
@sync="handleSync"
@@ -212,6 +214,7 @@ export default {
ArrowUp,
query: emptyQuery(),
searchExpanded: false,
searchVisible: true,
activeSettlementType: 'payable',
searchFields: formalSettlementSearchFields,
columns: formalSettlementTableColumns,
+25 -11
View File
@@ -1,6 +1,6 @@
<template>
<basic-container class="pre-settlement-page">
<section class="pre-settlement-page__search">
<section v-show="searchVisible" class="pre-settlement-page__search">
<el-form :model="query" label-position="right" label-width="88px" @submit.prevent>
<div class="pre-settlement-page__search-grid">
<template v-for="field in visibleSearchFields" :key="field.prop">
@@ -94,16 +94,19 @@
导出
</el-button>
</div>
<div class="pre-settlement-page__toolbar-right">
<el-tooltip content="刷新" placement="top">
<el-button :icon="Refresh" text @click="loadTable" />
</el-tooltip>
</div>
<settlement-table-tools
:columns="columnSettingOptions"
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
class="pre-settlement-page__table"
@selection-change="handleSelectionChange"
@@ -111,7 +114,7 @@
<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 tableColumns"
v-for="column in visibleTableColumns"
:key="column.prop"
:prop="column.prop"
:label="column.label"
@@ -285,7 +288,7 @@
</template>
<script>
import { ArrowDown, ArrowUp, Refresh } from '@element-plus/icons-vue';
import { ArrowDown, ArrowUp } from '@element-plus/icons-vue';
import { mapGetters } from 'vuex';
import {
approve,
@@ -306,6 +309,7 @@ import { downloadFile } from '@/utils/util';
import { getMKApprovalUrl } from '@/api/system/business-process';
import { loadMkEnabled, submitMkApprovalFlow } from '@/utils/mk-approval';
import PreSettlementEditor from './components/pre-settlement-editor.vue';
import SettlementTableTools from './components/settlement-table-tools.vue';
import { isAdministrator } from '@/utils/auth';
const emptyQuery = () => ({
@@ -323,18 +327,20 @@ const emptyQuery = () => ({
export default {
name: 'PreSettlement',
components: { PreSettlementEditor },
components: { PreSettlementEditor, SettlementTableTools },
mixins: [organizationSearch],
data() {
return {
ArrowDown,
ArrowUp,
Refresh,
loading: false,
query: emptyQuery(),
searchFields: preSettlementSearchFields,
searchExpanded: false,
searchVisible: true,
tableSize: 'default',
tableColumns: preSettlementTableColumns,
visibleColumnKeys: preSettlementTableColumns.map(column => column.prop),
rows: [],
selection: [],
page: {
@@ -365,6 +371,15 @@ export default {
visibleSearchFields() {
return this.searchExpanded ? this.searchFields : this.searchFields.slice(0, 4);
},
columnSettingOptions() {
return this.tableColumns.map(column => ({
prop: column.prop,
label: column.label,
}));
},
visibleTableColumns() {
return this.tableColumns.filter(column => this.visibleColumnKeys.includes(column.prop));
},
},
watch: {
'$route.query.detailNo'(detailNo) {
@@ -776,7 +791,6 @@ export default {
}
&__toolbar-left,
&__toolbar-right,
&__links {
display: flex;
flex-wrap: wrap;
@@ -1,6 +1,6 @@
<template>
<basic-container class="settlement-detail-page">
<section class="settlement-detail-page__search">
<section v-show="searchVisible" class="settlement-detail-page__search">
<el-form :model="query" label-position="right" label-width="88px" @submit.prevent>
<div class="settlement-detail-page__search-grid">
<template v-for="field in visibleSearchFields" :key="field.prop">
@@ -44,19 +44,19 @@
</el-button>
<el-button type="primary" plain @click="handleExport">导出</el-button>
</div>
<div class="settlement-detail-page__toolbar-right">
<el-tooltip content="刷新" placement="top">
<el-button :icon="Refresh" text @click="loadTable" />
</el-tooltip>
<el-tooltip content="列设置" placement="top">
<el-button :icon="Setting" text @click="noop" />
</el-tooltip>
</div>
<settlement-table-tools
:columns="columnSettingOptions"
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
class="settlement-detail-page__table"
@selection-change="selectionChange"
@@ -64,7 +64,7 @@
<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 displayTableColumns"
v-for="column in visibleTableColumns"
:key="column.prop"
:prop="column.prop"
:label="column.label"
@@ -938,7 +938,7 @@
</template>
<script>
import { ArrowDown, ArrowUp, Close, Refresh, Setting } from '@element-plus/icons-vue';
import { ArrowDown, ArrowUp, Close } from '@element-plus/icons-vue';
import {
changeRecordColumns,
feeDetailBaseColumns,
@@ -950,6 +950,7 @@ import {
tableColumns,
transferSearchFields,
} from '@/option/settlement/receivable-payable-detail';
import SettlementTableTools from './components/settlement-table-tools.vue';
import * as api from '@/api/settlement/receivable-payable-detail';
import { getList as getContractList } from '@/api/business/contract-manage';
import { getList as getCommonCargoList } from '@/api/business/common-cargo';
@@ -989,6 +990,7 @@ const ADJUST_BILLING_TYPE_MAP = {
};
export default {
components: { SettlementTableTools },
props: {
settlementType: {
type: String,
@@ -1000,8 +1002,6 @@ export default {
ArrowDown,
ArrowUp,
Close,
Refresh,
Setting,
searchFields,
tableColumns,
tableFeeItemNames: [],
@@ -1010,6 +1010,10 @@ export default {
generateWaybillColumns,
loading: false,
searchExpanded: false,
searchVisible: true,
tableSize: 'default',
visibleColumnKeys: [],
knownColumnProps: [],
query: {},
rows: [],
selection: [],
@@ -1169,6 +1173,18 @@ export default {
columns.splice(totalIndex, 0, ...dynamicColumns);
return columns;
},
columnSettingOptions() {
return this.displayTableColumns.map(column => ({
prop: column.prop,
label: column.label,
}));
},
visibleTableColumns() {
if (!this.visibleColumnKeys.length) return this.displayTableColumns;
return this.displayTableColumns.filter(column =>
this.visibleColumnKeys.includes(column.prop)
);
},
previewColumns() {
return [...generatePreviewColumns, ...this.dynamicFeeColumns, ...feeDetailTailColumns];
},
@@ -1191,6 +1207,27 @@ export default {
'$route.fullPath'() {
this.openRouteDetail();
},
displayTableColumns: {
immediate: true,
handler(columns) {
const props = columns.map(column => column.prop);
if (!this.visibleColumnKeys.length) {
this.visibleColumnKeys = props;
this.knownColumnProps = [...props];
return;
}
const known = new Set(this.knownColumnProps);
const visible = new Set(this.visibleColumnKeys);
props.forEach(prop => {
if (!known.has(prop)) {
known.add(prop);
visible.add(prop);
}
});
this.knownColumnProps = [...known];
this.visibleColumnKeys = props.filter(prop => visible.has(prop));
},
},
},
async mounted() {
this.loadTransportTypeOptions();
@@ -2664,7 +2701,6 @@ export default {
if (Array.isArray(data?.data?.records)) return data.data.records;
return [];
},
noop() {},
},
};
</script>
@@ -2718,8 +2754,7 @@ export default {
background: transparent;
}
.settlement-detail-page__toolbar-left,
.settlement-detail-page__toolbar-right {
.settlement-detail-page__toolbar-left {
display: flex;
align-items: center;
gap: 8px;
+32 -16
View File
@@ -1,6 +1,6 @@
<template>
<basic-container class="settlement-adjustment-page">
<section class="settlement-adjustment-page__search">
<section v-show="searchVisible" class="settlement-adjustment-page__search">
<el-form :model="query" label-position="right" label-width="88px" @submit.prevent>
<div class="settlement-adjustment-page__search-grid">
<el-form-item v-for="field in visibleSearchFields" :key="field.prop" :label="field.label">
@@ -55,13 +55,22 @@
type="primary"
@click="openCreate"
>新增</el-button
><div class="settlement-adjustment-page__toolbar-right">
<el-tooltip content="刷新" placement="top">
<el-button :icon="Refresh" text @click="loadTable" />
</el-tooltip>
</div>
>
<settlement-table-tools
:columns="columnSettingOptions"
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="序号"
@@ -70,7 +79,7 @@
align="center"
/>
<el-table-column
v-for="column in tableColumns"
v-for="column in visibleTableColumns"
:key="column.prop"
v-bind="column"
align="center"
@@ -165,13 +174,14 @@
</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 api from '@/api/settlement/settlementAdjustment';
import { settlementAdjustmentSearchFields } from '@/option/settlement/settlementAdjustmentSearch';
import organizationSearch from '@/mixins/organization-search';
import { settlementAdjustmentTableColumns } from '@/option/settlement/settlementAdjustmentTable';
import SettlementAdjustmentEditor from './components/settlement-adjustment-editor.vue';
import SettlementTableTools from './components/settlement-table-tools.vue';
import { isAdministrator } from '@/utils/auth';
const emptyQuery = () => ({
@@ -186,17 +196,19 @@ const emptyQuery = () => ({
});
export default {
name: 'SettlementAdjustment',
components: { SettlementAdjustmentEditor },
components: { SettlementAdjustmentEditor, SettlementTableTools },
mixins: [organizationSearch],
data: () => ({
ArrowDown,
ArrowUp,
Refresh,
loading: false,
query: emptyQuery(),
searchFields: settlementAdjustmentSearchFields,
searchExpanded: false,
searchVisible: true,
tableSize: 'default',
tableColumns: settlementAdjustmentTableColumns,
visibleColumnKeys: settlementAdjustmentTableColumns.map(column => column.prop),
rows: [],
selection: [],
page: { current: 1, size: 10, total: 0 },
@@ -207,6 +219,15 @@ export default {
visibleSearchFields() {
return this.searchExpanded ? this.searchFields : this.searchFields.slice(0, 4);
},
columnSettingOptions() {
return this.tableColumns.map(column => ({
prop: column.prop,
label: column.label,
}));
},
visibleTableColumns() {
return this.tableColumns.filter(column => this.visibleColumnKeys.includes(column.prop));
},
isAdmin() {
return isAdministrator(this.userInfo);
},
@@ -359,11 +380,6 @@ export default {
align-items: center;
min-height: 56px;
}
&__toolbar-right {
display: flex;
align-items: center;
gap: 8px;
}
&__links {
display: flex;
flex-wrap: wrap;
@@ -1,6 +1,6 @@
<template>
<basic-container class="reconciliation-page">
<section class="reconciliation-page__search">
<section v-show="searchVisible" class="reconciliation-page__search">
<el-form :model="query" label-position="right" label-width="88px" @submit.prevent>
<div class="reconciliation-page__search-grid">
<el-form-item v-for="field in visibleSearchFields" :key="field.prop" :label="field.label">
@@ -54,6 +54,7 @@
:loading="loading"
:page="page"
:has-permission="hasPermission"
v-model:search-visible="searchVisible"
@create="openCreate"
@export="handleExport"
@refresh="loadTable"
@@ -69,6 +70,7 @@
:loading="loading"
:page="page"
:has-permission="hasPermission"
v-model:search-visible="searchVisible"
@create="openCreate"
@export="handleExport"
@refresh="loadTable"
@@ -91,7 +93,7 @@
</template>
<script>
import { ArrowDown, ArrowUp, Refresh } from '@element-plus/icons-vue';
import { ArrowDown, ArrowUp } from '@element-plus/icons-vue';
import { mapGetters } from 'vuex';
import { downloadFile } from '@/utils/util';
import * as api from '@/api/settlement/transportReconciliation';
@@ -121,9 +123,9 @@ export default {
return {
ArrowDown,
ArrowUp,
Refresh,
query: emptyQuery(),
searchExpanded: false,
searchVisible: true,
searchFields: transportReconciliationSearchFields,
columns: transportReconciliationTableColumns,
settlementType: 'payable',