This commit is contained in:
weicw
2021-07-29 16:17:26 +08:00
commit a6eb6f83d1
127 changed files with 60792 additions and 0 deletions

View File

@@ -0,0 +1,602 @@
<template>
<div class="ele-body ele-body-card">
<!-- 顶部统计快 -->
<a-row :gutter="16">
<a-col :lg="6" :md="12" :sm="24" :xs="24">
<a-card class="analysis-chart-card" :bordered="false">
<div class="ele-text-secondary ele-cell">
<div class="ele-cell-content">总销售额</div>
<a-tooltip title="指标说明">
<question-circle-outlined/>
</a-tooltip>
</div>
<h1 class="analysis-chart-card-num">¥ 126,560</h1>
<div class="analysis-chart-card-content" style="padding-top: 16px;">
<a-space size="middle">
<span>周同比12% <caret-up-outlined class="ele-text-danger"/></span>
<span>日同比11% <caret-down-outlined class="ele-text-success"/></span>
</a-space>
</div>
<a-divider/>
<div>日销售额 12,423</div>
</a-card>
</a-col>
<a-col :lg="6" :md="12" :sm="24" :xs="24">
<a-card class="analysis-chart-card" :bordered="false">
<div class="ele-text-secondary ele-cell">
<div class="ele-cell-content">访问量</div>
<ele-tag color="red"></ele-tag>
</div>
<h1 class="analysis-chart-card-num">8,846</h1>
<ele-chart
ref="visitChart"
:options="visitChartOption"
class="analysis-chart-card-content"/>
<a-divider/>
<div>日访问量 1,234</div>
</a-card>
</a-col>
<a-col :lg="6" :md="12" :sm="24" :xs="24">
<a-card class="analysis-chart-card" :bordered="false">
<div class="ele-text-secondary ele-cell">
<div class="ele-cell-content">支付笔数</div>
<ele-tag color="blue"></ele-tag>
</div>
<h1 class="analysis-chart-card-num">6,560</h1>
<ele-chart
ref="payNumChart"
:options="payNumChartOption"
class="analysis-chart-card-content"/>
<a-divider/>
<div>转化率 60%</div>
</a-card>
</a-col>
<a-col :lg="6" :md="12" :sm="24" :xs="24">
<a-card class="analysis-chart-card" :bordered="false">
<div class="ele-text-secondary ele-cell">
<div class="ele-cell-content">活动运营效果</div>
<ele-tag color="green"></ele-tag>
</div>
<h1 class="analysis-chart-card-num">78%</h1>
<div class="analysis-chart-card-content" style="padding-top: 16px;">
<a-progress
:percent="78"
:show-info="false"
stroke-color="#13c2c2"/>
</div>
<a-divider/>
<a-space size="middle">
<span>周同比12% <caret-up-outlined class="ele-text-danger"/></span>
<span>日同比11% <caret-down-outlined class="ele-text-success"/></span>
</a-space>
</a-card>
</a-col>
</a-row>
<!-- 销售额访问量 -->
<a-card :bordered="false" :body-style="{padding: 0}">
<a-tabs size="large" class="monitor-card-tabs">
<a-tab-pane tab="销售额" key="saleroom">
<a-row :gutter="16">
<a-col :lg="17" :md="16" :sm="24" :xs="24">
<div class="demo-monitor-title">销售量趋势</div>
<ele-chart
ref="saleChart"
style="height: 320px;"
:options="saleChartOption"/>
</a-col>
<a-col :lg="7" :md="8" :sm="24" :xs="24">
<div class="demo-monitor-title">门店销售额排名</div>
<div
v-for="(item,index) in saleroomRankData"
:key="index"
class="demo-monitor-rank-item ele-cell">
<ele-tag
shape="circle"
:color="index<3?'#314659':''"
style="border: none;">{{ index + 1 }}
</ele-tag>
<div class="ele-cell-content">{{ item.name }}</div>
<div class="ele-text-secondary">{{ item.value }}</div>
</div>
</a-col>
</a-row>
</a-tab-pane>
<a-tab-pane tab="访问量" key="visits" force-render>
<a-row :gutter="16">
<a-col :lg="17" :md="16" :sm="24" :xs="24">
<div class="demo-monitor-title">访问量趋势</div>
<ele-chart
ref="visitsChart"
style="height: 320px;"
:options="visitsChartOption"/>
</a-col>
<a-col :lg="7" :md="8" :sm="24" :xs="24">
<div class="demo-monitor-title">门店访问量排名</div>
<div
v-for="(item,index) in visitsRankData"
:key="index"
class="demo-monitor-rank-item ele-cell">
<ele-tag
shape="circle"
:color="index<3?'#314659':''"
style="border: none;">{{ index + 1 }}
</ele-tag>
<div class="ele-cell-content">{{ item.name }}</div>
<div class="ele-text-secondary">{{ item.value }}</div>
</div>
</a-col>
</a-row>
</a-tab-pane>
<template #tabBarExtraContent>
<a-space size="middle" class="analysis-tabs-extra">
<a-radio-group v-model:value="saleSearch.dateType">
<a-radio-button value="1">今天</a-radio-button>
<a-radio-button value="2">本周</a-radio-button>
<a-radio-button value="3">本月</a-radio-button>
<a-radio-button value="4">本年</a-radio-button>
</a-radio-group>
<a-range-picker v-model:value="saleSearch.datetime">
<template #suffixIcon>
<calendar-outlined/>
</template>
</a-range-picker>
</a-space>
</template>
</a-tabs>
</a-card>
<!-- 折线图词云 -->
<a-row :gutter="16">
<a-col :lg="16" :md="14" :sm="24" :xs="24">
<a-card
:bordered="false"
title="最近1小时访问情况"
:body-style="{padding: '16px 6px 0 0'}">
<ele-chart
ref="visitHourChart"
style="height: 362px;"
:options="visitHourChartOption"/>
</a-card>
</a-col>
<a-col :lg="8" :md="10" :sm="24" :xs="24">
<a-card :bordered="false" title="热门搜索">
<ele-word-cloud
ref="hotSearchChart"
:data="hotSearchData"
style="height: 330px;"/>
</a-card>
</a-col>
</a-row>
</div>
</template>
<script>
import EleChart from 'ele-admin-pro/packages/ele-chart';
import EleWordCloud from 'ele-admin-pro/packages/ele-word-cloud';
import {
QuestionCircleOutlined,
CaretUpOutlined,
CaretDownOutlined,
CalendarOutlined
} from '@ant-design/icons-vue';
export default {
name: 'DashboardAnalysis',
components: {
EleChart,
EleWordCloud,
QuestionCircleOutlined,
CaretUpOutlined,
CaretDownOutlined,
CalendarOutlined
},
data() {
return {
// 支付笔数数据
payNumData: [],
// 销售量搜索参数
saleSearch: {
dateType: '4',
datetime: []
},
// 销售量数据
saleroomData: [],
// 销售量排名数据
saleroomRankData: [],
// 访问量数据
visitsData: [],
// 访问量排名数据
visitsRankData: [],
// 最近1小时访问情况数据
visitHourData: [],
// 词云数据
hotSearchData: []
};
},
computed: {
// 访问量折线图配置
visitChartOption() {
/*if (!this.payNumData.length) {
return null;
}*/
return {
color: '#975fe5',
tooltip: {
trigger: 'axis',
formatter: '<i class="ele-chart-dot" style="background: #975fe5;"></i>{b0}: {c0}'
},
grid: {
top: 10,
bottom: 0,
left: 0,
right: 0
},
xAxis: [
{
show: false,
type: 'category',
boundaryGap: false,
data: this.payNumData.map(d => d.date)
}
],
yAxis: [
{
show: false,
type: 'value',
splitLine: {
show: false
}
}
],
series: [
{
type: 'line',
smooth: true,
symbol: 'none',
areaStyle: {
opacity: 0.5
},
data: this.payNumData.map(d => d.value)
}
]
};
},
// 支付笔数柱状图配置
payNumChartOption() {
return {
tooltip: {
trigger: 'axis',
formatter: '<i class="ele-chart-dot" style="background: #3aa1ff;"></i>{b0}: {c0}'
},
grid: {
top: 10,
bottom: 0,
left: 0,
right: 0
},
xAxis: [
{
show: false,
type: 'category',
data: this.payNumData.map(d => d.date)
}
],
yAxis: [
{
show: false,
type: 'value',
splitLine: {
show: false
}
}
],
series: [
{
type: 'bar',
data: this.payNumData.map(d => d.value)
}
]
}
},
// 销售额柱状图配置
saleChartOption() {
return {
tooltip: {
trigger: 'axis'
},
xAxis: [
{
type: 'category',
data: this.saleroomData.map(d => d.month)
}
],
yAxis: [
{
type: 'value'
}
],
series: [
{
type: 'bar',
data: this.saleroomData.map(d => d.value)
}
]
};
},
// 访问量柱状图配置
visitsChartOption() {
return {
tooltip: {
trigger: 'axis'
},
xAxis: [
{
type: 'category',
data: this.visitsData.map(d => d.month)
}
],
yAxis: [
{
type: 'value'
}
],
series: [
{
type: 'bar',
data: this.visitsData.map(d => d.value)
}
]
};
},
// 最近1小时访问情况折线图配置
visitHourChartOption() {
/*if (!this.visitHourData.length) {
return null;
}*/
return {
tooltip: {
trigger: 'axis'
},
legend: {
data: ['浏览量', '访问量'],
right: 20
},
xAxis: [
{
type: 'category',
boundaryGap: false,
data: this.visitHourData.map(d => d.time)
}
],
yAxis: [
{
type: 'value'
}
],
series: [
{
name: '浏览量',
type: 'line',
smooth: true,
symbol: 'none',
areaStyle: {
opacity: 0.5
},
data: this.visitHourData.map(d => d.views)
},
{
name: '访问量',
type: 'line',
smooth: true,
symbol: 'none',
areaStyle: {
opacity: 0.5
},
data: this.visitHourData.map(d => d.visits)
}
]
}
}
},
mounted() {
this.getPayNumData();
this.getSaleroomData();
this.getVisitHourData();
this.getWordCloudData();
},
methods: {
/* 获取支付笔数数据 */
getPayNumData() {
this.payNumData = [
{date: '2020-06-12', value: 7},
{date: '2020-06-13', value: 5},
{date: '2020-06-14', value: 4},
{date: '2020-06-15', value: 2},
{date: '2020-06-16', value: 4},
{date: '2020-06-17', value: 7},
{date: '2020-06-18', value: 5},
{date: '2020-06-19', value: 6},
{date: '2020-06-20', value: 5},
{date: '2020-06-21', value: 9},
{date: '2020-06-22', value: 6},
{date: '2020-06-23', value: 3},
{date: '2020-06-24', value: 1},
{date: '2020-06-25', value: 5},
{date: '2020-06-26', value: 3},
{date: '2020-06-27', value: 6},
{date: '2020-06-18', value: 5}
];
},
/* 获取销售量数据 */
getSaleroomData() {
// 销售量
this.saleroomData = [
{month: '1月', value: 816},
{month: '2月', value: 542},
{month: '3月', value: 914},
{month: '4月', value: 781},
{month: '5月', value: 355},
{month: '6月', value: 796},
{month: '7月', value: 714},
{month: '8月', value: 1195},
{month: '9月', value: 1055},
{month: '10月', value: 271},
{month: '11月', value: 384},
{month: '12月', value: 1098}
];
this.saleroomRankData = [
{name: '工专路 1 号店', value: '323,234'},
{name: '工专路 2 号店', value: '323,234'},
{name: '工专路 3 号店', value: '323,234'},
{name: '工专路 4 号店', value: '323,234'},
{name: '工专路 5 号店', value: '323,234'},
{name: '工专路 6 号店', value: '323,234'},
{name: '工专路 7 号店', value: '323,234'}
];
// 访问量
this.visitsData = [
{month: '1月', value: 1098},
{month: '2月', value: 384},
{month: '3月', value: 271},
{month: '4月', value: 1055},
{month: '5月', value: 1195},
{month: '6月', value: 714},
{month: '7月', value: 796},
{month: '8月', value: 355},
{month: '9月', value: 781},
{month: '10月', value: 914},
{month: '11月', value: 542},
{month: '12月', value: 816}
];
this.visitsRankData = [
{name: '工专路 1 号店', value: '323,234'},
{name: '工专路 2 号店', value: '323,234'},
{name: '工专路 3 号店', value: '323,234'},
{name: '工专路 4 号店', value: '323,234'},
{name: '工专路 5 号店', value: '323,234'},
{name: '工专路 6 号店', value: '323,234'},
{name: '工专路 7 号店', value: '323,234'}
];
},
/* 获取最近1小时访问情况数据 */
getVisitHourData() {
this.visitHourData = [
{time: '16:00', visits: 15, views: 45},
{time: '16:05', visits: 39, views: 169},
{time: '16:10', visits: 152, views: 400},
{time: '16:15', visits: 94, views: 285},
{time: '16:20', visits: 102, views: 316},
{time: '16:25', visits: 86, views: 148},
{time: '16:30', visits: 39, views: 150},
{time: '16:35', visits: 38, views: 234},
{time: '16:40', visits: 95, views: 158},
{time: '16:45', visits: 30, views: 100},
{time: '16:50', visits: 86, views: 266}
];
},
/* 获取词云数据 */
getWordCloudData() {
this.hotSearchData = [
{name: "软妹子", value: 23},
{name: "汪星人", value: 23},
{name: "长腿欧巴", value: 23},
{name: "萝莉", value: 22},
{name: "辣~", value: 22},
{name: "K歌", value: 22},
{name: "大长腿", value: 21},
{name: "川妹子", value: 21},
{name: "女神", value: 21},
{name: "米粉", value: 20},
{name: "专注设计", value: 20},
{name: "逛街", value: 20},
{name: "黑长直", value: 20},
{name: "海纳百川", value: 19},
{name: "萌萌哒", value: 19},
{name: "坚持", value: 19},
{name: "话唠", value: 19},
{name: "果粉", value: 18},
{name: "喵星人", value: 18},
{name: "花粉", value: 18},
{name: "衬衫控", value: 18},
{name: "宅男", value: 17},
{name: "小清新", value: 17},
{name: "眼镜男", value: 17},
{name: "琼瑶", value: 17},
{name: "穷游党", value: 16},
{name: "铲屎官", value: 16},
{name: "正太", value: 16},
{name: "中二病", value: 16},
{name: "夜猫子", value: 15},
{name: "逗比", value: 15},
{name: "腹黑", value: 15},
{name: "吃鸡", value: 15},
{name: "为了联盟", value: 14},
{name: "背包客", value: 14},
{name: "民谣", value: 14},
{name: "为了部落", value: 14},
{name: "懒癌患者", value: 13},
{name: "追剧", value: 13},
{name: "IT民工", value: 13},
{name: "CNB成员", value: 13},
{name: "选择困难", value: 12},
{name: "锤粉", value: 12},
{name: "欧皇", value: 12},
{name: "仙气十足", value: 12}
];
}
},
activated() {
['visitChart', 'payNumChart', 'saleChart', 'visitsChart', 'visitHourChart', 'hotSearchChart'].forEach((name) => {
this.$refs[name].resize();
});
}
}
</script>
<style scoped>
/* 统计卡片 */
.analysis-chart-card :deep(.ant-card-body) {
padding: 16px 22px 12px 22px;
}
.analysis-chart-card-num {
font-size: 30px;
}
.analysis-chart-card-content {
height: 40px;
}
.analysis-chart-card :deep(.ant-divider) {
margin: 12px 0;
}
/* 销售额、访问量 */
.monitor-card-tabs :deep(.ant-tabs-bar) {
padding: 0 16px 0 4px;
}
.monitor-card-tabs :deep(.ant-tabs-tab) {
padding-left: 2px;
padding-right: 2px;
margin: 0 12px !important;
}
.monitor-card-tabs :deep(.ant-tabs-tabpane) {
padding-bottom: 10px;
}
.demo-monitor-title {
padding: 6px 20px;
}
.demo-monitor-rank-item {
padding: 0 20px;
margin-top: 18px;
}
@media screen and (max-width: 880px) {
.analysis-tabs-extra {
display: none;
}
}
</style>

View File

@@ -0,0 +1,668 @@
<template>
<div class="ele-body ele-body-card">
<!-- 顶部统计卡片 -->
<a-row :gutter="16">
<a-col :md="6" :sm="12" :xs="12">
<a-card :bordered="false" class="monitor-count-card">
<ele-tag
color="blue"
shape="circle"
size="large">
<eye-filled/>
</ele-tag>
<h1 class="monitor-count-card-num">21.2 k</h1>
<div class="monitor-count-card-text">总访问人数</div>
<ele-avatar-list
:data="visitUsers"
size="small"
:max="4"/>
</a-card>
</a-col>
<a-col :md="6" :sm="12" :xs="12">
<a-card :bordered="false" class="monitor-count-card">
<ele-tag
color="orange"
shape="circle"
size="large">
<fire-filled/>
</ele-tag>
<h1 class="monitor-count-card-num">1.6 k</h1>
<div class="monitor-count-card-text">点击量近30天</div>
<div class="monitor-count-card-trend ele-text-success">
<up-outlined/>
<span>110.5%</span>
</div>
<a-tooltip title="指标说明">
<question-circle-outlined class="monitor-count-card-tips"/>
</a-tooltip>
</a-card>
</a-col>
<a-col :md="6" :sm="12" :xs="12">
<a-card :bordered="false" class="monitor-count-card">
<ele-tag
color="red"
shape="circle"
size="large">
<flag-filled/>
</ele-tag>
<h1 class="monitor-count-card-num">826.0</h1>
<div class="monitor-count-card-text">到达量近30天</div>
<div class="monitor-count-card-trend ele-text-danger">
<down-outlined/>
<span>15.5%</span>
</div>
</a-card>
</a-col>
<a-col :md="6" :sm="12" :xs="12">
<a-card :bordered="false" class="monitor-count-card">
<ele-tag
color="green"
shape="circle"
size="large">
<thunderbolt-filled/>
</ele-tag>
<h1 class="monitor-count-card-num">28.8 %</h1>
<div class="monitor-count-card-text">转化率近30天</div>
<div class="monitor-count-card-trend ele-text-success">
<up-outlined/>
<span>65.8%</span>
</div>
<a-tooltip title="指标说明">
<question-circle-outlined class="monitor-count-card-tips"/>
</a-tooltip>
</a-card>
</a-col>
</a-row>
<a-row :gutter="16">
<!-- 用户分布 -->
<a-col :lg="18" :md="24" :sm="24" :xs="24">
<a-card :bordered="false" title="用户分布">
<a-row>
<a-col :sm="18" :xs="24">
<ele-chart
ref="userCountMapChart"
:options="userCountMapOption"
style="height: 485px;"/>
</a-col>
<a-col :sm="6" :xs="24">
<ele-chart
ref="userCountChart"
style="height: 485px;"
:options="userCountChartOption"/>
</a-col>
</a-row>
</a-card>
</a-col>
<!-- 在线人数 -->
<a-col :lg="6" :md="24" :sm="24" :xs="24">
<a-row :gutter="16">
<a-col :lg="24" :md="12" :sm="24" :xs="24">
<a-card :bordered="false" title="在线人数">
<div class="monitor-online-num-card">
<div>{{ currentTime }}</div>
<div class="monitor-online-num-title">
<ele-count-up
:end-val="228"
@ready="(ins) => { onlineNumAnimIns = ins; }"/>
</div>
<div class="monitor-online-num-text">在线总人数</div>
<a-badge status="processing" :text="updateTimeText"/>
</div>
</a-card>
</a-col>
<a-col :lg="24" :md="12" :sm="24" :xs="24">
<a-card
:bordered="false"
title="浏览器分布"
:body-style="{padding: '6px 0'}">
<ele-chart
ref="browserChart"
style="height: 240px;"
:options="browserChartOption"/>
</a-card>
</a-col>
</a-row>
</a-col>
<!-- 用户评价 -->
<a-col :lg="12" :md="24" :sm="24" :xs="24">
<a-card :bordered="false" title="用户评价">
<div class="ele-cell ele-cell-align-bottom">
<div style="font-size: 51px;line-height: 1;">4.5</div>
<div class="ele-cell-content">
<a-rate :value="userRate" disabled/>
<span style="color: #fadb14;margin-left: 8px;">很棒</span>
</div>
</div>
<div class="ele-cell" style="margin: 18px 0;">
<div style="font-size: 28px;line-height: 1;" class="ele-text-placeholder">-0%</div>
<div class="ele-cell-content ele-text-small ele-text-secondary">当前没有评价波动</div>
</div>
<div class="ele-cell">
<div class="ele-cell-content">
<a-progress
:percent="60"
stroke-color="#52c41a"
:show-info="false"/>
</div>
<div class="monitor-evaluate-text">
<star-filled/>
<span>5 : 368 </span>
</div>
</div>
<div class="ele-cell">
<div class="ele-cell-content">
<a-progress
:percent="40"
stroke-color="#1890ff"
:show-info="false"/>
</div>
<div class="monitor-evaluate-text">
<star-filled/>
<span>4 : 256 </span>
</div>
</div>
<div class="ele-cell">
<div class="ele-cell-content">
<a-progress
:percent="20"
stroke-color="#faad14"
:show-info="false"/>
</div>
<div class="monitor-evaluate-text">
<star-filled/>
<span>3 : 49 </span>
</div>
</div>
<div class="ele-cell">
<div class="ele-cell-content">
<a-progress
:percent="10"
stroke-color="#f5222d"
:show-info="false"/>
</div>
<div class="monitor-evaluate-text">
<star-filled/>
<span>2 : 14 </span>
</div>
</div>
<div class="ele-cell">
<div class="ele-cell-content">
<a-progress
:percent="0"
:show-info="false"/>
</div>
<div class="monitor-evaluate-text">
<star-filled/>
<span>1 : 0 </span>
</div>
</div>
</a-card>
</a-col>
<!-- 用户满意度 -->
<a-col :lg="6" :md="12" :sm="24" :xs="24">
<a-card :bordered="false" title="用户满意度">
<div class="ele-cell ele-text-center">
<div class="ele-cell-content" style="font-size: 24px;">856</div>
<div class="ele-cell-content">
<div class="monitor-face-smile"><i></i></div>
<div class="ele-text-secondary" style="margin-top: 8px;">正面评论</div>
</div>
<h2 class="ele-cell-content ele-text-success">82%</h2>
</div>
<a-divider style="margin: 26px 0;"/>
<div class="ele-cell ele-text-center">
<div class="ele-cell-content" style="font-size: 24px;">60</div>
<div class="ele-cell-content">
<div class="monitor-face-cry"><i></i></div>
<div class="ele-text-secondary" style="margin-top: 8px;">负面评论</div>
</div>
<h2 class="ele-cell-content ele-text-danger">9%</h2>
</div>
</a-card>
</a-col>
<!-- 用户活跃度 -->
<a-col :lg="6" :md="12" :sm="24" :xs="24">
<a-card :bordered="false" title="用户活跃度">
<div class="ele-cell" style="padding: 32px 0;">
<div class="ele-cell-content ele-text-center">
<div class="monitor-progress-group">
<a-progress
type="circle"
:percent="70"
stroke-color="#52c41a"
:show-info="false"
:width="161"/>
<a-progress
type="circle"
:percent="60"
stroke-color="#1890ff"
:show-info="false"
:width="121"
:stroke-width="5"/>
<a-progress
type="circle"
:percent="35"
stroke-color="#f5222d"
:show-info="false"
:width="91"
:stroke-width="4"/>
</div>
</div>
<div class="monitor-progress-legends">
<div class="ele-text-small">
<a-badge color="green" text="活跃率: 70%"/>
</div>
<div class="ele-text-small">
<a-badge color="blue" text="留存率: 60%"/>
</div>
<div class="ele-text-small">
<a-badge color="red" text="跳出率: 35%"/>
</div>
</div>
</div>
</a-card>
</a-col>
</a-row>
</div>
</template>
<script>
import EleCountUp from 'ele-admin-pro/packages/ele-count-up';
import EleChart from 'ele-admin-pro/packages/ele-chart';
import {
QuestionCircleOutlined,
EyeFilled,
FireFilled,
FlagFilled,
ThunderboltFilled,
UpOutlined,
DownOutlined,
StarFilled
} from '@ant-design/icons-vue';
export default {
name: 'DashboardMonitor',
components: {
EleCountUp,
EleChart,
QuestionCircleOutlined,
EyeFilled,
FireFilled,
FlagFilled,
ThunderboltFilled,
UpOutlined,
DownOutlined,
StarFilled
},
data() {
return {
// 访问人数头像列表数据
visitUsers: [
{
name: 'SunSmile',
avatar: 'https://cdn.eleadmin.com/20200609/c184eef391ae48dba87e3057e70238fb.jpg'
},
{
name: '你的名字很好听',
avatar: 'https://cdn.eleadmin.com/20200609/b6a811873e704db49db994053a5019b2.jpg'
},
{
name: '全村人的希望',
avatar: 'https://cdn.eleadmin.com/20200609/948344a2a77c47a7a7b332fe12ff749a.jpg'
},
{
name: 'Jasmine',
avatar: 'https://cdn.eleadmin.com/20200609/f6bc05af944a4f738b54128717952107.jpg'
},
{
name: '酷酷的大叔',
avatar: 'https://cdn.eleadmin.com/20200609/2d98970a51b34b6b859339c96b240dcd.jpg'
},
{
name: '管理员',
avatar: 'https://cdn.eleadmin.com/20200610/avatar.jpg'
}
],
// 在线总人数倒计时
updateTime: 5,
// 中国地图轮廓数据
chinaMapData: null,
// 用户分布数据
userCountData: [],
// 当前时间
currentTime: '20:58:22',
// 在线人数动画数字组件实例
onlineNumAnimIns: null,
// 在线人数更新定时器
onlineNumTimer: null,
// 浏览器分布环形图数据
browserCountData: [],
// 用户评分
userRate: 4.5
};
},
computed: {
// 在线人数倒计时文字
updateTimeText() {
return this.updateTime + ' 秒后更新';
},
// 用户分布地图配置
userCountMapOption() {
if (!this.chinaMapData) {
return null;
}
let data = this.userCountData.map(d => d.value).sort((a, b) => (a - b));
return {
tooltip: {
trigger: 'item'
},
visualMap: {
min: data[data.length - 1] || 0,
max: data[0] || 0,
text: ['高', '低'],
calculable: true,
color: ['#1890FF', '#EBF3FF']
},
series: [
{
name: '用户数',
type: 'map',
map: 'china',
label: {
show: true
},
data: this.userCountData
}
]
};
},
// 用户分布柱状图配置
userCountChartOption() {
let data = this.userCountData
.filter(d => d.value > 0)
.sort((a, b) => {
return a.value - b.value;
});
return {
tooltip: {
trigger: 'axis',
formatter: '<i class="ele-chart-dot" style="background: #3aa1ff;"></i>{b0}: {c0}'
},
grid: {
top: 0,
bottom: 0,
left: 50,
right: 0
},
yAxis: [
{
type: 'category',
axisLine: {
show: false
},
axisTick: {
show: false
},
data: data.map(d => d.name)
}
],
xAxis: [
{
show: false,
type: 'value',
splitLine: {
show: false
}
}
],
series: [
{
type: 'bar',
data: data.map(d => d.value)
}
]
};
},
// 浏览器分布饼图配置
browserChartOption() {
return {
tooltip: {
trigger: 'item'
},
legend: {
data: this.browserCountData.map(d => d.name),
bottom: 5,
itemWidth: 10,
itemHeight: 10,
icon: 'circle'
},
series: [
{
type: 'pie',
radius: ['45%', '70%'],
center: ['50%', '43%'],
label: {
show: false
},
data: this.browserCountData
}
]
};
}
},
mounted() {
this.doUpdateOnlineNum();
this.getChinaMapData();
this.getUserCountData();
this.getBrowserCountData();
},
methods: {
/* 在线人数更新倒计时 */
doUpdateOnlineNum() {
this.currentTime = this.$util.toDateString(new Date(), 'HH:mm:ss');
this.onlineNumTimer = setInterval(() => {
this.currentTime = this.$util.toDateString(new Date(), 'HH:mm:ss');
if (this.updateTime === 1) {
this.updateTime = 5;
if (this.onlineNumAnimIns) {
this.onlineNumAnimIns.update(100 + Math.round(Math.random() * 900));
}
} else {
this.updateTime--;
}
}, 1000);
},
/* 获取中国地图数据并注册地图 */
getChinaMapData() {
this.$http.get('https://cdn.eleadmin.com/20200610/china-provinces.geo.json').then(res => {
EleChart.registerMap('china', res.data);
this.chinaMapData = res.data;
}).catch(e => {
this.$message.error(e.message);
});
},
/* 获取用户分布数据 */
getUserCountData() {
this.userCountData = [
{name: "贵州", value: 570},
{name: "云南", value: 8890},
{name: "重庆", value: 10010},
{name: "吉林", value: 5056},
{name: "山西", value: 2123},
{name: "天津", value: 9130},
{name: "江西", value: 10170},
{name: "广西", value: 6172},
{name: "陕西", value: 9251},
{name: "黑龙江", value: 5125},
{name: "安徽", value: 9530},
{name: "北京", value: 51919},
{name: "福建", value: 3756},
{name: "上海", value: 59190},
{name: "湖北", value: 37109},
{name: "湖南", value: 8966},
{name: "四川", value: 31020},
{name: "辽宁", value: 7222},
{name: "河北", value: 3451},
{name: "河南", value: 9693},
{name: "浙江", value: 62310},
{name: "山东", value: 39231},
{name: "江苏", value: 35911},
{name: "广东", value: 55891}
];
},
/* 获取用户浏览器分布数据 */
getBrowserCountData() {
this.browserCountData = [
{name: 'Chrome', value: 9052},
{name: 'Safari', value: 535},
{name: 'Firefox', value: 1610},
{name: 'Edge', value: 2800},
{name: 'IE', value: 3200},
{name: 'Other', value: 1700}
];
}
},
activated() {
['userCountMapChart', 'userCountChart', 'browserChart'].forEach((name) => {
this.$refs[name].resize();
});
},
beforeUnmount() {
// 销毁定时器
if (this.onlineNumTimer) {
clearInterval(this.onlineNumTimer);
}
}
}
</script>
<style scoped>
/* 统计卡片 */
.monitor-count-card {
text-align: center;
}
.monitor-count-card .monitor-count-card-num {
margin-top: 6px;
font-size: 32px;
}
.monitor-count-card .monitor-count-card-text {
font-size: 12px;
margin: 8px 0;
opacity: .8;
}
.monitor-count-card .monitor-count-card-trend {
font-weight: bold;
line-height: 26px;
}
.monitor-count-card .monitor-count-card-trend > .anticon {
margin-right: 6px;
}
.monitor-count-card .monitor-count-card-tips {
position: absolute;
top: 16px;
right: 16px;
cursor: pointer;
opacity: .6;
}
/* 当前在线人数卡片 */
.monitor-online-num-card {
text-align: center;
}
.monitor-online-num-text {
margin-bottom: 6px;
}
.monitor-online-num-title {
font-size: 48px;
margin-bottom: 13px;
}
@media screen and (max-width: 992px) {
.monitor-online-num-card {
padding: 22px 0;
}
}
/* 用户评价 */
.monitor-evaluate-text {
width: 90px;
flex-shrink: 0;
white-space: nowrap;
opacity: .8;
}
.monitor-evaluate-text > .anticon {
font-size: 12px;
margin: 0 6px 0 8px;
}
/* 笑脸、哭脸 */
.monitor-face-smile, .monitor-face-cry {
width: 50px;
height: 50px;
display: inline-block;
background: #FBD971;
border-radius: 50%;
position: relative;
}
.monitor-face-smile > i, .monitor-face-smile:before, .monitor-face-smile:after,
.monitor-face-cry > i, .monitor-face-cry:before, .monitor-face-cry:after {
width: 28px;
height: 28px;
border-radius: 50%;
transform: rotate(225deg);
border: 3px solid #F0C419;
border-right-color: transparent !important;
border-bottom-color: transparent !important;
position: absolute;
bottom: 8px;
left: 11px;
}
.monitor-face-smile:before, .monitor-face-smile:after,
.monitor-face-cry:before, .monitor-face-cry:after {
content: "";
width: 12px;
height: 12px;
left: 8px;
top: 14px;
border-color: #F29C1F;
transform: rotate(45deg);
}
.monitor-face-smile:after, .monitor-face-cry:after {
left: auto;
right: 8px;
}
.monitor-face-cry > i {
transform: rotate(45deg);
bottom: -6px;
}
/** 圆形进度条组合 */
.monitor-progress-group {
position: relative;
display: inline-block;
}
.monitor-progress-group .ant-progress:not(:first-child) {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
margin-top: -1px;
}
.monitor-progress-legends > div + div {
margin-top: 8px;
}
</style>

View File

@@ -0,0 +1,708 @@
<template>
<div class="ele-body ele-body-card">
<!-- 顶部卡片 -->
<a-card
:bordered="false"
:body-style="{padding: '20px'}">
<div class="ele-cell workplace-user-card">
<div class="ele-cell-content ele-cell">
<a-avatar :size="68" :src="loginUser.avatar"/>
<div class="ele-cell-content">
<h4 class="ele-elip">早安{{ loginUser.nickname }}开始您一天的工作吧</h4>
<div class="ele-elip ele-text-secondary">
<cloud-outlined/>
<em>今日多云转阴18 - 22出门记得穿外套哦~</em>
</div>
</div>
</div>
<div class="workplace-count-group">
<div class="workplace-count-item">
<div class="workplace-count-header">
<ele-tag
color="blue"
shape="circle"
size="small">
<appstore-filled/>
</ele-tag>
<span class="workplace-count-name">项目数</span>
</div>
<h2>3</h2>
</div>
<div class="workplace-count-item">
<div class="workplace-count-header">
<ele-tag
color="orange"
shape="circle"
size="small">
<check-square-outlined/>
</ele-tag>
<span class="workplace-count-name">待办项</span>
</div>
<h2>6 / 24</h2>
</div>
<div class="workplace-count-item">
<div class="workplace-count-header">
<ele-tag
color="green"
shape="circle"
size="small">
<bell-filled/>
</ele-tag>
<span class="workplace-count-name">消息</span>
</div>
<h2>1,689</h2>
</div>
</div>
</div>
</a-card>
<!-- 快捷方式块 -->
<a-row :gutter="16">
<a-col :lg="3" :md="6" :sm="12" :xs="12">
<a-card
:bordered="false"
hoverable
:body-style="{padding: 0}">
<router-link
to="/system/user"
class="app-link-block">
<user-outlined class="app-link-icon"/>
<div class="app-link-title">用户</div>
</router-link>
</a-card>
</a-col>
<a-col :lg="3" :md="6" :sm="12" :xs="12">
<a-card
:bordered="false"
hoverable
:body-style="{padding: 0}">
<router-link
to="/dashboard/analysis"
class="app-link-block">
<shopping-cart-outlined
class="app-link-icon"
style="color: #95de64;"/>
<div class="app-link-title">分析</div>
</router-link>
</a-card>
</a-col>
<a-col :lg="3" :md="6" :sm="12" :xs="12">
<a-card
:bordered="false"
hoverable
:body-style="{padding: 0}">
<router-link
to="/list/card/project"
class="app-link-block">
<fund-projection-screen-outlined
class="app-link-icon"
style="color: #ff9c6e;"/>
<div class="app-link-title">商品</div>
</router-link>
</a-card>
</a-col>
<a-col :lg="3" :md="6" :sm="12" :xs="12">
<a-card
:bordered="false"
hoverable
:body-style="{padding: 0}">
<router-link
to="/list/basic"
class="app-link-block">
<file-search-outlined
class="app-link-icon"
style="color: #b37feb;"/>
<div class="app-link-title">订单</div>
</router-link>
</a-card>
</a-col>
<a-col :lg="3" :md="6" :sm="12" :xs="12">
<a-card
:bordered="false"
hoverable
:body-style="{padding: 0}">
<router-link
to="/list/advanced"
class="app-link-block">
<credit-card-outlined
class="app-link-icon"
style="color: #ffd666;"/>
<div class="app-link-title">票据</div>
</router-link>
</a-card>
</a-col>
<a-col :lg="3" :md="6" :sm="12" :xs="12">
<a-card
:bordered="false"
hoverable
:body-style="{padding: 0}">
<router-link
to="/user/message"
class="app-link-block">
<mail-outlined
class="app-link-icon"
style="color: #5cdbd3;"/>
<div class="app-link-title">消息</div>
</router-link>
</a-card>
</a-col>
<a-col :lg="3" :md="6" :sm="12" :xs="12">
<a-card
:bordered="false"
hoverable
:body-style="{padding: 0}">
<router-link
to="/extension/more"
class="app-link-block">
<tags-outlined
class="app-link-icon"
style="color: #ff85c0;"/>
<div class="app-link-title">标签</div>
</router-link>
</a-card>
</a-col>
<a-col :lg="3" :md="6" :sm="12" :xs="12">
<a-card
:bordered="false"
hoverable
:body-style="{padding: 0}">
<router-link
to="/user/profile"
class="app-link-block">
<control-outlined
class="app-link-icon"
style="color: #ffc069;"/>
<div class="app-link-title">配置</div>
</router-link>
</a-card>
</a-col>
</a-row>
<a-row :gutter="16">
<!-- 最新动态 -->
<a-col :lg="8" :md="24" :sm="24" :xs="24">
<a-card
title="最新动态"
:bordered="false"
:body-style="{padding: 0}">
<div
style="height: 347px;padding: 28px 20px 0 20px;"
class="ele-scrollbar-hover">
<a-timeline>
<a-timeline-item
v-for="(item, index) in activities"
:key="index"
:color="item.color">
<em>{{ item.time }}</em>
<em>{{ item.title }}</em>
</a-timeline-item>
</a-timeline>
</div>
</a-card>
</a-col>
<!-- 我的任务 -->
<a-col :lg="8" :md="24" :sm="24" :xs="24">
<a-card
title="我的任务"
:bordered="false"
:body-style="{padding: '10px 8px 10px 8px'}">
<div class="ant-table ant-table-middle">
<div class="ant-table-content">
<div class="ant-table-body" style="overflow-x: auto;">
<table style="min-width: max-content;">
<colgroup>
<col width="48"/>
<col width="60"/>
<col/>
<col width="80"/>
</colgroup>
<thead class="ant-table-thead">
<tr>
<th></th>
<th style="text-align: center;">优先级</th>
<th>任务名称</th>
<th style="text-align: center;">状态</th>
</tr>
</thead>
<draggable
tag="tbody"
item-key="id"
v-model="taskList"
:component-data="{class: 'ant-table-tbody'}"
handle=".anticon-menu"
:animation="300">
<template #item="{ element }">
<tr>
<td style="text-align: center;">
<menu-outlined style="cursor: move;"/>
</td>
<td style="text-align: center;padding: 8px;">
<ele-tag
:color="['red', 'orange', 'blue'][element.priority - 1]"
shape="circle">
{{ element.priority }}
</ele-tag>
</td>
<td>
<a>{{ element.taskName }}</a>
</td>
<td style="text-align: center;">
<span
:class="['ele-text-warning', 'ele-text-success', 'ele-text-info'][element.state]">
{{ ['未开始', '进行中', '已完成'][element.state] }}
</span>
</td>
</tr>
</template>
</draggable>
</table>
</div>
</div>
</div>
</a-card>
</a-col>
<!-- 本月目标 -->
<a-col :lg="8" :md="24" :sm="24" :xs="24">
<a-card title="本月目标" :bordered="false">
<div class="workplace-goal-group">
<a-progress
type="dashboard"
:percent="80"
:show-info="false"
:width="181"
:stroke-width="4"/>
<div class="workplace-goal-content">
<ele-tag
color="blue"
size="large"
shape="circle">
<trophy-outlined/>
</ele-tag>
<div class="workplace-goal-num">285</div>
</div>
<div class="workplace-goal-text">恭喜本月目标已达标</div>
</div>
</a-card>
</a-col>
<!-- 项目进度 -->
<a-col :lg="16" :md="24" :sm="24" :xs="24">
<a-card
title="项目进度"
:bordered="false"
:body-style="{padding: '12px 12px 1px 12px'}">
<a-table
:data-source="projectList"
row-key="id"
:pagination="false"
size="middle"
:scroll="{x: 'max-content'}">
<a-table-column
key="index"
align="center"
:width="48">
<template #default="{index}">{{ index + 1 }}</template>
</a-table-column>
<a-table-column
title="项目名称"
data-index="projectName">
<template #default="{text}">
<a>{{ text }}</a>
</template>
</a-table-column>
<a-table-column
title="开始时间"
data-index="startDate"/>
<a-table-column
title="结束时间"
data-index="endDate"/>
<a-table-column
title="状态"
data-index="state"
align="center"
:width="90">
<template #default="{text}">
<span
:class="['ele-text-success', 'ele-text-danger', 'ele-text-warning', 'ele-text-info ele-text-delete'][text]">
{{ ['进行中', '已延期', '未开始', '已结束'][text] }}
</span>
</template>
</a-table-column>
<a-table-column
title="进度"
data-index="progress"
align="center"
:width="180">
<template #default="{text}">
<a-progress
:percent="text"
size="small"/>
</template>
</a-table-column>
</a-table>
</a-card>
</a-col>
<!-- 小组成员 -->
<a-col :lg="8" :md="24" :sm="24" :xs="24">
<a-card
title="小组成员"
:bordered="false"
:body-style="{padding: 0}">
<div
v-for="(item,index) in userList"
:key="index"
class="ele-cell user-list-item">
<a-avatar
:size="46"
:src="item.avatar"/>
<div class="ele-cell-content">
<div class="ele-cell-title">{{ item.name }}</div>
<div class="ele-cell-desc">{{ item.desc }}</div>
</div>
<a-tag
:color="['green', 'red'][item.state]">
{{ ['在线', '离线'][item.state] }}
</a-tag>
</div>
</a-card>
</a-col>
</a-row>
</div>
</template>
<script>
import {
CloudOutlined,
AppstoreFilled,
CheckSquareOutlined,
BellFilled,
UserOutlined,
ShoppingCartOutlined,
FundProjectionScreenOutlined,
FileSearchOutlined,
CreditCardOutlined,
MailOutlined,
TagsOutlined,
ControlOutlined,
MenuOutlined,
TrophyOutlined
} from '@ant-design/icons-vue';
import draggable from 'vuedraggable';
export default {
name: 'DashboardWorkplace',
components: {
CloudOutlined,
AppstoreFilled,
CheckSquareOutlined,
BellFilled,
UserOutlined,
ShoppingCartOutlined,
FundProjectionScreenOutlined,
FileSearchOutlined,
CreditCardOutlined,
MailOutlined,
TagsOutlined,
ControlOutlined,
MenuOutlined,
TrophyOutlined,
draggable
},
data() {
return {
// 最新动态数据
activities: [
{
title: 'SunSmile 解决了bug 登录提示操作失败',
time: '20:30',
color: 'gray'
},
{
title: 'Jasmine 解决了bug 按钮颜色与设计不符',
time: '19:30',
color: 'gray'
},
{
title: '项目经理 指派了任务 解决项目一的bug',
time: '18:30'
},
{
title: '项目经理 指派了任务 解决项目二的bug',
time: '17:30'
},
{
title: '项目经理 指派了任务 解决项目三的bug',
time: '16:30'
},
{
title: '项目经理 指派了任务 解决项目四的bug',
time: '15:30',
color: 'gray'
},
{
title: '项目经理 指派了任务 解决项目五的bug',
time: '14:30',
color: 'gray'
},
{
title: '项目经理 指派了任务 解决项目六的bug',
time: '12:30',
color: 'gray'
},
{
title: '项目经理 指派了任务 解决项目七的bug',
time: '11:30'
},
{
title: '项目经理 指派了任务 解决项目八的bug',
time: '10:30',
color: 'gray'
},
{
title: '项目经理 指派了任务 解决项目九的bug',
time: '09:30',
color: 'green'
},
{
title: '项目经理 指派了任务 解决项目十的bug',
time: '08:30',
color: 'red'
}
],
// 我的任务数据
taskList: [
{
id: 1,
priority: 1,
taskName: '解决项目一的bug',
state: 0
},
{
id: 2,
priority: 2,
taskName: '解决项目二的bug',
state: 0
},
{
id: 3,
priority: 2,
taskName: '解决项目三的bug',
state: 1
},
{
id: 4,
priority: 3,
taskName: '解决项目四的bug',
state: 1
},
{
id: 5,
priority: 3,
taskName: '解决项目五的bug',
state: 2
},
{
id: 6,
priority: 3,
taskName: '解决项目六的bug',
state: 2
}
],
// 项目进度数据
projectList: [
{
id: 1,
projectName: '项目0000001',
state: 0,
startDate: '2020-03-01',
endDate: '2020-06-01',
progress: 30
},
{
id: 2,
projectName: '项目0000002',
state: 0,
startDate: '2020-03-01',
endDate: '2020-08-01',
progress: 10
},
{
id: 3,
projectName: '项目0000003',
state: 1,
startDate: '2020-01-01',
endDate: '2020-05-01',
progress: 60
},
{
id: 4,
projectName: '项目0000004',
state: 1,
startDate: '2020-06-01',
endDate: '2020-10-01',
progress: 0
},
{
id: 5,
projectName: '项目0000005',
state: 2,
startDate: '2020-01-01',
endDate: '2020-03-01',
progress: 100
},
{
id: 6,
projectName: '项目0000006',
state: 3,
startDate: '2020-01-01',
endDate: '2020-03-01',
progress: 100
},
{
id: 7,
projectName: '项目0000007',
state: 3,
startDate: '2020-01-01',
endDate: '2020-03-01',
progress: 100
}
],
// 小组成员数据
userList: [
{
name: 'SunSmile',
desc: 'UI设计师、交互专家',
state: 0,
avatar: 'https://cdn.eleadmin.com/20200609/c184eef391ae48dba87e3057e70238fb.jpg'
},
{
name: '你的名字很好听',
desc: '前端工程师',
state: 0,
avatar: 'https://cdn.eleadmin.com/20200609/b6a811873e704db49db994053a5019b2.jpg'
},
{
name: '全村人的希望',
desc: '前端工程师',
state: 0,
avatar: 'https://cdn.eleadmin.com/20200609/948344a2a77c47a7a7b332fe12ff749a.jpg'
},
{
name: 'Jasmine',
desc: '产品经理、项目经理',
state: 1,
avatar: 'https://cdn.eleadmin.com/20200609/f6bc05af944a4f738b54128717952107.jpg'
},
{
name: '酷酷的大叔',
desc: '组长、后端工程师',
state: 1,
avatar: 'https://cdn.eleadmin.com/20200609/2d98970a51b34b6b859339c96b240dcd.jpg'
}
]
};
},
computed: {
// 当前登录用户信息
loginUser() {
return this.$store.state.user.user;
}
},
mounted() {
}
}
</script>
<style scoped>
/** 用户卡片 */
.workplace-user-card .ele-cell-content {
overflow: hidden;
}
.workplace-user-card h4 {
margin-bottom: 6px;
}
.workplace-count-group {
white-space: nowrap;
text-align: right;
flex-shrink: 0;
}
.workplace-count-item {
display: inline-block;
margin: 0 4px 0 24px;
}
.workplace-count-name {
margin-left: 8px;
}
@media screen and (max-width: 992px) {
.workplace-count-item {
margin: 0 2px 0 12px;
}
}
@media screen and (max-width: 768px) {
.workplace-user-card {
display: block;
}
.workplace-count-group {
margin-top: 8px;
}
}
/** 快捷方式 */
.app-link-block {
padding: 12px;
text-align: center;
display: block;
color: inherit;
}
.app-link-block .app-link-icon {
color: #69c0ff;
font-size: 30px;
margin: 6px 0 10px 0;
}
/** 时间轴 */
.ele-scrollbar-hover :deep(.ant-timeline-item-last > .ant-timeline-item-content) {
min-height: auto;
}
/** 本月目标 */
.workplace-goal-group {
padding: 48px 0;
text-align: center;
position: relative;
}
.workplace-goal-group .workplace-goal-content {
position: absolute;
top: 90px;
left: 0;
width: 100%;
}
.workplace-goal-group .workplace-goal-num {
font-size: 40px;
}
/** 小组成员 */
.user-list-item {
padding: 16px 18px;
}
.user-list-item + .user-list-item {
border-top: 1px solid hsla(0, 0%, 60%, .15);
}
/** 表格拖拽 */
.ant-table-tbody tr.sortable-chosen {
background: hsla(0, 0%, 60%, .1) !important;
}
.ant-table-tbody tr.sortable-chosen td {
background: none !important;
}
</style>