改造流水明细详情弹窗并统一列表样式
This commit is contained in:
@@ -90,4 +90,10 @@ public class CcdiBankStatementDetailVO {
|
||||
|
||||
/** 创建时间 */
|
||||
private Date createDate;
|
||||
|
||||
/** 原始文件名 */
|
||||
private String originalFileName;
|
||||
|
||||
/** 原始文件上传时间 */
|
||||
private Date uploadTime;
|
||||
}
|
||||
|
||||
@@ -98,6 +98,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
<result property="paymentMethod" column="paymentMethod"/>
|
||||
<result property="cretNo" column="cretNo"/>
|
||||
<result property="createDate" column="createDate"/>
|
||||
<result property="originalFileName" column="originalFileName"/>
|
||||
<result property="uploadTime" column="uploadTime"/>
|
||||
</resultMap>
|
||||
|
||||
<resultMap id="CcdiBankStatementFilterOptionsVOResultMap"
|
||||
@@ -313,8 +315,11 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
bs.internal_flag AS internalFlag,
|
||||
bs.payment_method AS paymentMethod,
|
||||
bs.cret_no AS cretNo,
|
||||
bs.CREATE_DATE AS createDate
|
||||
bs.CREATE_DATE AS createDate,
|
||||
fur.file_name AS originalFileName,
|
||||
fur.upload_time AS uploadTime
|
||||
FROM ccdi_bank_statement bs
|
||||
LEFT JOIN ccdi_file_upload_record fur ON fur.log_id = bs.batch_id AND fur.project_id = bs.project_id
|
||||
WHERE bs.bank_statement_id = #{bankStatementId}
|
||||
</select>
|
||||
|
||||
|
||||
@@ -115,6 +115,20 @@ class CcdiBankStatementMapperXmlTest {
|
||||
assertTrue(sql.contains("END ) <= ?"), sql);
|
||||
}
|
||||
|
||||
@Test
|
||||
void selectStatementDetailById_shouldJoinUploadRecordForOriginalFileMetadata() throws Exception {
|
||||
try (InputStream inputStream = getClass().getClassLoader().getResourceAsStream(RESOURCE)) {
|
||||
String xml = new String(inputStream.readAllBytes(), StandardCharsets.UTF_8);
|
||||
|
||||
assertTrue(
|
||||
xml.contains("LEFT JOIN ccdi_file_upload_record fur ON fur.log_id = bs.batch_id AND fur.project_id = bs.project_id"),
|
||||
xml
|
||||
);
|
||||
assertTrue(xml.contains("fur.file_name AS originalFileName"), xml);
|
||||
assertTrue(xml.contains("fur.upload_time AS uploadTime"), xml);
|
||||
}
|
||||
}
|
||||
|
||||
private MappedStatement loadMappedStatement(String statementId) throws Exception {
|
||||
Configuration configuration = new Configuration();
|
||||
configuration.setEnvironment(new Environment("test", new JdbcTransactionFactory(), new NoOpDataSource()));
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
:data="dataList"
|
||||
style="width: 100%"
|
||||
>
|
||||
<!-- 项目名称(含描述) -->
|
||||
<el-table-column
|
||||
label="项目名称"
|
||||
min-width="180"
|
||||
@@ -14,12 +13,11 @@
|
||||
<template slot-scope="scope">
|
||||
<div class="project-info-cell">
|
||||
<div class="project-name">{{ scope.row.projectName }}</div>
|
||||
<div class="project-desc">{{ scope.row.description || '暂无描述' }}</div>
|
||||
<div class="project-desc">{{ scope.row.description || "暂无描述" }}</div>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<!-- 更新/创建时间 -->
|
||||
<el-table-column
|
||||
prop="updateTime"
|
||||
label="更新/创建时间"
|
||||
@@ -31,7 +29,6 @@
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<!-- 创建人 -->
|
||||
<el-table-column
|
||||
prop="createByName"
|
||||
label="创建人"
|
||||
@@ -39,7 +36,6 @@
|
||||
align="center"
|
||||
/>
|
||||
|
||||
<!-- 状态 -->
|
||||
<el-table-column
|
||||
prop="status"
|
||||
label="状态"
|
||||
@@ -54,7 +50,6 @@
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<!-- 目标人数 -->
|
||||
<el-table-column
|
||||
prop="targetCount"
|
||||
label="目标人数"
|
||||
@@ -62,7 +57,6 @@
|
||||
align="center"
|
||||
/>
|
||||
|
||||
<!-- 预警人数(带悬停详情) -->
|
||||
<el-table-column
|
||||
label="预警人数"
|
||||
width="120"
|
||||
@@ -71,26 +65,24 @@
|
||||
<template slot-scope="scope">
|
||||
<el-tooltip placement="top" effect="light">
|
||||
<div slot="content">
|
||||
<div style="padding: 8px;">
|
||||
<div style="margin-bottom: 8px; font-weight: bold; color: #303133;">
|
||||
风险人数统计
|
||||
<div class="risk-tooltip">
|
||||
<div class="risk-tooltip-title">风险人数统计</div>
|
||||
<div class="risk-tooltip-item risk-tooltip-item--high">
|
||||
<span>● 高风险:</span>
|
||||
<span class="risk-tooltip-count">{{ scope.row.highRiskCount }} 人</span>
|
||||
</div>
|
||||
<div style="margin-bottom: 6px;">
|
||||
<span style="color: #f56c6c;">● 高风险:</span>
|
||||
<span style="font-weight: bold;">{{ scope.row.highRiskCount }} 人</span>
|
||||
<div class="risk-tooltip-item risk-tooltip-item--medium">
|
||||
<span>● 中风险:</span>
|
||||
<span class="risk-tooltip-count">{{ scope.row.mediumRiskCount }} 人</span>
|
||||
</div>
|
||||
<div style="margin-bottom: 6px;">
|
||||
<span style="color: #e6a23c;">● 中风险:</span>
|
||||
<span style="font-weight: bold;">{{ scope.row.mediumRiskCount }} 人</span>
|
||||
</div>
|
||||
<div>
|
||||
<span style="color: #909399;">● 低风险:</span>
|
||||
<span style="font-weight: bold;">{{ scope.row.lowRiskCount }} 人</span>
|
||||
<div class="risk-tooltip-item risk-tooltip-item--low">
|
||||
<span>● 低风险:</span>
|
||||
<span class="risk-tooltip-count">{{ scope.row.lowRiskCount }} 人</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="warning-count-wrapper">
|
||||
<span :class="getWarningClass(scope.row)" style="cursor: pointer;">
|
||||
<span :class="getWarningClass(scope.row)" class="warning-count">
|
||||
{{ scope.row.highRiskCount + scope.row.mediumRiskCount + scope.row.lowRiskCount }}
|
||||
</span>
|
||||
</div>
|
||||
@@ -98,7 +90,6 @@
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<!-- 操作列 -->
|
||||
<el-table-column
|
||||
label="操作"
|
||||
width="350"
|
||||
@@ -106,50 +97,56 @@
|
||||
fixed="right"
|
||||
>
|
||||
<template slot-scope="scope">
|
||||
<!-- 进行中状态 (status = '0') -->
|
||||
<el-button
|
||||
v-if="scope.row.status === '0'"
|
||||
size="mini"
|
||||
type="text"
|
||||
icon="el-icon-right"
|
||||
@click="handleEnter(scope.row)"
|
||||
>进入项目</el-button>
|
||||
>
|
||||
进入项目
|
||||
</el-button>
|
||||
|
||||
<!-- 已完成状态 (status = '1') -->
|
||||
<template v-if="scope.row.status === '1'">
|
||||
<el-button
|
||||
size="mini"
|
||||
type="text"
|
||||
icon="el-icon-view"
|
||||
@click="handleViewResult(scope.row)"
|
||||
>查看结果</el-button>
|
||||
>
|
||||
查看结果
|
||||
</el-button>
|
||||
<el-button
|
||||
size="mini"
|
||||
type="text"
|
||||
icon="el-icon-refresh"
|
||||
@click="handleReAnalyze(scope.row)"
|
||||
>重新分析</el-button>
|
||||
>
|
||||
重新分析
|
||||
</el-button>
|
||||
<el-button
|
||||
size="mini"
|
||||
type="text"
|
||||
icon="el-icon-folder"
|
||||
@click="handleArchive(scope.row)"
|
||||
>归档</el-button>
|
||||
>
|
||||
归档
|
||||
</el-button>
|
||||
</template>
|
||||
|
||||
<!-- 已归档状态 (status = '2') -->
|
||||
<el-button
|
||||
v-if="scope.row.status === '2'"
|
||||
size="mini"
|
||||
type="text"
|
||||
icon="el-icon-view"
|
||||
@click="handleViewResult(scope.row)"
|
||||
>查看结果</el-button>
|
||||
>
|
||||
查看结果
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<!-- 分页 -->
|
||||
<el-pagination
|
||||
v-show="total > 0"
|
||||
:current-page="pageParams.pageNum"
|
||||
@@ -159,147 +156,89 @@
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange"
|
||||
style="margin-top: 16px; text-align: right;"
|
||||
style="margin-top: 16px; text-align: right"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'ProjectTable',
|
||||
dicts: ['ccdi_project_status', 'ccdi_config_type'],
|
||||
name: "ProjectTable",
|
||||
dicts: ["ccdi_project_status", "ccdi_config_type"],
|
||||
props: {
|
||||
dataList: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
default: () => [],
|
||||
},
|
||||
loading: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
default: false,
|
||||
},
|
||||
total: {
|
||||
type: Number,
|
||||
default: 0
|
||||
default: 0,
|
||||
},
|
||||
pageParams: {
|
||||
type: Object,
|
||||
default: () => ({
|
||||
pageNum: 1,
|
||||
pageSize: 10
|
||||
})
|
||||
}
|
||||
pageSize: 10,
|
||||
}),
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
getStatusColor(status) {
|
||||
const colorMap = {
|
||||
'0': '#1890ff', // 进行中 - 蓝色
|
||||
'1': '#52c41a', // 已完成 - 绿色
|
||||
'2': '#8c8c8c' // 已归档 - 灰色
|
||||
}
|
||||
return colorMap[status] || '#8c8c8c'
|
||||
0: "#1890ff",
|
||||
1: "#52c41a",
|
||||
2: "#8c8c8c",
|
||||
};
|
||||
return colorMap[status] || "#8c8c8c";
|
||||
},
|
||||
|
||||
getWarningClass(row) {
|
||||
const total = row.highRiskCount + row.mediumRiskCount + row.lowRiskCount
|
||||
const total = row.highRiskCount + row.mediumRiskCount + row.lowRiskCount;
|
||||
if (row.highRiskCount > 0) {
|
||||
return 'text-danger text-bold'
|
||||
} else if (row.mediumRiskCount > 0) {
|
||||
return 'text-warning text-bold'
|
||||
} else if (total > 0) {
|
||||
return 'text-info'
|
||||
return "text-danger text-bold";
|
||||
}
|
||||
return ''
|
||||
if (row.mediumRiskCount > 0) {
|
||||
return "text-warning text-bold";
|
||||
}
|
||||
if (total > 0) {
|
||||
return "text-info";
|
||||
}
|
||||
return "";
|
||||
},
|
||||
|
||||
handleEnter(row) {
|
||||
this.$emit('enter', row)
|
||||
this.$emit("enter", row);
|
||||
},
|
||||
|
||||
handleViewResult(row) {
|
||||
this.$emit('view-result', row)
|
||||
this.$emit("view-result", row);
|
||||
},
|
||||
|
||||
handleReAnalyze(row) {
|
||||
this.$emit('re-analyze', row)
|
||||
this.$emit("re-analyze", row);
|
||||
},
|
||||
|
||||
handleArchive(row) {
|
||||
this.$emit('archive', row)
|
||||
this.$emit("archive", row);
|
||||
},
|
||||
|
||||
handleSizeChange(val) {
|
||||
this.$emit('pagination', { pageNum: this.pageParams.pageNum, pageSize: val })
|
||||
this.$emit("pagination", {
|
||||
pageNum: this.pageParams.pageNum,
|
||||
pageSize: val,
|
||||
});
|
||||
},
|
||||
|
||||
handleCurrentChange(val) {
|
||||
this.$emit('pagination', { pageNum: val, pageSize: this.pageParams.pageSize })
|
||||
}
|
||||
}
|
||||
}
|
||||
this.$emit("pagination", {
|
||||
pageNum: val,
|
||||
pageSize: this.pageParams.pageSize,
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.project-table-container {
|
||||
margin-top: 16px;
|
||||
|
||||
// 表格整体样式 - 扁平化设计
|
||||
::v-deep .el-table {
|
||||
// 移除边框和卡片效果,设置透明背景
|
||||
border: none !important;
|
||||
background-color: transparent !important;
|
||||
overflow: hidden;
|
||||
|
||||
// 表头样式 - 扁平化,无背景色
|
||||
th.el-table__cell {
|
||||
background-color: transparent !important;
|
||||
color: #333;
|
||||
font-weight: 600;
|
||||
font-size: 14px;
|
||||
height: 44px;
|
||||
padding: 12px 10px;
|
||||
|
||||
// 只保留底部一条分隔线
|
||||
border-bottom: 2px solid #e0e0e0 !important;
|
||||
border-right: none !important;
|
||||
}
|
||||
|
||||
// 数据行样式 - 增加留白,移除分隔线
|
||||
td.el-table__cell {
|
||||
color: #333;
|
||||
font-size: 14px;
|
||||
height: 48px;
|
||||
padding: 12px 10px;
|
||||
border-bottom: none !important;
|
||||
border-right: none !important;
|
||||
}
|
||||
|
||||
// 移除列分隔线
|
||||
.el-table__body-wrapper {
|
||||
.cell {
|
||||
border-right: none;
|
||||
}
|
||||
}
|
||||
|
||||
// 悬停效果
|
||||
.el-table__row {
|
||||
transition: background-color 0.2s ease;
|
||||
|
||||
&:hover > td.el-table__cell {
|
||||
background-color: #fafafa !important;
|
||||
}
|
||||
}
|
||||
|
||||
// 移除额外边框
|
||||
&::before,
|
||||
&::after {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
// 移除 inner border
|
||||
.el-table__inner-wrapper::before {
|
||||
display: none !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.status-tag {
|
||||
@@ -336,10 +275,44 @@ export default {
|
||||
}
|
||||
}
|
||||
|
||||
.risk-tooltip {
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
.risk-tooltip-title {
|
||||
margin-bottom: 8px;
|
||||
font-weight: 600;
|
||||
color: #303133;
|
||||
}
|
||||
|
||||
.risk-tooltip-item {
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
|
||||
.risk-tooltip-item--high {
|
||||
color: #f56c6c;
|
||||
}
|
||||
|
||||
.risk-tooltip-item--medium {
|
||||
color: #e6a23c;
|
||||
}
|
||||
|
||||
.risk-tooltip-item--low {
|
||||
color: #909399;
|
||||
}
|
||||
|
||||
.risk-tooltip-count {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.warning-count-wrapper {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.warning-count {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.text-danger {
|
||||
color: #f56c6c;
|
||||
}
|
||||
@@ -353,10 +326,9 @@ export default {
|
||||
}
|
||||
|
||||
.text-bold {
|
||||
font-weight: bold;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
// 操作按钮样式 - Material Design 风格
|
||||
::v-deep .el-button--text {
|
||||
color: #1890ff;
|
||||
padding: 8px 12px;
|
||||
@@ -373,18 +345,15 @@ export default {
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
// 按钮间距
|
||||
& + .el-button--text {
|
||||
margin-left: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
// 分页样式优化 - Material Design 风格
|
||||
::v-deep .el-pagination {
|
||||
margin-top: 24px;
|
||||
text-align: right;
|
||||
|
||||
// 扁平化按钮
|
||||
.btn-prev,
|
||||
.btn-next,
|
||||
.el-pager li {
|
||||
@@ -398,7 +367,7 @@ export default {
|
||||
|
||||
.el-pager li.active {
|
||||
background-color: #1890ff;
|
||||
color: white;
|
||||
color: #fff;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
|
||||
@@ -136,7 +136,7 @@
|
||||
</div>
|
||||
<el-input
|
||||
v-model="queryParams.userMemo"
|
||||
placeholder="请输入摘要关键字"
|
||||
placeholder="请输入摘要关键词"
|
||||
clearable
|
||||
/>
|
||||
</el-form-item>
|
||||
@@ -184,8 +184,6 @@
|
||||
<el-table
|
||||
v-loading="loading"
|
||||
:data="list"
|
||||
border
|
||||
stripe
|
||||
class="result-table"
|
||||
@sort-change="handleSortChange"
|
||||
>
|
||||
@@ -265,103 +263,89 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<el-drawer
|
||||
<el-dialog
|
||||
:visible.sync="detailVisible"
|
||||
append-to-body
|
||||
custom-class="detail-drawer"
|
||||
size="520px"
|
||||
custom-class="detail-dialog"
|
||||
title="流水详情"
|
||||
width="980px"
|
||||
@close="closeDetailDialog"
|
||||
>
|
||||
<div v-loading="detailLoading" class="detail-drawer-body">
|
||||
<div class="detail-section">
|
||||
<div class="detail-section-title">基础信息</div>
|
||||
<div class="detail-grid">
|
||||
<div class="detail-item">
|
||||
<span class="detail-label">流水ID</span>
|
||||
<span class="detail-value">{{ formatField(detailData.bankStatementId) }}</span>
|
||||
<div v-loading="detailLoading" class="detail-dialog-body">
|
||||
<div class="detail-overview-grid">
|
||||
<div class="detail-field">
|
||||
<div class="detail-label">交易时间</div>
|
||||
<div class="detail-value">{{ formatField(detailData.trxDate) }}</div>
|
||||
</div>
|
||||
<div class="detail-item">
|
||||
<span class="detail-label">交易时间</span>
|
||||
<span class="detail-value">{{ formatField(detailData.trxDate) }}</span>
|
||||
</div>
|
||||
<div class="detail-item">
|
||||
<span class="detail-label">币种</span>
|
||||
<span class="detail-value">{{ formatField(detailData.currency) }}</span>
|
||||
</div>
|
||||
<div class="detail-item">
|
||||
<span class="detail-label">交易类型</span>
|
||||
<span class="detail-value">{{ formatField(detailData.cashType) }}</span>
|
||||
</div>
|
||||
<div class="detail-item">
|
||||
<span class="detail-label">显示金额</span>
|
||||
<span class="detail-value">{{ formatAmount(detailData.displayAmount) }}</span>
|
||||
</div>
|
||||
<div class="detail-item">
|
||||
<span class="detail-label">余额</span>
|
||||
<span class="detail-value">{{ formatAmount(detailData.amountBalance) }}</span>
|
||||
<div class="detail-field">
|
||||
<div class="detail-label">交易金额</div>
|
||||
<div class="detail-value amount-text" :class="getAmountClass(detailData.displayAmount)">
|
||||
{{ formatSignedAmount(detailData.displayAmount) }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="detail-field">
|
||||
<div class="detail-label">交易后余额</div>
|
||||
<div class="detail-value">{{ formatAmount(detailData.amountBalance) }}</div>
|
||||
</div>
|
||||
|
||||
<div class="detail-section">
|
||||
<div class="detail-section-title">账户信息</div>
|
||||
<div class="detail-grid">
|
||||
<div class="detail-item detail-item-full">
|
||||
<span class="detail-label">本方账户</span>
|
||||
<span class="detail-value">
|
||||
{{ formatField(detailData.leAccountName) }} / {{ formatField(detailData.leAccountNo) }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="detail-item detail-item-full">
|
||||
<span class="detail-label">对方账户</span>
|
||||
<span class="detail-value">
|
||||
{{ formatField(detailData.customerAccountName) }} /
|
||||
{{ formatField(detailData.customerAccountNo) }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="detail-item">
|
||||
<span class="detail-label">本方银行</span>
|
||||
<span class="detail-value">{{ formatField(detailData.bank) }}</span>
|
||||
</div>
|
||||
<div class="detail-item">
|
||||
<span class="detail-label">对方银行</span>
|
||||
<span class="detail-value">{{ formatField(detailData.customerBank) }}</span>
|
||||
<div class="detail-field">
|
||||
<div class="detail-label">本方主体</div>
|
||||
<div class="detail-value">{{ formatField(detailData.leAccountName) }}</div>
|
||||
</div>
|
||||
<div class="detail-field">
|
||||
<div class="detail-label">本方账号</div>
|
||||
<div class="detail-value">{{ formatField(detailData.leAccountNo) }}</div>
|
||||
</div>
|
||||
<div class="detail-field">
|
||||
<div class="detail-label">本方银行</div>
|
||||
<div class="detail-value">{{ formatField(detailData.bank) }}</div>
|
||||
</div>
|
||||
|
||||
<div class="detail-section">
|
||||
<div class="detail-section-title">补充信息</div>
|
||||
<div class="detail-grid">
|
||||
<div class="detail-item detail-item-full">
|
||||
<span class="detail-label">摘要</span>
|
||||
<span class="detail-value">{{ formatField(detailData.userMemo) }}</span>
|
||||
<div class="detail-field">
|
||||
<div class="detail-label">对方名称</div>
|
||||
<div class="detail-value">{{ formatCounterpartyName(detailData) }}</div>
|
||||
</div>
|
||||
<div class="detail-item detail-item-full">
|
||||
<span class="detail-label">银行摘要</span>
|
||||
<span class="detail-value">{{ formatField(detailData.bankComments) }}</span>
|
||||
<div class="detail-field">
|
||||
<div class="detail-label">对方账户</div>
|
||||
<div class="detail-value">{{ formatField(detailData.customerAccountNo) }}</div>
|
||||
</div>
|
||||
<div class="detail-item">
|
||||
<span class="detail-label">银行交易号</span>
|
||||
<span class="detail-value">{{ formatField(detailData.bankTrxNumber) }}</span>
|
||||
<div class="detail-field">
|
||||
<div class="detail-label">对方银行</div>
|
||||
<div class="detail-value">{{ formatField(detailData.customerBank) }}</div>
|
||||
</div>
|
||||
<div class="detail-item">
|
||||
<span class="detail-label">交易方式</span>
|
||||
<span class="detail-value">{{ formatField(detailData.paymentMethod) }}</span>
|
||||
|
||||
<div class="detail-field">
|
||||
<div class="detail-label">摘要</div>
|
||||
<div class="detail-value">{{ formatField(detailData.userMemo) }}</div>
|
||||
</div>
|
||||
<div class="detail-item">
|
||||
<span class="detail-label">异常类型</span>
|
||||
<span class="detail-value">{{ formatField(detailData.exceptionType) }}</span>
|
||||
<div class="detail-field">
|
||||
<div class="detail-label">交易类型</div>
|
||||
<div class="detail-value">{{ formatField(detailData.cashType) }}</div>
|
||||
</div>
|
||||
<div class="detail-item">
|
||||
<span class="detail-label">创建时间</span>
|
||||
<span class="detail-value">{{ formatDate(detailData.createDate) }}</span>
|
||||
<div class="detail-field">
|
||||
<div class="detail-label">银行摘要</div>
|
||||
<div class="detail-value">{{ formatField(detailData.bankComments) }}</div>
|
||||
</div>
|
||||
|
||||
<div class="detail-field detail-field--full">
|
||||
<div class="detail-label">原始文件</div>
|
||||
<div class="detail-file-block">
|
||||
<i class="el-icon-document detail-file-icon"></i>
|
||||
<div class="detail-file-meta">
|
||||
<div class="detail-file-name">{{ formatOriginalFileName(detailData) }}</div>
|
||||
<div class="detail-file-time">
|
||||
上传时间:{{ formatOriginalFileUploadTime(detailData) }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-drawer>
|
||||
</div>
|
||||
</div>
|
||||
<div slot="footer" class="detail-dialog-footer">
|
||||
<el-button @click="closeDetailDialog">取消</el-button>
|
||||
<el-button type="primary" @click="closeDetailDialog">确定</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -414,6 +398,7 @@ const createEmptyOptionData = () => ({
|
||||
|
||||
const createEmptyDetailData = () => ({
|
||||
bankStatementId: "",
|
||||
projectId: "",
|
||||
trxDate: "",
|
||||
currency: "",
|
||||
leAccountNo: "",
|
||||
@@ -421,16 +406,27 @@ const createEmptyDetailData = () => ({
|
||||
customerAccountName: "",
|
||||
customerAccountNo: "",
|
||||
customerBank: "",
|
||||
customerReference: "",
|
||||
userMemo: "",
|
||||
bankComments: "",
|
||||
bankTrxNumber: "",
|
||||
bank: "",
|
||||
cashType: "",
|
||||
amountDr: "",
|
||||
amountCr: "",
|
||||
amountBalance: "",
|
||||
displayAmount: "",
|
||||
paymentMethod: "",
|
||||
trxFlag: "",
|
||||
trxType: "",
|
||||
exceptionType: "",
|
||||
internalFlag: "",
|
||||
paymentMethod: "",
|
||||
cretNo: "",
|
||||
createDate: "",
|
||||
originalFileName: "",
|
||||
uploadTime: "",
|
||||
sourceFileName: "",
|
||||
fileName: "",
|
||||
});
|
||||
|
||||
export default {
|
||||
@@ -593,6 +589,7 @@ export default {
|
||||
},
|
||||
closeDetailDialog() {
|
||||
this.detailVisible = false;
|
||||
this.detailLoading = false;
|
||||
this.detailData = createEmptyDetailData();
|
||||
},
|
||||
handleExport() {
|
||||
@@ -607,7 +604,10 @@ export default {
|
||||
);
|
||||
},
|
||||
formatField(value) {
|
||||
return value || "-";
|
||||
if (value === null || value === undefined || value === "") {
|
||||
return "-";
|
||||
}
|
||||
return String(value);
|
||||
},
|
||||
formatDate(value) {
|
||||
return value ? parseTime(value, "{y}-{m}-{d} {h}:{i}:{s}") : "-";
|
||||
@@ -616,11 +616,55 @@ export default {
|
||||
if (value === null || value === undefined || value === "") {
|
||||
return "-";
|
||||
}
|
||||
return Number(value).toLocaleString("zh-CN", {
|
||||
const amount = Number(value);
|
||||
if (Number.isNaN(amount)) {
|
||||
return "-";
|
||||
}
|
||||
return amount.toLocaleString("zh-CN", {
|
||||
minimumFractionDigits: 2,
|
||||
maximumFractionDigits: 2,
|
||||
});
|
||||
},
|
||||
formatSignedAmount(value) {
|
||||
if (value === null || value === undefined || value === "") {
|
||||
return "-";
|
||||
}
|
||||
const amount = Number(value);
|
||||
if (Number.isNaN(amount)) {
|
||||
return "-";
|
||||
}
|
||||
const text = this.formatAmount(amount);
|
||||
return amount > 0 ? `+${text}` : text;
|
||||
},
|
||||
getAmountClass(value) {
|
||||
if (value === null || value === undefined || value === "") {
|
||||
return "";
|
||||
}
|
||||
return Number(value) >= 0 ? "amount-in" : "amount-out";
|
||||
},
|
||||
formatCounterpartyName(detail) {
|
||||
if (!detail) {
|
||||
return "-";
|
||||
}
|
||||
return this.formatField(detail.customerAccountName);
|
||||
},
|
||||
formatOriginalFileName(detail) {
|
||||
if (!detail) {
|
||||
return "暂无原始文件";
|
||||
}
|
||||
return (
|
||||
detail.originalFileName ||
|
||||
detail.sourceFileName ||
|
||||
detail.fileName ||
|
||||
"暂无原始文件"
|
||||
);
|
||||
},
|
||||
formatOriginalFileUploadTime(detail) {
|
||||
if (!detail) {
|
||||
return "-";
|
||||
}
|
||||
return this.formatDate(detail.uploadTime);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -747,7 +791,7 @@ export default {
|
||||
}
|
||||
|
||||
.result-card {
|
||||
border: 1px solid #ebeef5;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
overflow: hidden;
|
||||
}
|
||||
@@ -789,51 +833,106 @@ export default {
|
||||
color: #f56c6c;
|
||||
}
|
||||
|
||||
.detail-drawer-body {
|
||||
padding: 0 4px 24px;
|
||||
.detail-dialog-body {
|
||||
min-height: 280px;
|
||||
}
|
||||
|
||||
.detail-section {
|
||||
margin-bottom: 20px;
|
||||
padding: 16px;
|
||||
border: 1px solid #ebeef5;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.detail-section-title {
|
||||
margin-bottom: 14px;
|
||||
font-size: 15px;
|
||||
font-weight: 600;
|
||||
color: #303133;
|
||||
}
|
||||
|
||||
.detail-grid {
|
||||
.detail-overview-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
gap: 14px 16px;
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
gap: 24px 32px;
|
||||
}
|
||||
|
||||
.detail-item {
|
||||
.detail-field {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
gap: 10px;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.detail-item-full {
|
||||
.detail-field--full {
|
||||
grid-column: 1 / -1;
|
||||
}
|
||||
|
||||
.detail-label {
|
||||
font-size: 12px;
|
||||
font-size: 14px;
|
||||
line-height: 20px;
|
||||
color: #909399;
|
||||
}
|
||||
|
||||
.detail-value {
|
||||
color: #303133;
|
||||
line-height: 20px;
|
||||
line-height: 22px;
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.detail-file-block {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: 12px;
|
||||
padding: 2px 0;
|
||||
}
|
||||
|
||||
.detail-file-icon {
|
||||
margin-top: 2px;
|
||||
font-size: 20px;
|
||||
color: #f59a23;
|
||||
}
|
||||
|
||||
.detail-file-meta {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.detail-file-name {
|
||||
color: #303133;
|
||||
line-height: 22px;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.detail-file-time {
|
||||
color: #909399;
|
||||
font-size: 12px;
|
||||
line-height: 18px;
|
||||
}
|
||||
|
||||
.detail-dialog-footer {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
:deep(.detail-dialog) {
|
||||
border-radius: 8px;
|
||||
|
||||
.el-dialog__header {
|
||||
padding: 20px 24px;
|
||||
border-bottom: 1px solid #ebeef5;
|
||||
}
|
||||
|
||||
.el-dialog__title {
|
||||
font-size: 20px;
|
||||
font-weight: 600;
|
||||
color: #303133;
|
||||
}
|
||||
|
||||
.el-dialog__body {
|
||||
padding: 24px;
|
||||
}
|
||||
|
||||
.el-dialog__footer {
|
||||
padding: 8px 24px 24px;
|
||||
}
|
||||
|
||||
.el-button {
|
||||
min-width: 180px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 992px) {
|
||||
.query-page-shell {
|
||||
grid-template-columns: 1fr;
|
||||
@@ -842,6 +941,11 @@ export default {
|
||||
.filter-actions {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.detail-overview-grid {
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
gap: 20px 24px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
@@ -862,8 +966,30 @@ export default {
|
||||
margin: 12px 12px 0;
|
||||
}
|
||||
|
||||
.detail-grid {
|
||||
.detail-overview-grid {
|
||||
grid-template-columns: 1fr;
|
||||
gap: 18px;
|
||||
}
|
||||
|
||||
.detail-dialog-footer {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
:deep(.detail-dialog) {
|
||||
width: calc(100vw - 24px) !important;
|
||||
margin-top: 8vh !important;
|
||||
|
||||
.el-dialog__header,
|
||||
.el-dialog__body,
|
||||
.el-dialog__footer {
|
||||
padding-left: 16px;
|
||||
padding-right: 16px;
|
||||
}
|
||||
|
||||
.el-button {
|
||||
width: 100%;
|
||||
min-width: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -58,7 +58,7 @@
|
||||
<el-button icon="el-icon-refresh" @click="handleManualRefresh">刷新</el-button>
|
||||
</div>
|
||||
|
||||
<el-table :data="fileUploadList" v-loading="listLoading" stripe border>
|
||||
<el-table :data="fileUploadList" v-loading="listLoading">
|
||||
<el-table-column prop="fileName" label="文件名" min-width="200"></el-table-column>
|
||||
<el-table-column prop="fileSize" label="文件大小" width="120">
|
||||
<template slot-scope="scope">
|
||||
|
||||
46
ruoyi-ui/tests/unit/detail-query-detail-dialog.test.js
Normal file
46
ruoyi-ui/tests/unit/detail-query-detail-dialog.test.js
Normal file
@@ -0,0 +1,46 @@
|
||||
const assert = require("assert");
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
|
||||
const componentPath = path.resolve(
|
||||
__dirname,
|
||||
"../../src/views/ccdiProject/components/detail/DetailQuery.vue"
|
||||
);
|
||||
const source = fs.readFileSync(componentPath, "utf8");
|
||||
|
||||
assert(
|
||||
source.includes("<el-dialog"),
|
||||
"详情应改为 el-dialog 弹窗展示"
|
||||
);
|
||||
|
||||
assert(
|
||||
!source.includes("<el-drawer"),
|
||||
"详情不应再使用抽屉展示"
|
||||
);
|
||||
|
||||
[
|
||||
'class="detail-dialog"',
|
||||
'class="detail-overview-grid"',
|
||||
'class="detail-dialog-footer"',
|
||||
"formatCounterpartyName(detailData)",
|
||||
"formatOriginalFileName(detailData)",
|
||||
'width="980px"',
|
||||
].forEach((token) => {
|
||||
assert(
|
||||
source.includes(token),
|
||||
`详情弹窗缺少关键结构或方法: ${token}`
|
||||
);
|
||||
});
|
||||
|
||||
const tableBlockMatch = source.match(/<el-table[\s\S]*?class="result-table"[\s\S]*?>/m);
|
||||
assert(tableBlockMatch, "未找到流水明细列表表格");
|
||||
assert(
|
||||
!/\sborder(\s|>)/.test(tableBlockMatch[0]),
|
||||
"流水明细列表不应再启用表格边框"
|
||||
);
|
||||
assert(
|
||||
!/\sstripe(\s|>)/.test(tableBlockMatch[0]),
|
||||
"流水明细列表不应再启用斑马纹"
|
||||
);
|
||||
|
||||
console.log("detail-query-detail-dialog test passed");
|
||||
@@ -53,12 +53,12 @@ assert(
|
||||
|
||||
assert(
|
||||
!source.includes("queryParams.transactionType"),
|
||||
"筛选逻辑不应再保留交易类型参数"
|
||||
"筛选逻辑中不应再保留交易类型参数"
|
||||
);
|
||||
|
||||
assert(
|
||||
!source.includes("queryParams.transactionTypeEmpty"),
|
||||
"筛选逻辑不应再保留交易类型空值匹配参数"
|
||||
"筛选逻辑中不应再保留交易类型空值匹配参数"
|
||||
);
|
||||
|
||||
assert(
|
||||
|
||||
27
ruoyi-ui/tests/unit/project-table-style.test.js
Normal file
27
ruoyi-ui/tests/unit/project-table-style.test.js
Normal file
@@ -0,0 +1,27 @@
|
||||
const assert = require("assert");
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
|
||||
const componentPath = path.resolve(
|
||||
__dirname,
|
||||
"../../src/views/ccdiProject/components/ProjectTable.vue"
|
||||
);
|
||||
const source = fs.readFileSync(componentPath, "utf8");
|
||||
|
||||
const tableBlockMatch = source.match(/<el-table[\s\S]*?style="width: 100%"[\s\S]*?>/m);
|
||||
|
||||
assert(tableBlockMatch, "未找到项目列表表格");
|
||||
assert(
|
||||
!/\sborder(\s|>)/.test(tableBlockMatch[0]),
|
||||
"项目列表表格不应启用边框"
|
||||
);
|
||||
assert(
|
||||
!/\sstripe(\s|>)/.test(tableBlockMatch[0]),
|
||||
"项目列表表格不应启用斑马纹"
|
||||
);
|
||||
assert(
|
||||
!source.includes("::v-deep .el-table"),
|
||||
"项目列表不应继续保留自定义深度表格皮肤"
|
||||
);
|
||||
|
||||
console.log("project-table-style test passed");
|
||||
25
ruoyi-ui/tests/unit/upload-data-file-list-table.test.js
Normal file
25
ruoyi-ui/tests/unit/upload-data-file-list-table.test.js
Normal file
@@ -0,0 +1,25 @@
|
||||
const assert = require("assert");
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
|
||||
const componentPath = path.resolve(
|
||||
__dirname,
|
||||
"../../src/views/ccdiProject/components/detail/UploadData.vue"
|
||||
);
|
||||
const source = fs.readFileSync(componentPath, "utf8");
|
||||
|
||||
const tableBlockMatch = source.match(
|
||||
/<el-table[\s\S]*?:data="fileUploadList"[\s\S]*?>/m
|
||||
);
|
||||
|
||||
assert(tableBlockMatch, "未找到上传数据文件列表表格");
|
||||
assert(
|
||||
!/\sborder(\s|>)/.test(tableBlockMatch[0]),
|
||||
"上传数据文件列表表格不应再启用边框"
|
||||
);
|
||||
assert(
|
||||
!/\sstripe(\s|>)/.test(tableBlockMatch[0]),
|
||||
"上传数据文件列表表格不应再启用斑马纹"
|
||||
);
|
||||
|
||||
console.log("upload-data-file-list-table test passed");
|
||||
Reference in New Issue
Block a user