提交 52ee35c4 编写于 作者: V vben

feat(analysis): add analysis page

上级 1cd75fcf
......@@ -216,17 +216,17 @@ yarn clean:lib # 删除node_modules,兼容window系统
- [x] 图片预览组件
- [x] 表格组件
- [x] 图表库
- [x] 数字动画
## 正在开发的功能
- [ ] 数字动画
- [ ] 主题配置
- [ ] 富文本组件
- [ ] 首屏加载等待动画
- [ ] 上传组件
- [ ] 富文本组件
- [ ] 数据导入导出
- [ ] 黑暗主题
- [ ] 全局错误处理
- [ ] 首屏加载等待动画
- [ ] 打包 Gzip
- [ ] 抽取生产环境配置文件
- [ ] 系统性能优化
......
<?xml version="1.0" encoding="UTF-8"?>
<svg width="20px" height="12px" viewBox="0 0 20 12" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 61 (89581) - https://sketch.com -->
<title>下跌-24px</title>
<desc>Created with Sketch.</desc>
<g id="页面-2" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="系统首页" transform="translate(-850.000000, -241.000000)">
<g id="1" transform="translate(234.000000, 120.000000)">
<g id="Total-Sales" transform="translate(598.000000, 0.000000)">
<g id="8.5%-Up-from-yesterday" transform="translate(16.000000, 114.000000)">
<g id="下跌-24px" transform="translate(0.000000, 1.000000)">
<polygon id="Path" points="0 0 24 0 24 24 0 24"></polygon>
<polygon id="Path" fill="#ED6F6F" fill-rule="nonzero" points="16 18 18.29 15.71 13.41 10.83 9.41 14.83 2 7.41 3.41 6 9.41 12 13.41 8 19.71 14.29 22 12 22 18"></polygon>
</g>
</g>
</g>
</g>
</g>
</g>
</svg>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<svg width="60px" height="60px" viewBox="0 0 60 60" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 61 (89581) - https://sketch.com -->
<title>Icon1@3x</title>
<desc>Created with Sketch.</desc>
<g id="页面-2" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="系统首页" transform="translate(-419.000000, -136.000000)" fill="#0593FF">
<g id="1" transform="translate(234.000000, 120.000000)">
<g id="Total-Users">
<g id="Icon1" transform="translate(185.000000, 16.000000)">
<path d="M23,60 C10.2974508,60 1.55561363e-15,49.7025492 0,37 L0,23 C-1.55561363e-15,10.2974508 10.2974508,2.33342044e-15 23,0 L37,0 C49.7025492,-2.33342044e-15 60,10.2974508 60,23 L60,37 C60,49.7025492 49.7025492,60 37,60 L23,60 Z" id="Circle-2" opacity="0.209999993"></path>
<g id="Group" transform="translate(14.000000, 18.000000)" fill-rule="nonzero">
<path d="M24,6.66666667 C26.209139,6.66666667 28,8.45752767 28,10.6666667 C28,12.8758057 26.209139,14.6666667 24,14.6666667 C21.790861,14.6666667 20,12.8758057 20,10.6666667 C20,8.45752767 21.790861,6.66666667 24,6.66666667 Z M12,0 C14.9455187,0 17.3333333,2.38781467 17.3333333,5.33333333 C17.3333333,8.278852 14.9455187,10.6666667 12,10.6666667 C9.05448133,10.6666667 6.66666667,8.278852 6.66666667,5.33333333 C6.66666667,2.38781467 9.05448133,0 12,0 Z" id="Combined-Shape" opacity="0.587820871"></path>
<path d="M23.4686027,16.0012776 L23.3172917,16 C27.927838,16 31.7158139,18.2931929 31.9979916,23.2 C32.0092328,23.3954741 31.9979916,24 31.2745999,24 L26.1333333,24 L26.1333333,24 C26.1333333,20.9989578 25.1418595,18.2294867 23.4686027,16.0012776 Z M11.9777884,13.3333333 C18.3616218,13.3333333 23.6065116,16.3909238 23.9972191,22.9333333 C24.0127839,23.1939654 23.9972191,24 22.9955999,24 L0.97000297,24 L0.97000297,24 C0.635616207,24 -0.027282334,23.2789066 0.000868912387,22.932274 C0.517678033,16.5686878 5.6825498,13.3333333 11.9777884,13.3333333 Z" id="Combined-Shape"></path>
</g>
</g>
</g>
</g>
</g>
</g>
</svg>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<svg width="60px" height="60px" viewBox="0 0 60 60" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 61 (89581) - https://sketch.com -->
<title>Icon2@3x</title>
<desc>Created with Sketch.</desc>
<g id="页面-2" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="系统首页" transform="translate(-719.000000, -136.000000)">
<g id="1" transform="translate(234.000000, 120.000000)">
<g id="Total-Order" transform="translate(299.000000, 0.000000)">
<g id="Icon2" transform="translate(186.000000, 16.000000)">
<path d="M23,60 C10.2974508,60 1.55561363e-15,49.7025492 0,37 L0,23 C-1.55561363e-15,10.2974508 10.2974508,2.33342044e-15 23,0 L37,0 C49.7025492,-2.33342044e-15 60,10.2974508 60,23 L60,37 C60,49.7025492 49.7025492,60 37,60 L23,60 Z" id="Circle-2" fill="#FFD164" opacity="0.209999993"></path>
<g id="icon" transform="translate(15.000000, 13.000000)">
<path d="M0,11.3164701 L12.9004912,18.7645722 C13.0394036,18.8447733 13.1850623,18.9027046 13.3333333,18.9394739 L13.3333333,33.3847054 L0.920064885,26.0385088 C0.349783865,25.7010154 0,25.0875659 0,24.4249029 L0,11.3164701 Z M30,11.1184665 L30,24.4249029 C30,25.0875659 29.6502161,25.7010154 29.0799351,26.0385088 L16.6666667,33.3847054 L16.6666667,18.8129235 C16.6969108,18.7978151 16.7268876,18.7817016 16.7565565,18.7645722 L30,11.1184665 L30,11.1184665 Z" id="Combined-Shape" fill="#FFC741"></path>
<path d="M0.405221909,7.70142332 C0.562796988,7.50243849 0.761684783,7.33426405 0.993563997,7.21076013 L14.118564,0.220099528 C14.6695479,-0.0733665093 15.3304521,-0.0733665093 15.881436,0.220099528 L29.006436,7.21076013 C29.1851826,7.30596446 29.3443248,7.42771319 29.480051,7.56965747 L15.0898899,15.8778209 C14.9952678,15.9324509 14.9080291,15.9949583 14.8285239,16.0640363 C14.7490186,15.9949583 14.66178,15.9324509 14.5671579,15.8778209 L0.405221909,7.70142332 Z" id="Path" fill="#FFD164" opacity="0.659481957"></path>
</g>
</g>
</g>
</g>
</g>
</g>
</svg>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<svg width="60px" height="60px" viewBox="0 0 60 60" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 61 (89581) - https://sketch.com -->
<title>Icon3@3x</title>
<desc>Created with Sketch.</desc>
<g id="页面-2" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="系统首页" transform="translate(-1018.000000, -136.000000)" fill="#55D187">
<g id="1" transform="translate(234.000000, 120.000000)">
<g id="Total-Sales" transform="translate(598.000000, 0.000000)">
<g id="Icon3" transform="translate(186.000000, 16.000000)">
<path d="M23,60 C10.2974508,60 1.55561363e-15,49.7025492 0,37 L0,23 C-1.55561363e-15,10.2974508 10.2974508,2.33342044e-15 23,0 L37,0 C49.7025492,-2.33342044e-15 60,10.2974508 60,23 L60,37 C60,49.7025492 49.7025492,60 37,60 L23,60 Z" id="Circle-2" opacity="0.209999993"></path>
<g id="icon" transform="translate(16.000000, 16.000000)" fill-rule="nonzero">
<path d="M3.11111111,24.8888889 L26.4444444,24.8888889 C27.3035541,24.8888889 28,25.5853348 28,26.4444444 C28,27.3035541 27.3035541,28 26.4444444,28 L1.55555556,28 C0.696445945,28 0,27.3035541 0,26.4444444 L0,1.55555556 C0,0.696445945 0.696445945,0 1.55555556,0 C2.41466517,0 3.11111111,0.696445945 3.11111111,1.55555556 L3.11111111,24.8888889 Z" id="Path-95"></path>
<path d="M8.91261343,18.1750195 C8.32503303,18.801772 7.34062178,18.8335272 6.71386936,18.2459468 C6.08711693,17.6583664 6.05536173,16.6739551 6.64294213,16.0472027 L12.4762755,9.82498047 C13.044535,9.21883699 13.9888279,9.16627114 14.6208522,9.70559855 L19.2248856,13.6343737 L25.2235157,6.03610888 C25.7558581,5.36180856 26.7340352,5.24672889 27.4083356,5.77907125 C28.0826359,6.31141362 28.1977156,7.28959079 27.6653732,7.96389112 L20.6653732,16.8305578 C20.118618,17.5231144 19.1059101,17.6227201 18.4347034,17.049957 L13.7306235,13.0358088 L8.91261343,18.1750195 Z" id="Path-97" opacity="0.657133557"></path>
</g>
</g>
</g>
</g>
</g>
</g>
</svg>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<svg width="60px" height="60px" viewBox="0 0 60 60" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 61 (89581) - https://sketch.com -->
<title>Icon</title>
<desc>Created with Sketch.</desc>
<g id="页面-2" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="系统首页" transform="translate(-1317.000000, -136.000000)" fill="#FF9066">
<g id="1" transform="translate(234.000000, 120.000000)">
<g id="Order-Pending" transform="translate(897.000000, 0.000000)">
<g id="Icon" transform="translate(186.000000, 16.000000)">
<path d="M23,60 C10.2974508,60 1.55561363e-15,49.7025492 0,37 L0,23 C-1.55561363e-15,10.2974508 10.2974508,2.33342044e-15 23,0 L37,0 C49.7025492,-2.33342044e-15 60,10.2974508 60,23 L60,37 C60,49.7025492 49.7025492,60 37,60 L23,60 Z" id="Circle-2" opacity="0.3"></path>
<g id="icon" transform="translate(16.000000, 15.000000)">
<path d="M13.1296822,8.34718934 L13.5475062,8.34718934 C13.8043819,8.34718934 14.0194647,8.54183658 14.0450248,8.79743748 L14.6666667,15.013856 L14.6666667,15.013856 L19.0814028,17.5365624 C19.2371903,17.6255838 19.3333333,17.7912555 19.3333333,17.9706839 L19.3333333,18.3592308 C19.3333333,18.6353732 19.1094757,18.8592308 18.8333333,18.8592308 C18.7888923,18.8592308 18.7446497,18.8533059 18.7017746,18.8416127 L12.3986612,17.1225818 C12.1672824,17.0594785 12.0132986,16.8409746 12.0316926,16.6018516 L12.631155,8.80884109 C12.6511933,8.54834251 12.8684141,8.34718934 13.1296822,8.34718934 Z" id="Path-107" opacity="0.779999971"></path>
<path d="M6.01733907,-0.0772351689 C6.2288764,-0.254736066 6.5442542,-0.227144084 6.72175509,-0.0156067521 L6.72175509,-0.0156067521 L8.51913552,2.1273858 C10.2024553,1.41052645 12.054904,1.01385601 14,1.01385601 C21.7319865,1.01385601 28,7.28186951 28,15.013856 C28,22.6413562 21.9002476,28.8441829 14.312645,29.010434 L14,29.013856 L14,29.013856 C6.2680135,29.013856 0,22.7458425 0,15.013856 C0,13.7006992 0.180792724,12.4297687 0.518844853,11.224598 L3.08641434,11.944805 C2.80896017,12.9339413 2.66666667,13.9630912 2.66666667,15.013856 C2.66666667,21.2730832 7.74077284,26.3471893 14,26.3471893 C20.2592272,26.3471893 25.3333333,21.2730832 25.3333333,15.013856 C25.3333333,8.85242927 20.4165542,3.83937783 14.2925184,3.68422422 L14,3.68052267 L14,3.68052267 C12.7318949,3.68052267 11.4968995,3.88835566 10.3322213,4.2862714 L12.1330448,6.43331723 C12.2023675,6.51593278 12.24312,6.61874811 12.2492217,6.7264223 C12.2648452,7.00212236 12.0540114,7.23828671 11.7783113,7.25391015 L11.7783113,7.25391015 L4.73355552,7.65312407 C4.68508783,7.65587065 4.6364785,7.65154413 4.58925778,7.64028071 C4.32065092,7.57621071 4.15484104,7.30652283 4.21891104,7.03791597 L4.21891104,7.03791597 L5.85237713,0.189778054 C5.87728008,0.0853749765 5.93511798,-0.00824348388 6.01733907,-0.0772351689 Z" id="Combined-Shape" opacity="0.901274182"></path>
</g>
</g>
</g>
</g>
</g>
</g>
</svg>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<svg width="20px" height="12px" viewBox="0 0 20 12" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 61 (89581) - https://sketch.com -->
<title>上涨-24px</title>
<desc>Created with Sketch.</desc>
<g id="页面-2" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="系统首页" transform="translate(-551.000000, -240.000000)">
<g id="1" transform="translate(234.000000, 120.000000)">
<g id="Total-Order" transform="translate(299.000000, 0.000000)">
<g id="8.5%-Up-from-yesterday" transform="translate(16.000000, 114.000000)">
<g id="上涨-24px">
<polygon id="Path" points="0 0 24 0 24 24 0 24"></polygon>
<polygon id="Path" fill="#55D187" fill-rule="nonzero" points="16 6 18.29 8.29 13.41 13.17 9.41 9.17 2 16.59 3.41 18 9.41 12 13.41 16 19.71 9.71 22 12 22 6"></polygon>
</g>
</g>
</g>
</g>
</g>
</g>
</svg>
\ No newline at end of file
// 对vue-count-to进行改造成支持vue3版本
export { default as CountTo } from './src/index.vue';
<template>
<span>
{{ displayValue }}
</span>
</template>
<script lang="ts">
import { defineComponent, reactive, computed, watch, onMounted, unref, toRef } from 'vue';
import { countToProps } from './props';
import { useRaf } from '/@/hooks/event/useRaf';
import { isNumber } from '/@/utils/is';
export default defineComponent({
name: 'CountTo',
props: countToProps,
emits: ['mounted', 'callback'],
setup(props, { emit }) {
const { requestAnimationFrame, cancelAnimationFrame } = useRaf();
const state = reactive<{
localStartVal: number;
printVal: number | null;
displayValue: string;
paused: boolean;
localDuration: number | null;
startTime: number | null;
timestamp: number | null;
rAF: any;
remaining: number | null;
}>({
localStartVal: props.startVal,
displayValue: formatNumber(props.startVal),
printVal: null,
paused: false,
localDuration: props.duration,
startTime: null,
timestamp: null,
remaining: null,
rAF: null,
});
onMounted(() => {
if (props.autoplay) {
start();
}
emit('mounted');
});
const getCountDown = computed(() => {
return props.startVal > props.endVal;
});
watch([() => props.startVal, () => props.endVal], () => {
if (props.autoplay) {
start();
}
});
function start() {
const { startVal, duration } = props;
state.localStartVal = startVal;
state.startTime = null;
state.localDuration = duration;
state.paused = false;
state.rAF = requestAnimationFrame(count);
}
function pauseResume() {
if (state.paused) {
resume();
state.paused = false;
} else {
pause();
state.paused = true;
}
}
function pause() {
cancelAnimationFrame(state.rAF);
}
function resume() {
state.startTime = null;
state.localDuration = +(state.remaining as number);
state.localStartVal = +(state.printVal as number);
requestAnimationFrame(count);
}
function reset() {
state.startTime = null;
cancelAnimationFrame(state.rAF);
state.displayValue = formatNumber(props.startVal);
}
function count(timestamp: number) {
const { useEasing, easingFn, endVal } = props;
if (!state.startTime) state.startTime = timestamp;
state.timestamp = timestamp;
const progress = timestamp - state.startTime;
state.remaining = (state.localDuration as number) - progress;
if (useEasing) {
if (unref(getCountDown)) {
state.printVal =
state.localStartVal -
easingFn(progress, 0, state.localStartVal - endVal, state.localDuration as number);
} else {
state.printVal = easingFn(
progress,
state.localStartVal,
endVal - state.localStartVal,
state.localDuration as number
);
}
} else {
if (unref(getCountDown)) {
state.printVal =
state.localStartVal -
(state.localStartVal - endVal) * (progress / (state.localDuration as number));
} else {
state.printVal =
state.localStartVal +
(endVal - state.localStartVal) * (progress / (state.localDuration as number));
}
}
if (unref(getCountDown)) {
state.printVal = state.printVal < endVal ? endVal : state.printVal;
} else {
state.printVal = state.printVal > endVal ? endVal : state.printVal;
}
state.displayValue = formatNumber(state.printVal);
if (progress < (state.localDuration as number)) {
state.rAF = requestAnimationFrame(count);
} else {
emit('callback');
}
}
function formatNumber(num: number | string) {
const { decimals, decimal, separator, suffix, prefix } = props;
num = Number(num).toFixed(decimals);
num += '';
const x = num.split('.');
let x1 = x[0];
const x2 = x.length > 1 ? decimal + x[1] : '';
const rgx = /(\d+)(\d{3})/;
if (separator && !isNumber(separator)) {
while (rgx.test(x1)) {
x1 = x1.replace(rgx, '$1' + separator + '$2');
}
}
return prefix + x1 + x2 + suffix;
}
return {
count,
reset,
resume,
start,
pauseResume,
displayValue: toRef(state, 'displayValue'),
};
},
});
</script>
import { PropType } from 'vue';
export const countToProps = {
startVal: {
type: Number as PropType<number>,
required: false,
default: 0,
},
endVal: {
type: Number as PropType<number>,
required: false,
default: 2017,
},
duration: {
type: Number as PropType<number>,
required: false,
default: 3000,
},
autoplay: {
type: Boolean as PropType<boolean>,
required: false,
default: true,
},
decimals: {
type: Number as PropType<number>,
required: false,
default: 0,
validator(value: number) {
return value >= 0;
},
},
decimal: {
type: String as PropType<string>,
required: false,
default: '.',
},
separator: {
type: String as PropType<string>,
required: false,
default: ',',
},
prefix: {
type: String as PropType<string>,
required: false,
default: '',
},
suffix: {
type: String as PropType<string>,
required: false,
default: '',
},
useEasing: {
type: Boolean as PropType<boolean>,
required: false,
default: true,
},
easingFn: {
type: Function as PropType<(t: number, b: number, c: number, d: number) => number>,
default(t: number, b: number, c: number, d: number) {
return (c * (-Math.pow(2, (-10 * t) / d) + 1) * 1024) / 1023 + b;
},
},
};
......@@ -41,7 +41,8 @@
display: flex;
width: 100%;
height: 100%;
background: rgba(255, 255, 255, 0.3);
// background: rgba(255, 255, 255, 0.5);
background: #f1f1f63d;
justify-content: center;
align-items: center;
}
......
@import './helper/distance.less';
// 生成样式
.distance();
.hidden {
......@@ -10,6 +9,10 @@
display: flex;
}
.align-middle {
vertical-align: middle;
}
.flex-wrap {
flex-wrap: wrap;
}
......@@ -48,3 +51,27 @@
word-wrap: normal;
white-space: nowrap;
}
.shadow-xs {
box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.05);
}
.shadow-sm {
box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
}
.shadow {
box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06);
}
.shadow-md {
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
}
.shadow-lg {
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
}
.shadow-xl {
box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
}
......@@ -4,27 +4,10 @@
}
.fade-enter-from,
.fade-enter,
.fade-leave-to {
opacity: 0;
}
/* fade-transform */
// .fade-transform-leave-active,
// .fade-transform-enter-active {
// transition: all 0.5s;
// }
// .fade-transform-enter {
// opacity: 0;
// transform: translateX(-30px);
// }
// .fade-transform-leave-to {
// opacity: 0;
// transform: translateX(30px);
// }
// side-fade
.slide-fade-enter-active,
.slide-fade-leave-active {
......@@ -42,35 +25,6 @@
transform: translateX(30%);
}
// zoom-out
.zoom-out-enter-active,
.zoom-out-leave-active {
transition: opacity 0.35s ease-in-out, transform 0.45s ease-out;
}
.zoom-out-enter-from,
.zoom-out-enter,
.zoom-out-leave-to {
opacity: 0;
transform: scale(0);
}
// zoom-fade
.zoom-fade-enter-active,
.zoom-fade-leave-active {
transition: transform 0.35s, opacity 0.35s ease-out;
}
.zoom-fade-enter-from {
opacity: 0;
transform: scale(0.97);
}
.zoom-fade-leave-to {
opacity: 0;
transform: scale(1.03);
}
// ///////////////////////////////////////////////
// Fade Bottom
// ///////////////////////////////////////////////
......@@ -92,23 +46,6 @@
transform: translateY(8%);
}
// Speed: 2x
.fade-bottom-2x-enter-active,
.fade-bottom-2x-leave-active {
transition: opacity 0.2s, transform 0.25s;
}
.fade-bottom-2x-enter-from,
.fade-bottom-2x-enter {
opacity: 0;
transform: translateY(-4%);
}
.fade-bottom-2x-leave-to {
opacity: 0;
transform: translateY(4%);
}
// ///////////////////////////////////////////////
// Fade Top
// ///////////////////////////////////////////////
......@@ -119,8 +56,7 @@
transition: opacity 0.3s, transform 0.35s;
}
.fade-top-enter-from,
.fade-top-enter {
.fade-top-enter-from {
opacity: 0;
transform: translateY(8%);
}
......@@ -129,20 +65,3 @@
opacity: 0;
transform: translateY(-8%);
}
// Speed: 2x
.fade-top-2x-enter-active,
.fade-top-2x-leave-active {
transition: opacity 0.2s, transform 0.25s;
}
.fade-top-2x-enter-from,
.fade-top-2x-enter {
opacity: 0;
transform: translateY(4%);
}
.fade-top-2x-leave-to {
opacity: 0;
transform: translateY(-4%);
}
......@@ -3,4 +3,5 @@
@import './scale.less';
@import './slide.less';
@import './scroll.less';
@import './zoom.less';
@import './breadcrumb.less';
......@@ -12,7 +12,6 @@
.scale-rotate-transition {
.transition-default();
&-enter,
&-enter-from,
&-leave,
&-leave-to {
......
.scroll-y-transition {
.transition-default();
&-enter,
&-enter-from,
&-leave-to {
opacity: 0;
}
&-enter-from,
&-enter {
&-enter-from {
transform: translateY(-15px);
}
......@@ -20,14 +18,12 @@
.scroll-y-reverse-transition {
.transition-default();
&-enter,
&-enter-from,
&-leave-to {
opacity: 0;
}
&-enter-from,
&-enter {
&-enter-from {
transform: translateY(15px);
}
......@@ -39,14 +35,12 @@
.scroll-x-transition {
.transition-default();
&-enter,
&-enter-from,
&-leave-to {
opacity: 0;
}
&-enter-from,
&-enter {
&-enter-from {
transform: translateX(-15px);
}
......@@ -58,14 +52,12 @@
.scroll-x-reverse-transition {
.transition-default();
&-enter,
&-enter-from,
&-leave-to {
opacity: 0;
}
&-enter-from,
&-enter {
&-enter-from {
transform: translateX(15px);
}
......
......@@ -2,7 +2,6 @@
.transition-default();
&-enter-from,
&-enter,
&-leave-to {
opacity: 0;
transform: translateY(-15px);
......@@ -13,7 +12,6 @@
.transition-default();
&-enter-from,
&-enter,
&-leave-to {
opacity: 0;
transform: translateY(15px);
......@@ -24,7 +22,6 @@
.transition-default();
&-enter-from,
&-enter,
&-leave-to {
opacity: 0;
transform: translateX(-15px);
......@@ -35,7 +32,6 @@
.transition-default();
&-enter-from,
&-enter,
&-leave-to {
opacity: 0;
transform: translateX(15px);
......
// zoom-out
.zoom-out-enter-active,
.zoom-out-leave-active {
transition: opacity 0.35s ease-in-out, transform 0.45s ease-out;
}
.zoom-out-enter-from,
.zoom-out-leave-to {
opacity: 0;
transform: scale(0);
}
// zoom-fade
.zoom-fade-enter-active,
.zoom-fade-leave-active {
transition: transform 0.35s, opacity 0.35s ease-out;
}
.zoom-fade-enter-from {
opacity: 0;
transform: scale(0.97);
}
.zoom-fade-leave-to {
opacity: 0;
transform: scale(1.03);
}
......@@ -51,22 +51,23 @@ if (isServer) {
}
export function useRaf() {
if (getCurrentInstance()) {
onUnmounted(() => {
cancelAnimationFrame();
});
}
return { requestAnimationFrame };
// if (getCurrentInstance()) {
// onUnmounted(() => {
// cancelAnimationFrame();
// });
// }
return { requestAnimationFrame, cancelAnimationFrame };
}
export function useRafFn(fn: () => any, options: { immediate?: boolean } = {}) {
export function useRafFn(fn: (...arg: any) => any, options: { immediate?: boolean } = {}) {
const { immediate = false } = options;
let started = false;
let id: ReturnType<typeof window.requestAnimationFrame>;
function loop() {
if (!started) return;
fn();
requestAnimationFrame(loop);
id = requestAnimationFrame(loop);
}
function start() {
......@@ -86,7 +87,7 @@ export function useRafFn(fn: () => any, options: { immediate?: boolean } = {}) {
if (getCurrentInstance()) {
onUnmounted(() => {
cancelAnimationFrame();
cancelAnimationFrame(id);
stop();
});
}
......
......@@ -8,17 +8,17 @@ export function useApexCharts(elRef: Ref<HTMLDivElement>) {
const chartInstanceRef = ref<Nullable<ApexCharts>>(null);
function setOptions(options: any) {
const el = unref(elRef);
nextTick(() => {
useTimeout(() => {
const el = unref(elRef);
if (!el || !unref(el)) {
return;
}
chartInstanceRef.value = new ApexCharts(el, options);
if (!el || !unref(el)) {
return;
}
chartInstanceRef.value = new ApexCharts(el, options);
const chartInstance = unref(chartInstanceRef);
const chartInstance = unref(chartInstanceRef);
nextTick(() => {
useTimeout(() => {
chartInstance && chartInstance.render();
}, 30);
});
......
......@@ -34,24 +34,24 @@ export function useECharts(
if (unref(widthRef) <= screenEnum.MD) {
useTimeout(() => {
resizeFn();
}, 0);
}, 30);
}
}
function setOptions(options: any, clear = true) {
// function setOptions(options: EChartOption, clear = true) {
let chartInstance = unref(chartInstanceRef);
if (!chartInstance) {
init();
chartInstance = chartInstance = unref(chartInstanceRef);
if (!chartInstance) {
return;
}
}
clear && chartInstance.clear();
nextTick(() => {
useTimeout(() => {
let chartInstance = unref(chartInstanceRef);
if (!chartInstance) {
init();
chartInstance = chartInstance = unref(chartInstanceRef);
if (!chartInstance) {
return;
}
}
clear && chartInstance.clear();
chartInstance && chartInstance.setOption(options);
}, 30);
});
......
......@@ -9,6 +9,10 @@ const menu: MenuModule = {
path: '/workbench',
name: '工作台',
},
{
path: '/analysis',
name: '分析页',
},
{
path: '/welcome',
name: '首页',
......
......@@ -32,5 +32,13 @@ export default {
affix: true,
},
},
{
path: '/analysis',
name: 'Analysis',
component: () => import('/@/views/dashboard/analysis/index.vue'),
meta: {
title: '分析页',
},
},
],
} as AppRouteModule;
<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>
<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>
<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>
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>
);
},
});
<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>
<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>
<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>
.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;
}
}
}
}
}
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',
},
};
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,
];
<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>
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;
}
<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] },
],
chart: {
height: 350,
type: 'rangeBar',
},
plotOptions: {
bar: {
horizontal: true,
distributed: true,
dataLabels: {
hideOverflowingLabels: false,
},
},
},
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'],
colors: ['#b9c3cd', '#b9c3cd', '#b9c3cd', '#b9c3cd', '#b9c3cd', '#b9c3cd'],
},
},
xaxis: {
type: 'datetime',
chart: {
height: 350,
type: 'radar',
dropShadow: {
enabled: true,
blur: 1,
left: 1,
top: 1,
},
},
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],
},
},
});
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册