|
|
<template> <div class="cash-management"> <div class="cash-title"> <div class="text1"> 现金管理 <!-- <span class="text1-update-time">--> <!-- 最后更新时间:{{ workDataUpdateTime || '该地区暂无数据' }}--> <!-- </span>--> <el-popover placement="top-start" title="数据说明" :width="240" trigger="hover" content="此数据实时计算,存在误差,请勿作为最终数据使用。" > <template #reference> <el-icon class="service-icon" style=" margin-left: 5px; cursor: pointer; font-size: 16px; transition: all 0.3s ease;"> <Warning/> </el-icon> </template> </el-popover>
</div> </div>
<div class=" text2 "> <span class="text2-income">总营收:{{ totalIncome.toFixed(2) }} 新币</span> </div>
<div class="chart-container"> <!-- 左侧数据列表 --> <div class="market-data"> <div v-if="marksFlag" v-for="market in cashData.markets" :key="market.name" class="market-item"> <span class="market-name">{{ market.name }}:</span> <span class="market-value">{{ market.value.toLocaleString() }} 新币</span> </div> <div v-else> <div v-for="item in cashData.markets" :key="item.name" class="market-item"> <span class="market-name">代收{{ item.name }}:</span> <span class="market-value">{{ item.value.toLocaleString() }} </span> </div> </div>
</div>
<!-- 图表 --> <div ref="chartRef" class="chart"></div> </div> </div></template>
<script setup>import * as echarts from 'echarts'import {onMounted, ref} from 'vue'import request from "@/util/http.js";import API from "@/util/http.js";import {Warning,Service} from "@element-plus/icons-vue";
const chartRef = ref(null)let chartInstance = null
// 响应式数据
const cashData = ref({ markets: []})
const markets = ref()
// 定义默认市场
const defaultMarkets = [ {name: '新加坡', value: 0}, {name: '马来西亚', value: 0}, {name: '香港', value: 0}, {name: '泰国', value: 0}, {name: '越南HCM', value: 0}, {name: '加拿大', value: 0}, // {name: '未知', value: 0},
// { name: '其他', value: 0 },
// {name: '市场部', value: 0},
// { name: '深圳运营', value: 0 },
// { name: '研发部', value: 0 },
]
const workDataUpdateTime = ref('')const totalIncome = ref(0)
// 获取当前年份
const currentYear = new Date().getFullYear();
// 本年第一天 00:00:00
const startDate = `${currentYear}-01-01 00:00:00`;// 本年最后一天 23:59:59
const endDate = `${currentYear}-12-31 23:59:59`;// 获取接口数据
const fetchCashData = async () => { try { const res = await request({ url: '/workbench/getTotalRevenue', method: 'POST', data: { startDate: startDate, endDate: endDate }
})
console.log("jjjjjjj", res.market)
// const data = res
console.log("jjjjjjj", res) // 总新币
console.log("totalIncome", res) totalIncome.value = res.reduce((sum, item) => { return sum + (item.totalSGD || 0); }, 0); // 格式化数据
if (marksFlag.value) { // 生成接口数据映射表
const resMap = new Map( res.map(item => [item.market, Number(item.totalSGD) || 0]) ) // 合并:优先用接口数据,否则默认 0
markets.value = defaultMarkets.map(m => ({ name: m.name, value: resMap.get(m.name) ?? 0 })) } else { // 1. 定义币种中英文对照表
const currencyMap = { usd: '美元', hkd: '港币', sgd: '新币', myr: '马币', thb: '泰铢', cad: '加币', vdn: '越南盾', krw: '韩元' }
// 2. 取出所有币种字段(排除 market 与 totalSGD)
const currencyKeys = Object.keys(res[0]).filter( key => key !== 'market' && key !== 'totalSGD' )
// 3. 累加每个币种的总额并替换中文名
markets.value = currencyKeys.map(currency => { const total = res.reduce((sum, item) => sum + (Number(item[currency]) || 0), 0) return { name: currencyMap[currency.toLowerCase()] || currency.toUpperCase(), value: total } }) }
// 更新数据
cashData.value.markets = markets.value console.log("cashData", cashData.value.markets) // // 使用reduce方法遍历markets数组,将所有市场的value值累加,赋值给totalIncome响应式变量
// totalIncome.value = markets.value.reduce((sum, cur) => sum + cur.value, 0)
// workDataUpdateTime.value = new Date().toLocaleString('zh-CN', { hour12: false })
renderChart() } catch (err) { console.error('获取数据失败:', err) }}
// 标记地区 为 研发部、总部时值为
const marksFlag = ref();const loading = ref(true); // 新增加载状态
const getAdminData = async function () { try { loading.value = true; // 开始加载
const result = await API({url: '/admin/userinfo', data: {}}); marksFlag.value = result.markets === '总部' || result.markets === '研发部'; console.log("marksFlag", marksFlag.value); // alert(marksFlag.value)
} catch (error) { console.log('请求失败', error); } finally { loading.value = false; // 无论成功失败都结束加载
}};
// 渲染饼图
const renderChart = () => { if (!chartRef.value) return if (!chartInstance) chartInstance = echarts.init(chartRef.value)
const option = { tooltip: {trigger: 'item'}, legend: { bottom: 5, icon: 'circle', left: 'center' }, series: [ { label: {show: false}, type: 'pie', radius: ['40%', '70%'], data: cashData.value.markets, center: ['60%', '45%'] } ] } chartInstance.setOption(option)}
onMounted(() => { fetchCashData() getAdminData()})</script>
<style scoped>/* 保留你原来的样式 */.cash-management { margin: 10px 5px; width: 100%; height: 550px; border-radius: 8px; background: #E7F4FD; box-shadow: 0 2px 2px 0 #00000040; display: flex; flex-direction: column; align-items: center;}
.cash-title { width: 100%; height: 5vh; flex-shrink: 0; border-radius: 8px; background: linear-gradient(90deg, #E4F0FC 0%, #C6ADFF 50%, #E4F0FC 100%); box-shadow: 0 2px 2px 0 #00152940; display: flex; align-items: center; justify-content: center;}
.text1 { color: #040a2d; font-family: "PingFang SC"; font-size: 28px; font-weight: 900;}
.text1-update-time { margin-left: 10px; color: #040a2d; font-size: 20px; font-weight: 700;}
.text2 { margin: 13px; width: 95%; height: 48px; border-radius: 8px; background: linear-gradient(90deg, #E4F0FC 0%, #C1DCF8 50%, #E4F0FC 100%); box-shadow: 0 2px 2px 0 #00152940; display: flex; align-items: center; justify-content: center;}
.text2-income { color: #040a2d; font-size: 20px; font-weight: 900;}
.chart-container { display: flex; align-items: center; width: 100%; height: 100%; padding: 10px;}
.market-data { display: flex; width: 245px; flex-direction: column; align-items: flex-start; gap: 20px; padding: 10px; margin-left: 40px;}
.market-item { display: flex; justify-content: space-between; width: 100%; font-family: "PingFang SC"; font-size: 16px; color: #040a2d; white-space: nowrap; /* 禁止换行 */ overflow: hidden; /* 隐藏溢出内容 */ text-overflow: ellipsis; /* 溢出显示省略号 */ margin-bottom: 8px; /* 增加项间距,提升可读性 */}
.market-name { flex: 0 0 auto; /* 名称部分自适应宽度 */ margin-right: 16px; /* 与金额保持距离 */}
.market-value { flex: 1; /* 金额部分占剩余宽度 */ text-align: right;}
.chart { flex: 1; height: 300px; width: auto; margin-top: 10px;}
</style>
|