大屏项目初始化

This commit is contained in:
2026-02-27 23:52:07 +08:00
parent f7f1e393c8
commit 6dc7e99b4b
20 changed files with 1085 additions and 2 deletions

View File

@@ -31,4 +31,26 @@ export function getErpAccountList(params) {
method: 'get',
params: params
})
}
/**
* 获取交易分类信息列表
*/
export function getErpCategoryList(params) {
return request({
url: '/biz/erpCategory/list',
method: 'get',
params: params
})
}
/**
* 获取明细信息列表
*/
export function getErpTransactionFlowList(params) {
return request({
url: '/biz/erpTransactionFlow/list',
method: 'get',
params: params
})
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 236 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.9 KiB

View File

@@ -6,12 +6,24 @@
</div>
<div class="pie-chart-container" ref="chartRef"></div>
</div>
<teleport to="body">
<div v-if="modalVisible" class="modal-overlay" @click.self="closeModal">
<div class="modal-content">
<IndexV01
:account-data="selectedAccountData"
@close="closeModal"
/>
</div>
</div>
</teleport>
</template>
<script setup>
import { ref, onMounted, onUnmounted } from 'vue'
import * as echarts from 'echarts'
import { getErpAccountList } from '@/api/bizApi'
import IndexV01 from './detail/indexV01.vue'
const vList = ref([])
const totalAmount = ref(0)
@@ -19,6 +31,9 @@ const chartRef = ref(null)
let chartInstance = null
const resizeHandler = () => chartInstance?.resize()
const modalVisible = ref(false)
const selectedAccountData = ref({})
const formatAmount = (amount) => {
return Number(amount).toFixed(2)
}
@@ -47,6 +62,11 @@ function calculateTotalAmount(data) {
}, 0)
}
const closeModal = () => {
modalVisible.value = false
selectedAccountData.value = {}
}
const initPieChart = () => {
const el = chartRef.value
if (!el) return
@@ -60,7 +80,8 @@ const initPieChart = () => {
const pieData = vList.value.map(item => ({
name: item.accountName || '未知账户',
value: (Number(item.currentBalance) || 0) / 10000,
originalValue: Number(item.currentBalance) || 0
originalValue: Number(item.currentBalance) || 0,
rawData: item
})).filter(item => item.value > 0)
const colorList = [
@@ -136,6 +157,17 @@ const initPieChart = () => {
chartInstance.setOption(option)
chartInstance.on('click', (params) => {
selectedAccountData.value = {
name: params.name,
originalValue: params.data.originalValue,
value: params.data.value,
percent: params.percent,
rawData: params.data.rawData
}
modalVisible.value = true
})
chartInstance.on('legendselectchanged', (params) => {
const selectedNames = Object.keys(params.selected).filter(name => params.selected[name])
const selectedData = vList.value.filter(item => {
@@ -201,6 +233,31 @@ onUnmounted(() => {
padding: 0;
}
:global(.modal-overlay) {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.6);
display: flex;
align-items: center;
justify-content: center;
z-index: 9999;
}
:global(.modal-content) {
width: 90vw;
height: 90vh;
max-width: 1400px;
max-height: 800px;
background: transparent !important;
border: none !important;
border-radius: 8px;
overflow: hidden;
box-shadow: none !important;
}
:deep(.echarts-tooltip) {
background-color: rgba(145, 200, 255, 0.9) !important;
border-color: #409EFF !important;

View File

@@ -0,0 +1,506 @@
<template>
<div class="detail-container">
<div class="detail-header">
<h3>{{ accountData.name }}详情</h3>
<button class="close-btn" @click="handleClose">×</button>
</div>
<div class="split-line"></div>
<div class="detail-body">
<el-form :model="searchForm" class="search-form">
<div class="form-items-wrapper">
<el-form-item label="交易名称:" class="form-item">
<el-input
v-model="searchForm.flowName"
placeholder="请输入交易名称"
clearable
/>
</el-form-item>
<el-form-item label="交易分类:" class="form-item">
<el-select
v-model="searchForm.categoryId"
placeholder="请选择交易分类"
clearable
class="custom-select"
teleport="body"
popper-class="theme-select-popper"
:popper-append-to-body="true"
>
<el-option
v-for="item in tranTypes"
:key="item.categoryId"
:label="item.categoryName"
:value="item.categoryId"
/>
</el-select>
</el-form-item>
<el-form-item label="交易类型:" class="form-item">
<el-select
v-model="searchForm.transactionType"
placeholder="请选择交易类型"
clearable
class="custom-select"
teleport="body"
popper-class="theme-select-popper"
:popper-append-to-body="true"
>
<el-option label="收入" value="2" />
<el-option label="支出" value="1" />
</el-select>
</el-form-item>
</div>
<el-form-item class="form-btn-group">
<el-button type="primary" @click="handleSearch">查询</el-button>
<el-button type="default" @click="handleReset" class="reset-btn">重置</el-button>
</el-form-item>
</el-form>
<el-table
:data="tableData"
stripe
style="width: 100%"
empty-text="暂无相关交易数据"
class="data-table"
v-loading="loading"
:header-cell-style="{
background: 'rgba(10, 30, 60, 0.8)',
color: '#a0cfff',
border: 'none',
borderBottom: '1px solid rgba(64, 158, 255, 0.3)'
}"
:row-style="{
background: 'transparent',
color: '#a0cfff',
border: 'none'
}"
:cell-style="{
border: 'none',
borderBottom: '1px solid rgba(64, 158, 255, 0.2)'
}"
>
<el-table-column prop="flowId" label="交易编号" />
<el-table-column prop="flowName" label="交易名称" />
<el-table-column prop="categoryName" label="交易分类" />
<el-table-column prop="tranType" label="交易类型" />
<el-table-column prop="amount" label="交易金额">
<template #default="scope">
¥{{ scope.row.amount }}
</template>
</el-table-column>
<el-table-column prop="remark" label="交易备注" />
<el-table-column prop="transactionTime" label="交易时间" />
</el-table>
<div class="pagination-wrapper">
<el-pagination
v-model:current-page="currentPage"
v-model:page-size="pageSize"
:page-sizes="[20,50,99]"
:total="total"
layout="total, sizes, prev, pager, next, jumper"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
class="custom-pagination"
teleport="body"
popper-class="theme-pagination-popper"
:popper-append-to-body="true"
/>
</div>
</div>
</div>
</template>
<script setup>
import { defineProps, defineEmits, ref, onMounted, reactive } from 'vue'
import { ElMessage } from 'element-plus'
import { getErpCategoryList, getErpTransactionFlowList } from '@/api/bizApi'
const props = defineProps({
accountData: {
type: Object,
default: () => ({})
}
})
const emit = defineEmits(['close'])
const handleClose = () => emit('close')
const tranTypes = ref();
const loading = ref(false);
const searchForm = reactive({
flowName: '',
transactionType: '',
categoryId: '',
})
const tableData = ref([]);
const currentPage = ref(1);
const pageSize = ref(20);
const total = ref(0);
const handleSearch = () => {
getList();
}
const handleReset = () => {
Object.assign(searchForm, {
flowName: '',
transactionType: '',
categoryId: '',
})
currentPage.value = 1;
getList();
}
const handleSizeChange = (val) => {
pageSize.value = val;
getList();
}
const handleCurrentChange = (val) => {
currentPage.value = val;
getList();
}
async function getTranTypes(){
try {
const res = await getErpCategoryList();
tranTypes.value = res || [];
} catch (error) {
console.error('获取数据失败:', error);
tranTypes.value = [];
}
}
async function getList() {
try {
const reqParmas = {
... searchForm,
pageNum: currentPage.value, // 当前页
pageSize: pageSize.value, // 每页条数
accountId: props.accountData.rawData?.accountId || '',
}
const res = await getErpTransactionFlowList(reqParmas);
total.value = res.total;
tableData.value = res.list || [];
} catch (error) {
console.error('获取数据失败:', error);
tableData.value = [];
}
}
onMounted(async () => {
await getList();
await getTranTypes();
})
</script>
<style scoped>
.detail-container {
width: 100%;
height: 100%;
padding: 12px;
color: #e0e6ff;
background: url('@/assets/images/border.png') no-repeat center center;
background-size: 100% 100%;
background-color: transparent !important;
border: none !important;
box-sizing: border-box;
position: relative;
z-index: 10001;
}
.detail-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 10px;
}
.detail-header h3 {
margin: 0;
color: #409EFF;
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.5);
font-size: 18px;
}
.close-btn {
background: transparent;
border: none;
font-size: 24px;
color: #e0e6ff;
cursor: pointer;
width: 40px;
height: 40px;
display: flex;
align-items: center;
justify-content: center;
transition: color 0.2s;
z-index: 10002;
}
.close-btn:hover {
color: #409EFF;
}
.split-line {
height: 1px;
background-color: #409EFF;
opacity: 0.6;
margin-bottom: 16px;
}
.detail-body {
width: 100%;
height: calc(100% - 80px);
border: 1px solid #409EFF;
border-radius: 6px;
padding: 16px;
background-color: rgba(10, 30, 60, 0.2);
box-sizing: border-box;
display: flex;
flex-direction: column;
gap: 16px;
overflow: visible;
position: relative;
z-index: 10001;
}
.search-form {
display: flex;
align-items: center;
width: 100%;
padding-bottom: 16px;
border-bottom: 1px solid rgba(64, 158, 255, 0.3);
flex-wrap: wrap;
position: relative;
z-index: 10001;
}
.form-items-wrapper {
display: flex;
flex: 1;
gap: 20px;
min-width: 0;
flex-wrap: wrap;
}
.form-item {
flex: 1;
margin-bottom: 0 !important;
min-width: 180px;
}
.date-range-item {
min-width: 280px !important;
}
.form-btn-group {
margin-left: 20px;
margin-bottom: 0 !important;
flex-shrink: 0;
display: flex;
gap: 10px;
}
.data-table {
flex: 1;
overflow: auto;
position: relative;
z-index: 10001;
}
.pagination-wrapper {
display: flex;
justify-content: flex-end;
align-items: center;
padding-top: 10px;
border-top: 1px solid rgba(64, 158, 255, 0.2);
background-color: rgba(10, 30, 60, 0.2);
flex-shrink: 0;
position: relative;
z-index: 10001;
}
:deep(.el-form-item__label) {
color: #e0e6ff !important;
font-size: 14px;
}
:deep(.el-input__wrapper),
:deep(.el-select__wrapper),
:deep(.el-date-editor__wrapper) {
background-color: rgba(0, 0, 0, 0.2) !important;
border: 1px solid #409EFF !important;
box-shadow: none !important;
width: 100% !important;
position: relative;
z-index: 10001;
}
:deep(.el-input__inner),
:deep(.el-select__inner),
:deep(.el-date-editor input) {
color: #e0e6ff !important;
background-color: transparent !important;
}
:deep(.el-input__placeholder),
:deep(.el-date-editor__placeholder) {
color: rgba(224, 230, 255, 0.6) !important;
}
:deep(.custom-pagination) {
--el-pagination-text-color: #e0e6ff;
--el-pagination-button-color: #e0e6ff;
--el-pagination-button-hover-color: #409EFF;
--el-pagination-button-active-color: #409EFF;
--el-pagination-border-color: #409EFF;
--el-pagination-bg-color: rgba(10, 30, 60, 0.2) !important;
z-index: 10001;
}
:deep(.el-pagination button) {
background-color: rgba(0, 0, 0, 0.2) !important;
border-color: #409EFF !important;
color: #e0e6ff !important;
}
:deep(.el-pagination .el-pager li) {
color: #e0e6ff !important;
}
:deep(.el-pagination .el-pager li.active) {
color: #409EFF !important;
font-weight: bold;
}
:deep(.el-table) {
--el-table-text-color: #a0cfff;
--el-table-header-text-color: #a0cfff;
--el-table-row-hover-bg-color: rgba(64, 158, 255, 0.2);
--el-table-border-color: transparent !important;
--el-table-stripe-row-bg-color: rgba(10, 30, 60, 0.3);
background-color: transparent !important;
border: none !important;
z-index: 10001;
}
:deep(.el-table th) {
border: none !important;
border-bottom: 1px solid rgba(64, 158, 255, 0.3) !important;
background-color: rgba(10, 30, 60, 0.8) !important;
color: #a0cfff !important;
}
:deep(.el-table td) {
border: none !important;
border-bottom: 1px solid rgba(64, 158, 255, 0.2) !important;
background-color: transparent !important;
color: #a0cfff !important;
}
:deep(.el-table--striped .el-table__row--striped td) {
background-color: rgba(10, 30, 60, 0.3) !important;
border-bottom-color: rgba(64, 158, 255, 0.2) !important;
}
:deep(.el-table__row:hover > td) {
background-color: rgba(64, 158, 255, 0.2) !important;
border-bottom-color: rgba(64, 158, 255, 0.3) !important;
}
:deep(.el-table tr:last-child td) {
border-bottom: none !important;
}
:deep(.el-table-empty-text) {
color: #a0cfff !important;
background-color: transparent !important;
}
:deep(.el-button) {
--el-button-text-color: #e0e6ff !important;
--el-button-border-color: #409EFF !important;
--el-button-hover-text-color: #fff !important;
--el-button-hover-border-color: #409EFF !important;
--el-button-hover-bg-color: rgba(64, 158, 255, 0.2) !important;
height: 32px;
padding: 0 16px;
z-index: 10001;
}
:deep(.el-button--primary) {
--el-button-text-color: #fff !important;
--el-button-bg-color: rgba(64, 158, 255, 0.8) !important;
--el-button-border-color: #409EFF !important;
--el-button-hover-bg-color: #409EFF !important;
}
:deep(.reset-btn) {
background-color: rgba(0, 0, 0, 0.2) !important;
border-color: #409EFF !important;
color: #e0e6ff !important;
}
:deep(.reset-btn:hover) {
background-color: rgba(64, 158, 255, 0.2) !important;
color: #fff !important;
}
:deep(.el-loading-mask) {
background-color: rgba(10, 30, 60, 0.8) !important;
z-index: 10002;
}
:deep(.el-table__loading-wrapper) {
background-color: transparent !important;
}
:deep(.el-loading-spinner .path) {
stroke: #409EFF !important;
}
:deep(.el-loading-text) {
color: #a0cfff !important;
}
.detail-body::-webkit-scrollbar,
:deep(.el-table__body-wrapper)::-webkit-scrollbar {
width: 6px;
height: 6px;
}
.detail-body::-webkit-scrollbar-track {
background: rgba(10, 30, 60, 0.1);
border-radius: 3px;
}
.detail-body::-webkit-scrollbar-thumb {
background: rgba(64, 158, 255, 0.5);
border-radius: 3px;
}
</style>
<style>
.theme-select-popper {
background-color: rgba(10, 30, 60, 0.95) !important;
border: 1px solid #409EFF !important;
color: #e0e6ff !important;
z-index: 99999 !important;
pointer-events: auto !important;
position: fixed !important;
}
.theme-select-popper .el-select-dropdown__item {
color: #e0e6ff !important;
background-color: transparent !important;
padding: 6px 12px !important;
}
.theme-select-popper .el-select-dropdown__item:hover {
background-color: rgba(64, 158, 255, 0.2) !important;
color: #fff !important;
}
.theme-select-popper .el-select-dropdown__item.selected {
background-color: rgba(64, 158, 255, 0.5) !important;
color: #fff !important;
}
.theme-pagination-popper {
background-color: rgba(10, 30, 60, 0.95) !important;
border: 1px solid #409EFF !important;
color: #e0e6ff !important;
z-index: 99999 !important;
pointer-events: auto !important;
position: fixed !important;
}
.theme-pagination-popper .el-pagination__sizes-option {
color: #e0e6ff !important;
background-color: transparent !important;
}
.theme-pagination-popper .el-pagination__sizes-option:hover {
background-color: rgba(64, 158, 255, 0.2) !important;
color: #fff !important;
}
.modal-overlay {
pointer-events: auto !important;
}
.modal-overlay .modal-content {
pointer-events: auto !important;
}
</style>