mirror of
https://github.com/vbenjs/vue-vben-admin.git
synced 2025-08-27 19:29:04 +08:00
feat(analysis): add analysis page
This commit is contained in:
91
src/views/dashboard/analysis/components/AnalysisBar.vue
Normal file
91
src/views/dashboard/analysis/components/AnalysisBar.vue
Normal file
@@ -0,0 +1,91 @@
|
||||
<template>
|
||||
<div ref="chartRef" :style="{ height, width }" />
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent, onMounted, ref, Ref } from 'vue';
|
||||
|
||||
import { useECharts } from '/@/hooks/web/useECharts';
|
||||
|
||||
import { basicProps } from './props';
|
||||
export default defineComponent({
|
||||
name: 'AnalysisLine',
|
||||
props: basicProps,
|
||||
setup() {
|
||||
const chartRef = ref<HTMLDivElement | null>(null);
|
||||
const { setOptions } = useECharts(chartRef as Ref<HTMLDivElement>);
|
||||
|
||||
onMounted(() => {
|
||||
setOptions({
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
backgroundColor: 'rgba(0, 0, 0, .6)',
|
||||
axisPointer: {
|
||||
// 坐标轴指示器,坐标轴触发有效
|
||||
type: 'shadow', // 默认为直线,可选为:'line' | 'shadow'
|
||||
},
|
||||
},
|
||||
legend: {
|
||||
itemWidth: 15,
|
||||
right: 10,
|
||||
data: ['产品一', '产品二', '产品三'],
|
||||
},
|
||||
grid: {
|
||||
left: '3%',
|
||||
right: '4%',
|
||||
bottom: '3%',
|
||||
containLabel: true,
|
||||
},
|
||||
xAxis: [
|
||||
{
|
||||
type: 'category',
|
||||
axisTick: {
|
||||
inside: true, // 刻度朝内
|
||||
},
|
||||
data: ['付费用户', '免费用户', '自主'],
|
||||
},
|
||||
],
|
||||
yAxis: [
|
||||
{
|
||||
type: 'value',
|
||||
axisTick: {
|
||||
inside: true, // 刻度朝内
|
||||
},
|
||||
},
|
||||
],
|
||||
series: [
|
||||
{
|
||||
name: '产品一',
|
||||
type: 'bar',
|
||||
itemStyle: {
|
||||
color: '#3ca0f6',
|
||||
},
|
||||
data: [3200, 3320, 3010],
|
||||
animationDuration: 4000,
|
||||
},
|
||||
{
|
||||
name: '产品二',
|
||||
type: 'bar',
|
||||
itemStyle: {
|
||||
color: '#7dd9b9',
|
||||
},
|
||||
data: [1200, 2600, 1010],
|
||||
animationDuration: 4000,
|
||||
},
|
||||
|
||||
{
|
||||
name: '产品三',
|
||||
type: 'bar',
|
||||
itemStyle: {
|
||||
color: '#e6a23c',
|
||||
},
|
||||
data: [862, 2500, 964],
|
||||
animationDuration: 4000,
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
return { chartRef };
|
||||
},
|
||||
});
|
||||
</script>
|
101
src/views/dashboard/analysis/components/AnalysisLine.vue
Normal file
101
src/views/dashboard/analysis/components/AnalysisLine.vue
Normal file
@@ -0,0 +1,101 @@
|
||||
<template>
|
||||
<div ref="chartRef" :style="{ height, width }" />
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent, onMounted, ref, Ref } from 'vue';
|
||||
|
||||
import { useECharts } from '/@/hooks/web/useECharts';
|
||||
|
||||
import { basicProps } from './props';
|
||||
export default defineComponent({
|
||||
name: 'AnalysisLine',
|
||||
props: basicProps,
|
||||
setup() {
|
||||
const chartRef = ref<HTMLDivElement | null>(null);
|
||||
const { setOptions } = useECharts(chartRef as Ref<HTMLDivElement>);
|
||||
|
||||
onMounted(() => {
|
||||
setOptions({
|
||||
// title: {
|
||||
// text: '产品成交额',
|
||||
// },
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
padding: 3,
|
||||
backgroundColor: 'rgba(0, 0, 0, .6)',
|
||||
borderColor: '#777',
|
||||
borderWidth: 1,
|
||||
},
|
||||
legend: {
|
||||
icon: 'rect',
|
||||
itemWidth: 15,
|
||||
itemHeight: 4,
|
||||
left: 80,
|
||||
top: 0,
|
||||
orient: 'horizontal',
|
||||
data: ['产品一', '产品二'],
|
||||
},
|
||||
grid: {
|
||||
left: '3%',
|
||||
right: '4%',
|
||||
bottom: '3%',
|
||||
containLabel: true,
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
boundaryGap: false,
|
||||
axisTick: {
|
||||
inside: true, // 刻度朝内
|
||||
},
|
||||
data: [
|
||||
'一月',
|
||||
'二月',
|
||||
'三月',
|
||||
'四月',
|
||||
'五月',
|
||||
'六月',
|
||||
'七月',
|
||||
'八月',
|
||||
'九月',
|
||||
'十月',
|
||||
'十一月',
|
||||
'十二月',
|
||||
],
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
axisTick: {
|
||||
inside: true, // 刻度朝内
|
||||
},
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: '产品一',
|
||||
type: 'line',
|
||||
itemStyle: {
|
||||
normal: {
|
||||
color: '#5B8FF9',
|
||||
},
|
||||
},
|
||||
// areaStyle: {},
|
||||
data: [330, 132, 101, 134, 90, 230, 210, 150, 232, 234, 230, 400],
|
||||
animationDuration: 4000,
|
||||
},
|
||||
{
|
||||
name: '产品二',
|
||||
type: 'line',
|
||||
itemStyle: {
|
||||
normal: {
|
||||
color: '#55D187',
|
||||
},
|
||||
},
|
||||
data: [220, 182, 191, 234, 290, 330, 310, 330, 232, 201, 330, 190],
|
||||
animationDuration: 4000,
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
return { chartRef };
|
||||
},
|
||||
});
|
||||
</script>
|
79
src/views/dashboard/analysis/components/AnalysisPie.vue
Normal file
79
src/views/dashboard/analysis/components/AnalysisPie.vue
Normal file
@@ -0,0 +1,79 @@
|
||||
<template>
|
||||
<div ref="chartRef" :style="{ height, width }" />
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent, onMounted, ref, Ref } from 'vue';
|
||||
|
||||
import { useECharts } from '/@/hooks/web/useECharts';
|
||||
|
||||
import { basicProps } from './props';
|
||||
|
||||
const m2R2Data = [
|
||||
{ value: 335, name: '移动设备', itemStyle: { color: '#1b65b9' } },
|
||||
{ value: 310, name: '网页端', itemStyle: { color: '#3ca0f6' } },
|
||||
{ value: 234, name: '手表', itemStyle: { color: '#2dc0c0' } },
|
||||
{ value: 234, name: '其他', itemStyle: { color: '#7dd9b9' } },
|
||||
];
|
||||
export default defineComponent({
|
||||
name: 'AnalysisLine',
|
||||
props: basicProps,
|
||||
setup() {
|
||||
const chartRef = ref<HTMLDivElement | null>(null);
|
||||
const { setOptions } = useECharts(chartRef as Ref<HTMLDivElement>);
|
||||
|
||||
onMounted(() => {
|
||||
setOptions({
|
||||
title: [
|
||||
{
|
||||
text: '总设备',
|
||||
subtext: '1,430',
|
||||
textStyle: {
|
||||
fontSize: 12,
|
||||
color: '#4B535E85',
|
||||
},
|
||||
subtextStyle: {
|
||||
fontSize: 24,
|
||||
color: 'black',
|
||||
},
|
||||
textAlign: 'center',
|
||||
// @ts-ignore
|
||||
x: '34.5%',
|
||||
y: '40%',
|
||||
},
|
||||
],
|
||||
tooltip: {
|
||||
trigger: 'item',
|
||||
backgroundColor: 'rgba(0, 0, 0, .6)',
|
||||
},
|
||||
legend: {
|
||||
icon: 'circle',
|
||||
itemHeight: 10,
|
||||
type: 'scroll',
|
||||
orient: 'vertical',
|
||||
left: '70%',
|
||||
align: 'left',
|
||||
top: 'middle',
|
||||
textStyle: {
|
||||
color: '#8C8C8C',
|
||||
},
|
||||
height: 250,
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: '成交额',
|
||||
type: 'pie',
|
||||
center: ['35%', '50%'],
|
||||
radius: ['45%', '65%'],
|
||||
label: {
|
||||
show: false,
|
||||
},
|
||||
data: m2R2Data,
|
||||
animationDuration: 3000,
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
return { chartRef };
|
||||
},
|
||||
});
|
||||
</script>
|
82
src/views/dashboard/analysis/components/FlowAnalysis.tsx
Normal file
82
src/views/dashboard/analysis/components/FlowAnalysis.tsx
Normal file
@@ -0,0 +1,82 @@
|
||||
import { defineComponent } from 'vue';
|
||||
import { Tabs, Row, Col, Progress, Divider } from 'ant-design-vue';
|
||||
import { CollapseContainer } from '/@/components/Container/index';
|
||||
import TrendLine from './TrendLine.vue';
|
||||
import './flow-ana.less';
|
||||
const prefixCls = 'flow-analysis';
|
||||
export default defineComponent({
|
||||
name: 'AnalysisFLow',
|
||||
setup() {
|
||||
const renderContent = () => {
|
||||
return (
|
||||
<Row>
|
||||
{() => (
|
||||
<>
|
||||
<Col md={24} lg={8}>
|
||||
{() => (
|
||||
<CollapseContainer
|
||||
title="整体流量评分"
|
||||
canExpan={false}
|
||||
class={`${prefixCls}__left`}
|
||||
>
|
||||
{() => (
|
||||
<>
|
||||
<div class={`${prefixCls}__score`}>
|
||||
86.2<span>分</span>
|
||||
</div>
|
||||
<div class={`${prefixCls}__rank`}>
|
||||
排名<span>前20%</span>
|
||||
</div>
|
||||
<Progress percent={70} showInfo={false} status="active" />
|
||||
<Divider />
|
||||
|
||||
<ul class={`${prefixCls}__rs`}>
|
||||
<li>
|
||||
<span>平均分</span>
|
||||
<span>77.5</span>
|
||||
</li>
|
||||
<li>
|
||||
<span>最高分</span>
|
||||
<span>99.5</span>
|
||||
</li>
|
||||
<li>
|
||||
<span>最低分</span>
|
||||
<span>56.5</span>
|
||||
</li>
|
||||
</ul>
|
||||
</>
|
||||
)}
|
||||
</CollapseContainer>
|
||||
)}
|
||||
</Col>
|
||||
<Col md={24} lg={16}>
|
||||
{() => (
|
||||
<CollapseContainer title="整体流量趋势" canExpan={false}>
|
||||
{() => <TrendLine />}
|
||||
</CollapseContainer>
|
||||
)}
|
||||
</Col>
|
||||
</>
|
||||
)}
|
||||
</Row>
|
||||
);
|
||||
};
|
||||
return () => (
|
||||
<Tabs class={prefixCls} default-active-key="1">
|
||||
{() => (
|
||||
<>
|
||||
<Tabs.TabPane key="1" tab="产品一">
|
||||
{() => renderContent()}
|
||||
</Tabs.TabPane>
|
||||
<Tabs.TabPane key="2" tab="产品二">
|
||||
{() => renderContent()}
|
||||
</Tabs.TabPane>
|
||||
<Tabs.TabPane key="3" tab="产品三">
|
||||
{() => renderContent()}
|
||||
</Tabs.TabPane>
|
||||
</>
|
||||
)}
|
||||
</Tabs>
|
||||
);
|
||||
},
|
||||
});
|
116
src/views/dashboard/analysis/components/GrowCard.vue
Normal file
116
src/views/dashboard/analysis/components/GrowCard.vue
Normal file
@@ -0,0 +1,116 @@
|
||||
<template>
|
||||
<div class="grow-card">
|
||||
<div class="grow-card-header">
|
||||
<div class="grow-card__info">
|
||||
<p class="grow-card__title">{{ info.title }}</p>
|
||||
<CountTo prefix="$" :startVal="1" :endVal="info.price" />
|
||||
</div>
|
||||
<img :src="info.icon" />
|
||||
</div>
|
||||
<div class="grow-card-footer" :class="{ 'is-up': info.up }">
|
||||
<Statistic :value="info.percent">
|
||||
<template #prefix> <img :src="info.up ? riseSvg : downSvg" /> </template>
|
||||
</Statistic>
|
||||
<span class="grow-card__mom">{{ info.mom }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent, PropType } from 'vue';
|
||||
import { Statistic } from 'ant-design-vue';
|
||||
import { CountTo } from '/@/components/CountTo/index';
|
||||
|
||||
import riseSvg from '/@/assets/svg/dashboard/analysis-rise.svg';
|
||||
import downSvg from '/@/assets/svg/dashboard/analysis-down.svg';
|
||||
import { GrowCardItem } from '../types';
|
||||
|
||||
export default defineComponent({
|
||||
components: { Statistic, CountTo },
|
||||
props: {
|
||||
info: {
|
||||
type: Object as PropType<GrowCardItem>,
|
||||
default: null,
|
||||
},
|
||||
},
|
||||
setup() {
|
||||
return {
|
||||
riseSvg,
|
||||
downSvg,
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
<style lang="less">
|
||||
@import (reference) '../../../../design/index.less';
|
||||
|
||||
.grow-card {
|
||||
display: flex;
|
||||
width: calc(100% - 12px);
|
||||
height: 158px;
|
||||
padding: 16px 16px 12px 16px;
|
||||
// margin: 0 12px 12px 12px;
|
||||
cursor: pointer;
|
||||
background: @white;
|
||||
border-radius: 4px;
|
||||
box-shadow: 6px 6px 54px 0 rgba(0, 0, 0, 0.05);
|
||||
flex-direction: column;
|
||||
|
||||
&:hover {
|
||||
box-shadow: 6px 6px 54px 0 rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
&-header {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
&__title {
|
||||
font-family: PingFangSC-Regular;
|
||||
font-size: 16px;
|
||||
letter-spacing: 0;
|
||||
color: #2c3a61;
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
&__info {
|
||||
span {
|
||||
font-family: NeoSans;
|
||||
font-size: 26px;
|
||||
line-height: 38px;
|
||||
}
|
||||
}
|
||||
|
||||
&-footer {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
margin-top: 24px;
|
||||
align-items: center;
|
||||
|
||||
.ant-statistic-content-value {
|
||||
color: @error-color;
|
||||
}
|
||||
|
||||
.ant-statistic-content-prefix svg {
|
||||
width: 0.98rem !important;
|
||||
height: 0.98rem !important;
|
||||
}
|
||||
|
||||
&.is-up {
|
||||
.ant-statistic-content-value {
|
||||
color: @success-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__mom {
|
||||
display: inline-block;
|
||||
padding-left: 10px;
|
||||
font-family: PingFangSC-Regular;
|
||||
font-size: 12px;
|
||||
line-height: 22px;
|
||||
letter-spacing: 0;
|
||||
color: #606060;
|
||||
}
|
||||
}
|
||||
</style>
|
154
src/views/dashboard/analysis/components/TaskCard.vue
Normal file
154
src/views/dashboard/analysis/components/TaskCard.vue
Normal file
@@ -0,0 +1,154 @@
|
||||
<template>
|
||||
<div :class="prefixCls">
|
||||
<div :class="`${prefixCls}-header`">
|
||||
<div :class="`${prefixCls}__info`">
|
||||
<span :class="`${prefixCls}__title`">{{ info.title }}</span>
|
||||
<span :class="`${prefixCls}__desc`">{{ info.desc }}</span>
|
||||
</div>
|
||||
<span :class="`${prefixCls}__tag ${info.status}`">{{ info.text }}</span>
|
||||
</div>
|
||||
|
||||
<div :class="`${prefixCls}-body mt-5`">
|
||||
<div :class="`${prefixCls}__process-nfo`">
|
||||
<span>进度</span>
|
||||
<span>{{ info.percent }}%</span>
|
||||
</div>
|
||||
<Progress :percent="info.percent" :showInfo="false" :status="info.status" />
|
||||
</div>
|
||||
<div :class="`${prefixCls}-footer`">
|
||||
<span :class="`${prefixCls}__date`">
|
||||
更新日期: <span>{{ info.updateTime }}</span>
|
||||
</span>
|
||||
<div :class="`${prefixCls}__avatar`">
|
||||
<Avatar src="https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png" />
|
||||
<Avatar src="https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png" />
|
||||
<Avatar>+3</Avatar>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, PropType } from 'vue';
|
||||
import { Progress, Avatar } from 'ant-design-vue';
|
||||
|
||||
import { TaskItem } from '../types';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'GrowCard',
|
||||
components: { Progress, Avatar },
|
||||
props: {
|
||||
info: {
|
||||
type: Object as PropType<TaskItem>,
|
||||
default: null,
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
return {
|
||||
prefixCls: 'task-card',
|
||||
text: computed(() => {
|
||||
const { status } = props.info || {};
|
||||
return status === 'active'
|
||||
? '进度正常'
|
||||
: status === 'exception'
|
||||
? '进度滞后'
|
||||
: '项目完成';
|
||||
}),
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.task-card {
|
||||
display: flex;
|
||||
width: calc(100% - 24px);
|
||||
height: 199px;
|
||||
padding: 24px 20px 12px 16px;
|
||||
margin: 0 12px 12px 12px;
|
||||
background: #fff;
|
||||
border: 1px solid #ececf2;
|
||||
border-radius: 12px;
|
||||
flex-direction: column;
|
||||
|
||||
&-header {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
&__tag {
|
||||
display: inline-block;
|
||||
padding: 4px 6px;
|
||||
font-family: PingFangSC-Regular;
|
||||
font-size: 12px;
|
||||
border-radius: 6px;
|
||||
|
||||
&.success {
|
||||
color: #55d187;
|
||||
background: rgba(85, 209, 135, 0.16);
|
||||
}
|
||||
|
||||
&.warn {
|
||||
color: #ffa07d;
|
||||
background: #ffd16416;
|
||||
}
|
||||
|
||||
&.done {
|
||||
color: #0593ff;
|
||||
background: #0593ff16;
|
||||
}
|
||||
}
|
||||
|
||||
&__info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
&__title {
|
||||
font-family: PingFangSC-Medium;
|
||||
font-size: 16px;
|
||||
line-height: 24px;
|
||||
color: #2c3a61;
|
||||
}
|
||||
|
||||
&__desc {
|
||||
font-family: PingFangSC-Regular;
|
||||
font-size: 12px;
|
||||
line-height: 21px;
|
||||
color: #8181a5;
|
||||
}
|
||||
|
||||
&__process-nfo {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
||||
span {
|
||||
font-size: 14px;
|
||||
line-height: 21px;
|
||||
color: #8181a5;
|
||||
}
|
||||
}
|
||||
|
||||
&-footer {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
margin-top: 16px;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
&__date {
|
||||
font-size: 12px;
|
||||
line-height: 21px;
|
||||
color: #2c3a61;
|
||||
|
||||
span {
|
||||
color: #7c8087;
|
||||
}
|
||||
}
|
||||
|
||||
&__avatar {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
</style>
|
105
src/views/dashboard/analysis/components/TrendLine.vue
Normal file
105
src/views/dashboard/analysis/components/TrendLine.vue
Normal file
@@ -0,0 +1,105 @@
|
||||
<template>
|
||||
<div ref="chartRef" :style="{ height, width }" />
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent, onMounted, ref, Ref } from 'vue';
|
||||
|
||||
import { useECharts } from '/@/hooks/web/useECharts';
|
||||
|
||||
import { basicProps } from './props';
|
||||
export default defineComponent({
|
||||
name: 'AnalysisLine',
|
||||
props: basicProps,
|
||||
setup() {
|
||||
const chartRef = ref<HTMLDivElement | null>(null);
|
||||
const { setOptions, echarts } = useECharts(chartRef as Ref<HTMLDivElement>);
|
||||
|
||||
onMounted(() => {
|
||||
setOptions({
|
||||
// title: {
|
||||
// text: '产品成交额',
|
||||
// },
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
padding: 3,
|
||||
backgroundColor: 'rgba(0, 0, 0, .6)',
|
||||
borderColor: '#777',
|
||||
borderWidth: 1,
|
||||
},
|
||||
legend: {
|
||||
show: false,
|
||||
},
|
||||
grid: {
|
||||
left: '3%',
|
||||
right: '4%',
|
||||
bottom: '3%',
|
||||
containLabel: true,
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
boundaryGap: false,
|
||||
axisTick: {
|
||||
inside: true, // 刻度朝内
|
||||
},
|
||||
data: [
|
||||
'一月',
|
||||
'二月',
|
||||
'三月',
|
||||
'四月',
|
||||
'五月',
|
||||
'六月',
|
||||
'七月',
|
||||
'八月',
|
||||
'九月',
|
||||
'十月',
|
||||
'十一月',
|
||||
'十二月',
|
||||
],
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
axisTick: {
|
||||
inside: true, // 刻度朝内
|
||||
},
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: '产品一',
|
||||
type: 'line',
|
||||
itemStyle: {
|
||||
color: '#5B8FF9',
|
||||
},
|
||||
areaStyle: {
|
||||
// 线性渐变,前4个参数分别是x0,y0,x2,y2(范围0~1);相当于图形包围盒中的百分比。如果最后一个参数是‘true’,则该四个值是绝对像素位置。
|
||||
// @ts-ignore
|
||||
color: new echarts.graphic.LinearGradient(
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
[
|
||||
{
|
||||
offset: 0,
|
||||
color: '#5B8FF9',
|
||||
},
|
||||
{
|
||||
offset: 1,
|
||||
color: 'rgba(118,168,248, 0)',
|
||||
},
|
||||
],
|
||||
false
|
||||
),
|
||||
shadowColor: 'rgba(118,168,248, 0.9)', // 阴影颜色
|
||||
shadowBlur: 20, // shadowBlur设图形阴影的模糊大小。配合shadowColor,shadowOffsetX/Y, 设置图形的阴影效果。
|
||||
},
|
||||
// areaStyle: {},
|
||||
data: [134, 330, 132, 101, 90, 230, 210, 150, 230, 400, 232, 234],
|
||||
animationDuration: 3000,
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
return { chartRef };
|
||||
},
|
||||
});
|
||||
</script>
|
56
src/views/dashboard/analysis/components/flow-ana.less
Normal file
56
src/views/dashboard/analysis/components/flow-ana.less
Normal file
@@ -0,0 +1,56 @@
|
||||
.flow-analysis {
|
||||
width: 100%;
|
||||
background: #fff;
|
||||
|
||||
&__left {
|
||||
padding: 10px 20px !important;
|
||||
border-right: 1px solid rgba(0, 0, 0, 0.06);
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
&__score {
|
||||
margin-top: 20px;
|
||||
font-size: 30px;
|
||||
line-height: 38px;
|
||||
color: rgba(0, 0, 0, 0.85);
|
||||
|
||||
span {
|
||||
font-size: 20px;
|
||||
line-height: 28px;
|
||||
color: rgba(0, 0, 0, 0.85);
|
||||
}
|
||||
}
|
||||
|
||||
&__rank {
|
||||
margin: 16px 0;
|
||||
font-size: 12px;
|
||||
line-height: 20px;
|
||||
color: #7c8087;
|
||||
|
||||
span {
|
||||
display: inline-block;
|
||||
margin-left: 10px;
|
||||
color: #1c1d21;
|
||||
}
|
||||
}
|
||||
|
||||
&__rs {
|
||||
li {
|
||||
display: flex;
|
||||
line-height: 28px;
|
||||
justify-content: space-between;
|
||||
|
||||
span {
|
||||
&:nth-child(1) {
|
||||
font-size: 14px;
|
||||
color: #1c1d21;
|
||||
}
|
||||
|
||||
&:nth-child(2) {
|
||||
font-size: 16px;
|
||||
color: #1c1d21;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
16
src/views/dashboard/analysis/components/props.ts
Normal file
16
src/views/dashboard/analysis/components/props.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import { PropType } from 'vue';
|
||||
|
||||
export interface BasicProps {
|
||||
width: string;
|
||||
height: string;
|
||||
}
|
||||
export const basicProps = {
|
||||
width: {
|
||||
type: String as PropType<string>,
|
||||
default: '100%',
|
||||
},
|
||||
height: {
|
||||
type: String as PropType<string>,
|
||||
default: '280px',
|
||||
},
|
||||
};
|
107
src/views/dashboard/analysis/data.tsx
Normal file
107
src/views/dashboard/analysis/data.tsx
Normal file
@@ -0,0 +1,107 @@
|
||||
import { GrowCardItem, TaskItem } from './types';
|
||||
import iconSvg1 from '/@/assets/svg/dashboard/analysis-icon1.svg';
|
||||
import iconSvg2 from '/@/assets/svg/dashboard/analysis-icon2.svg';
|
||||
import iconSvg3 from '/@/assets/svg/dashboard/analysis-icon3.svg';
|
||||
import iconSvg4 from '/@/assets/svg/dashboard/analysis-icon4.svg';
|
||||
export const taskList: TaskItem[] = [
|
||||
{
|
||||
percent: 50,
|
||||
title: '开发任务一',
|
||||
updateTime: '2020.7.12',
|
||||
desc: '开发任务一简介',
|
||||
status: 'active',
|
||||
},
|
||||
{
|
||||
percent: 67,
|
||||
title: '开发任务二',
|
||||
updateTime: '2020.3.12',
|
||||
desc: '开发任务二简介',
|
||||
status: 'exception',
|
||||
},
|
||||
{
|
||||
percent: 100,
|
||||
title: '开发任务三',
|
||||
updateTime: '2020.4.12',
|
||||
desc: '开发任务三简介',
|
||||
|
||||
status: 'success',
|
||||
},
|
||||
];
|
||||
export const growCardList: GrowCardItem[] = [
|
||||
{
|
||||
title: '总用户数',
|
||||
icon: iconSvg1,
|
||||
price: 80000,
|
||||
up: true,
|
||||
mom: '环比增长',
|
||||
percent: 2.5,
|
||||
},
|
||||
{
|
||||
title: '产品数量',
|
||||
icon: iconSvg2,
|
||||
price: 4000,
|
||||
up: true,
|
||||
mom: '同比增长',
|
||||
percent: 3,
|
||||
},
|
||||
{
|
||||
title: '总营业额',
|
||||
icon: iconSvg3,
|
||||
price: 3000000,
|
||||
up: false,
|
||||
mom: '环比降低',
|
||||
percent: 2,
|
||||
},
|
||||
{
|
||||
title: '总任务数',
|
||||
icon: iconSvg4,
|
||||
price: 10000,
|
||||
up: false,
|
||||
mom: '同比降低',
|
||||
percent: 1,
|
||||
},
|
||||
];
|
||||
export const randomizeArray = function (arg: any) {
|
||||
const array = arg.slice();
|
||||
let currentIndex = array.length,
|
||||
temporaryValue,
|
||||
randomIndex;
|
||||
|
||||
while (0 !== currentIndex) {
|
||||
randomIndex = Math.floor(Math.random() * currentIndex);
|
||||
currentIndex -= 1;
|
||||
|
||||
temporaryValue = array[currentIndex];
|
||||
array[currentIndex] = array[randomIndex];
|
||||
array[randomIndex] = temporaryValue;
|
||||
}
|
||||
|
||||
return array;
|
||||
};
|
||||
|
||||
export const sparklineData = [
|
||||
47,
|
||||
45,
|
||||
54,
|
||||
38,
|
||||
56,
|
||||
24,
|
||||
65,
|
||||
31,
|
||||
37,
|
||||
39,
|
||||
62,
|
||||
51,
|
||||
35,
|
||||
41,
|
||||
35,
|
||||
27,
|
||||
93,
|
||||
53,
|
||||
61,
|
||||
27,
|
||||
54,
|
||||
43,
|
||||
19,
|
||||
46,
|
||||
];
|
83
src/views/dashboard/analysis/index.vue
Normal file
83
src/views/dashboard/analysis/index.vue
Normal file
@@ -0,0 +1,83 @@
|
||||
<template>
|
||||
<div class="analysis p-4">
|
||||
<Row class="pl-2">
|
||||
<template v-for="item in growCardList" :key="item.title">
|
||||
<ACol :sm="24" :md="12" :lg="6">
|
||||
<GrowCard :info="item" />
|
||||
</ACol>
|
||||
</template>
|
||||
</Row>
|
||||
|
||||
<Row>
|
||||
<ACol :md="24" :lg="17" class="my-3">
|
||||
<CollapseContainer class="mr-3" title="产品成交额" :canExpan="false">
|
||||
<AnalysisLine />
|
||||
</CollapseContainer>
|
||||
<Row class="mt-3">
|
||||
<ACol :md="24" :lg="12" class="product-total">
|
||||
<CollapseContainer class="mr-3" title="产品成交额" :canExpan="false">
|
||||
<AnalysisPie />
|
||||
</CollapseContainer>
|
||||
</ACol>
|
||||
<ACol :md="24" :lg="12">
|
||||
<CollapseContainer class="mr-3" title="用户来源" :canExpan="false">
|
||||
<AnalysisBar />
|
||||
</CollapseContainer>
|
||||
</ACol>
|
||||
</Row>
|
||||
</ACol>
|
||||
<ACol :md="24" :lg="7">
|
||||
<CollapseContainer class="mt-3" title="项目进度" :canExpan="false">
|
||||
<template v-for="item in taskList" :key="item.title">
|
||||
<TaskCard :info="item" />
|
||||
</template>
|
||||
</CollapseContainer>
|
||||
</ACol>
|
||||
</Row>
|
||||
<Row>
|
||||
<FlowAnalysis />
|
||||
</Row>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue';
|
||||
import GrowCard from './components/GrowCard.vue';
|
||||
import TrendLine from './components/TrendLine.vue';
|
||||
import AnalysisLine from './components/AnalysisLine.vue';
|
||||
import AnalysisPie from './components/AnalysisPie.vue';
|
||||
import AnalysisBar from './components/AnalysisBar.vue';
|
||||
import TaskCard from './components/TaskCard.vue';
|
||||
import FlowAnalysis from './components/FlowAnalysis';
|
||||
import { Row, Col } from 'ant-design-vue';
|
||||
import { CollapseContainer } from '/@/components/Container/index';
|
||||
|
||||
import { growCardList, taskList } from './data';
|
||||
export default defineComponent({
|
||||
components: {
|
||||
Row,
|
||||
ACol: Col,
|
||||
GrowCard,
|
||||
CollapseContainer,
|
||||
TrendLine,
|
||||
AnalysisLine,
|
||||
AnalysisPie,
|
||||
AnalysisBar,
|
||||
TaskCard,
|
||||
FlowAnalysis,
|
||||
},
|
||||
setup() {
|
||||
return { growCardList, taskList };
|
||||
},
|
||||
});
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
@import (reference) '../../../design/index.less';
|
||||
|
||||
.analysis {
|
||||
width: 100%;
|
||||
|
||||
.product-total {
|
||||
.respond-to(small-and-medium, {padding-right: 0;margin-bottom: 24px;});
|
||||
}
|
||||
}
|
||||
</style>
|
16
src/views/dashboard/analysis/types.ts
Normal file
16
src/views/dashboard/analysis/types.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
export interface GrowCardItem {
|
||||
icon: string;
|
||||
title: string;
|
||||
price: number;
|
||||
up: boolean;
|
||||
mom: string;
|
||||
percent: number;
|
||||
}
|
||||
|
||||
export interface TaskItem {
|
||||
percent: number;
|
||||
status: 'success' | 'exception' | 'active';
|
||||
updateTime: string;
|
||||
title: string;
|
||||
desc: string;
|
||||
}
|
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<CollapseContainer title="任务安排" :canExpan="false">
|
||||
<CollapseContainer title="销售统计" :canExpan="false">
|
||||
<div ref="chartRef" :style="{ width: '100%' }" />
|
||||
</CollapseContainer>
|
||||
</template>
|
||||
@@ -9,7 +9,6 @@
|
||||
import { CollapseContainer } from '/@/components/Container/index';
|
||||
import { useApexCharts } from '/@/hooks/web/useApexCharts';
|
||||
|
||||
import moment from 'moment';
|
||||
export default defineComponent({
|
||||
components: { CollapseContainer },
|
||||
setup() {
|
||||
@@ -18,72 +17,72 @@
|
||||
onMounted(() => {
|
||||
setOptions({
|
||||
series: [
|
||||
{
|
||||
data: [
|
||||
{
|
||||
x: 'Analysis',
|
||||
y: [new Date('2019-02-27').getTime(), new Date('2019-03-04').getTime()],
|
||||
fillColor: '#008FFB',
|
||||
},
|
||||
{
|
||||
x: 'Design',
|
||||
y: [new Date('2019-03-04').getTime(), new Date('2019-03-08').getTime()],
|
||||
fillColor: '#00E396',
|
||||
},
|
||||
{
|
||||
x: 'Coding',
|
||||
y: [new Date('2019-03-07').getTime(), new Date('2019-03-10').getTime()],
|
||||
fillColor: '#775DD0',
|
||||
},
|
||||
{
|
||||
x: 'Testing',
|
||||
y: [new Date('2019-03-08').getTime(), new Date('2019-03-12').getTime()],
|
||||
fillColor: '#FEB019',
|
||||
},
|
||||
{
|
||||
x: 'Deployment',
|
||||
y: [new Date('2019-03-12').getTime(), new Date('2019-03-17').getTime()],
|
||||
fillColor: '#FF4560',
|
||||
},
|
||||
],
|
||||
},
|
||||
{ name: 'Visits', data: [90, 50, 86, 40, 100, 20] },
|
||||
{ name: 'Sales', data: [70, 75, 70, 76, 20, 85] },
|
||||
],
|
||||
dataLabels: {
|
||||
style: {
|
||||
colors: ['#b9c3cd', '#b9c3cd', '#b9c3cd', '#b9c3cd', '#b9c3cd', '#b9c3cd'],
|
||||
},
|
||||
},
|
||||
chart: {
|
||||
height: 350,
|
||||
type: 'rangeBar',
|
||||
},
|
||||
plotOptions: {
|
||||
bar: {
|
||||
horizontal: true,
|
||||
distributed: true,
|
||||
dataLabels: {
|
||||
hideOverflowingLabels: false,
|
||||
},
|
||||
type: 'radar',
|
||||
dropShadow: {
|
||||
enabled: true,
|
||||
blur: 1,
|
||||
left: 1,
|
||||
top: 1,
|
||||
},
|
||||
},
|
||||
dataLabels: {
|
||||
enabled: true,
|
||||
formatter: function (val: any, opts: any) {
|
||||
var label = opts.w.globals.labels[opts.dataPointIndex];
|
||||
var a = moment(val[0]);
|
||||
var b = moment(val[1]);
|
||||
var diff = b.diff(a, 'days');
|
||||
return label + ': ' + diff + (diff > 1 ? ' days' : ' day');
|
||||
},
|
||||
style: {
|
||||
colors: ['#f3f4f5', '#fff'],
|
||||
},
|
||||
},
|
||||
xaxis: {
|
||||
type: 'datetime',
|
||||
},
|
||||
yaxis: {
|
||||
show: false,
|
||||
},
|
||||
grid: {
|
||||
row: {
|
||||
colors: ['#f3f4f5', '#fff'],
|
||||
opacity: 1,
|
||||
show: false,
|
||||
},
|
||||
legend: { show: false },
|
||||
title: {
|
||||
show: false,
|
||||
},
|
||||
tooltip: {
|
||||
x: { show: false },
|
||||
},
|
||||
markers: {
|
||||
size: 0,
|
||||
},
|
||||
xaxis: {
|
||||
categories: ['2011', '2012', '2013', '2014', '2015', '2016'],
|
||||
},
|
||||
stroke: {
|
||||
width: 0,
|
||||
},
|
||||
colors: ['#9f8ed7', '#1edec5'],
|
||||
plotOptions: {
|
||||
radar: {
|
||||
polygons: {
|
||||
strokeColors: [
|
||||
'#e8e8e8',
|
||||
'transparent',
|
||||
'transparent',
|
||||
'transparent',
|
||||
'transparent',
|
||||
'transparent',
|
||||
],
|
||||
connectorColors: 'transparent',
|
||||
},
|
||||
},
|
||||
},
|
||||
fill: {
|
||||
type: 'gradient',
|
||||
gradient: {
|
||||
shade: 'dark',
|
||||
gradientToColors: ['#8e9ad6', '#1fcadb'],
|
||||
shadeIntensity: 1,
|
||||
type: 'horizontal',
|
||||
opacityFrom: 1,
|
||||
opacityTo: 1,
|
||||
stops: [0, 100, 100, 100],
|
||||
},
|
||||
},
|
||||
});
|
||||
|
Reference in New Issue
Block a user