整合前端

This commit is contained in:
砂糖
2026-04-13 17:04:38 +08:00
parent 69609a2cb1
commit 5d4794c9bd
915 changed files with 144259 additions and 0 deletions

View File

@@ -0,0 +1,431 @@
<template>
<div class="app-container">
<!-- 查询表单 -->
<el-form :inline="true" :model="queryParams" class="demo-form-inline" label-width="100px">
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-form-item label="排序字段">
<el-select v-model="queryParams.sortField" placeholder="请选择" clearable @change="handleQuery">
<el-option label="盈亏额" value="profit_loss" />
<el-option label="启动时间" value="begin_time" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="1.5">
<el-form-item label="排序类型">
<el-select v-model="queryParams.sortOrder" placeholder="请选择" @change="handleQuery">
<el-option label="正序" value="asc" />
<el-option label="倒序" value="desc" />
</el-select>
</el-form-item>
</el-col>
<div style="float: right; margin-left: 10px;">
<el-tooltip class="item" effect="dark" content="刷新" placement="top">
<el-button size="mini" circle icon="el-icon-refresh" @click="handleQuery" />
</el-tooltip>
<el-dropdown trigger="click" :hide-on-click="false" style="margin-left: 10px;">
<el-tooltip class="item" effect="dark" content="显隐列" placement="top">
<el-button size="mini" circle icon="el-icon-menu" />
</el-tooltip>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item v-for="column in columns" :key="column.prop">
<el-checkbox v-model="column.visible">{{ column.label }}</el-checkbox>
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</div>
</el-row>
<!-- <el-form-item>
<el-button type="primary" icon="el-icon-search" @click="handleQuery">查询</el-button>
<el-button icon="el-icon-refresh" @click="resetQuery">重置</el-button>
</el-form-item> -->
</el-form>
<!-- 盈亏列表表格 -->
<el-table :data="profitList" v-loading="loading" border style="width: 100%; margin-top: 20px;">
<el-table-column fixed="left" prop="projectName" label="项目名称" min-width="120" v-if="columnVisibility.projectName"
show-overflow-tooltip>
<template slot="header" slot-scope="scope">
<div style="text-align: center;">项目名称</div>
<el-input v-model="queryParams.projectName" placeholder="筛选" clearable @input="handleQuery" size="mini"
style="margin-top: 5px;" />
</template>
</el-table-column>
<el-table-column prop="projectNum" label="项目编号" min-width="120" v-if="columnVisibility.projectNum">
<template slot="header" slot-scope="scope">
<div style="text-align: center;">项目编号</div>
<el-input v-model="queryParams.projectNum" placeholder="筛选" clearable @input="handleQuery" size="mini"
style="margin-top: 5px;" />
</template>
</el-table-column>
<el-table-column prop="projectCode" label="项目代号" min-width="120" v-if="columnVisibility.projectCode">
<template slot="header" slot-scope="scope">
<div style="text-align: center;">项目代号</div>
<el-input v-model="queryParams.projectCode" placeholder="筛选" clearable @input="handleQuery" size="mini"
style="margin-top: 5px;" />
</template>
</el-table-column>
<el-table-column prop="projectStatus" label="项目状态" min-width="100" v-if="columnVisibility.projectStatus">
<template slot="header" slot-scope="scope">
<div style="text-align: center;">项目状态</div>
<el-select v-model="queryParams.projectStatus" placeholder="筛选" clearable @change="handleQuery" size="mini"
style="width: 100%; margin-top: 5px;">
<el-option label="进行中" :value="0" />
<el-option label="完结" :value="1" />
</el-select>
</template>
<template slot-scope="scope">
<el-tag :type="scope.row.projectStatus === '0' ? 'success' : 'info'">
{{ scope.row.projectStatus === '0' ? '进行中' : '完结' }}
</el-tag>
</template>
</el-table-column>
<el-table-column prop="signingCompany" label="签约公司" min-width="120" v-if="columnVisibility.signingCompany">
<template slot="header" slot-scope="scope">
<div style="text-align: center;">签约公司</div>
<el-select v-model="queryParams.signingCompany" placeholder="筛选" clearable @change="handleQuery" size="mini"
style="width: 100%; margin-top: 5px;">
<el-option v-for="dict in dict.type.signing_company" :key="dict.value" :label="dict.label"
:value="dict.value" />
</el-select>
</template>
<template slot-scope="scope">
<dict-tag :options="dict.type.signing_company" :value="scope.row.signingCompany" />
</template>
</el-table-column>
<el-table-column prop="tradeType" label="贸易类型" min-width="100" v-if="columnVisibility.tradeType">
<template slot="header" slot-scope="scope">
<div style="text-align: center;">贸易类型</div>
<el-select v-model="queryParams.tradeType" placeholder="筛选" clearable @change="handleQuery" size="mini"
style="width: 100%; margin-top: 5px;">
<el-option v-for="dict in dict.type.sys_trade_type" :key="dict.value" :label="dict.label"
:value="dict.value" />
</el-select>
</template>
<template slot-scope="scope">
<dict-tag :options="dict.type.sys_trade_type" :value="scope.row.tradeType" />
</template>
</el-table-column>
<el-table-column prop="originalFunds" label="原始合同金额" min-width="120" v-if="columnVisibility.originalFunds">
<template slot="header" slot-scope="scope">
<div style="text-align: center;">原始合同金额</div>
<div style="margin-top: 5px;">
<el-input v-model="queryParams.minContractAmount" placeholder="最小" clearable @input="handleQuery"
size="mini" style="width: 45%;" />
<span style="margin: 0 2px;">-</span>
<el-input v-model="queryParams.maxContractAmount" placeholder="最大" clearable @input="handleQuery"
size="mini" style="width: 45%;" />
</div>
</template>
<template slot-scope="scope">
<span>{{ scope.row.originalFunds == null ? scope.row.detailIncome : scope.row.originalFunds }}</span>
</template>
</el-table-column>
<el-table-column prop="totalIncomeCny" label="人民币金额(¥)" min-width="120"
v-if="columnVisibility.contractAmountCny" />
<el-table-column prop="totalExpenditure" label="支出(¥)" min-width="120" v-if="columnVisibility.totalExpenditure">
<template slot="header" slot-scope="scope">
<div style="text-align: center;">支出(¥)</div>
<!-- <div style="margin-top: 5px;">
<el-input v-model="queryParams.minTotalExpenditure" placeholder="最小" clearable @input="handleQuery" size="mini" style="width: 45%;" />
<span style="margin: 0 2px;">-</span>
<el-input v-model="queryParams.maxTotalExpenditure" placeholder="最大" clearable @input="handleQuery" size="mini" style="width: 45%;" />
</div> -->
</template>
</el-table-column>
<el-table-column prop="profitLoss" label="盈亏金额(元)" min-width="120" v-if="columnVisibility.profitLoss">
<template slot="header" slot-scope="scope">
<div style="text-align: center;">盈亏金额()</div>
<div style="margin-top: 5px;">
<el-input v-model="queryParams.minProfitLoss" placeholder="最小" clearable @input="handleQuery" size="mini"
style="width: 45%;" />
<span style="margin: 0 2px;">-</span>
<el-input v-model="queryParams.maxProfitLoss" placeholder="最大" clearable @input="handleQuery" size="mini"
style="width: 45%;" />
</div>
</template>
<template slot-scope="scope">
<span v-if="scope.row.profitLoss !== null && scope.row.profitLoss !== undefined">
<span :class="getProfitLossClass(scope.row)" :style="getProfitLossStyle(scope.row)">
{{ parseFloat(scope.row.profitLoss).toFixed(2) }}
</span>
</span>
</template>
</el-table-column>
<el-table-column prop="beginTime" label="启动时间" min-width="120" v-if="columnVisibility.beginTime">
<template slot="header" slot-scope="scope">
<div style="text-align: center;">启动时间</div>
<el-date-picker v-model="queryParams.beginTimeRange" type="daterange" range-separator="至"
start-placeholder="开始" end-placeholder="结束" value-format="yyyy-MM-dd" size="mini"
style="width: 100%; margin-top: 5px;" @change="handleQuery" />
</template>
</el-table-column>
<el-table-column prop="profitType" label="盈亏类型" min-width="100" v-if="columnVisibility.profitType">
<template slot="header" slot-scope="scope">
<div style="text-align: center;">盈亏类型</div>
<el-select v-model="queryParams.profitType" placeholder="筛选" clearable @change="handleQuery" size="mini"
style="width: 100%; margin-top: 5px;">
<el-option label="盈利" value="profit" />
<el-option label="亏损" value="loss" />
</el-select>
</template>
<template slot-scope="scope">
<el-tag v-if="scope.row.profitLoss !== null && scope.row.profitLoss !== undefined"
:type="scope.row.profitLoss >= 0 ? 'success' : 'danger'">
{{ scope.row.profitLoss >= 0 ? '盈利' : '亏损' }}
</el-tag>
<el-tag size="mini" style="margin-left: 6px;" v-if="getProfitRate(scope.row) !== null">{{
getProfitRateTag(scope.row) }}</el-tag>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<el-pagination style="margin-top: 20px; text-align: right;" background
layout="total, sizes, prev, pager, next, jumper" :total="total" :page-size.sync="queryParams.pageSize"
:current-page.sync="queryParams.pageNum" :page-sizes="[10, 20, 50, 100]" @size-change="handleSizeChange"
@current-change="handlePageChange" />
</div>
</template>
<script>
import { listProfit } from '@/api/oa/finance/profit';
export default {
name: 'ProfitList',
dicts: ['sys_project_code', 'sys_trade_type', 'signing_company'],
data () {
return {
loading: false,
profitList: [],
total: 0,
// 盈亏阈值配置
profitThresholds: {
highProfit: 100000, // 高盈利阈值
highLoss: -50000, // 高亏损阈值
warningProfit: 50000, // 警告盈利阈值
warningLoss: -20000 // 警告亏损阈值
},
queryParams: {
projectName: '',
projectNum: '',
projectStatus: 1,
isDomestic: '',
minContractAmount: '',
maxContractAmount: '',
minUsdAmount: '',
maxUsdAmount: '',
minRmbAmount: '',
maxRmbAmount: '',
minProfitLoss: '',
maxProfitLoss: '',
beginTimeRange: [], // [beginTimeStart, beginTimeEnd]
profitType: '',
sortField: '',
sortOrder: 'desc',
pageNum: 1,
pageSize: 10,
projectCode: '',
minTotalExpenditure: '',
maxTotalExpenditure: '',
tradeType: '',
signingCompany: '',
},
// 列信息
columns: [
{ key: 0, prop: 'projectName', label: `项目名称`, visible: true },
{ key: 1, prop: 'projectNum', label: `项目编号`, visible: true },
{ key: 2, prop: 'projectCode', label: `项目代号`, visible: true },
{ key: 3, prop: 'projectStatus', label: `项目状态`, visible: true },
{ key: 4, prop: 'tradeType', label: `贸易类型`, visible: true },
{ key: 5, prop: 'signingCompany', label: `签约公司`, visible: true },
{ key: 5, prop: 'originalFunds', label: `原始合同金额`, visible: true },
{ key: 6, prop: 'contractAmountCny', label: `人民币金额(¥)`, visible: true },
{ key: 7, prop: 'totalExpenditure', label: `支出(¥)`, visible: true },
{ key: 8, prop: 'profitLoss', label: `盈亏金额(元)`, visible: true },
{ key: 9, prop: 'beginTime', label: `启动时间`, visible: true },
{ key: 10, prop: 'profitType', label: `盈亏类型`, visible: true }
],
}
},
computed: {
columnVisibility () {
return this.columns.reduce((acc, col) => {
acc[col.prop] = col.visible;
return acc;
}, {});
}
},
methods: {
getList () {
this.loading = true
// 拆分时间范围
const params = { ...this.queryParams }
if (params.beginTimeRange && params.beginTimeRange.length === 2) {
params.beginTimeStart = params.beginTimeRange[0]
params.beginTimeEnd = params.beginTimeRange[1]
}
delete params.beginTimeRange
listProfit(params).then(res => {
this.profitList = res.rows || []
this.total = res.total || 0
this.loading = false
}).catch(() => {
this.loading = false
})
},
handleQuery () {
this.queryParams.pageNum = 1
this.getList()
},
resetQuery () {
this.queryParams = {
projectName: '',
projectNum: '',
projectStatus: '',
isDomestic: '',
minContractAmount: '',
maxContractAmount: '',
minUsdAmount: '',
maxUsdAmount: '',
minRmbAmount: '',
maxRmbAmount: '',
minProfitLoss: '',
maxProfitLoss: '',
beginTimeRange: [],
profitType: '',
sortField: '',
sortOrder: 'desc',
pageNum: 1,
pageSize: 10,
projectCode: '',
minTotalExpenditure: '',
maxTotalExpenditure: '',
tradeType: '',
}
this.getList()
},
handleSizeChange (val) {
this.queryParams.pageSize = val
this.getList()
},
handlePageChange (val) {
this.queryParams.pageNum = val
this.getList()
},
getProfitRate (row) {
// 计算盈亏百分比originalFunds为0则用detailIncome
const base = row.originalFunds && row.originalFunds !== 0 ? row.originalFunds : row.detailIncome;
if (!base || base === 0) return null;
return row.profitLoss / base;
},
getProfitRateTag (row) {
const rate = this.getProfitRate(row);
console.log(rate, 'rate' + row.projectName, row);
if (row.totalIncomeCny < 0) return '亏损';
if (rate === null) return '-';
if (rate >= 0.2) return '高盈利';
if (rate <= -0.2) return '高亏损';
if (rate < 0) return '亏损';
if (rate >= 0 && rate <= 0.05) return '低盈利';
return '盈利';
},
getProfitLossClass (row) {
const rate = this.getProfitRate(row);
if (rate === null) return '';
if (row.totalIncomeCny < 0) return 'profit-high-loss';
if (rate >= 0.2) {
return 'profit-high-profit';
} else if (rate <= -0.2) {
return 'profit-high-loss';
} else if (rate < 0) {
return 'profit-warning-loss';
} else if (rate >= 0 && rate <= 0.05) {
return 'profit-warning-profit';
} else {
return 'profit-normal-profit';
}
},
getProfitLossStyle (row) {
const rate = this.getProfitRate(row);
if (rate === null) return {};
if (row.totalIncomeCny < 0) return { color: '#F56C6C', padding: '2px 6px', borderRadius: '4px' };
if (rate >= 0.2) {
return {
color: '#67C23A',
fontWeight: 'bold',
fontSize: '14px',
backgroundColor: '#f0f9ff',
padding: '2px 6px',
borderRadius: '4px'
};
} else if (rate <= -0.2) {
return {
color: '#F56C6C',
fontWeight: 'bold',
fontSize: '14px',
backgroundColor: '#fef0f0',
padding: '2px 6px',
borderRadius: '4px'
};
} else if (rate < 0) {
return {
color: '#F56C6C',
fontWeight: 'bold',
backgroundColor: '#fef0f0',
padding: '2px 6px',
borderRadius: '4px'
};
} else if (rate >= 0 && rate <= 0.05) {
return {
color: '#E6A23C',
fontWeight: 'bold',
backgroundColor: '#fdf6ec',
padding: '2px 6px',
borderRadius: '4px'
};
} else {
return { color: '#67C23A' };
}
},
},
mounted () {
this.getList()
}
}
</script>
<style scoped>
.demo-form-inline .el-form-item {
margin-bottom: 10px;
}
/* 盈亏金额样式 */
.profit-high-profit {
border: 2px solid #67C23A;
box-shadow: 0 2px 4px rgba(103, 194, 58, 0.2);
}
.profit-high-loss {
border: 2px solid #F56C6C;
box-shadow: 0 2px 4px rgba(245, 108, 108, 0.2);
}
.profit-warning-profit {
border: 1px solid #E6A23C;
box-shadow: 0 1px 3px rgba(230, 162, 60, 0.2);
}
.profit-warning-loss {
border: 1px solid #F56C6C;
box-shadow: 0 1px 3px rgba(245, 108, 108, 0.2);
}
.profit-normal-profit {
/* 正常盈利样式 */
}
.profit-normal-loss {
/* 正常亏损样式 */
}
</style>