Initial commit

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-09-17 12:02:35 +08:00
co-authored by Claude Opus 5
commit d999a5c0e6
643 changed files with 178681 additions and 0 deletions
+964
View File
@@ -0,0 +1,964 @@
<template>
<div class="home-box">
<div class="data-box" v-if="hasItemAuth('isTodayStatistics')">
<p class="title">
今日数据统计:
<span class="right">刷新时间: {{updatedAt | changeDate}}</span>
</p>
<ul class="item-box">
<li
class="data-item-box"
v-for="(item, i) in todayListData"
:key="i"
:class="'color-' + (i + 1)"
>
<div class="popup">
<div class="icon">
<img :src="item.icon" />
</div>
<div class="content">
<p>{{item.name }}</p>
<span v-if="item.text" class="number">2018-12-15</span>
<p v-else-if="item.type==='money'" class="number">
{{item.value |transformFloat| numFormat}}
<span
v-if="item.type === 'money'"
style="font-size: 18px"
>元</span>
</p>
<p v-else class="number">{{item.value | numFormat}}</p>
</div>
</div>
</li>
</ul>
</div>
<div class="data-box" v-if="hasItemAuth('isTotalStatistics')">
<p class="title">
数据汇总统计:
<span class="right">刷新时间: {{sumUpdateAt | changeDate}}</span>
</p>
<ul class="item-box">
<li
class="data-item-box"
v-for="(item, i) in sumListData"
:key="i"
:class="'color-' + (i + 1)"
>
<div class="popup">
<div class="icon">
<img :src="item.icon" />
</div>
<div class="content">
<p>{{item.name }}</p>
<span v-if="item.text" class="number">2018-12-15</span>
<p v-else-if="item.type === 'money'||item.type === 'avgMoney'" class="number">
{{item.value |transformFloat| numFormat }}
<span
v-if="item.type === 'money'"
style="font-size: 18px"
>元</span>
<span v-if="item.type === 'avgMoney'" style="font-size: 18px">元/人</span>
</p>
<p v-else class="number">{{item.value | numFormat}}</p>
</div>
</div>
</li>
</ul>
</div>
<!-- 访问量走势图 -->
<div class="action-chart">
<el-button
type="primary"
icon="el-icon-refresh"
size="small"
@click="chartData('views')"
v-if="hasItemAuth('isTrafficChart')"
>刷新</el-button>
</div>
<div class="data-chart" v-if="hasItemAuth('isTrafficChart')">
<div class="line" ref="chartline1"></div>
</div>
<!-- 注册量走势图 -->
<div class="action-chart" v-if="hasItemAuth('isRegisteredChart')">
<el-button
type="primary"
icon="el-icon-refresh"
size="small"
@click="chartData('registered')"
>刷新</el-button>
</div>
<div class="data-chart1" v-if="hasItemAuth('isRegisteredChart')">
<div class="line2" ref="chartline2"></div>
</div>
</div>
</template>
<script>
import API from "@/api";
import moment from "moment";
import echarts from "echarts";
import local from "@/utils/localStroage";
import { mapActions, mapGetters } from "vuex";
export default {
data() {
return {
showMap: {},
updatedAt: "",
sumUpdateAt: "",
todayListData: [
{
icon: require("@/assets/images/user.png"),
name: "新增用户",
value: 0,
filed: "newUserCount",
},
{
icon: require("@/assets/images/bind.png"),
name: "用户绑定数",
value: 0,
filed: "bindUserCount",
},
{
icon: require("@/assets/images/user.png"),
name: "新增绑定数",
value: 0,
filed: "newBindUserCount",
},
{
icon: require("@/assets/images/czrs.png"),
name: "充值人数",
value: 0,
filed: "rechargeUserCount",
},
{
icon: require("@/assets/images/czje.png"),
name: "在线充值金额",
type: "money",
value: 0,
filed: "onlineRechargeAmount",
},
{
icon: require("@/assets/images/gm.png"),
name: "商人充值金额",
type: "money",
value: 0,
filed: "merchantRechargeAmount",
},
{
icon: require("@/assets/images/user.png"),
name: "今日活跃用户",
value: 0,
filed: "visitUserCount",
},
{
icon: require("@/assets/images/vip.png"),
name: "购买VIP人数",
value: 0,
filed: "payVipUserCount",
},
{
icon: require("@/assets/images/gm.png"),
name: "购买VIP金币",
value: 0,
filed: "payVipAmount",
},
{
icon: require("@/assets/images/dsp.png"),
name: "新增短视频数",
value: 0,
filed: "newVideoCount",
},
{
icon: require("@/assets/images/xf.png"),
name: "视频消费金币",
value: 0,
filed: "payVidAmount",
},
//{
// icon: require('@/assets/images/dsp.png'),
// name: '观看视频人数',
// value: 1,
// filed: 'playUserCount'
//},
// {
// icon: require('@/assets/images/fzsj.png'),
// name: '在线人数峰值时间',
// text: true,
// value: 1,
// filed: 'addUser'
// },
{
icon: require("@/assets/images/user.png"),
name: "消费人数",
value: 0,
filed: "payUserCount",
},
{
icon: require("@/assets/images/jb.png"),
name: "消费金币",
value: 0,
filed: "payAmount",
},
{
icon: require("@/assets/images/zj.png"),
name: "新增充值率",
type: "percent",
value: 0,
filed: "newAndRechargeRate",
},
{
icon: require("@/assets/images/dl.png"),
name: "登录充值率",
type: "percent",
value: 0,
filed: "loginRechargeRate",
},
{
icon: require("@/assets/images/jb.png"),
name: "新增消费率",
type: "percent",
value: 0,
filed: "newAndPayUseRate",
},
{
icon: require("@/assets/images/tx.png"),
name: "金币提现金额",
type: "money",
value: 0,
filed: "goldWithdrawAmount",
},
{
icon: require("@/assets/images/gm.png"),
name: "代理提现金额",
type: "money",
value: 0,
filed: "proxyWithdrawAmount",
},
// {
// icon: require('@/assets/images/yq.png'),
// name: '拉流人数',
// value: 1,
// filed: 'addUser'
// },
],
sumListData: [
{
icon: require("@/assets/images/user.png"),
name: "总用户数",
value: 0,
filed: "userCount",
},
{
icon: require("@/assets/images/user.png"),
name: "总绑定用户数",
value: 0,
filed: "bindUserCount",
},
{
icon: require("@/assets/images/xf.png"),
name: "用户平均收入",
type: "avgMoney",
value: 0,
filed: "arpu",
},
{
icon: require("@/assets/images/xf.png"),
name: "充值用户平均收益",
value: 0,
type: "avgMoney",
filed: "arppu",
},
{
icon: require("@/assets/images/xf.png"),
name: "总充值金额",
value: 0,
type: "money",
filed: "rechargeAmount",
},
{
icon: require("@/assets/images/dsp.png"),
name: "视频总数",
value: 0,
filed: "videoCount",
},
],
arrList: [],
};
},
computed: {
//映射模拟倍率
...mapGetters([
"expansionFactor", //使用对象展开运算符将 getter 混入 computed 对象中
]),
isTodayStatistics() {
return this.arrList.find((it) => it === "isTodayStatistics");
},
isTotalStatistics() {
return this.arrList.find((it) => it === "isTotalStatistics");
},
isTrafficChart() {
return this.arrList.find((it) => it === "isTrafficChart");
},
isRegisteredChart() {
return this.arrList.find((it) => it === "isRegisteredChart");
},
},
created() {
this.getStatData();
let actJson = local.get("userInfo").actJson
? JSON.parse(local.get("userInfo").actJson)
: {};
this.initShowMap(actJson.checked);
this.initShowMap(actJson.halfChecked);
setInterval(() => {
this.getStatData();
}, 30000);
},
mounted() {
this.$nextTick(() => {
this.chartData("views");
this.chartData("registered");
});
setInterval(() => {
this.chartData("views");
this.chartData("registered");
}, 30000);
},
methods: {
//初始化显示项
initShowMap(actJson) {
if (!actJson) return;
for (let k in actJson) {
let auth = actJson[k];
if (auth.children) {
this.initShowMap(auth.children);
}
if (typeof auth === "string") {
this.showMap[auth] = true;
} else {
this.showMap[auth.name] = true;
}
}
},
//根据勾选权限判断是否显示
hasItemAuth(key) {
if (!this.showMap[key]) return false;
return this.showMap[key];
},
//映射模拟倍率方法
...mapActions(["setBeilv"]),
// 转换时间格式
changeTime(time) {
if (!time || time === "未知") {
return "未知";
}
let date = moment.utc(time).utcOffset(480).format("HH:mm");
return date;
},
// 统计数据接口
getStatData() {
API.getStatData({ expansionFactor: this.expansionFactor }).then((res) => {
this.setBeilv(this.expansionFactor);
if (res.code === 200 && res.data) {
this.updatedAt = res.data.today.updatedAt;
this.sumUpdateAt = res.data.total.updatedAt;
for (let key in res.data.today) {
this.todayListData.forEach((item) => {
if (item.filed === key) {
item.value =
item.type === "money"
? res.data.today[key] / 100
: res.data.today[key];
}
});
}
for (let key in res.data.total) {
this.sumListData.forEach((item) => {
if (item.filed === key) {
item.value =
item.type === "money" || item.type === "avgMoney"
? res.data.total[key] / 100
: res.data.total[key];
}
});
}
}
});
},
// 折线图展示数据
chartData(type) {
const myChart =
type === "views"
? echarts.init(this.$refs.chartline1)
: echarts.init(this.$refs.chartline2);
const tooltipObject = {
trigger: "axis",
axisPointer: {
lineStyle: {
color: "#ddd",
},
},
backgroundColor: "rgba(255,255,255,1)",
padding: [5, 10],
textStyle: {
color: "#7588E4",
},
extraCssText: "box-shadow: 0 0 5px rgba(0,0,0,0.3)",
};
// 加载样式
myChart.showLoading({
text: "拼命加载中",
color: "#d54867",
textColor: "#d54867",
maskColor: "rgba(255,255,255,0.8)",
zlevel: 0,
});
myChart.setOption(
{
title: {
text: type === "views" ? "访问量走势图" : "注册量走势图",
left: "20px",
textStyle: {
color: "#e63765",
},
},
grid: {
top: "80px",
left: "3%",
right: "4%",
bottom: "40px",
containLabel: true,
},
xAxis: {
type: "category",
boundaryGap: false,
splitLine: {
show: true,
interval: "auto",
lineStyle: {
color: ["#D4DFF5"],
},
},
axisTick: {
show: false,
},
axisLine: {
lineStyle: {
color: "#609ee9",
},
},
axisLabel: {
margin: 10,
interval: 10,
textStyle: {
fontSize: 14,
},
},
data: [],
},
yAxis: {
type: "value",
splitLine: {
lineStyle: {
color: ["#D4DFF5"],
},
},
axisTick: {
show: false,
},
axisLine: {
lineStyle: {
color: "#609ee9",
},
},
axisLabel: {
margin: 10,
type: "value",
formatter: function (val) {
return val > 0 ? `${val}人` : val;
},
textStyle: {
fontSize: 14,
},
},
},
series: [],
},
true
);
// 折线图数据接口
let getLineChartData =
type === "views"
? API.getViewsData({ expansionFactor: this.expansionFactor })
: API.getRegisteredChart({ expansionFactor: this.expansionFactor });
getLineChartData
.then((res) => {
this.setBeilv(this.expansionFactor);
if (
res.code === 200 &&
(res.data.yesterdayList || res.data.todayList)
) {
myChart.hideLoading();
let yesterdayIos = [];
let yesterdayAndroid = [];
let yesterdayH5 = [];
let yesterdayTotal = [];
let yesterdayTime = [];
let todayIos = [];
let todayAndroid = [];
let todayH5 = [];
let todayTotal = [];
let todayTime = [];
res.data.yesterdayList.forEach((item) => {
if (type === "views") {
yesterdayIos.push(item.iosVitCount);
yesterdayAndroid.push(item.ardVitCount);
yesterdayH5.push(item.iosH5VitCount);
yesterdayTotal.push(item.totalCount);
yesterdayTime.push(this.changeTime(item.recordAt));
} else {
yesterdayIos.push(item.iosRegCount);
yesterdayAndroid.push(item.ardRegCount);
yesterdayH5.push(item.iosH5RegCount);
yesterdayTotal.push(item.totalCount);
yesterdayTime.push(this.changeTime(item.recordAt));
}
});
res.data.todayList.forEach((item) => {
if (type === "views") {
todayIos.push(item.iosVitCount);
todayAndroid.push(item.ardVitCount);
todayH5.push(item.iosH5VitCount);
todayTotal.push(item.totalCount);
todayTime.push(this.changeTime(item.recordAt));
} else {
todayIos.push(item.iosRegCount);
todayAndroid.push(item.ardRegCount);
todayH5.push(item.iosH5RegCount);
todayTotal.push(item.totalCount);
todayTime.push(this.changeTime(item.recordAt));
}
});
// 昨日ios
let yesios = {
name: type === "views" ? "昨日ios访问量" : "昨日ios注册量",
data: yesterdayIos,
type: "line",
smooth: true,
symbol: "circle",
symbolSize: 1,
itemStyle: {
normal: {
color: "rgba(255,127,80,0.5)",
},
},
lineStyle: {
normal: {
width: 2,
},
},
areaStyle: {
color: ["rgba(255,127,80,0"],
},
};
// 昨日安卓
let yesand = {
name:
type === "views" ? "昨日android访问量" : "昨日android注册量",
data: yesterdayAndroid,
type: "line",
smooth: true,
symbol: "circle",
symbolSize: 1,
itemStyle: {
normal: {
color: "rgb(103,133,41,0.4)",
},
},
lineStyle: {
normal: {
width: 2,
},
},
areaStyle: {
color: "rgba(91,196,159,0)",
},
};
// 昨日h5
let yesh5 = {
name: type === "views" ? "昨日h5访问量" : "昨日h5注册量",
data: yesterdayH5,
type: "line",
smooth: true,
symbol: "circle",
symbolSize: 1,
itemStyle: {
normal: {
color: "rgba(135,206,255,0.6)",
},
},
lineStyle: {
normal: {
width: 2,
},
},
areaStyle: {
color: ["rgba(135,206,255,0)"],
},
};
// 昨日总访问量
let yestotal = {
name: type === "views" ? "昨日总访问量" : "昨日总注册量",
data: yesterdayTotal,
type: "line",
smooth: true,
symbol: "circle",
symbolSize: 1,
itemStyle: {
normal: {
color: "rgba(238,0,238,0.3)",
},
},
lineStyle: {
normal: {
width: 2,
},
},
areaStyle: {
color: ["rgba(238,0,238,0)"],
},
};
// 今日ios
let todios = {
name: type === "views" ? "今日ios访问量" : "今日ios注册量",
data: todayIos,
type: "line",
smooth: true,
symbol: "circle",
symbolSize: 1,
itemStyle: {
normal: {
color: "rgb(255, 127, 80)",
},
},
lineStyle: {
normal: {
width: 2,
},
},
areaStyle: {
color: ["rgba(255, 127, 80,0)"],
},
};
// 今日android
let toand = {
name:
type === "views" ? "今日android访问量" : "今日android注册量",
data: todayAndroid,
type: "line",
smooth: true,
symbol: "circle",
symbolSize: 1,
itemStyle: {
normal: {
color: "rgb(103,133,41)",
},
},
lineStyle: {
normal: {
width: 2,
},
},
areaStyle: {
color: ["rgba(91,196,159,0)"],
},
};
// 今日h5
let toh5 = {
name: type === "views" ? "今日h5访问量" : "今日h5注册量",
data: todayH5,
type: "line",
smooth: true,
symbol: "circle",
symbolSize: 1,
itemStyle: {
normal: {
color: "rgb(135,206,255)",
},
},
lineStyle: {
normal: {
width: 2,
},
},
areaStyle: {
color: ["rgba(135,206,255,0)"],
},
};
// 今日总访问量
let tototal = {
name: type === "views" ? "今日总访问量" : "今日总注册量",
data: todayTotal,
type: "line",
smooth: true,
symbol: "circle",
symbolSize: 1,
itemStyle: {
normal: {
color: "rgb(238,0,238)",
},
},
lineStyle: {
normal: {
width: 2,
},
},
areaStyle: {
color: ["rgba(238,0,238,0)"],
},
};
// 今日图例
let toData =
type === "views"
? [
"今日ios访问量",
"今日android访问量",
"今日h5访问量",
"今日总访问量",
]
: [
"今日ios注册量",
"今日android注册量",
"今日h5注册量",
"今日总注册量",
];
let toSelec =
type === "views"
? {
今日ios访问量: true,
今日android访问量: true,
今日h5访问量: false,
今日总访问量: true,
}
: {
今日ios注册量: true,
今日android注册量: true,
今日h5注册量: false,
今日总注册量: true,
};
// 昨日图例
let yesData =
type === "views"
? [
"昨日ios访问量",
"昨日android访问量",
"昨日h5访问量",
"昨日总访问量",
]
: [
"昨日ios注册量",
"昨日android注册量",
"昨日h5注册量",
"昨日总注册量",
];
let yewSelec =
type === "views"
? {
昨日ios访问量: true,
昨日android访问量: true,
昨日h5访问量: false,
昨日总访问量: true,
}
: {
昨日ios注册量: true,
昨日android注册量: true,
昨日h5注册量: false,
昨日总注册量: true,
};
myChart.setOption({
tooltip: tooltipObject,
legend: [
{
x: "center",
y: "3%",
data: toData,
selected: toSelec,
},
{
x: "center",
y: "7%",
data: yesData,
selected: yewSelec,
},
],
xAxis: {
type: "category",
data: yesterdayTime,
},
yAxis: {
minInterval: 1,
},
series: [
todios,
toand,
toh5,
tototal,
yesios,
yesand,
yesh5,
yestotal,
],
});
} else {
myChart.showLoading({
text: "暂无数据",
color: "#ffffff",
textColor: "#8a8e91",
maskColor: "rgba(255, 255, 255, 0.8)",
});
this.load = false;
}
})
.catch(() => {
myChart.showLoading({
text: "暂无数据",
color: "#ffffff",
textColor: "#8a8e91",
maskColor: "rgba(255, 255, 255, 0.8)",
});
this.load = false;
});
// 图表大小适应窗口尺寸,不需要可删除
// window.onresize = function() {
// myChart.resize()
// }
},
},
};
</script>
<style scoped lang="scss">
.home-box {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
.data-box {
width: 100%;
flex: 1;
flex-direction: row;
padding-bottom: 50px;
.title {
font-size: 16px;
text-align: left;
color: #666;
}
.right {
text-align: right;
float: right;
margin-right: 22px;
}
}
.action-chart {
width: 100%;
padding-top: 100px;
display: flex;
justify-content: flex-end;
.change {
display: flex;
justify-content: space-between;
align-items: center;
padding-bottom: 30px;
.el-select {
margin-right: 15px;
}
}
.el-button {
width: 70px;
height: 32px;
}
}
.data-chart,
.data-chart1 {
display: flex;
flex-direction: column;
justify-content: flex-start;
width: 100%;
.line {
flex-grow: 1;
height: 600px;
}
.line2 {
flex-grow: 1;
height: 600px;
}
}
.dsn {
background: white;
}
.data-item-box {
width: 250px;
height: 80px;
float: left;
color: white !important;
border-radius: 5px;
margin: 30px 10px 0 10px;
background-size: 300% 100%;
display: flex;
position: relative;
overflow: hidden;
-o-transition: all 0.4s ease-in-out;
-webkit-transition: all 0.4s ease-in-out;
transition: all 0.4s ease-in-out;
&:hover {
cursor: pointer;
background-position: 100% 0;
-o-transition: all 0.4s ease-in-out;
-webkit-transition: all 0.4s ease-in-out;
transition: all 0.4s ease-in-out;
}
.popup {
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.3);
display: flex;
}
.icon {
background: white;
width: 50px;
height: 50px;
border-radius: 100%;
margin: 15px 10px 0 5px;
img {
width: 35px;
height: 35px;
margin-left: 7px;
margin-top: 7px;
}
}
.content {
flex: 1;
p {
font-size: 16px !important;
text-align: left;
line-height: 1;
margin: 15px 0 5px;
}
.number {
font-size: 24px !important;
// font-weight: bold;
}
}
}
}
</style>