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

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
+113
View File
@@ -0,0 +1,113 @@
<template>
<div class="avue-crud__right table-header-tools">
<el-button v-if="showRefresh" icon="el-icon-refresh" circle @click="$emit('refresh')" />
<el-button
v-if="showColumn"
icon="el-icon-operation"
circle
@click="columnSettingVisible = true"
/>
<el-button
v-if="showSearch"
icon="el-icon-search"
circle
@click="$emit('update:searchVisible', !searchVisible)"
/>
<el-button v-if="showGrid" icon="el-icon-grid" circle @click="toggleTableSize" />
<el-dialog
v-if="showColumn"
v-model="columnSettingVisible"
title="列设置"
width="360px"
append-to-body
destroy-on-close
>
<el-checkbox-group
class="table-header-tools__column-setting"
:model-value="visibleColumnKeys"
@update:model-value="$emit('update:visibleColumnKeys', $event)"
>
<el-checkbox v-for="item in columns" :key="item.prop" :label="item.prop">
{{ item.label }}
</el-checkbox>
</el-checkbox-group>
<template #footer>
<el-button @click="columnSettingVisible = false">关闭</el-button>
</template>
</el-dialog>
</div>
</template>
<script>
const TABLE_SIZE_OPTIONS = ['default', 'large', 'small'];
export default {
name: 'TableHeaderTools',
props: {
columns: {
type: Array,
default: () => [],
},
visibleColumnKeys: {
type: Array,
default: () => [],
},
tableSize: {
type: String,
default: 'default',
},
searchVisible: {
type: Boolean,
default: true,
},
showRefresh: {
type: Boolean,
default: true,
},
showColumn: {
type: Boolean,
default: true,
},
showSearch: {
type: Boolean,
default: true,
},
showGrid: {
type: Boolean,
default: true,
},
},
emits: ['refresh', 'update:visibleColumnKeys', 'update:tableSize', 'update:searchVisible'],
data() {
return {
columnSettingVisible: false,
};
},
methods: {
toggleTableSize() {
const index = TABLE_SIZE_OPTIONS.indexOf(this.tableSize);
const next = TABLE_SIZE_OPTIONS[(index + 1) % TABLE_SIZE_OPTIONS.length];
this.$emit('update:tableSize', next);
},
},
};
</script>
<style scoped lang="scss">
.table-header-tools.avue-crud__right {
width: auto;
margin: 0 0 0 auto;
flex: none;
white-space: nowrap;
text-align: right;
}
.table-header-tools__column-setting {
display: flex;
flex-direction: column;
gap: 8px;
max-height: 360px;
overflow: auto;
}
</style>
@@ -9,18 +9,21 @@
<el-table :data="rows" border @selection-change="selectedRows = $event"> <el-table :data="rows" border @selection-change="selectedRows = $event">
<el-table-column v-if="!readonly" type="selection" width="55" align="center" /> <el-table-column v-if="!readonly" type="selection" width="55" align="center" />
<el-table-column type="index" label="序号" width="70" align="center" /> <el-table-column type="index" label="序号" width="70" align="center" />
<el-table-column label="文件名" min-width="240" show-overflow-tooltip> <el-table-column
label="文件名"
min-width="240"
show-overflow-tooltip
class-name="is-ellipsis-link"
>
<template #default="{ row }"> <template #default="{ row }">
<span <span
class="vehicle-attachment-table__file-name" class="attachment-file-name"
role="button" role="button"
tabindex="0" tabindex="0"
@click="previewAttachment(row)" @click="previewAttachment(row)"
@keydown.enter="previewAttachment(row)" @keydown.enter="previewAttachment(row)"
@keydown.space.prevent="previewAttachment(row)" @keydown.space.prevent="previewAttachment(row)"
> >{{ attachmentName(row) }}</span>
{{ attachmentName(row) }}
</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="附件描述" min-width="220"> <el-table-column label="附件描述" min-width="220">
@@ -308,16 +311,6 @@ export default {
margin-bottom: 16px; margin-bottom: 16px;
} }
&__file-name {
color: #409eff;
cursor: pointer;
}
&__file-name:hover,
&__file-name:focus-visible {
text-decoration: underline;
}
&__upload { &__upload {
display: flex; display: flex;
justify-content: flex-start; justify-content: flex-start;
+30 -3
View File
@@ -1003,7 +1003,7 @@ td.el-table-fixed-column--right {
text-overflow: clip; text-overflow: clip;
} }
// 全站统一:内容型长文本列(文件名 / 单号 / 备注等)单元格内也放了 el-link, // 全站统一:内容型长文本列(文件名 / 单号 / 备注等)单元格内也放了 el-link / span.attachment-file-name,
// 会被上面两条「含 el-link 的单元格」规则一并命中,导致: // 会被上面两条「含 el-link 的单元格」规则一并命中,导致:
// ① 上面第 950 行的 display: flex 让链接成为 flex item,flex item 默认 min-width: auto 无法收缩, // ① 上面第 950 行的 display: flex 让链接成为 flex item,flex item 默认 min-width: auto 无法收缩,
// 超长文本(如未规范命名的附件名)会直接把列撑破; // 超长文本(如未规范命名的附件名)会直接把列撑破;
@@ -1011,7 +1011,7 @@ td.el-table-fixed-column--right {
// 因此对「内容列」做显式兜底:单元格自身恢复块级 + 省略号截断,链接参与收缩并显示省略号。 // 因此对「内容列」做显式兜底:单元格自身恢复块级 + 省略号截断,链接参与收缩并显示省略号。
// 用法:在 <el-table-column> 上配置 class-name="is-ellipsis-link"(动态列可 :class-name 绑定)。 // 用法:在 <el-table-column> 上配置 class-name="is-ellipsis-link"(动态列可 :class-name 绑定)。
// 操作列不要加此类,否则会失去自动换行能力。 // 操作列不要加此类,否则会失去自动换行能力。
.el-table .el-table__body .cell.is-ellipsis-link:has(.el-link) { .el-table .el-table__body .cell.is-ellipsis-link {
display: block; display: block;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
@@ -1034,6 +1034,33 @@ td.el-table-fixed-column--right {
white-space: nowrap; white-space: nowrap;
} }
} }
.attachment-file-name {
display: inline-block;
min-width: 0;
max-width: 100%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
vertical-align: middle;
}
}
// 附件上传表格:文件名统一用 span,视觉与可点击行为对齐原 el-link primary
.attachment-file-name {
color: var(--el-color-primary, #409eff);
cursor: pointer;
&:hover,
&:focus-visible {
text-decoration: underline;
}
&.is-disabled {
color: var(--el-text-color-placeholder, #c0c4cc);
cursor: not-allowed;
text-decoration: none;
}
} }
// 全站统一:Avue 内置行操作按钮(查看 / 编辑 / 删除 / 复制等)视觉对齐为 el-link 链接样式。 // 全站统一:Avue 内置行操作按钮(查看 / 编辑 / 删除 / 复制等)视觉对齐为 el-link 链接样式。
@@ -1294,6 +1321,6 @@ td.el-table-fixed-column--right {
cursor: not-allowed; cursor: not-allowed;
} }
} }
.is-ellipsis-link{ .is-ellipsis-link {
overflow: hidden; overflow: hidden;
} }
@@ -2073,9 +2073,14 @@
class-name="is-ellipsis-link" class-name="is-ellipsis-link"
> >
<template #default="{ row }"> <template #default="{ row }">
<el-link type="primary" @click="previewAttachment(row)"> <span
{{ row.originalName || row.name }} class="attachment-file-name"
</el-link> role="button"
tabindex="0"
@click="previewAttachment(row)"
@keydown.enter="previewAttachment(row)"
@keydown.space.prevent="previewAttachment(row)"
>{{ row.originalName || row.name }}</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="附件描述" min-width="220" align="center"> <el-table-column label="附件描述" min-width="220" align="center">
@@ -2344,14 +2349,16 @@
<div class="business-crud-page__transport-plan-detail-field is-attachments"> <div class="business-crud-page__transport-plan-detail-field is-attachments">
<span>附件</span> <span>附件</span>
<div class="business-crud-page__transport-plan-detail-attachments"> <div class="business-crud-page__transport-plan-detail-attachments">
<el-link <span
v-for="file in attachmentRows" v-for="file in attachmentRows"
:key="file.url || file.name || file.originalName" :key="file.url || file.name || file.originalName"
type="primary" class="attachment-file-name"
role="button"
tabindex="0"
@click="previewAttachment(file)" @click="previewAttachment(file)"
> @keydown.enter="previewAttachment(file)"
{{ attachmentName(file) }} @keydown.space.prevent="previewAttachment(file)"
</el-link> >{{ attachmentName(file) }}</span>
<span v-if="!attachmentRows.length">-</span> <span v-if="!attachmentRows.length">-</span>
</div> </div>
</div> </div>
@@ -2537,14 +2544,16 @@
<div class="business-crud-page__waybill-attachments"> <div class="business-crud-page__waybill-attachments">
<span class="business-crud-page__waybill-label">附件</span> <span class="business-crud-page__waybill-label">附件</span>
<div> <div>
<el-link <span
v-for="file in attachmentRows" v-for="file in attachmentRows"
:key="file.url || file.name || file.originalName" :key="file.url || file.name || file.originalName"
type="primary" class="attachment-file-name"
role="button"
tabindex="0"
@click="previewAttachment(file)" @click="previewAttachment(file)"
> @keydown.enter="previewAttachment(file)"
{{ file.originalName || file.name || '-' }} @keydown.space.prevent="previewAttachment(file)"
</el-link> >{{ file.originalName || file.name || '-' }}</span>
<span v-if="!attachmentRows.length">-</span> <span v-if="!attachmentRows.length">-</span>
</div> </div>
</div> </div>
@@ -2826,11 +2835,21 @@
</div> </div>
<el-table :data="attachmentRows" empty-text="暂无附件"> <el-table :data="attachmentRows" empty-text="暂无附件">
<el-table-column type="index" label="序号" width="70" align="center" /> <el-table-column type="index" label="序号" width="70" align="center" />
<el-table-column label="文件名" min-width="260"> <el-table-column
label="文件名"
min-width="260"
show-overflow-tooltip
class-name="is-ellipsis-link"
>
<template #default="{ row }"> <template #default="{ row }">
<el-link type="primary" @click="previewAttachment(row)"> <span
{{ attachmentName(row) }} class="attachment-file-name"
</el-link> role="button"
tabindex="0"
@click="previewAttachment(row)"
@keydown.enter="previewAttachment(row)"
@keydown.space.prevent="previewAttachment(row)"
>{{ attachmentName(row) }}</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column <el-table-column
@@ -4239,9 +4258,14 @@
class-name="is-ellipsis-link" class-name="is-ellipsis-link"
> >
<template #default="{ row }"> <template #default="{ row }">
<el-link type="primary" @click="previewAttachment(row, dispatchItemAttachmentRows)"> <span
{{ attachmentName(row) }} class="attachment-file-name"
</el-link> role="button"
tabindex="0"
@click="previewAttachment(row, dispatchItemAttachmentRows)"
@keydown.enter="previewAttachment(row, dispatchItemAttachmentRows)"
@keydown.space.prevent="previewAttachment(row, dispatchItemAttachmentRows)"
>{{ attachmentName(row) }}</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="附件描述" min-width="220" align="center"> <el-table-column label="附件描述" min-width="220" align="center">
@@ -48,9 +48,14 @@
class-name="is-ellipsis-link" class-name="is-ellipsis-link"
> >
<template #default="{ row }"> <template #default="{ row }">
<el-link type="primary" @click="preview?.(row, rows)">{{ <span
attachmentName(row) class="attachment-file-name"
}}</el-link> role="button"
tabindex="0"
@click="preview?.(row, rows)"
@keydown.enter="preview?.(row, rows)"
@keydown.space.prevent="preview?.(row, rows)"
>{{ attachmentName(row) }}</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column v-if="description" label="附件描述" min-width="220"> <el-table-column v-if="description" label="附件描述" min-width="220">
@@ -44,13 +44,16 @@
<dt>附件</dt> <dt>附件</dt>
<dd> <dd>
<template v-if="attachments.length"> <template v-if="attachments.length">
<el-link <span
v-for="file in attachments" v-for="file in attachments"
:key="file.url || file.link || file.name || file.originalName" :key="file.url || file.link || file.name || file.originalName"
type="primary" class="attachment-file-name"
role="button"
tabindex="0"
@click="previewAttachment(file)" @click="previewAttachment(file)"
>{{ attachmentName(file) }}</el-link @keydown.enter="previewAttachment(file)"
> @keydown.space.prevent="previewAttachment(file)"
>{{ attachmentName(file) }}</span>
</template> </template>
<span v-else>-</span> <span v-else>-</span>
</dd> </dd>
@@ -330,7 +333,7 @@ export default {
.transport-flow-tag { .transport-flow-tag {
margin-left: 8px; margin-left: 8px;
} }
.detail-meta { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 18px 24px; margin: 0; padding: 0 24px 20px; dt { margin-bottom: 6px; color: #909399; font-size: 13px; } dd { display: flex; flex-wrap: wrap; gap: 8px 16px; margin: 0; color: #303133; font-size: 14px; word-break: break-all; } :deep(.el-link) { font-size: 14px; } } .detail-meta { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 18px 24px; margin: 0; padding: 0 24px 20px; dt { margin-bottom: 6px; color: #909399; font-size: 13px; } dd { display: flex; flex-wrap: wrap; gap: 8px 16px; margin: 0; color: #303133; font-size: 14px; word-break: break-all; } .attachment-file-name { font-size: 14px; max-width: 100%; } }
.route-map { display: flex; align-items: flex-start; padding: 16px 24px 20px; border-top: 1px solid #eff1f7; overflow-x: auto; } .route-map { display: flex; align-items: flex-start; padding: 16px 24px 20px; border-top: 1px solid #eff1f7; overflow-x: auto; }
.route-map__node { display: grid; flex: 0 0 150px; justify-items: center; gap: 6px; text-align: center; strong { font-size: 16px; white-space: nowrap; } small { color: #606266; white-space: nowrap; } } .route-map__node { display: grid; flex: 0 0 150px; justify-items: center; gap: 6px; text-align: center; strong { font-size: 16px; white-space: nowrap; } small { color: #606266; white-space: nowrap; } }
.route-map__progress { color: #303133 !important; } .route-map__progress { color: #303133 !important; }
@@ -269,9 +269,14 @@
class-name="is-ellipsis-link" class-name="is-ellipsis-link"
> >
<template #default="{ row }"> <template #default="{ row }">
<el-link type="primary" @click="previewAttachment(row)"> <span
{{ attachmentName(row) }} class="attachment-file-name"
</el-link> role="button"
tabindex="0"
@click="previewAttachment(row)"
@keydown.enter="previewAttachment(row)"
@keydown.space.prevent="previewAttachment(row)"
>{{ attachmentName(row) }}</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="附件描述" min-width="220" align="center"> <el-table-column label="附件描述" min-width="220" align="center">
@@ -454,11 +454,20 @@
> >
<el-table-column type="selection" width="55" /> <el-table-column type="selection" width="55" />
<el-table-column type="index" label="序号" width="70" /> <el-table-column type="index" label="序号" width="70" />
<el-table-column label="文件名" min-width="220" <el-table-column
label="文件名"
min-width="220"
show-overflow-tooltip
class-name="is-ellipsis-link"
><template #default="{ row }" ><template #default="{ row }"
><el-link type="primary" @click="previewAttachment(row)">{{ ><span
attachmentName(row) class="attachment-file-name"
}}</el-link></template 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
> >
<el-table-column label="附件描述" min-width="220" <el-table-column label="附件描述" min-width="220"
@@ -721,11 +730,21 @@
</div> </div>
<el-table :data="detailAttachmentRows" border empty-text="暂无附件"> <el-table :data="detailAttachmentRows" border empty-text="暂无附件">
<el-table-column type="index" label="序号" width="70" /> <el-table-column type="index" label="序号" width="70" />
<el-table-column label="文件名" min-width="220"> <el-table-column
label="文件名"
min-width="220"
show-overflow-tooltip
class-name="is-ellipsis-link"
>
<template #default="{ row }"> <template #default="{ row }">
<el-link type="primary" @click="previewAttachment(row)">{{ <span
attachmentName(row) class="attachment-file-name"
}}</el-link> role="button"
tabindex="0"
@click="previewAttachment(row)"
@keydown.enter="previewAttachment(row)"
@keydown.space.prevent="previewAttachment(row)"
>{{ attachmentName(row) }}</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="附件描述" min-width="220"> <el-table-column label="附件描述" min-width="220">
@@ -500,9 +500,14 @@
class-name="is-ellipsis-link" class-name="is-ellipsis-link"
> >
<template #default="{ row }"> <template #default="{ row }">
<el-link type="primary" @click="previewAttachment(row)"> <span
{{ row.originalName || row.name }} class="attachment-file-name"
</el-link> role="button"
tabindex="0"
@click="previewAttachment(row)"
@keydown.enter="previewAttachment(row)"
@keydown.space.prevent="previewAttachment(row)"
>{{ row.originalName || row.name }}</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="附件描述" min-width="220" align="center"> <el-table-column label="附件描述" min-width="220" align="center">
@@ -679,14 +684,16 @@
<div class="transport-plan-page__transport-plan-detail-field is-attachments"> <div class="transport-plan-page__transport-plan-detail-field is-attachments">
<span>附件</span> <span>附件</span>
<div class="transport-plan-page__transport-plan-detail-attachments"> <div class="transport-plan-page__transport-plan-detail-attachments">
<el-link <span
v-for="file in attachmentRows" v-for="file in attachmentRows"
:key="file.url || file.name || file.originalName" :key="file.url || file.name || file.originalName"
type="primary" class="attachment-file-name"
role="button"
tabindex="0"
@click="previewAttachment(file)" @click="previewAttachment(file)"
> @keydown.enter="previewAttachment(file)"
{{ attachmentName(file) }} @keydown.space.prevent="previewAttachment(file)"
</el-link> >{{ attachmentName(file) }}</span>
<span v-if="!attachmentRows.length">-</span> <span v-if="!attachmentRows.length">-</span>
</div> </div>
</div> </div>
@@ -861,11 +868,21 @@
</div> </div>
<el-table :data="attachmentRows" empty-text="暂无附件"> <el-table :data="attachmentRows" empty-text="暂无附件">
<el-table-column type="index" label="序号" width="70" align="center" /> <el-table-column type="index" label="序号" width="70" align="center" />
<el-table-column label="文件名" min-width="260"> <el-table-column
label="文件名"
min-width="260"
show-overflow-tooltip
class-name="is-ellipsis-link"
>
<template #default="{ row }"> <template #default="{ row }">
<el-link type="primary" @click="previewAttachment(row)"> <span
{{ attachmentName(row) }} class="attachment-file-name"
</el-link> role="button"
tabindex="0"
@click="previewAttachment(row)"
@keydown.enter="previewAttachment(row)"
@keydown.space.prevent="previewAttachment(row)"
>{{ attachmentName(row) }}</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column <el-table-column
@@ -2215,9 +2232,14 @@
class-name="is-ellipsis-link" class-name="is-ellipsis-link"
> >
<template #default="{ row }"> <template #default="{ row }">
<el-link type="primary" @click="previewAttachment(row, dispatchItemAttachmentRows)"> <span
{{ attachmentName(row) }} class="attachment-file-name"
</el-link> role="button"
tabindex="0"
@click="previewAttachment(row, dispatchItemAttachmentRows)"
@keydown.enter="previewAttachment(row, dispatchItemAttachmentRows)"
@keydown.space.prevent="previewAttachment(row, dispatchItemAttachmentRows)"
>{{ attachmentName(row) }}</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="附件描述" min-width="220" align="center"> <el-table-column label="附件描述" min-width="220" align="center">
@@ -1481,9 +1481,14 @@
class-name="is-ellipsis-link" class-name="is-ellipsis-link"
> >
<template #default="{ row }"> <template #default="{ row }">
<el-link type="primary" @click="previewAttachment(row)"> <span
{{ row.originalName || row.name }} class="attachment-file-name"
</el-link> role="button"
tabindex="0"
@click="previewAttachment(row)"
@keydown.enter="previewAttachment(row)"
@keydown.space.prevent="previewAttachment(row)"
>{{ row.originalName || row.name }}</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="附件描述" min-width="220" align="center"> <el-table-column label="附件描述" min-width="220" align="center">
@@ -1864,14 +1869,16 @@
<div class="waybill-manage-page__waybill-attachments"> <div class="waybill-manage-page__waybill-attachments">
<span class="waybill-manage-page__waybill-label">附件</span> <span class="waybill-manage-page__waybill-label">附件</span>
<div> <div>
<el-link <span
v-for="file in attachmentRows" v-for="file in attachmentRows"
:key="file.url || file.name || file.originalName" :key="file.url || file.name || file.originalName"
type="primary" class="attachment-file-name"
role="button"
tabindex="0"
@click="previewAttachment(file)" @click="previewAttachment(file)"
> @keydown.enter="previewAttachment(file)"
{{ file.originalName || file.name || '-' }} @keydown.space.prevent="previewAttachment(file)"
</el-link> >{{ file.originalName || file.name || '-' }}</span>
<span v-if="!attachmentRows.length">-</span> <span v-if="!attachmentRows.length">-</span>
</div> </div>
</div> </div>
+26 -2
View File
@@ -106,6 +106,7 @@
placeholder="请输入" placeholder="请输入"
clearable clearable
@input="handleContractAmountInput" @input="handleContractAmountInput"
@blur="formatContractAmountField"
@clear="form.contractAmount = null" @clear="form.contractAmount = null"
/> />
</el-form-item> </el-form-item>
@@ -386,6 +387,19 @@ const normalizeOptionalAmount = value => {
const number = Number(value); const number = Number(value);
return Number.isFinite(number) && number >= 0 ? Number(number.toFixed(2)) : null; return Number.isFinite(number) && number >= 0 ? Number(number.toFixed(2)) : null;
}; };
const formatContractAmountInput = (value, emptyValue = null) => {
if (
value === undefined ||
value === null ||
value === '' ||
Number(value) === -1 ||
String(value) === '-1'
) {
return emptyValue;
}
const number = Number(value);
return Number.isFinite(number) && number >= 0 ? number.toFixed(2) : emptyValue;
};
const normalizeCustomPeriods = (periods = []) => const normalizeCustomPeriods = (periods = []) =>
@@ -541,6 +555,9 @@ export default {
parts.length > 1 ? `${parts[0]}.${parts.slice(1).join('').slice(0, 2)}` : parts[0]; parts.length > 1 ? `${parts[0]}.${parts.slice(1).join('').slice(0, 2)}` : parts[0];
this.form.contractAmount = normalized === '' ? null : normalized; this.form.contractAmount = normalized === '' ? null : normalized;
}, },
formatContractAmountField() {
this.form.contractAmount = formatContractAmountInput(this.form.contractAmount);
},
loadDictionaries() { loadDictionaries() {
Promise.all([ Promise.all([
getSystemDictionary({ code: 'currency_type' }), getSystemDictionary({ code: 'currency_type' }),
@@ -583,7 +600,7 @@ export default {
copyCount: normalizeOptionalPositiveInteger(data.copyCount), copyCount: normalizeOptionalPositiveInteger(data.copyCount),
invoiceCycle: normalizeOptionalPositiveInteger(data.invoiceCycle), invoiceCycle: normalizeOptionalPositiveInteger(data.invoiceCycle),
paymentDays: normalizeOptionalPositiveInteger(data.paymentDays), paymentDays: normalizeOptionalPositiveInteger(data.paymentDays),
contractAmount: normalizeOptionalAmount(data.contractAmount), contractAmount: formatContractAmountInput(data.contractAmount),
templateFlag: data.templateFlag ?? 0, templateFlag: data.templateFlag ?? 0,
electronicSealFlag: data.electronicSealFlag ?? 0, electronicSealFlag: data.electronicSealFlag ?? 0,
archiveStatus: data.archiveStatus || '未归档', archiveStatus: data.archiveStatus || '未归档',
@@ -735,7 +752,14 @@ export default {
.contract-basic-section > .dialog-section-title { margin-bottom: 20px; color: #303133; } .contract-basic-section > .dialog-section-title { margin-bottom: 20px; color: #303133; }
.contract-basic-section__grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); column-gap: 48px; } .contract-basic-section__grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); column-gap: 48px; }
.contract-basic-section__change-type { grid-column: 1 / -1; } .contract-basic-section__change-type { grid-column: 1 / -1; }
.contract-basic-section__remark { width: 100%; margin-bottom: 0 !important; } .contract-basic-section__remark {
width: 100%;
margin-bottom: 24px !important;
&:last-child {
margin-bottom: 0 !important;
}
}
.contract-basic-section__date-range { display: grid; grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr); align-items: center; gap: 8px; width: 360px; max-width: 100%; } .contract-basic-section__date-range { display: grid; grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr); align-items: center; gap: 8px; width: 360px; max-width: 100%; }
.contract-basic-section__date-range span { color: #606266; } .contract-basic-section__date-range span { color: #606266; }
.contract-basic-section__date-range :deep(.el-date-editor) { width: auto; min-width: 0; } .contract-basic-section__date-range :deep(.el-date-editor) { width: auto; min-width: 0; }
+25 -9
View File
@@ -525,6 +525,7 @@
placeholder="请输入" placeholder="请输入"
clearable clearable
@input="handleContractAmountInput" @input="handleContractAmountInput"
@blur="formatContractAmountField"
@clear="form.contractAmount = null" @clear="form.contractAmount = null"
/> />
</el-form-item> </el-form-item>
@@ -1098,6 +1099,19 @@ const normalizeOptionalAmount = (value, emptyValue = null) => {
const number = Number(value); const number = Number(value);
return Number.isFinite(number) && number >= 0 ? Number(number.toFixed(2)) : emptyValue; return Number.isFinite(number) && number >= 0 ? Number(number.toFixed(2)) : emptyValue;
}; };
const formatContractAmountInput = (value, emptyValue = null) => {
if (
value === undefined ||
value === null ||
value === '' ||
Number(value) === -1 ||
String(value) === '-1'
) {
return emptyValue;
}
const number = Number(value);
return Number.isFinite(number) && number >= 0 ? number.toFixed(2) : emptyValue;
};
const normalizeProjectValue = value => { const normalizeProjectValue = value => {
if (value === undefined || value === null || value === '' || String(value) === '-1') return ''; if (value === undefined || value === null || value === '' || String(value) === '-1') return '';
return value; return value;
@@ -1794,7 +1808,7 @@ export default {
copyCount: normalizeOptionalInteger(detail.copyCount, ''), copyCount: normalizeOptionalInteger(detail.copyCount, ''),
invoiceCycle: normalizeOptionalInteger(detail.invoiceCycle, ''), invoiceCycle: normalizeOptionalInteger(detail.invoiceCycle, ''),
paymentDays: normalizeOptionalInteger(detail.paymentDays, ''), paymentDays: normalizeOptionalInteger(detail.paymentDays, ''),
contractAmount: normalizeOptionalAmount(detail.contractAmount, null), contractAmount: formatContractAmountInput(detail.contractAmount, null),
archiveStatus: detail.archiveStatus || '未归档', archiveStatus: detail.archiveStatus || '未归档',
feeGenerationMode: feeGenerationMode:
detail.feeGenerationMode || (Number(detail.billingEnabled) === 0 ? 'manual' : 'system'), detail.feeGenerationMode || (Number(detail.billingEnabled) === 0 ? 'manual' : 'system'),
@@ -2356,6 +2370,9 @@ export default {
parts.length > 1 ? `${parts[0]}.${parts.slice(1).join('').slice(0, 2)}` : parts[0]; parts.length > 1 ? `${parts[0]}.${parts.slice(1).join('').slice(0, 2)}` : parts[0];
this.form.contractAmount = normalized === '' ? null : normalized; this.form.contractAmount = normalized === '' ? null : normalized;
}, },
formatContractAmountField() {
this.form.contractAmount = formatContractAmountInput(this.form.contractAmount, null);
},
positiveIntegerInput(prop, value) { positiveIntegerInput(prop, value) {
const normalized = String(value || '').replace(/\D/g, '').replace(/^0+/, ''); const normalized = String(value || '').replace(/\D/g, '').replace(/^0+/, '');
this.form[prop] = normalized; this.form[prop] = normalized;
@@ -2929,13 +2946,8 @@ export default {
detailValue(prop) { detailValue(prop) {
const value = this.detailRow[prop]; const value = this.detailRow[prop];
if (prop === 'contractAmount') { if (prop === 'contractAmount') {
return value === undefined || const amountText = formatContractAmountInput(value, '');
value === null || return amountText === '' ? '-' : amountText;
value === '' ||
Number(value) === -1 ||
String(value) === '-1'
? '-'
: value;
} }
if ( if (
prop === 'contractStage' || prop === 'contractStage' ||
@@ -3248,7 +3260,11 @@ export default {
&__remark { &__remark {
width: 100%; width: 100%;
margin-bottom: 0 !important; margin-bottom: 24px !important;
&:last-child {
margin-bottom: 0 !important;
}
} }
&__date-range { &__date-range {
+135 -40
View File
@@ -1,6 +1,6 @@
<template> <template>
<basic-container class="loading-manage-page"> <basic-container class="loading-manage-page">
<div v-if="!isStandalonePage" class="loading-manage-page__search"> <div v-if="!isStandalonePage && searchVisible" class="loading-manage-page__search">
<el-form :model="searchForm" label-position="right" label-width="88px"> <el-form :model="searchForm" label-position="right" label-width="88px">
<div class="loading-manage-page__search-grid"> <div class="loading-manage-page__search-grid">
<el-form-item label="配载单号"> <el-form-item label="配载单号">
@@ -228,17 +228,13 @@
<el-button type="primary" plain @click="handleExport">批量导出</el-button> <el-button type="primary" plain @click="handleExport">批量导出</el-button>
<el-button type="primary" plain @click="handleBatchComplete">批量完成</el-button> <el-button type="primary" plain @click="handleBatchComplete">批量完成</el-button>
</div> </div>
<div class="loading-manage-page__toolbar-right"> <table-header-tools
<el-tooltip content="刷新" placement="top"> :columns="columnSettingOptions"
<el-button :icon="Refresh" text @click="loadTable" /> v-model:visible-column-keys="visibleColumnKeys"
</el-tooltip> v-model:table-size="tableSize"
<el-tooltip content="表格密度" placement="top"> v-model:search-visible="searchVisible"
<el-button :icon="Rank" text @click="toggleTableSize" /> @refresh="loadTable"
</el-tooltip> />
<el-tooltip content="列设置" placement="top">
<el-button :icon="Setting" text @click="handleColumnSetting" />
</el-tooltip>
</div>
</div> </div>
<el-table <el-table
@@ -254,7 +250,12 @@
> >
<el-table-column type="selection" width="52" fixed="left" align="center" /> <el-table-column type="selection" width="52" fixed="left" align="center" />
<el-table-column type="index" label="序号" width="58" fixed="left" align="center" /> <el-table-column type="index" label="序号" width="58" fixed="left" align="center" />
<el-table-column label="配载单号" prop="loadingNo" min-width="170"> <el-table-column
v-if="isColumnVisible('loadingNo')"
label="配载单号"
prop="loadingNo"
min-width="170"
>
<template #default="{ row }"> <template #default="{ row }">
<el-link <el-link
type="primary" type="primary"
@@ -264,7 +265,12 @@
> >
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="运单号" prop="loadingSubNos" min-width="220"> <el-table-column
v-if="isColumnVisible('loadingSubNos')"
label="运单号"
prop="loadingSubNos"
min-width="220"
>
<template #default="{ row }"> <template #default="{ row }">
<span class="loading-manage-page__sub-nos"> <span class="loading-manage-page__sub-nos">
<template v-if="splitText(row.loadingSubNos).length"> <template v-if="splitText(row.loadingSubNos).length">
@@ -283,11 +289,40 @@
</span> </span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="车牌号" prop="vehicleNo" min-width="170" show-overflow-tooltip /> <el-table-column
<el-table-column label="司机" prop="driverName" min-width="120" show-overflow-tooltip /> v-if="isColumnVisible('vehicleNo')"
<el-table-column label="联系电话" prop="driverPhone" min-width="140" show-overflow-tooltip /> label="车牌号"
<el-table-column label="承运类型" prop="carrierType" min-width="120" show-overflow-tooltip /> prop="vehicleNo"
<el-table-column label="发货地" prop="departureAddress" min-width="180"> min-width="170"
show-overflow-tooltip
/>
<el-table-column
v-if="isColumnVisible('driverName')"
label="司机"
prop="driverName"
min-width="120"
show-overflow-tooltip
/>
<el-table-column
v-if="isColumnVisible('driverPhone')"
label="联系电话"
prop="driverPhone"
min-width="140"
show-overflow-tooltip
/>
<el-table-column
v-if="isColumnVisible('carrierType')"
label="承运类型"
prop="carrierType"
min-width="120"
show-overflow-tooltip
/>
<el-table-column
v-if="isColumnVisible('departureAddress')"
label="发货地"
prop="departureAddress"
min-width="180"
>
<template #default="{ row }"> <template #default="{ row }">
<el-tooltip <el-tooltip
v-if="formatFullRouteAddress(row, 'departure')" v-if="formatFullRouteAddress(row, 'departure')"
@@ -304,7 +339,12 @@
</div> </div>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="途经地" prop="transitAddress" min-width="190"> <el-table-column
v-if="isColumnVisible('transitAddress')"
label="途经地"
prop="transitAddress"
min-width="190"
>
<template #default="{ row }"> <template #default="{ row }">
<el-tooltip <el-tooltip
v-if="formatFullRouteAddress(row, 'transit')" v-if="formatFullRouteAddress(row, 'transit')"
@@ -321,7 +361,12 @@
</div> </div>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="到货地" prop="arrivalAddress" min-width="180"> <el-table-column
v-if="isColumnVisible('arrivalAddress')"
label="到货地"
prop="arrivalAddress"
min-width="180"
>
<template #default="{ row }"> <template #default="{ row }">
<el-tooltip <el-tooltip
v-if="formatFullRouteAddress(row, 'arrival')" v-if="formatFullRouteAddress(row, 'arrival')"
@@ -338,20 +383,40 @@
</div> </div>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="承运商" prop="carrierName" min-width="160" show-overflow-tooltip /> <el-table-column
<el-table-column label="运输方式" prop="transportType" min-width="150" show-overflow-tooltip> v-if="isColumnVisible('carrierName')"
label="承运商"
prop="carrierName"
min-width="160"
show-overflow-tooltip
/>
<el-table-column
v-if="isColumnVisible('transportType')"
label="运输方式"
prop="transportType"
min-width="150"
show-overflow-tooltip
>
<template #default="{ row }"> <template #default="{ row }">
{{ transportTypeLabel(row.transportType) }} {{ transportTypeLabel(row.transportType) }}
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="数据来源" prop="dataSource" min-width="130" show-overflow-tooltip />
<el-table-column <el-table-column
v-if="isColumnVisible('dataSource')"
label="数据来源"
prop="dataSource"
min-width="130"
show-overflow-tooltip
/>
<el-table-column
v-if="isColumnVisible('createUserName')"
label="创建人" label="创建人"
prop="createUserName" prop="createUserName"
min-width="120" min-width="120"
show-overflow-tooltip show-overflow-tooltip
/> />
<el-table-column <el-table-column
v-if="isColumnVisible('createTime')"
label="创建时间" label="创建时间"
prop="createTime" prop="createTime"
min-width="170" min-width="170"
@@ -359,6 +424,7 @@
sortable sortable
/> />
<el-table-column <el-table-column
v-if="isColumnVisible('updateTime')"
label="更新时间" label="更新时间"
prop="updateTime" prop="updateTime"
min-width="170" min-width="170"
@@ -366,12 +432,20 @@
sortable sortable
/> />
<el-table-column <el-table-column
v-if="isColumnVisible('currentProcessNode')"
label="过程节点" label="过程节点"
prop="currentProcessNode" prop="currentProcessNode"
min-width="130" min-width="130"
show-overflow-tooltip show-overflow-tooltip
/> />
<el-table-column label="状态" prop="businessStatus" width="110" fixed="right" align="center"> <el-table-column
v-if="isColumnVisible('businessStatus')"
label="状态"
prop="businessStatus"
width="110"
fixed="right"
align="center"
>
<template #default="{ row }"> <template #default="{ row }">
<span :class="['loading-manage-page__status', `is-${row.businessStatus || 'unknown'}`]"> <span :class="['loading-manage-page__status', `is-${row.businessStatus || 'unknown'}`]">
{{ statusText(row) }} {{ statusText(row) }}
@@ -484,12 +558,16 @@
<div class="loading-detail__field loading-detail__attachment-field"> <div class="loading-detail__field loading-detail__attachment-field">
<span class="loading-detail__label">附件</span> <span class="loading-detail__label">附件</span>
<span class="loading-detail__value" <span class="loading-detail__value"
><el-link ><span
v-for="file in detailAttachments" v-for="file in detailAttachments"
:key="file.url || file.name" :key="file.url || file.name"
type="primary" class="attachment-file-name"
role="button"
tabindex="0"
@click="previewAttachment(file)" @click="previewAttachment(file)"
>{{ file.name }}</el-link @keydown.enter="previewAttachment(file)"
@keydown.space.prevent="previewAttachment(file)"
>{{ file.name }}</span
><span v-if="!detailAttachments.length">-</span></span ><span v-if="!detailAttachments.length">-</span></span
> >
</div> </div>
@@ -1720,7 +1798,8 @@ import {
} from '@/option/business/loading-manage'; } from '@/option/business/loading-manage';
import { option as waybillOption } from '@/option/business/waybill-manage'; import { option as waybillOption } from '@/option/business/waybill-manage';
import { ElMessage, ElMessageBox } from 'element-plus'; import { ElMessage, ElMessageBox } from 'element-plus';
import { Location, Rank, Refresh, Search, Setting } from '@element-plus/icons-vue'; import { Location, Rank, Search } from '@element-plus/icons-vue';
import TableHeaderTools from '@/components/table-header-tools/main.vue';
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import { isMobile } from '@/utils/validate'; import { isMobile } from '@/utils/validate';
import { normalizeMapSearchResults, searchAmapPlaceText } from '@/utils/map-search'; import { normalizeMapSearchResults, searchAmapPlaceText } from '@/utils/map-search';
@@ -1917,10 +1996,31 @@ const uniqueText = (rows, prop) =>
), ),
].join('、'); ].join('、');
const LOADING_TABLE_COLUMNS = [
{ prop: 'loadingNo', label: '配载单号' },
{ prop: 'loadingSubNos', label: '运单号' },
{ prop: 'vehicleNo', label: '车牌号' },
{ prop: 'driverName', label: '司机' },
{ prop: 'driverPhone', label: '联系电话' },
{ prop: 'carrierType', label: '承运类型' },
{ prop: 'departureAddress', label: '发货地' },
{ prop: 'transitAddress', label: '途经地' },
{ prop: 'arrivalAddress', label: '到货地' },
{ prop: 'carrierName', label: '承运商' },
{ prop: 'transportType', label: '运输方式' },
{ prop: 'dataSource', label: '数据来源' },
{ prop: 'createUserName', label: '创建人' },
{ prop: 'createTime', label: '创建时间' },
{ prop: 'updateTime', label: '更新时间' },
{ prop: 'currentProcessNode', label: '过程节点' },
{ prop: 'businessStatus', label: '状态' },
];
export default { export default {
components: { components: {
Rank, Rank,
Search, Search,
TableHeaderTools,
VoucherExecutionDetail, VoucherExecutionDetail,
PunchRecordPhotos, PunchRecordPhotos,
}, },
@@ -1928,11 +2028,12 @@ export default {
return { return {
Rank, Rank,
Location, Location,
Refresh,
Search, Search,
Setting,
loading: false, loading: false,
tableSize: 'default', tableSize: 'default',
searchVisible: true,
columnSettingOptions: LOADING_TABLE_COLUMNS,
visibleColumnKeys: LOADING_TABLE_COLUMNS.map(column => column.prop),
tableData: [], tableData: [],
page: { page: {
currentPage: 1, currentPage: 1,
@@ -2247,13 +2348,8 @@ export default {
selectionChange(rows) { selectionChange(rows) {
this.selectionRows = rows || []; this.selectionRows = rows || [];
}, },
toggleTableSize() { isColumnVisible(prop) {
const order = ['default', 'small', 'large']; return this.visibleColumnKeys.includes(prop);
const index = order.indexOf(this.tableSize);
this.tableSize = order[(index + 1) % order.length];
},
handleColumnSetting() {
ElMessage.info('列设置按原型保留入口,当前默认展示全部列表字段');
}, },
statusText(row) { statusText(row) {
return row.businessStatusName || loadingStatusMap[row.businessStatus] || '未知'; return row.businessStatusName || loadingStatusMap[row.businessStatus] || '未知';
@@ -4472,8 +4568,7 @@ export default {
margin: 12px 0; margin: 12px 0;
} }
.loading-manage-page__toolbar-left, .loading-manage-page__toolbar-left {
.loading-manage-page__toolbar-right {
display: flex; display: flex;
align-items: center; align-items: center;
gap: 12px; gap: 12px;
+24 -4
View File
@@ -1,7 +1,7 @@
<template> <template>
<basic-container class="master-order-page"> <basic-container class="master-order-page">
<template v-if="mode === 'list'"> <template v-if="mode === 'list'">
<div class="master-order-page__search"> <div v-show="searchVisible" class="master-order-page__search">
<el-form :model="query" label-position="right" label-width="88px" @submit.prevent> <el-form :model="query" label-position="right" label-width="88px" @submit.prevent>
<div class="master-order-page__search-grid"> <div class="master-order-page__search-grid">
<el-form-item v-for="field in primaryFields" :key="field.prop" :label="field.label"> <el-form-item v-for="field in primaryFields" :key="field.prop" :label="field.label">
@@ -55,8 +55,16 @@
</div> </div>
<section class="master-list-panel"> <section class="master-list-panel">
<div class="toolbar"> <div class="toolbar">
<el-button type="primary" @click="goCreate()">新建多联总单</el-button <div class="toolbar-left">
><el-button type="primary" plain @click="download">批量导出</el-button> <el-button type="primary" @click="goCreate()">新建多联总单</el-button>
<el-button type="primary" plain @click="download">批量导出</el-button>
</div>
<table-header-tools
:show-column="false"
:show-grid="false"
v-model:search-visible="searchVisible"
@refresh="load"
/>
</div> </div>
<div v-loading="loading" class="master-cards"> <div v-loading="loading" class="master-cards">
<article v-for="row in records" :key="row.id" class="master-card"> <article v-for="row in records" :key="row.id" class="master-card">
@@ -147,12 +155,13 @@
<script> <script>
import * as api from '@/api/business/master-order'; import * as api from '@/api/business/master-order';
import TableHeaderTools from '@/components/table-header-tools/main.vue';
import MasterOrderEditor from './components/master-order-editor.vue'; import MasterOrderEditor from './components/master-order-editor.vue';
import MasterOrderDispatch from './components/master-order-dispatch.vue'; import MasterOrderDispatch from './components/master-order-dispatch.vue';
import MasterOrderDetail from './components/master-order-detail.vue'; import MasterOrderDetail from './components/master-order-detail.vue';
export default { export default {
components: { MasterOrderEditor, MasterOrderDispatch, MasterOrderDetail }, components: { TableHeaderTools, MasterOrderEditor, MasterOrderDispatch, MasterOrderDetail },
data() { data() {
return { return {
// 实例创建时锁定所属路由。keep-alive 缓存后 $route 会变成其它页面, // 实例创建时锁定所属路由。keep-alive 缓存后 $route 会变成其它页面,
@@ -160,6 +169,7 @@ export default {
//(mode=add 且无 id)会落入详情分支并请求缺少 id 的详情接口。 //(mode=add 且无 id)会落入详情分支并请求缺少 id 的详情接口。
routePathLocked: this.$route.path, routePathLocked: this.$route.path,
searchExpanded: false, searchExpanded: false,
searchVisible: true,
loading: false, loading: false,
records: [], records: [],
query: { businessStatus: '' }, query: { businessStatus: '' },
@@ -633,8 +643,18 @@ export default {
} }
.master-list-panel { .master-list-panel {
.toolbar { .toolbar {
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
padding: 8px 0; padding: 8px 0;
} }
.toolbar-left {
display: flex;
align-items: center;
gap: 12px;
}
} }
.master-card { .master-card {
display: flex; display: flex;
+8 -3
View File
@@ -653,9 +653,14 @@
class-name="is-ellipsis-link" class-name="is-ellipsis-link"
> >
<template #default="{ row }"> <template #default="{ row }">
<el-link type="primary" @click="previewAttachment(row)"> <span
{{ attachmentName(row) }} class="attachment-file-name"
</el-link> role="button"
tabindex="0"
@click="previewAttachment(row)"
@keydown.enter="previewAttachment(row)"
@keydown.space.prevent="previewAttachment(row)"
>{{ attachmentName(row) }}</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="附件描述" min-width="240" align="center"> <el-table-column label="附件描述" min-width="240" align="center">
+32 -8
View File
@@ -106,9 +106,14 @@
class-name="is-ellipsis-link" class-name="is-ellipsis-link"
> >
<template #default="{ row }"> <template #default="{ row }">
<el-link type="primary" @click="previewAttachment(row)"> <span
{{ attachmentName(row) }} class="attachment-file-name"
</el-link> role="button"
tabindex="0"
@click="previewAttachment(row)"
@keydown.enter="previewAttachment(row)"
@keydown.space.prevent="previewAttachment(row)"
>{{ attachmentName(row) }}</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="附件描述" min-width="220"> <el-table-column label="附件描述" min-width="220">
@@ -189,6 +194,7 @@
title="查看临时额度申请" title="查看临时额度申请"
append-to-body append-to-body
destroy-on-close destroy-on-close
align-center
:width="formDialogWidth" :width="formDialogWidth"
class="temporary-credit-limit-dialog temporary-credit-limit-detail-dialog" class="temporary-credit-limit-dialog temporary-credit-limit-detail-dialog"
> >
@@ -228,9 +234,14 @@
class-name="is-ellipsis-link" class-name="is-ellipsis-link"
> >
<template #default="{ row }"> <template #default="{ row }">
<el-link type="primary" @click="previewAttachment(row)"> <span
{{ attachmentName(row) }} class="attachment-file-name"
</el-link> role="button"
tabindex="0"
@click="previewAttachment(row)"
@keydown.enter="previewAttachment(row)"
@keydown.space.prevent="previewAttachment(row)"
>{{ attachmentName(row) }}</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="附件描述" min-width="220" show-overflow-tooltip> <el-table-column label="附件描述" min-width="220" show-overflow-tooltip>
@@ -1198,10 +1209,10 @@ export default {
} }
// 新增/编辑/查看:宽度与高度规则统一(Avue setPx 对 '1100px' 会拼成 '1100pxpx',故 option 用数字 1100) // 新增/编辑/查看:宽度与高度规则统一(Avue setPx 对 '1100px' 会拼成 '1100pxpx',故 option 用数字 1100)
// margin:auto 配合下方 unscoped 的 overlay flex,实现垂直水平居中
.temporary-credit-limit-dialog.el-dialog { .temporary-credit-limit-dialog.el-dialog {
width: 1100px !important; width: 1100px !important;
margin-top: 20px !important; margin: auto !important;
margin-bottom: 20px !important;
height: auto !important; height: auto !important;
max-height: calc(100vh - 40px) !important; max-height: calc(100vh - 40px) !important;
display: flex; display: flex;
@@ -1339,3 +1350,16 @@ export default {
} }
</style> </style>
<!-- append-to-body 弹窗挂到 body,overlay 无 scoped 属性,需全局样式才能居中 -->
<style lang="scss">
.el-overlay-dialog:has(> .temporary-credit-limit-dialog) {
display: flex;
align-items: center;
justify-content: center;
}
.temporary-credit-limit-dialog.el-dialog {
margin: auto !important;
}
</style>
+113 -12
View File
@@ -1,6 +1,6 @@
<template> <template>
<basic-container class="voucher-manage-page"> <basic-container class="voucher-manage-page">
<section class="voucher-manage-page__search"> <section v-show="searchVisible" class="voucher-manage-page__search">
<el-form :model="query" label-position="right" label-width="88px"> <el-form :model="query" label-position="right" label-width="88px">
<div class="voucher-manage-page__search-grid"> <div class="voucher-manage-page__search-grid">
<el-form-item label="凭证批次号" <el-form-item label="凭证批次号"
@@ -55,10 +55,25 @@
</section> </section>
<section> <section>
<div class="voucher-manage-page__toolbar"> <div class="voucher-manage-page__toolbar">
<el-button type="primary" @click="openUpload">批量导入凭证</el-button <div class="voucher-manage-page__toolbar-left">
><el-button plain @click="openProgress">上传进度</el-button> <el-button type="primary" @click="openUpload">批量导入凭证</el-button>
<el-button plain @click="openProgress">上传进度</el-button>
</div>
<table-header-tools
:columns="columnSettingOptions"
v-model:visible-column-keys="visibleColumnKeys"
v-model:table-size="tableSize"
v-model:search-visible="searchVisible"
@refresh="load"
/>
</div> </div>
<el-table v-loading="loading" :data="rows" border class="voucher-manage-page__table"> <el-table
v-loading="loading"
:data="rows"
:size="tableSize"
border
class="voucher-manage-page__table"
>
<el-table-column type="selection" width="52" fixed="left" align="center" /><el-table-column <el-table-column type="selection" width="52" fixed="left" align="center" /><el-table-column
type="index" type="index"
label="序号" label="序号"
@@ -66,27 +81,47 @@
fixed="left" fixed="left"
align="center" align="center"
/> />
<el-table-column prop="voucherBatchNo" label="凭证批次号" min-width="150" fixed="left" <el-table-column
v-if="isColumnVisible('voucherBatchNo')"
prop="voucherBatchNo"
label="凭证批次号"
min-width="150"
fixed="left"
><template #default="{ row }" ><template #default="{ row }"
><el-link class="voucher-manage-page__link" type="primary" @click="view(row)">{{ ><el-link class="voucher-manage-page__link" type="primary" @click="view(row)">{{
row.voucherBatchNo row.voucherBatchNo
}}</el-link></template }}</el-link></template
></el-table-column ></el-table-column
> >
<el-table-column prop="waybillBatchNo" label="运单批次号" min-width="170" /><el-table-column <el-table-column
v-if="isColumnVisible('waybillBatchNo')"
prop="waybillBatchNo"
label="运单批次号"
min-width="170"
/><el-table-column
v-if="isColumnVisible('fileName')"
prop="fileName" prop="fileName"
label="文件名" label="文件名"
min-width="200" min-width="200"
show-overflow-tooltip show-overflow-tooltip
/> />
<el-table-column v-if="!isCarrier" prop="uploadSource" label="上传来源" width="100" /><el-table-column <el-table-column
v-if="!isCarrier" v-if="!isCarrier && isColumnVisible('uploadSource')"
prop="uploadSource"
label="上传来源"
width="100"
/><el-table-column
v-if="!isCarrier && isColumnVisible('carrierName')"
prop="carrierName" prop="carrierName"
label="承运商名称" label="承运商名称"
min-width="160" min-width="160"
><template #default="{ row }">{{ row.carrierName || '-' }}</template></el-table-column ><template #default="{ row }">{{ row.carrierName || '-' }}</template></el-table-column
> >
<el-table-column prop="processStatus" label="处理状态" width="120" <el-table-column
v-if="isColumnVisible('processStatus')"
prop="processStatus"
label="处理状态"
width="120"
><template #default="{ row }" ><template #default="{ row }"
><span ><span
:class="{ 'voucher-manage-page__process-failed': row.processStatus === '处理失败' }" :class="{ 'voucher-manage-page__process-failed': row.processStatus === '处理失败' }"
@@ -94,17 +129,35 @@
></template ></template
></el-table-column ></el-table-column
><el-table-column ><el-table-column
v-if="isColumnVisible('voucherCount')"
prop="voucherCount" prop="voucherCount"
label="凭证数量" label="凭证数量"
width="100" width="100"
/><el-table-column /><el-table-column
v-if="isColumnVisible('relatedWaybillCount')"
prop="relatedWaybillCount" prop="relatedWaybillCount"
label="凭证已关联数量" label="凭证已关联数量"
width="125" width="125"
/> <el-table-column prop="unRelatedWaybillCount" label="凭证未关联数量" width="125" /> /><el-table-column
<el-table-column prop="createUserName" label="创建人" min-width="120" /> v-if="isColumnVisible('unRelatedWaybillCount')"
<el-table-column prop="createTime" label="创建时间" min-width="170" /> prop="unRelatedWaybillCount"
label="凭证未关联数量"
width="125"
/>
<el-table-column <el-table-column
v-if="isColumnVisible('createUserName')"
prop="createUserName"
label="创建人"
min-width="120"
/>
<el-table-column
v-if="isColumnVisible('createTime')"
prop="createTime"
label="创建时间"
min-width="170"
/>
<el-table-column
v-if="isColumnVisible('auditStatus')"
prop="auditStatus" prop="auditStatus"
label="审核状态" label="审核状态"
width="120" width="120"
@@ -512,6 +565,7 @@ import { WarnTriangleFilled } from '@element-plus/icons-vue';
import { getList as getProjectList } from '@/api/business/project-apply'; import { getList as getProjectList } from '@/api/business/project-apply';
import * as api from '@/api/business/voucher-manage'; import * as api from '@/api/business/voucher-manage';
import SectionCard from '@/components/section-card/main.vue'; import SectionCard from '@/components/section-card/main.vue';
import TableHeaderTools from '@/components/table-header-tools/main.vue';
const router = useRouter(); const router = useRouter();
const store = useStore(); const store = useStore();
@@ -539,6 +593,47 @@ const checkIfCarrier = () => {
isCarrier.value = topDeptName === '外部组织'; isCarrier.value = topDeptName === '外部组织';
}; };
const VOUCHER_BASE_COLUMNS = [
{ prop: 'voucherBatchNo', label: '凭证批次号' },
{ prop: 'waybillBatchNo', label: '运单批次号' },
{ prop: 'fileName', label: '文件名' },
{ prop: 'uploadSource', label: '上传来源', carrierHidden: true },
{ prop: 'carrierName', label: '承运商名称', carrierHidden: true },
{ prop: 'processStatus', label: '处理状态' },
{ prop: 'voucherCount', label: '凭证数量' },
{ prop: 'relatedWaybillCount', label: '凭证已关联数量' },
{ prop: 'unRelatedWaybillCount', label: '凭证未关联数量' },
{ prop: 'createUserName', label: '创建人' },
{ prop: 'createTime', label: '创建时间' },
{ prop: 'auditStatus', label: '审核状态' },
];
const searchVisible = ref(true);
const tableSize = ref('default');
const visibleColumnKeys = ref([]);
const columnSettingOptions = computed(() =>
VOUCHER_BASE_COLUMNS.filter(column => !isCarrier.value || !column.carrierHidden).map(column => ({
prop: column.prop,
label: column.label,
}))
);
const isColumnVisible = prop => visibleColumnKeys.value.includes(prop);
watch(
columnSettingOptions,
options => {
const props = options.map(column => column.prop);
if (!visibleColumnKeys.value.length) {
visibleColumnKeys.value = props;
return;
}
const visible = new Set(visibleColumnKeys.value);
visibleColumnKeys.value = props.filter(prop => visible.has(prop));
if (!visibleColumnKeys.value.length) visibleColumnKeys.value = props;
},
{ immediate: true }
);
onMounted(() => { onMounted(() => {
checkIfCarrier(); checkIfCarrier();
}); });
@@ -1329,9 +1424,15 @@ load();
&__toolbar { &__toolbar {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: space-between;
gap: 12px; gap: 12px;
margin: 12px 0; margin: 12px 0;
} }
&__toolbar-left {
display: flex;
align-items: center;
gap: 12px;
}
&__table { &__table {
width: 100%; width: 100%;
} }
+15 -44
View File
@@ -345,19 +345,22 @@
value="special_approval" /><el-option value="special_approval" /><el-option
label="其他" label="其他"
value="other" /></el-select></template></el-table-column value="other" /></el-select></template></el-table-column
><el-table-column label="文件名" min-width="220" ><el-table-column
label="文件名"
min-width="220"
show-overflow-tooltip
class-name="is-ellipsis-link"
><template #default="{ row }" ><template #default="{ row }"
><div ><span
class="payment-form-page__attachment-file-name-cell" class="attachment-file-name"
:title="attachmentFileName(row) || '-'" :class="{ 'is-disabled': !attachmentFileUrl(row) }"
> role="button"
<span tabindex="0"
class="payment-form-page__attachment-file-name" @click="attachmentFileUrl(row) && previewAttachment(row)"
:class="{ 'is-disabled': !attachmentFileUrl(row) }" @keydown.enter="attachmentFileUrl(row) && previewAttachment(row)"
@click="attachmentFileUrl(row) && previewAttachment(row)" @keydown.space.prevent="attachmentFileUrl(row) && previewAttachment(row)"
>{{ attachmentFileName(row) || '-' }}</span >{{ attachmentFileName(row) || '-' }}</span
> ></template
</div></template
></el-table-column ></el-table-column
><el-table-column label="附件描述" min-width="220" ><el-table-column label="附件描述" min-width="220"
><template #default="{ row }" ><template #default="{ row }"
@@ -2749,38 +2752,6 @@ export default {
justify-content: center; justify-content: center;
gap: 8px; gap: 8px;
} }
.payment-form-page__attachment-file-name-cell {
display: block;
width: 100%;
min-width: 0;
overflow: hidden;
text-align: left;
text-overflow: ellipsis;
white-space: nowrap;
}
.payment-form-page__attachment-file-name {
display: block;
width: 100%;
overflow: hidden;
color: var(--el-text-color-regular);
text-overflow: ellipsis;
white-space: nowrap;
cursor: pointer;
transition: color 0.2s ease;
&:hover {
color: #409eff;
}
&.is-disabled {
color: var(--el-text-color-regular);
cursor: default;
&:hover {
color: var(--el-text-color-regular);
}
}
}
.payment-form-page__attachment-upload .vehicle-attachment-upload { .payment-form-page__attachment-upload .vehicle-attachment-upload {
width: auto; width: auto;
} }
@@ -306,13 +306,15 @@
class-name="is-ellipsis-link" class-name="is-ellipsis-link"
> >
<template #default="{ row }"> <template #default="{ row }">
<el-link <span
:disabled="!getAttachmentUrl(row)" class="attachment-file-name"
type="primary" :class="{ 'is-disabled': !getAttachmentUrl(row) }"
@click="previewAttachment(row)" role="button"
> tabindex="0"
{{ row.originalName || row.name || '-' }} @click="getAttachmentUrl(row) && previewAttachment(row)"
</el-link> @keydown.enter="getAttachmentUrl(row) && previewAttachment(row)"
@keydown.space.prevent="getAttachmentUrl(row) && previewAttachment(row)"
>{{ row.originalName || row.name || '-' }}</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="uploadUserName" label="上传人" min-width="120" align="center"> <el-table-column prop="uploadUserName" label="上传人" min-width="120" align="center">
@@ -39,16 +39,20 @@
>导出</el-button >导出</el-button
> >
</div> </div>
<div class="fs-table-panel__toolbar-right"> <settlement-table-tools
<el-tooltip content="刷新" placement="top"> :columns="columnSettingOptions"
<el-button :icon="Refresh" text @click="$emit('refresh')" /> v-model:visible-column-keys="visibleColumnKeys"
</el-tooltip> v-model:table-size="tableSize"
</div> :search-visible="searchVisible"
@update:search-visible="$emit('update:searchVisible', $event)"
@refresh="$emit('refresh')"
/>
</div> </div>
<el-table <el-table
ref="tableRef" ref="tableRef"
v-loading="loading" v-loading="loading"
:data="rows" :data="rows"
:size="tableSize"
border border
highlight-current-row highlight-current-row
@current-change="handleCurrentChange" @current-change="handleCurrentChange"
@@ -57,7 +61,7 @@
<el-table-column type="index" label="序号" width="64" fixed="left" align="center" /> <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 type="selection" width="52" fixed="left" align="center" />
<el-table-column <el-table-column
v-for="column in columns" v-for="column in visibleColumns"
:key="column.prop" :key="column.prop"
v-bind="column" v-bind="column"
align="center" align="center"
@@ -119,15 +123,16 @@
</template> </template>
<script> <script>
import { Refresh } from '@element-plus/icons-vue';
import { import {
invoiceStatusName, invoiceStatusName,
kingdeeSyncStatusOptions, kingdeeSyncStatusOptions,
paymentStatusOptions, paymentStatusOptions,
} from '@/option/settlement/formalSettlementSearch'; } from '@/option/settlement/formalSettlementSearch';
import SettlementTableTools from './settlement-table-tools.vue';
export default { export default {
name: 'FormalSettlementTablePanel', name: 'FormalSettlementTablePanel',
components: { SettlementTableTools },
props: { props: {
rows: { type: Array, default: () => [] }, rows: { type: Array, default: () => [] },
columns: { type: Array, default: () => [] }, columns: { type: Array, default: () => [] },
@@ -135,6 +140,7 @@ export default {
page: { type: Object, required: true }, page: { type: Object, required: true },
hasPermission: { type: Function, required: true }, hasPermission: { type: Function, required: true },
mkEnabled: { type: Boolean, default: false }, mkEnabled: { type: Boolean, default: false },
searchVisible: { type: Boolean, default: true },
}, },
emits: [ emits: [
'create', 'create',
@@ -146,14 +152,47 @@ export default {
'page-change', 'page-change',
'action', 'action',
'update:selection', 'update:selection',
'update:searchVisible',
], ],
data() { data() {
return { return {
Refresh,
selection: [], 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: { 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() { rows() {
this.selection = []; this.selection = [];
this.$refs.tableRef?.clearSelection(); this.$refs.tableRef?.clearSelection();
@@ -245,11 +284,6 @@ export default {
align-items: center; align-items: center;
padding: 12px 0; padding: 12px 0;
} }
.fs-table-panel__toolbar-right {
display: flex;
align-items: center;
gap: 8px;
}
.fs-table-panel__links { .fs-table-panel__links {
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
@@ -361,9 +361,14 @@
class-name="is-ellipsis-link" class-name="is-ellipsis-link"
> >
<template #default="{ row }"> <template #default="{ row }">
<el-link type="primary" @click="previewAttachment(row)"> <span
{{ attachmentName(row) }} class="attachment-file-name"
</el-link> role="button"
tabindex="0"
@click="previewAttachment(row)"
@keydown.enter="previewAttachment(row)"
@keydown.space.prevent="previewAttachment(row)"
>{{ attachmentName(row) }}</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="附件描述" min-width="220"> <el-table-column label="附件描述" min-width="220">
@@ -200,9 +200,14 @@
class-name="is-ellipsis-link" class-name="is-ellipsis-link"
> >
<template #default="{ row }"> <template #default="{ row }">
<el-link type="primary" @click="previewAttachment(row)"> <span
{{ attachmentName(row) }} class="attachment-file-name"
</el-link> role="button"
tabindex="0"
@click="previewAttachment(row)"
@keydown.enter="previewAttachment(row)"
@keydown.space.prevent="previewAttachment(row)"
>{{ attachmentName(row) }}</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="附件描述" min-width="240"> <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> <el-button type="primary" plain @click="$emit('export')">导出</el-button>
</div> </div>
<div class="tr-table-panel__toolbar-right"> <settlement-table-tools
<el-tooltip content="刷新" placement="top"> :columns="columnSettingOptions"
<el-button :icon="Refresh" text @click="$emit('refresh')" /> v-model:visible-column-keys="visibleColumnKeys"
</el-tooltip> v-model:table-size="tableSize"
</div> :search-visible="searchVisible"
@update:search-visible="$emit('update:searchVisible', $event)"
@refresh="$emit('refresh')"
/>
</div> </div>
<el-table <el-table
v-loading="loading" v-loading="loading"
:data="rows" :data="rows"
:size="tableSize"
border border
@selection-change="handleSelectionChange" @selection-change="handleSelectionChange"
> >
<el-table-column type="selection" width="52" fixed="left" align="center" /> <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 type="index" label="序号" width="64" fixed="left" align="center" />
<el-table-column <el-table-column
v-for="column in columns" v-for="column in visibleColumns"
:key="column.prop" :key="column.prop"
v-bind="column" v-bind="column"
align="center" align="center"
@@ -73,24 +77,68 @@
</template> </template>
<script> <script>
import { Refresh } from '@element-plus/icons-vue'; import SettlementTableTools from './settlement-table-tools.vue';
export default { export default {
name: 'TransportReconciliationTablePanel', name: 'TransportReconciliationTablePanel',
components: { SettlementTableTools },
props: { props: {
rows: { type: Array, default: () => [] }, rows: { type: Array, default: () => [] },
columns: { type: Array, default: () => [] }, columns: { type: Array, default: () => [] },
loading: { type: Boolean, default: false }, loading: { type: Boolean, default: false },
page: { type: Object, required: true }, page: { type: Object, required: true },
hasPermission: { type: Function, 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() { data() {
return { return {
Refresh,
selection: [], 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: { methods: {
handleSelectionChange(value) { handleSelectionChange(value) {
this.selection = value; this.selection = value;
@@ -127,11 +175,6 @@ export default {
align-items: center; align-items: center;
padding: 12px 0; padding: 12px 0;
} }
.tr-table-panel__toolbar-right {
display: flex;
align-items: center;
gap: 8px;
}
.tr-table-panel__links { .tr-table-panel__links {
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
+4 -1
View File
@@ -1,6 +1,6 @@
<template> <template>
<basic-container class="formal-page"> <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> <el-form :model="query" label-position="right" label-width="88px" @submit.prevent>
<div class="formal-page__search-grid"> <div class="formal-page__search-grid">
<el-form-item v-for="field in visibleSearchFields" :key="field.prop" :label="field.label"> <el-form-item v-for="field in visibleSearchFields" :key="field.prop" :label="field.label">
@@ -65,6 +65,7 @@
:page="page" :page="page"
:has-permission="hasPermissionFn" :has-permission="hasPermissionFn"
:mk-enabled="mkEnabled" :mk-enabled="mkEnabled"
v-model:search-visible="searchVisible"
@create="openCreate" @create="openCreate"
@payment="openPaymentDialog" @payment="openPaymentDialog"
@sync="handleSync" @sync="handleSync"
@@ -84,6 +85,7 @@
:page="page" :page="page"
:has-permission="hasPermissionFn" :has-permission="hasPermissionFn"
:mk-enabled="mkEnabled" :mk-enabled="mkEnabled"
v-model:search-visible="searchVisible"
@create="openCreate" @create="openCreate"
@payment="openPaymentDialog" @payment="openPaymentDialog"
@sync="handleSync" @sync="handleSync"
@@ -212,6 +214,7 @@ export default {
ArrowUp, ArrowUp,
query: emptyQuery(), query: emptyQuery(),
searchExpanded: false, searchExpanded: false,
searchVisible: true,
activeSettlementType: 'payable', activeSettlementType: 'payable',
searchFields: formalSettlementSearchFields, searchFields: formalSettlementSearchFields,
columns: formalSettlementTableColumns, columns: formalSettlementTableColumns,
+25 -11
View File
@@ -1,6 +1,6 @@
<template> <template>
<basic-container class="pre-settlement-page"> <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> <el-form :model="query" label-position="right" label-width="88px" @submit.prevent>
<div class="pre-settlement-page__search-grid"> <div class="pre-settlement-page__search-grid">
<template v-for="field in visibleSearchFields" :key="field.prop"> <template v-for="field in visibleSearchFields" :key="field.prop">
@@ -94,16 +94,19 @@
导出 导出
</el-button> </el-button>
</div> </div>
<div class="pre-settlement-page__toolbar-right"> <settlement-table-tools
<el-tooltip content="刷新" placement="top"> :columns="columnSettingOptions"
<el-button :icon="Refresh" text @click="loadTable" /> v-model:visible-column-keys="visibleColumnKeys"
</el-tooltip> v-model:table-size="tableSize"
</div> v-model:search-visible="searchVisible"
@refresh="loadTable"
/>
</div> </div>
<el-table <el-table
v-loading="loading" v-loading="loading"
:data="rows" :data="rows"
:size="tableSize"
border border
class="pre-settlement-page__table" class="pre-settlement-page__table"
@selection-change="handleSelectionChange" @selection-change="handleSelectionChange"
@@ -111,7 +114,7 @@
<el-table-column type="selection" width="52" fixed="left" align="center" /> <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 type="index" label="序号" width="64" fixed="left" align="center" />
<el-table-column <el-table-column
v-for="column in tableColumns" v-for="column in visibleTableColumns"
:key="column.prop" :key="column.prop"
:prop="column.prop" :prop="column.prop"
:label="column.label" :label="column.label"
@@ -285,7 +288,7 @@
</template> </template>
<script> <script>
import { ArrowDown, ArrowUp, Refresh } from '@element-plus/icons-vue'; import { ArrowDown, ArrowUp } from '@element-plus/icons-vue';
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
import { import {
approve, approve,
@@ -306,6 +309,7 @@ import { downloadFile } from '@/utils/util';
import { getMKApprovalUrl } from '@/api/system/business-process'; import { getMKApprovalUrl } from '@/api/system/business-process';
import { loadMkEnabled, submitMkApprovalFlow } from '@/utils/mk-approval'; import { loadMkEnabled, submitMkApprovalFlow } from '@/utils/mk-approval';
import PreSettlementEditor from './components/pre-settlement-editor.vue'; import PreSettlementEditor from './components/pre-settlement-editor.vue';
import SettlementTableTools from './components/settlement-table-tools.vue';
import { isAdministrator } from '@/utils/auth'; import { isAdministrator } from '@/utils/auth';
const emptyQuery = () => ({ const emptyQuery = () => ({
@@ -323,18 +327,20 @@ const emptyQuery = () => ({
export default { export default {
name: 'PreSettlement', name: 'PreSettlement',
components: { PreSettlementEditor }, components: { PreSettlementEditor, SettlementTableTools },
mixins: [organizationSearch], mixins: [organizationSearch],
data() { data() {
return { return {
ArrowDown, ArrowDown,
ArrowUp, ArrowUp,
Refresh,
loading: false, loading: false,
query: emptyQuery(), query: emptyQuery(),
searchFields: preSettlementSearchFields, searchFields: preSettlementSearchFields,
searchExpanded: false, searchExpanded: false,
searchVisible: true,
tableSize: 'default',
tableColumns: preSettlementTableColumns, tableColumns: preSettlementTableColumns,
visibleColumnKeys: preSettlementTableColumns.map(column => column.prop),
rows: [], rows: [],
selection: [], selection: [],
page: { page: {
@@ -365,6 +371,15 @@ export default {
visibleSearchFields() { visibleSearchFields() {
return this.searchExpanded ? this.searchFields : this.searchFields.slice(0, 4); 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: { watch: {
'$route.query.detailNo'(detailNo) { '$route.query.detailNo'(detailNo) {
@@ -776,7 +791,6 @@ export default {
} }
&__toolbar-left, &__toolbar-left,
&__toolbar-right,
&__links { &__links {
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
@@ -1,6 +1,6 @@
<template> <template>
<basic-container class="settlement-detail-page"> <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> <el-form :model="query" label-position="right" label-width="88px" @submit.prevent>
<div class="settlement-detail-page__search-grid"> <div class="settlement-detail-page__search-grid">
<template v-for="field in visibleSearchFields" :key="field.prop"> <template v-for="field in visibleSearchFields" :key="field.prop">
@@ -44,19 +44,19 @@
</el-button> </el-button>
<el-button type="primary" plain @click="handleExport">导出</el-button> <el-button type="primary" plain @click="handleExport">导出</el-button>
</div> </div>
<div class="settlement-detail-page__toolbar-right"> <settlement-table-tools
<el-tooltip content="刷新" placement="top"> :columns="columnSettingOptions"
<el-button :icon="Refresh" text @click="loadTable" /> v-model:visible-column-keys="visibleColumnKeys"
</el-tooltip> v-model:table-size="tableSize"
<el-tooltip content="列设置" placement="top"> v-model:search-visible="searchVisible"
<el-button :icon="Setting" text @click="noop" /> @refresh="loadTable"
</el-tooltip> />
</div>
</div> </div>
<el-table <el-table
v-loading="loading" v-loading="loading"
:data="rows" :data="rows"
:size="tableSize"
border border
class="settlement-detail-page__table" class="settlement-detail-page__table"
@selection-change="selectionChange" @selection-change="selectionChange"
@@ -64,7 +64,7 @@
<el-table-column type="selection" width="52" fixed="left" align="center" /> <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 type="index" label="序号" width="64" fixed="left" align="center" />
<el-table-column <el-table-column
v-for="column in displayTableColumns" v-for="column in visibleTableColumns"
:key="column.prop" :key="column.prop"
:prop="column.prop" :prop="column.prop"
:label="column.label" :label="column.label"
@@ -938,7 +938,7 @@
</template> </template>
<script> <script>
import { ArrowDown, ArrowUp, Close, Refresh, Setting } from '@element-plus/icons-vue'; import { ArrowDown, ArrowUp, Close } from '@element-plus/icons-vue';
import { import {
changeRecordColumns, changeRecordColumns,
feeDetailBaseColumns, feeDetailBaseColumns,
@@ -950,6 +950,7 @@ import {
tableColumns, tableColumns,
transferSearchFields, transferSearchFields,
} from '@/option/settlement/receivable-payable-detail'; } from '@/option/settlement/receivable-payable-detail';
import SettlementTableTools from './components/settlement-table-tools.vue';
import * as api from '@/api/settlement/receivable-payable-detail'; import * as api from '@/api/settlement/receivable-payable-detail';
import { getList as getContractList } from '@/api/business/contract-manage'; import { getList as getContractList } from '@/api/business/contract-manage';
import { getList as getCommonCargoList } from '@/api/business/common-cargo'; import { getList as getCommonCargoList } from '@/api/business/common-cargo';
@@ -989,6 +990,7 @@ const ADJUST_BILLING_TYPE_MAP = {
}; };
export default { export default {
components: { SettlementTableTools },
props: { props: {
settlementType: { settlementType: {
type: String, type: String,
@@ -1000,8 +1002,6 @@ export default {
ArrowDown, ArrowDown,
ArrowUp, ArrowUp,
Close, Close,
Refresh,
Setting,
searchFields, searchFields,
tableColumns, tableColumns,
tableFeeItemNames: [], tableFeeItemNames: [],
@@ -1010,6 +1010,10 @@ export default {
generateWaybillColumns, generateWaybillColumns,
loading: false, loading: false,
searchExpanded: false, searchExpanded: false,
searchVisible: true,
tableSize: 'default',
visibleColumnKeys: [],
knownColumnProps: [],
query: {}, query: {},
rows: [], rows: [],
selection: [], selection: [],
@@ -1169,6 +1173,18 @@ export default {
columns.splice(totalIndex, 0, ...dynamicColumns); columns.splice(totalIndex, 0, ...dynamicColumns);
return columns; 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() { previewColumns() {
return [...generatePreviewColumns, ...this.dynamicFeeColumns, ...feeDetailTailColumns]; return [...generatePreviewColumns, ...this.dynamicFeeColumns, ...feeDetailTailColumns];
}, },
@@ -1191,6 +1207,27 @@ export default {
'$route.fullPath'() { '$route.fullPath'() {
this.openRouteDetail(); 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() { async mounted() {
this.loadTransportTypeOptions(); this.loadTransportTypeOptions();
@@ -2664,7 +2701,6 @@ export default {
if (Array.isArray(data?.data?.records)) return data.data.records; if (Array.isArray(data?.data?.records)) return data.data.records;
return []; return [];
}, },
noop() {},
}, },
}; };
</script> </script>
@@ -2718,8 +2754,7 @@ export default {
background: transparent; background: transparent;
} }
.settlement-detail-page__toolbar-left, .settlement-detail-page__toolbar-left {
.settlement-detail-page__toolbar-right {
display: flex; display: flex;
align-items: center; align-items: center;
gap: 8px; gap: 8px;
+32 -16
View File
@@ -1,6 +1,6 @@
<template> <template>
<basic-container class="settlement-adjustment-page"> <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> <el-form :model="query" label-position="right" label-width="88px" @submit.prevent>
<div class="settlement-adjustment-page__search-grid"> <div class="settlement-adjustment-page__search-grid">
<el-form-item v-for="field in visibleSearchFields" :key="field.prop" :label="field.label"> <el-form-item v-for="field in visibleSearchFields" :key="field.prop" :label="field.label">
@@ -55,13 +55,22 @@
type="primary" type="primary"
@click="openCreate" @click="openCreate"
>新增</el-button >新增</el-button
><div class="settlement-adjustment-page__toolbar-right"> >
<el-tooltip content="刷新" placement="top"> <settlement-table-tools
<el-button :icon="Refresh" text @click="loadTable" /> :columns="columnSettingOptions"
</el-tooltip> v-model:visible-column-keys="visibleColumnKeys"
</div> v-model:table-size="tableSize"
v-model:search-visible="searchVisible"
@refresh="loadTable"
/>
</div> </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 <el-table-column type="selection" width="52" fixed="left" align="center" /><el-table-column
type="index" type="index"
label="序号" label="序号"
@@ -70,7 +79,7 @@
align="center" align="center"
/> />
<el-table-column <el-table-column
v-for="column in tableColumns" v-for="column in visibleTableColumns"
:key="column.prop" :key="column.prop"
v-bind="column" v-bind="column"
align="center" align="center"
@@ -165,13 +174,14 @@
</template> </template>
<script> <script>
import { ArrowDown, ArrowUp, Refresh } from '@element-plus/icons-vue'; import { ArrowDown, ArrowUp } from '@element-plus/icons-vue';
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
import * as api from '@/api/settlement/settlementAdjustment'; import * as api from '@/api/settlement/settlementAdjustment';
import { settlementAdjustmentSearchFields } from '@/option/settlement/settlementAdjustmentSearch'; import { settlementAdjustmentSearchFields } from '@/option/settlement/settlementAdjustmentSearch';
import organizationSearch from '@/mixins/organization-search'; import organizationSearch from '@/mixins/organization-search';
import { settlementAdjustmentTableColumns } from '@/option/settlement/settlementAdjustmentTable'; import { settlementAdjustmentTableColumns } from '@/option/settlement/settlementAdjustmentTable';
import SettlementAdjustmentEditor from './components/settlement-adjustment-editor.vue'; import SettlementAdjustmentEditor from './components/settlement-adjustment-editor.vue';
import SettlementTableTools from './components/settlement-table-tools.vue';
import { isAdministrator } from '@/utils/auth'; import { isAdministrator } from '@/utils/auth';
const emptyQuery = () => ({ const emptyQuery = () => ({
@@ -186,17 +196,19 @@ const emptyQuery = () => ({
}); });
export default { export default {
name: 'SettlementAdjustment', name: 'SettlementAdjustment',
components: { SettlementAdjustmentEditor }, components: { SettlementAdjustmentEditor, SettlementTableTools },
mixins: [organizationSearch], mixins: [organizationSearch],
data: () => ({ data: () => ({
ArrowDown, ArrowDown,
ArrowUp, ArrowUp,
Refresh,
loading: false, loading: false,
query: emptyQuery(), query: emptyQuery(),
searchFields: settlementAdjustmentSearchFields, searchFields: settlementAdjustmentSearchFields,
searchExpanded: false, searchExpanded: false,
searchVisible: true,
tableSize: 'default',
tableColumns: settlementAdjustmentTableColumns, tableColumns: settlementAdjustmentTableColumns,
visibleColumnKeys: settlementAdjustmentTableColumns.map(column => column.prop),
rows: [], rows: [],
selection: [], selection: [],
page: { current: 1, size: 10, total: 0 }, page: { current: 1, size: 10, total: 0 },
@@ -207,6 +219,15 @@ export default {
visibleSearchFields() { visibleSearchFields() {
return this.searchExpanded ? this.searchFields : this.searchFields.slice(0, 4); 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() { isAdmin() {
return isAdministrator(this.userInfo); return isAdministrator(this.userInfo);
}, },
@@ -359,11 +380,6 @@ export default {
align-items: center; align-items: center;
min-height: 56px; min-height: 56px;
} }
&__toolbar-right {
display: flex;
align-items: center;
gap: 8px;
}
&__links { &__links {
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
@@ -1,6 +1,6 @@
<template> <template>
<basic-container class="reconciliation-page"> <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> <el-form :model="query" label-position="right" label-width="88px" @submit.prevent>
<div class="reconciliation-page__search-grid"> <div class="reconciliation-page__search-grid">
<el-form-item v-for="field in visibleSearchFields" :key="field.prop" :label="field.label"> <el-form-item v-for="field in visibleSearchFields" :key="field.prop" :label="field.label">
@@ -54,6 +54,7 @@
:loading="loading" :loading="loading"
:page="page" :page="page"
:has-permission="hasPermission" :has-permission="hasPermission"
v-model:search-visible="searchVisible"
@create="openCreate" @create="openCreate"
@export="handleExport" @export="handleExport"
@refresh="loadTable" @refresh="loadTable"
@@ -69,6 +70,7 @@
:loading="loading" :loading="loading"
:page="page" :page="page"
:has-permission="hasPermission" :has-permission="hasPermission"
v-model:search-visible="searchVisible"
@create="openCreate" @create="openCreate"
@export="handleExport" @export="handleExport"
@refresh="loadTable" @refresh="loadTable"
@@ -91,7 +93,7 @@
</template> </template>
<script> <script>
import { ArrowDown, ArrowUp, Refresh } from '@element-plus/icons-vue'; import { ArrowDown, ArrowUp } from '@element-plus/icons-vue';
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
import { downloadFile } from '@/utils/util'; import { downloadFile } from '@/utils/util';
import * as api from '@/api/settlement/transportReconciliation'; import * as api from '@/api/settlement/transportReconciliation';
@@ -121,9 +123,9 @@ export default {
return { return {
ArrowDown, ArrowDown,
ArrowUp, ArrowUp,
Refresh,
query: emptyQuery(), query: emptyQuery(),
searchExpanded: false, searchExpanded: false,
searchVisible: true,
searchFields: transportReconciliationSearchFields, searchFields: transportReconciliationSearchFields,
columns: transportReconciliationTableColumns, columns: transportReconciliationTableColumns,
settlementType: 'payable', settlementType: 'payable',
+9 -6
View File
@@ -394,15 +394,18 @@
<el-table-column label="附件" min-width="120" align="center"> <el-table-column label="附件" min-width="120" align="center">
<template #default="{ row }"> <template #default="{ row }">
<template v-if="parseAttachments(row.attachmentsJson).length"> <template v-if="parseAttachments(row.attachmentsJson).length">
<el-link <span
v-for="(file, index) in parseAttachments(row.attachmentsJson)" v-for="(file, index) in parseAttachments(row.attachmentsJson)"
:key="index" :key="index"
type="primary" class="attachment-file-name exception-disposal-page__attachment-link"
class="exception-disposal-page__attachment-link" role="button"
tabindex="0"
@click="previewAttachment(file, parseAttachments(row.attachmentsJson))" @click="previewAttachment(file, parseAttachments(row.attachmentsJson))"
> @keydown.enter="previewAttachment(file, parseAttachments(row.attachmentsJson))"
{{ file.name || '附件' + (index + 1) }} @keydown.space.prevent="
</el-link> previewAttachment(file, parseAttachments(row.attachmentsJson))
"
>{{ file.name || '附件' + (index + 1) }}</span>
</template> </template>
<span v-else>-</span> <span v-else>-</span>
</template> </template>
+23 -49
View File
@@ -781,20 +781,23 @@
</el-select> </el-select>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="文件名称" min-width="180" align="left"> <el-table-column
label="文件名称"
min-width="180"
align="left"
show-overflow-tooltip
class-name="is-ellipsis-link"
>
<template #default="{ row }"> <template #default="{ row }">
<div <span
class="qualification-file-name-cell" class="attachment-file-name"
:title="row.originalName || row.name || '-'" :class="{ 'is-disabled': !row.url }"
> role="button"
<span tabindex="0"
class="qualification-file-name" @click="row.url && previewQualificationFile(row)"
:class="{ 'is-disabled': !row.url }" @keydown.enter="row.url && previewQualificationFile(row)"
@click="row.url && previewQualificationFile(row)" @keydown.space.prevent="row.url && previewQualificationFile(row)"
> >{{ row.originalName || row.name || '-' }}</span>
{{ row.originalName || row.name || '-' }}
</span>
</div>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="附件描述" min-width="220"> <el-table-column label="附件描述" min-width="220">
@@ -1438,9 +1441,14 @@
</template> </template>
<el-table :data="scoreAttachmentFiles" border class="score-material-table"> <el-table :data="scoreAttachmentFiles" border class="score-material-table">
<el-table-column label="序号" type="index" width="90" align="center" /> <el-table-column label="序号" type="index" width="90" align="center" />
<el-table-column label="文件名" min-width="220"> <el-table-column
label="文件名"
min-width="220"
show-overflow-tooltip
class-name="is-ellipsis-link"
>
<template #default="{ row }"> <template #default="{ row }">
{{ row.originalName || row.name || '-' }} <span>{{ row.originalName || row.name || '-' }}</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="附件描述" min-width="220"> <el-table-column label="附件描述" min-width="220">
@@ -5302,40 +5310,6 @@ export default {
font-weight: 400; font-weight: 400;
} }
.qualification-file-name-cell {
display: block;
width: 100%;
min-width: 0;
overflow: hidden;
text-align: left;
text-overflow: ellipsis;
white-space: nowrap;
}
.qualification-file-name {
display: block;
width: 100%;
overflow: hidden;
text-overflow: ellipsis;
vertical-align: middle;
white-space: nowrap;
cursor: pointer;
color: #606266;
transition: color 0.2s ease;
&:hover {
color: #409eff;
}
&.is-disabled {
cursor: default;
color: #606266;
&:hover {
color: #606266;
}
}
}
.qualification-upload-bar { .qualification-upload-bar {
display: flex; display: flex;