You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
343 lines
8.3 KiB
343 lines
8.3 KiB
<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 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 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 () => {
|
|
getAdminData()
|
|
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 if (marksFlag.value=== false) {
|
|
// 1. 定义币种中英文对照表
|
|
const currencyMap = {
|
|
sgd: '新币',
|
|
myr: '马币',
|
|
hkd: '港币',
|
|
cad: '加币',
|
|
thb: '泰铢',
|
|
vdn: '越南盾',
|
|
};
|
|
|
|
// 2. 取出所有币种字段(排除 market 与 totalSGD),只保留 currencyMap 中定义的币种
|
|
const currencyKeys =
|
|
res.length > 0
|
|
? Object.keys(res[0]).filter(
|
|
key =>
|
|
key !== 'market' &&
|
|
key !== 'totalSGD' &&
|
|
Object.keys(currencyMap).includes(key.toLowerCase())
|
|
)
|
|
: Object.keys(currencyMap);
|
|
|
|
// 3. 累加每个币种的总额并替换中文名
|
|
markets.value = currencyKeys.map(currency => {
|
|
const lowerCurrency = currency.toLowerCase();
|
|
const total =
|
|
res.length > 0
|
|
? res.reduce((sum, item) => sum + (Number(item[currency]) || 0), 0)
|
|
: 0;
|
|
|
|
return {
|
|
name: currencyMap[lowerCurrency],
|
|
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(() => {
|
|
// getAdminData()
|
|
fetchCashData()
|
|
})
|
|
</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>
|