mirror of
https://github.com/apache/cloudstack.git
synced 2025-10-26 08:42:29 +01:00
src: codebase wide cleanup and refactorings
Signed-off-by: Rohit Yadav <rohit.yadav@shapeblue.com>
This commit is contained in:
parent
7dad796113
commit
8b196ed56c
@ -1,102 +0,0 @@
|
|||||||
<template>
|
|
||||||
<span>
|
|
||||||
{{ lastTime | format }}
|
|
||||||
</span>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
|
|
||||||
function fixedZero (val) {
|
|
||||||
return val * 1 < 10 ? `0${val}` : val
|
|
||||||
}
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: 'CountDown',
|
|
||||||
props: {
|
|
||||||
format: {
|
|
||||||
type: Function,
|
|
||||||
default: undefined
|
|
||||||
},
|
|
||||||
target: {
|
|
||||||
type: [Date, Number],
|
|
||||||
required: true
|
|
||||||
},
|
|
||||||
onEnd: {
|
|
||||||
type: Function,
|
|
||||||
default: () => ({})
|
|
||||||
}
|
|
||||||
},
|
|
||||||
data () {
|
|
||||||
return {
|
|
||||||
dateTime: '0',
|
|
||||||
originTargetTime: 0,
|
|
||||||
lastTime: 0,
|
|
||||||
timer: 0,
|
|
||||||
interval: 1000
|
|
||||||
}
|
|
||||||
},
|
|
||||||
filters: {
|
|
||||||
format (time) {
|
|
||||||
const hours = 60 * 60 * 1000
|
|
||||||
const minutes = 60 * 1000
|
|
||||||
|
|
||||||
const h = Math.floor(time / hours)
|
|
||||||
const m = Math.floor((time - h * hours) / minutes)
|
|
||||||
const s = Math.floor((time - h * hours - m * minutes) / 1000)
|
|
||||||
return `${fixedZero(h)}:${fixedZero(m)}:${fixedZero(s)}`
|
|
||||||
}
|
|
||||||
},
|
|
||||||
created () {
|
|
||||||
this.initTime()
|
|
||||||
this.tick()
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
initTime () {
|
|
||||||
let lastTime = 0
|
|
||||||
let targetTime = 0
|
|
||||||
this.originTargetTime = this.target
|
|
||||||
try {
|
|
||||||
if (Object.prototype.toString.call(this.target) === '[object Date]') {
|
|
||||||
targetTime = this.target
|
|
||||||
} else {
|
|
||||||
targetTime = new Date(this.target).getTime()
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
throw new Error('invalid target prop')
|
|
||||||
}
|
|
||||||
|
|
||||||
lastTime = targetTime - new Date().getTime()
|
|
||||||
|
|
||||||
this.lastTime = lastTime < 0 ? 0 : lastTime
|
|
||||||
},
|
|
||||||
tick () {
|
|
||||||
const { onEnd } = this
|
|
||||||
|
|
||||||
this.timer = setTimeout(() => {
|
|
||||||
if (this.lastTime < this.interval) {
|
|
||||||
clearTimeout(this.timer)
|
|
||||||
this.lastTime = 0
|
|
||||||
if (typeof onEnd === 'function') {
|
|
||||||
onEnd()
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this.lastTime -= this.interval
|
|
||||||
this.tick()
|
|
||||||
}
|
|
||||||
}, this.interval)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
beforeUpdate () {
|
|
||||||
if (this.originTargetTime !== this.target) {
|
|
||||||
this.initTime()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
beforeDestroy () {
|
|
||||||
clearTimeout(this.timer)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
|
|
||||||
</style>
|
|
||||||
@ -1,3 +0,0 @@
|
|||||||
import CountDown from './CountDown'
|
|
||||||
|
|
||||||
export default CountDown
|
|
||||||
@ -1,64 +0,0 @@
|
|||||||
<script>
|
|
||||||
import Tooltip from 'ant-design-vue/es/tooltip'
|
|
||||||
import { cutStrByFullLength, getStrFullLength } from '@/components/_util/util'
|
|
||||||
/*
|
|
||||||
const isSupportLineClamp = document.body.style.webkitLineClamp !== undefined;
|
|
||||||
|
|
||||||
const TooltipOverlayStyle = {
|
|
||||||
overflowWrap: 'break-word',
|
|
||||||
wordWrap: 'break-word',
|
|
||||||
};
|
|
||||||
*/
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: 'Ellipsis',
|
|
||||||
components: {
|
|
||||||
Tooltip
|
|
||||||
},
|
|
||||||
props: {
|
|
||||||
prefixCls: {
|
|
||||||
type: String,
|
|
||||||
default: 'ant-pro-ellipsis'
|
|
||||||
},
|
|
||||||
tooltip: {
|
|
||||||
type: Boolean
|
|
||||||
},
|
|
||||||
length: {
|
|
||||||
type: Number,
|
|
||||||
required: true
|
|
||||||
},
|
|
||||||
lines: {
|
|
||||||
type: Number,
|
|
||||||
default: 1
|
|
||||||
},
|
|
||||||
fullWidthRecognition: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
getStrDom (str, fullLength) {
|
|
||||||
return (
|
|
||||||
<span>{ cutStrByFullLength(str, this.length) + (fullLength > this.length ? '...' : '') }</span>
|
|
||||||
)
|
|
||||||
},
|
|
||||||
getTooltip (fullStr, fullLength) {
|
|
||||||
return (
|
|
||||||
<Tooltip>
|
|
||||||
<template slot="title">{ fullStr }</template>
|
|
||||||
{ this.getStrDom(fullStr, fullLength) }
|
|
||||||
</Tooltip>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
render () {
|
|
||||||
const { tooltip, length } = this.$props
|
|
||||||
const str = this.$slots.default.map(vNode => vNode.text).join('')
|
|
||||||
const fullLength = getStrFullLength(str)
|
|
||||||
const strDom = tooltip && fullLength > length ? this.getTooltip(str, fullLength) : this.getStrDom(str, fullLength)
|
|
||||||
return (
|
|
||||||
strDom
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
@ -1,3 +0,0 @@
|
|||||||
import Ellipsis from './Ellipsis'
|
|
||||||
|
|
||||||
export default Ellipsis
|
|
||||||
@ -1,57 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="footer-toolbar">
|
|
||||||
<div class="footer-toolbar-left">
|
|
||||||
<slot name="extra">{{ extra }}</slot>
|
|
||||||
</div>
|
|
||||||
<div class="footer-toolbar-right">
|
|
||||||
<slot></slot>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
export default {
|
|
||||||
name: 'FooterToolBar',
|
|
||||||
props: {
|
|
||||||
prefixCls: {
|
|
||||||
type: String,
|
|
||||||
default: 'reduced'
|
|
||||||
},
|
|
||||||
extra: {
|
|
||||||
type: [String, Object],
|
|
||||||
default: ''
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="less" scoped>
|
|
||||||
.footer-toolbar {
|
|
||||||
position: fixed;
|
|
||||||
width: 100%;
|
|
||||||
bottom: 0;
|
|
||||||
right: 0;
|
|
||||||
height: 56px;
|
|
||||||
line-height: 56px;
|
|
||||||
box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.03);
|
|
||||||
background: #fff;
|
|
||||||
border-top: 1px solid #e8e8e8;
|
|
||||||
padding: 0 24px;
|
|
||||||
z-index: 9;
|
|
||||||
|
|
||||||
&:after {
|
|
||||||
content: "";
|
|
||||||
display: block;
|
|
||||||
clear: both;
|
|
||||||
}
|
|
||||||
|
|
||||||
&-left {
|
|
||||||
float: left;
|
|
||||||
}
|
|
||||||
|
|
||||||
&-right {
|
|
||||||
float: right;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@ -1,4 +0,0 @@
|
|||||||
import FooterToolBar from './FooterToolBar'
|
|
||||||
import './index.less'
|
|
||||||
|
|
||||||
export default FooterToolBar
|
|
||||||
@ -1,23 +0,0 @@
|
|||||||
@import "../../style/variables/prefixes";
|
|
||||||
|
|
||||||
@footer-toolbar-prefix-cls: ~"@{ant-pro-prefix}-footer-toolbar";
|
|
||||||
|
|
||||||
.@{footer-toolbar-prefix-cls} {
|
|
||||||
position: fixed;
|
|
||||||
width: 100%;
|
|
||||||
bottom: 0;
|
|
||||||
right: 0;
|
|
||||||
height: 56px;
|
|
||||||
line-height: 56px;
|
|
||||||
box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.03);
|
|
||||||
background: #fff;
|
|
||||||
border-top: 1px solid #e8e8e8;
|
|
||||||
padding: 0 24px;
|
|
||||||
z-index: 9;
|
|
||||||
|
|
||||||
&:after {
|
|
||||||
content: "";
|
|
||||||
display: block;
|
|
||||||
clear: both;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,106 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div :class="[prefixCls]">
|
|
||||||
<slot name="subtitle">
|
|
||||||
<div :class="[`${prefixCls}-subtitle`]">{{ typeof subTitle === 'string' ? subTitle : subTitle() }}</div>
|
|
||||||
</slot>
|
|
||||||
<div class="number-info-value">
|
|
||||||
<span>{{ total }}</span>
|
|
||||||
<span class="sub-total">
|
|
||||||
{{ subTotal }}
|
|
||||||
<icon :type="`caret-${status}`" />
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import Icon from 'ant-design-vue/es/icon'
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: 'NumberInfo',
|
|
||||||
props: {
|
|
||||||
prefixCls: {
|
|
||||||
type: String,
|
|
||||||
default: 'number-info'
|
|
||||||
},
|
|
||||||
total: {
|
|
||||||
type: Number,
|
|
||||||
required: true
|
|
||||||
},
|
|
||||||
subTotal: {
|
|
||||||
type: Number,
|
|
||||||
required: true
|
|
||||||
},
|
|
||||||
subTitle: {
|
|
||||||
type: [String, Function],
|
|
||||||
default: ''
|
|
||||||
},
|
|
||||||
status: {
|
|
||||||
type: String,
|
|
||||||
default: 'up'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
components: {
|
|
||||||
Icon
|
|
||||||
},
|
|
||||||
data () {
|
|
||||||
return {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="less" scoped>
|
|
||||||
@import '~ant-design-vue/lib/style/themes/default';
|
|
||||||
|
|
||||||
.number-info {
|
|
||||||
|
|
||||||
.number-info-subtitle {
|
|
||||||
color: @text-color-secondary;
|
|
||||||
font-size: @font-size-base;
|
|
||||||
height: 22px;
|
|
||||||
line-height: 22px;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
word-break: break-all;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
.number-info-value {
|
|
||||||
margin-top: 4px;
|
|
||||||
font-size: 0;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
word-break: break-all;
|
|
||||||
white-space: nowrap;
|
|
||||||
|
|
||||||
& > span {
|
|
||||||
color: @heading-color;
|
|
||||||
display: inline-block;
|
|
||||||
line-height: 32px;
|
|
||||||
height: 32px;
|
|
||||||
font-size: 24px;
|
|
||||||
margin-right: 32px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sub-total {
|
|
||||||
color: @text-color-secondary;
|
|
||||||
font-size: @font-size-lg;
|
|
||||||
vertical-align: top;
|
|
||||||
margin-right: 0;
|
|
||||||
i {
|
|
||||||
font-size: 12px;
|
|
||||||
transform: scale(0.82);
|
|
||||||
margin-left: 4px;
|
|
||||||
}
|
|
||||||
:global {
|
|
||||||
.anticon-caret-up {
|
|
||||||
color: @red-6;
|
|
||||||
}
|
|
||||||
.anticon-caret-down {
|
|
||||||
color: @green-6;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@ -1,3 +0,0 @@
|
|||||||
import NumberInfo from './NumberInfo'
|
|
||||||
|
|
||||||
export default NumberInfo
|
|
||||||
@ -1,56 +0,0 @@
|
|||||||
@import '~ant-design-vue/lib/style/themes/default';
|
|
||||||
@import '../../style/variables/prefixes';
|
|
||||||
|
|
||||||
@numberInfo-prefix-cls: ~"@{ant-pro-prefix}-number-info";
|
|
||||||
|
|
||||||
.@{numberInfo-prefix-cls} {
|
|
||||||
|
|
||||||
.ant-pro-number-info-subtitle {
|
|
||||||
color: @text-color-secondary;
|
|
||||||
font-size: @font-size-base;
|
|
||||||
height: 22px;
|
|
||||||
line-height: 22px;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
word-break: break-all;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
.number-info-value {
|
|
||||||
margin-top: 4px;
|
|
||||||
font-size: 0;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
word-break: break-all;
|
|
||||||
white-space: nowrap;
|
|
||||||
|
|
||||||
& > span {
|
|
||||||
color: @heading-color;
|
|
||||||
display: inline-block;
|
|
||||||
line-height: 32px;
|
|
||||||
height: 32px;
|
|
||||||
font-size: 24px;
|
|
||||||
margin-right: 32px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sub-total {
|
|
||||||
color: @text-color-secondary;
|
|
||||||
font-size: @font-size-lg;
|
|
||||||
vertical-align: top;
|
|
||||||
margin-right: 0;
|
|
||||||
i {
|
|
||||||
font-size: 12px;
|
|
||||||
transform: scale(0.82);
|
|
||||||
margin-left: 4px;
|
|
||||||
}
|
|
||||||
:global {
|
|
||||||
.anticon-caret-up {
|
|
||||||
color: @red-6;
|
|
||||||
}
|
|
||||||
.anticon-caret-down {
|
|
||||||
color: @green-6;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,90 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="result">
|
|
||||||
<div>
|
|
||||||
<a-icon :class="{ 'icon': true, 'success': isSuccess, 'error': !isSuccess }" :type="isSuccess ? 'check-circle' : 'close-circle'"/>
|
|
||||||
</div>
|
|
||||||
<div class="title" v-if="title">{{ title }}</div>
|
|
||||||
<div class="description" v-if="description">{{ description }}</div>
|
|
||||||
<div class="content" v-if="content">
|
|
||||||
<slot></slot>
|
|
||||||
</div>
|
|
||||||
<div class="action">
|
|
||||||
<slot name="action"></slot>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
export default {
|
|
||||||
name: 'Result',
|
|
||||||
props: {
|
|
||||||
isSuccess: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false
|
|
||||||
},
|
|
||||||
title: {
|
|
||||||
type: String,
|
|
||||||
default: ''
|
|
||||||
},
|
|
||||||
description: {
|
|
||||||
type: String,
|
|
||||||
default: ''
|
|
||||||
},
|
|
||||||
content: {
|
|
||||||
type: Boolean,
|
|
||||||
default: true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="less" scoped>
|
|
||||||
.result {
|
|
||||||
text-align: center;
|
|
||||||
width: 72%;
|
|
||||||
margin: 0 auto;
|
|
||||||
padding: 24px 0 8px;
|
|
||||||
|
|
||||||
.icon {
|
|
||||||
font-size: 72px;
|
|
||||||
line-height: 72px;
|
|
||||||
margin-bottom: 24px;
|
|
||||||
}
|
|
||||||
.success {
|
|
||||||
color: #52c41a;
|
|
||||||
}
|
|
||||||
.error {
|
|
||||||
color: red;
|
|
||||||
}
|
|
||||||
.title {
|
|
||||||
font-size: 24px;
|
|
||||||
color: rgba(0, 0, 0, .85);
|
|
||||||
font-weight: 500;
|
|
||||||
line-height: 32px;
|
|
||||||
margin-bottom: 16px;
|
|
||||||
}
|
|
||||||
.description {
|
|
||||||
font-size: 14px;
|
|
||||||
line-height: 22px;
|
|
||||||
color: rgba(0, 0, 0, 0.45);
|
|
||||||
margin-bottom: 24px;
|
|
||||||
}
|
|
||||||
.content {
|
|
||||||
background: #fafafa;
|
|
||||||
padding: 24px 40px;
|
|
||||||
border-radius: 2px;
|
|
||||||
text-align: left;
|
|
||||||
}
|
|
||||||
.action {
|
|
||||||
margin-top: 32px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.mobile {
|
|
||||||
.result {
|
|
||||||
width: 100%;
|
|
||||||
margin: 0 auto;
|
|
||||||
padding: unset;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@ -1,2 +0,0 @@
|
|||||||
import Result from './Result.vue'
|
|
||||||
export default Result
|
|
||||||
@ -1,124 +0,0 @@
|
|||||||
import { Menu, Icon, Input } from 'ant-design-vue'
|
|
||||||
|
|
||||||
const { Item, ItemGroup, SubMenu } = Menu
|
|
||||||
const { Search } = Input
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: 'Tree',
|
|
||||||
props: {
|
|
||||||
dataSource: {
|
|
||||||
type: Array,
|
|
||||||
required: true
|
|
||||||
},
|
|
||||||
openKeys: {
|
|
||||||
type: Array,
|
|
||||||
default: () => []
|
|
||||||
},
|
|
||||||
search: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
created () {
|
|
||||||
this.localOpenKeys = this.openKeys.slice(0)
|
|
||||||
},
|
|
||||||
data () {
|
|
||||||
return {
|
|
||||||
localOpenKeys: []
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
handlePlus (item) {
|
|
||||||
this.$emit('add', item)
|
|
||||||
},
|
|
||||||
handleTitleClick (...args) {
|
|
||||||
this.$emit('titleClick', { args })
|
|
||||||
},
|
|
||||||
|
|
||||||
renderSearch () {
|
|
||||||
return (
|
|
||||||
<Search
|
|
||||||
placeholder="input search text"
|
|
||||||
style="width: 100%; margin-bottom: 1rem"
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
},
|
|
||||||
renderIcon (icon) {
|
|
||||||
return icon && (<Icon type={icon} />) || null
|
|
||||||
},
|
|
||||||
renderMenuItem (item) {
|
|
||||||
return (
|
|
||||||
<Item key={item.key}>
|
|
||||||
{ this.renderIcon(item.icon) }
|
|
||||||
{ item.title }
|
|
||||||
<a class="btn" style="width: 20px;z-index:1300" {...{ on: { click: () => this.handlePlus(item) } }}><a-icon type="plus"/></a>
|
|
||||||
</Item>
|
|
||||||
)
|
|
||||||
},
|
|
||||||
renderItem (item) {
|
|
||||||
return item.children ? this.renderSubItem(item, item.key) : this.renderMenuItem(item, item.key)
|
|
||||||
},
|
|
||||||
renderItemGroup (item) {
|
|
||||||
const childrenItems = item.children.map(o => {
|
|
||||||
return this.renderItem(o, o.key)
|
|
||||||
})
|
|
||||||
|
|
||||||
return (
|
|
||||||
<ItemGroup key={item.key}>
|
|
||||||
<template slot="title">
|
|
||||||
<span>{ item.title }</span>
|
|
||||||
<a-dropdown>
|
|
||||||
<a class="btn"><a-icon type="ellipsis" /></a>
|
|
||||||
<a-menu slot="overlay">
|
|
||||||
<a-menu-item key="1">新增</a-menu-item>
|
|
||||||
<a-menu-item key="2">合并</a-menu-item>
|
|
||||||
<a-menu-item key="3">移除</a-menu-item>
|
|
||||||
</a-menu>
|
|
||||||
</a-dropdown>
|
|
||||||
</template>
|
|
||||||
{ childrenItems }
|
|
||||||
</ItemGroup>
|
|
||||||
)
|
|
||||||
},
|
|
||||||
renderSubItem (item, key) {
|
|
||||||
const childrenItems = item.children && item.children.map(o => {
|
|
||||||
return this.renderItem(o, o.key)
|
|
||||||
})
|
|
||||||
|
|
||||||
const title = (
|
|
||||||
<span slot="title">
|
|
||||||
{ this.renderIcon(item.icon) }
|
|
||||||
<span>{ item.title }</span>
|
|
||||||
</span>
|
|
||||||
)
|
|
||||||
|
|
||||||
if (item.group) {
|
|
||||||
return this.renderItemGroup(item)
|
|
||||||
}
|
|
||||||
// titleClick={this.handleTitleClick(item)}
|
|
||||||
return (
|
|
||||||
<SubMenu key={key}>
|
|
||||||
{ title }
|
|
||||||
{ childrenItems }
|
|
||||||
</SubMenu>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
render () {
|
|
||||||
const { dataSource, search } = this.$props
|
|
||||||
|
|
||||||
// this.localOpenKeys = openKeys.slice(0)
|
|
||||||
const list = dataSource.map(item => {
|
|
||||||
return this.renderItem(item)
|
|
||||||
})
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div class="tree-wrapper">
|
|
||||||
{ search ? this.renderSearch() : null }
|
|
||||||
<Menu mode="inline" class="custom-tree" {...{ on: { click: item => this.$emit('click', item), 'update:openKeys': val => { this.localOpenKeys = val } } }} openKeys={this.localOpenKeys}>
|
|
||||||
{ list }
|
|
||||||
</Menu>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,73 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="trend" :class="[ reverseColor && 'reverse-color' ]">
|
|
||||||
<span>
|
|
||||||
<slot name="term"></slot>
|
|
||||||
<span class="item-text">
|
|
||||||
<slot></slot>
|
|
||||||
</span>
|
|
||||||
</span>
|
|
||||||
<span :class="[flag]"><a-icon :type="`caret-${flag}`"/></span>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
export default {
|
|
||||||
name: 'Trend',
|
|
||||||
props: {
|
|
||||||
prefixCls: {
|
|
||||||
type: String,
|
|
||||||
default: 'ant-pro-trend'
|
|
||||||
},
|
|
||||||
flag: {
|
|
||||||
type: String,
|
|
||||||
required: true
|
|
||||||
},
|
|
||||||
reverseColor: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="less" scoped>
|
|
||||||
@import "~ant-design-vue/lib/style/themes/default";
|
|
||||||
.trend {
|
|
||||||
display: inline-block;
|
|
||||||
font-size: @font-size-base;
|
|
||||||
line-height: 22px;
|
|
||||||
|
|
||||||
.up,
|
|
||||||
.down {
|
|
||||||
margin-left: 4px;
|
|
||||||
position: relative;
|
|
||||||
top: 1px;
|
|
||||||
|
|
||||||
i {
|
|
||||||
font-size: 12px;
|
|
||||||
transform: scale(0.83);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.item-text {
|
|
||||||
display: inline-block;
|
|
||||||
margin-left: 8px;
|
|
||||||
color: rgba(0,0,0,.85);
|
|
||||||
}
|
|
||||||
|
|
||||||
.up {
|
|
||||||
color: @red-6;
|
|
||||||
}
|
|
||||||
.down {
|
|
||||||
color: @green-6;
|
|
||||||
top: -1px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.reverse-color .up {
|
|
||||||
color: @green-6;
|
|
||||||
}
|
|
||||||
&.reverse-color .down {
|
|
||||||
color: @red-6;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@ -1,3 +0,0 @@
|
|||||||
import Trend from './Trend.vue'
|
|
||||||
|
|
||||||
export default Trend
|
|
||||||
@ -1,43 +0,0 @@
|
|||||||
@import '~ant-design-vue/lib/style/themes/default';
|
|
||||||
@import '../../style/variables/prefixes';
|
|
||||||
|
|
||||||
@trend-prefix-cls: ~"@{ant-pro-prefix}-trend";
|
|
||||||
|
|
||||||
.@{trend-prefix-cls} {
|
|
||||||
display: inline-block;
|
|
||||||
font-size: @font-size-base;
|
|
||||||
line-height: 22px;
|
|
||||||
|
|
||||||
.up,
|
|
||||||
.down {
|
|
||||||
margin-left: 4px;
|
|
||||||
position: relative;
|
|
||||||
top: 1px;
|
|
||||||
|
|
||||||
i {
|
|
||||||
font-size: 12px;
|
|
||||||
transform: scale(0.83);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.item-text {
|
|
||||||
display: inline-block;
|
|
||||||
margin-left: 8px;
|
|
||||||
color: rgba(0,0,0,.85);
|
|
||||||
}
|
|
||||||
|
|
||||||
.up {
|
|
||||||
color: @red-6;
|
|
||||||
}
|
|
||||||
.down {
|
|
||||||
color: @green-6;
|
|
||||||
top: -1px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.reverse-color .up {
|
|
||||||
color: @green-6;
|
|
||||||
}
|
|
||||||
&.reverse-color .down {
|
|
||||||
color: @red-6;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,32 +0,0 @@
|
|||||||
/**
|
|
||||||
* components util
|
|
||||||
*/
|
|
||||||
|
|
||||||
export function filterEmpty (children = []) {
|
|
||||||
return children.filter(c => c.tag || (c.text && c.text.trim() !== ''))
|
|
||||||
}
|
|
||||||
|
|
||||||
export const getStrFullLength = (str = '') =>
|
|
||||||
str.split('').reduce((pre, cur) => {
|
|
||||||
const charCode = cur.charCodeAt(0)
|
|
||||||
if (charCode >= 0 && charCode <= 128) {
|
|
||||||
return pre + 1
|
|
||||||
}
|
|
||||||
return pre + 2
|
|
||||||
}, 0)
|
|
||||||
|
|
||||||
export const cutStrByFullLength = (str = '', maxLength) => {
|
|
||||||
let showLength = 0
|
|
||||||
return str.split('').reduce((pre, cur) => {
|
|
||||||
const charCode = cur.charCodeAt(0)
|
|
||||||
if (charCode >= 0 && charCode <= 128) {
|
|
||||||
showLength += 1
|
|
||||||
} else {
|
|
||||||
showLength += 2
|
|
||||||
}
|
|
||||||
if (showLength <= maxLength) {
|
|
||||||
return pre + cur
|
|
||||||
}
|
|
||||||
return pre
|
|
||||||
}, '')
|
|
||||||
}
|
|
||||||
@ -1,73 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="bar-wrapper">
|
|
||||||
<h4 class="bar-headline">{{ title }}</h4>
|
|
||||||
<v-chart
|
|
||||||
class="bar-chart"
|
|
||||||
:data="data"
|
|
||||||
:forceFit="true">
|
|
||||||
<v-tooltip />
|
|
||||||
<v-axis />
|
|
||||||
<v-bar position="x*y"/>
|
|
||||||
</v-chart>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
const data = []
|
|
||||||
for (let i = 0; i < 12; i += 1) {
|
|
||||||
data.push({
|
|
||||||
x: `${i + 1}X`,
|
|
||||||
y: Math.floor(Math.random() * 1000) + 200
|
|
||||||
})
|
|
||||||
}
|
|
||||||
const tooltip = [
|
|
||||||
'x*y',
|
|
||||||
(x, y) => ({
|
|
||||||
name: x,
|
|
||||||
value: y
|
|
||||||
})
|
|
||||||
]
|
|
||||||
const scale = [{
|
|
||||||
dataKey: 'x',
|
|
||||||
min: 2
|
|
||||||
}, {
|
|
||||||
dataKey: 'y',
|
|
||||||
title: 'Data',
|
|
||||||
min: 1,
|
|
||||||
max: 22
|
|
||||||
}]
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: 'Bar',
|
|
||||||
props: {
|
|
||||||
title: {
|
|
||||||
type: String,
|
|
||||||
default: ''
|
|
||||||
}
|
|
||||||
},
|
|
||||||
data () {
|
|
||||||
return {
|
|
||||||
data,
|
|
||||||
scale,
|
|
||||||
tooltip
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="less" scoped>
|
|
||||||
.bar {
|
|
||||||
&-wrapper {
|
|
||||||
padding: 0 0 32px 32px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&-headline {
|
|
||||||
margin-bottom: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&-chart {
|
|
||||||
height: 254px;
|
|
||||||
padding: 0 0 40px 50px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@ -1,76 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div>
|
|
||||||
<v-chart
|
|
||||||
class="liquid-chart"
|
|
||||||
:forceFit="true"
|
|
||||||
:height="height"
|
|
||||||
:width="width"
|
|
||||||
:data="data"
|
|
||||||
:scale="scale">
|
|
||||||
<v-tooltip />
|
|
||||||
<v-interval
|
|
||||||
:shape="['liquid-fill-gauge']"
|
|
||||||
position="transfer*value"
|
|
||||||
color=""
|
|
||||||
class="liquid-interval"
|
|
||||||
:v-style="{
|
|
||||||
lineWidth: 10
|
|
||||||
}"
|
|
||||||
:tooltip="[
|
|
||||||
'transfer*value',
|
|
||||||
(transfer, value) => {
|
|
||||||
return {
|
|
||||||
name: transfer,
|
|
||||||
value,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
]"
|
|
||||||
></v-interval>
|
|
||||||
<v-guide
|
|
||||||
class="liquid-guide"
|
|
||||||
v-for="(row, index) in data"
|
|
||||||
:key="index"
|
|
||||||
type="text"
|
|
||||||
:top="true"
|
|
||||||
:position="{
|
|
||||||
gender: row.transfer,
|
|
||||||
value: 45
|
|
||||||
}"
|
|
||||||
:content="row.value + '%'"
|
|
||||||
/>
|
|
||||||
</v-chart>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
export default {
|
|
||||||
name: 'Liquid',
|
|
||||||
props: {
|
|
||||||
height: {
|
|
||||||
type: Number,
|
|
||||||
default: 0
|
|
||||||
},
|
|
||||||
width: {
|
|
||||||
type: Number,
|
|
||||||
default: 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="less" scoped>
|
|
||||||
.liquid {
|
|
||||||
&-graph {
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
&-interval {
|
|
||||||
opacity: 0.75;
|
|
||||||
}
|
|
||||||
|
|
||||||
&-guide {
|
|
||||||
text-align: 'center';
|
|
||||||
opacity: 0.75;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@ -1,73 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="mini-area-wrapper">
|
|
||||||
<div class="mini-area-wrapper2">
|
|
||||||
<v-chart class="mini-area-chart" :force-fit="true" :data="data">
|
|
||||||
<v-tooltip />
|
|
||||||
<v-smooth-area position="x*y" />
|
|
||||||
</v-chart>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import moment from 'moment'
|
|
||||||
const data = []
|
|
||||||
const beginDay = new Date().getTime()
|
|
||||||
|
|
||||||
for (let i = 0; i < 10; i++) {
|
|
||||||
data.push({
|
|
||||||
x: moment(new Date(beginDay + 1000 * 60 * 60 * 24 * i)).format('YYYY-MM-DD'),
|
|
||||||
y: Math.round(Math.random() * 10)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
const tooltip = [
|
|
||||||
'x*y',
|
|
||||||
(x, y) => ({
|
|
||||||
name: x,
|
|
||||||
value: y
|
|
||||||
})
|
|
||||||
]
|
|
||||||
|
|
||||||
const scale = [{
|
|
||||||
dataKey: 'x',
|
|
||||||
min: 2
|
|
||||||
}, {
|
|
||||||
dataKey: 'y',
|
|
||||||
title: '时间',
|
|
||||||
min: 1,
|
|
||||||
max: 22
|
|
||||||
}]
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: 'MiniArea',
|
|
||||||
data () {
|
|
||||||
return {
|
|
||||||
data,
|
|
||||||
tooltip,
|
|
||||||
scale
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="less" scoped>
|
|
||||||
.mini-area {
|
|
||||||
&-wrapper {
|
|
||||||
position: relative;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
&-wrapper2 {
|
|
||||||
position: absolute;
|
|
||||||
bottom: -28px;
|
|
||||||
width: 100%;
|
|
||||||
height: 46px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&-chart {
|
|
||||||
padding: 36px 0 18px 0;
|
|
||||||
height: 100px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@ -1,73 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="mini-bar-wrapper">
|
|
||||||
<div class="mini-bar-wrapper2">
|
|
||||||
<v-chart class="mini-bar-chart" :force-fit="true" :data="data">
|
|
||||||
<v-tooltip />
|
|
||||||
<v-bar position="x*y" />
|
|
||||||
</v-chart>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import moment from 'moment'
|
|
||||||
const data = []
|
|
||||||
const beginDay = new Date().getTime()
|
|
||||||
|
|
||||||
for (let i = 0; i < 10; i++) {
|
|
||||||
data.push({
|
|
||||||
x: moment(new Date(beginDay + 1000 * 60 * 60 * 24 * i)).format('YYYY-MM-DD'),
|
|
||||||
y: Math.round(Math.random() * 10)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
const tooltip = [
|
|
||||||
'x*y',
|
|
||||||
(x, y) => ({
|
|
||||||
name: x,
|
|
||||||
value: y
|
|
||||||
})
|
|
||||||
]
|
|
||||||
|
|
||||||
const scale = [{
|
|
||||||
dataKey: 'x',
|
|
||||||
min: 2
|
|
||||||
}, {
|
|
||||||
dataKey: 'y',
|
|
||||||
title: '时间',
|
|
||||||
min: 1,
|
|
||||||
max: 22
|
|
||||||
}]
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: 'MiniArea',
|
|
||||||
data () {
|
|
||||||
return {
|
|
||||||
data,
|
|
||||||
tooltip,
|
|
||||||
scale
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="less" scoped>
|
|
||||||
.mini-bar {
|
|
||||||
&-wrapper {
|
|
||||||
position: relative;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
&-wrapper2 {
|
|
||||||
position: absolute;
|
|
||||||
bottom: -28px;
|
|
||||||
width: 100%;
|
|
||||||
height: 46px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&-chart {
|
|
||||||
padding: 36px 0 18px 0;
|
|
||||||
height: 100px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@ -1,93 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="mini-progress-wrapper">
|
|
||||||
<div class="mini-progress-target target" :style="{ left: target + '%'}">
|
|
||||||
<span class="mini-progress-background"/>
|
|
||||||
<span class="mini-progress-background2"/>
|
|
||||||
</div>
|
|
||||||
<div class="mini-progress-wrapper-inner">
|
|
||||||
<div class="mini-progress-progress"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
export default {
|
|
||||||
name: 'MiniProgress',
|
|
||||||
props: {
|
|
||||||
target: {
|
|
||||||
type: Number,
|
|
||||||
default: 0
|
|
||||||
},
|
|
||||||
height: {
|
|
||||||
type: String,
|
|
||||||
default: '10px'
|
|
||||||
},
|
|
||||||
color: {
|
|
||||||
type: String,
|
|
||||||
default: '#13C2C2'
|
|
||||||
},
|
|
||||||
percentage: {
|
|
||||||
type: Number,
|
|
||||||
default: 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="less" scoped>
|
|
||||||
@import "~ant-design-vue/lib/style/themes/default";
|
|
||||||
|
|
||||||
.mini-progress {
|
|
||||||
&-wrapper {
|
|
||||||
padding: 5px 0;
|
|
||||||
position: relative;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
&-wrapper-inner {
|
|
||||||
background-color: #f5f5f5;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
&-target {
|
|
||||||
left: 0;
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
bottom: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
&-background {
|
|
||||||
background-color: @cyan-6;
|
|
||||||
border-radius: 100px;
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
height: 4px;
|
|
||||||
width: 2px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&-background2 {
|
|
||||||
background-color: @cyan-6;
|
|
||||||
border-radius: 100px;
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
height: 4px;
|
|
||||||
width: 2px;
|
|
||||||
top: auto;
|
|
||||||
bottom: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
&-progress {
|
|
||||||
background-color: @cyan-6;
|
|
||||||
width: 0%;
|
|
||||||
height: 0;
|
|
||||||
|
|
||||||
transition: all .4s cubic-bezier(.08, .82, .17, 1) 0s;
|
|
||||||
border-radius: 1px 0 0 1px;
|
|
||||||
background-color: #1890ff;
|
|
||||||
width: 0;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@ -1,73 +0,0 @@
|
|||||||
<template>
|
|
||||||
<v-chart class="radar-chart" :forceFit="true" :data="data" :scale="scale">
|
|
||||||
<v-tooltip></v-tooltip>
|
|
||||||
<v-axis :dataKey="axis1Opts.dataKey" :line="axis1Opts.line" :tickLine="axis1Opts.tickLine" :grid="axis1Opts.grid" />
|
|
||||||
<v-axis :dataKey="axis2Opts.dataKey" :line="axis2Opts.line" :tickLine="axis2Opts.tickLine" :grid="axis2Opts.grid" />
|
|
||||||
<v-legend dataKey="user" marker="circle" :offset="30" />
|
|
||||||
<v-coord type="polar" radius="0.8" />
|
|
||||||
<v-line position="item*score" color="user" :size="2" />
|
|
||||||
<v-point position="item*score" color="user" :size="4" shape="circle" />
|
|
||||||
</v-chart>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
const axis1Opts = {
|
|
||||||
dataKey: 'item',
|
|
||||||
line: null,
|
|
||||||
tickLine: null,
|
|
||||||
grid: {
|
|
||||||
lineStyle: {
|
|
||||||
lineDash: null
|
|
||||||
},
|
|
||||||
hideFirstLine: false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const axis2Opts = {
|
|
||||||
dataKey: 'score',
|
|
||||||
line: null,
|
|
||||||
tickLine: null,
|
|
||||||
grid: {
|
|
||||||
type: 'polygon',
|
|
||||||
lineStyle: {
|
|
||||||
lineDash: null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const scale = [
|
|
||||||
{
|
|
||||||
dataKey: 'score',
|
|
||||||
min: 0,
|
|
||||||
max: 80
|
|
||||||
}, {
|
|
||||||
dataKey: 'user',
|
|
||||||
alias: 'Alias'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: 'Radar',
|
|
||||||
props: {
|
|
||||||
data: {
|
|
||||||
type: Array,
|
|
||||||
default: null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
data () {
|
|
||||||
return {
|
|
||||||
axis1Opts,
|
|
||||||
axis2Opts,
|
|
||||||
scale
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="less" scoped>
|
|
||||||
.radar {
|
|
||||||
&-chart {
|
|
||||||
height: 400px;
|
|
||||||
padding: 20 20 95 20;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@ -1,74 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="rank-list-wrapper">
|
|
||||||
<h4>{{ title }}</h4>
|
|
||||||
<ul class="rank-list-list">
|
|
||||||
<li class="rank-list-item" :key="index" v-for="(item, index) in list">
|
|
||||||
<span class="rank-list-index" :class="index < 3 ? 'is-active' : null">{{ index + 1 }}</span>
|
|
||||||
<span class="rank-list-name">{{ item.name }}</span>
|
|
||||||
<span class="rank-list-total">{{ item.total }}</span>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
export default {
|
|
||||||
name: 'RankList',
|
|
||||||
// ['title', 'list']
|
|
||||||
props: {
|
|
||||||
title: {
|
|
||||||
type: String,
|
|
||||||
default: ''
|
|
||||||
},
|
|
||||||
list: {
|
|
||||||
type: Array,
|
|
||||||
default: null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="less" scoped>
|
|
||||||
.rank-list {
|
|
||||||
margin: 25px 0 0;
|
|
||||||
padding: 0;
|
|
||||||
list-style: none;
|
|
||||||
|
|
||||||
&-wrapper {
|
|
||||||
padding: 0 32px 32px 72px;
|
|
||||||
|
|
||||||
.mobile & {
|
|
||||||
padding-left: 32px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&-item {
|
|
||||||
margin-top: 16px;
|
|
||||||
color: rgba(0, 0, 0, .65);
|
|
||||||
font-size: 14px;
|
|
||||||
line-height: 22px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&-index {
|
|
||||||
background-color: #f5f5f5;
|
|
||||||
border-radius: 20px;
|
|
||||||
display: inline-block;
|
|
||||||
font-size: 12px;
|
|
||||||
font-weight: 600;
|
|
||||||
margin-right: 24px;
|
|
||||||
height: 20px;
|
|
||||||
line-height: 20px;
|
|
||||||
width: 20px;
|
|
||||||
text-align: center;
|
|
||||||
|
|
||||||
&.is-active {
|
|
||||||
background-color: #314659;
|
|
||||||
color: #fff;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&-total {
|
|
||||||
float: right;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@ -1,81 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="transfer-bar-wrapper">
|
|
||||||
<h4 class="transfer-bar-headline">{{ title }}</h4>
|
|
||||||
<v-chart
|
|
||||||
class="transfer-bar-chart"
|
|
||||||
:data="data"
|
|
||||||
:scale="scale"
|
|
||||||
:forceFit="true"
|
|
||||||
>
|
|
||||||
<v-tooltip />
|
|
||||||
<v-axis />
|
|
||||||
<v-bar position="x*y"/>
|
|
||||||
</v-chart>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
const tooltip = [
|
|
||||||
'x*y',
|
|
||||||
(x, y) => ({
|
|
||||||
name: x,
|
|
||||||
value: y
|
|
||||||
})
|
|
||||||
]
|
|
||||||
const scale = [{
|
|
||||||
dataKey: 'x',
|
|
||||||
title: '日期(天)',
|
|
||||||
alias: '日期(天)',
|
|
||||||
min: 2
|
|
||||||
}, {
|
|
||||||
dataKey: 'y',
|
|
||||||
title: 'Title',
|
|
||||||
alias: 'Alias',
|
|
||||||
min: 1
|
|
||||||
}]
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: 'Bar',
|
|
||||||
props: {
|
|
||||||
title: {
|
|
||||||
type: String,
|
|
||||||
default: ''
|
|
||||||
}
|
|
||||||
},
|
|
||||||
data () {
|
|
||||||
return {
|
|
||||||
data: [],
|
|
||||||
scale,
|
|
||||||
tooltip
|
|
||||||
}
|
|
||||||
},
|
|
||||||
created () {
|
|
||||||
this.getMonthBar()
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
getMonthBar () {
|
|
||||||
this.$http.get('/analysis/month-bar')
|
|
||||||
.then(res => {
|
|
||||||
this.data = res.result
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="less" scoped>
|
|
||||||
.c-transfer-bar {
|
|
||||||
&-wrapper {
|
|
||||||
padding: 0 0 32px 32px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&-headline {
|
|
||||||
margin-bottom: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&-chart {
|
|
||||||
height: 254px;
|
|
||||||
padding: 0 0 40px 50px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@ -1,86 +0,0 @@
|
|||||||
<template class="trend">
|
|
||||||
<div class="trend-wrapper chart-trend">
|
|
||||||
{{ term }}
|
|
||||||
<span class="trend-rate">{{ rate }}%</span>
|
|
||||||
<span class="trend-icon " :class="[trend]"><a-icon :type="'caret-' + trend"/></span>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
export default {
|
|
||||||
name: 'Trend',
|
|
||||||
props: {
|
|
||||||
term: {
|
|
||||||
type: String,
|
|
||||||
default: '',
|
|
||||||
required: true
|
|
||||||
},
|
|
||||||
percentage: {
|
|
||||||
type: Number,
|
|
||||||
default: null
|
|
||||||
},
|
|
||||||
type: {
|
|
||||||
type: Boolean,
|
|
||||||
default: null
|
|
||||||
},
|
|
||||||
target: {
|
|
||||||
type: Number,
|
|
||||||
default: 0
|
|
||||||
},
|
|
||||||
value: {
|
|
||||||
type: Number,
|
|
||||||
default: 0
|
|
||||||
},
|
|
||||||
fixed: {
|
|
||||||
type: Number,
|
|
||||||
default: 2
|
|
||||||
}
|
|
||||||
},
|
|
||||||
data () {
|
|
||||||
return {
|
|
||||||
trend: this.type && 'up' || 'down',
|
|
||||||
rate: this.percentage
|
|
||||||
}
|
|
||||||
},
|
|
||||||
created () {
|
|
||||||
const type = this.type === null ? this.value >= this.target : this.type
|
|
||||||
this.trend = type ? 'up' : 'down'
|
|
||||||
this.rate = (this.percentage === null ? Math.abs(this.value - this.target) * 100 / this.target : this.percentage).toFixed(this.fixed)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="less" scoped>
|
|
||||||
.trend {
|
|
||||||
&-wrapper {
|
|
||||||
display: inline-block;
|
|
||||||
font-size: 14px;
|
|
||||||
line-height: 22px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&-icon {
|
|
||||||
font-size: 12px;
|
|
||||||
|
|
||||||
&.up,
|
|
||||||
&.down {
|
|
||||||
margin-left: 4px;
|
|
||||||
position: relative;
|
|
||||||
|
|
||||||
i {
|
|
||||||
font-size: 12px;
|
|
||||||
transform: scale(.83);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.up {
|
|
||||||
color: #f5222d;
|
|
||||||
top: 1px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.down {
|
|
||||||
color: #52c41a;
|
|
||||||
top: -1px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@ -1,10 +0,0 @@
|
|||||||
.antv-chart-mini {
|
|
||||||
position: relative;
|
|
||||||
width: 100%;
|
|
||||||
|
|
||||||
.chart-wrapper {
|
|
||||||
position: absolute;
|
|
||||||
bottom: -28px;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -6,7 +6,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import ProjectMenu from '../tools/ProjectMenu'
|
import ProjectMenu from './ProjectMenu'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'Logo',
|
name: 'Logo',
|
||||||
@ -1,46 +0,0 @@
|
|||||||
// chart
|
|
||||||
import Bar from '@/components/chart/Bar'
|
|
||||||
import ChartCard from '@/components/chart/ChartCard'
|
|
||||||
import Liquid from '@/components/chart/Liquid'
|
|
||||||
import MiniArea from '@/components/chart/MiniArea'
|
|
||||||
import MiniBar from '@/components/chart/MiniBar'
|
|
||||||
import MiniProgress from '@/components/chart/MiniProgress'
|
|
||||||
import Radar from '@/components/chart/Radar'
|
|
||||||
import RankList from '@/components/chart/RankList'
|
|
||||||
import TransferBar from '@/components/chart/TransferBar'
|
|
||||||
|
|
||||||
// pro components
|
|
||||||
import AvatarList from '@/components/AvatarList'
|
|
||||||
import CountDown from '@/components/CountDown'
|
|
||||||
import Ellipsis from '@/components/Ellipsis'
|
|
||||||
import FooterToolbar from '@/components/FooterToolbar'
|
|
||||||
import NumberInfo from '@/components/NumberInfo'
|
|
||||||
import DetailList from '@/components/tools/DetailList'
|
|
||||||
import Tree from '@/components/Tree/Tree'
|
|
||||||
import Trend from '@/components/Trend'
|
|
||||||
import STable from '@/components/table'
|
|
||||||
import MultiTab from '@/components/MultiTab'
|
|
||||||
import Result from '@/components/Result'
|
|
||||||
|
|
||||||
export {
|
|
||||||
AvatarList,
|
|
||||||
Bar,
|
|
||||||
ChartCard,
|
|
||||||
Liquid,
|
|
||||||
MiniArea,
|
|
||||||
MiniBar,
|
|
||||||
MiniProgress,
|
|
||||||
Radar,
|
|
||||||
RankList,
|
|
||||||
TransferBar,
|
|
||||||
Trend,
|
|
||||||
CountDown,
|
|
||||||
Ellipsis,
|
|
||||||
FooterToolbar,
|
|
||||||
NumberInfo,
|
|
||||||
DetailList,
|
|
||||||
Tree,
|
|
||||||
STable,
|
|
||||||
MultiTab,
|
|
||||||
Result
|
|
||||||
}
|
|
||||||
@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import ALayoutSider from 'ant-design-vue/es/layout/Sider'
|
import ALayoutSider from 'ant-design-vue/es/layout/Sider'
|
||||||
import Logo from '../tools/Logo'
|
import Logo from '../header/Logo'
|
||||||
import SMenu from './index'
|
import SMenu from './index'
|
||||||
import { mixin, mixinDevice } from '@/utils/mixin.js'
|
import { mixin, mixinDevice } from '@/utils/mixin.js'
|
||||||
|
|
||||||
|
|||||||
@ -40,9 +40,9 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import Breadcrumb from '@/components/widgets/Breadcrumb'
|
import Breadcrumb from '@/components/widgets/Breadcrumb'
|
||||||
import Logo from '../tools/Logo'
|
import Logo from '../header/Logo'
|
||||||
import SMenu from '../menu/'
|
import SMenu from '../menu/'
|
||||||
import UserMenu from '../tools/UserMenu'
|
import UserMenu from '../header/UserMenu'
|
||||||
|
|
||||||
import { mixin } from '@/utils/mixin.js'
|
import { mixin } from '@/utils/mixin.js'
|
||||||
|
|
||||||
|
|||||||
@ -1,256 +0,0 @@
|
|||||||
import T from 'ant-design-vue/es/table/Table'
|
|
||||||
import get from 'lodash.get'
|
|
||||||
|
|
||||||
export default {
|
|
||||||
data () {
|
|
||||||
return {
|
|
||||||
needTotalList: [],
|
|
||||||
|
|
||||||
selectedRows: [],
|
|
||||||
selectedRowKeys: [],
|
|
||||||
|
|
||||||
localLoading: false,
|
|
||||||
localDataSource: [],
|
|
||||||
localPagination: Object.assign({}, T.props.pagination)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
props: Object.assign({}, T.props, {
|
|
||||||
rowKey: {
|
|
||||||
type: [String, Function],
|
|
||||||
default: 'id'
|
|
||||||
},
|
|
||||||
data: {
|
|
||||||
type: Function,
|
|
||||||
required: true
|
|
||||||
},
|
|
||||||
pageNum: {
|
|
||||||
type: Number,
|
|
||||||
default: 1
|
|
||||||
},
|
|
||||||
pageSize: {
|
|
||||||
type: Number,
|
|
||||||
default: 10
|
|
||||||
},
|
|
||||||
showSizeChanger: {
|
|
||||||
type: Boolean,
|
|
||||||
default: true
|
|
||||||
},
|
|
||||||
size: {
|
|
||||||
type: String,
|
|
||||||
default: 'default'
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* {
|
|
||||||
* show: true,
|
|
||||||
* clear: Function
|
|
||||||
* }
|
|
||||||
*/
|
|
||||||
alert: {
|
|
||||||
type: [Object, Boolean],
|
|
||||||
default: null
|
|
||||||
},
|
|
||||||
rowSelection: {
|
|
||||||
type: Object,
|
|
||||||
default: null
|
|
||||||
},
|
|
||||||
/** @Deprecated */
|
|
||||||
showAlertInfo: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false
|
|
||||||
},
|
|
||||||
showPagination: {
|
|
||||||
type: String,
|
|
||||||
default: 'auto'
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
watch: {
|
|
||||||
'localPagination.current' (val) {
|
|
||||||
this.$router.push({
|
|
||||||
name: this.$route.name,
|
|
||||||
params: Object.assign({}, this.$route.params, {
|
|
||||||
pageNo: val
|
|
||||||
})
|
|
||||||
})
|
|
||||||
},
|
|
||||||
pageNum (val) {
|
|
||||||
Object.assign(this.localPagination, {
|
|
||||||
current: val
|
|
||||||
})
|
|
||||||
},
|
|
||||||
pageSize (val) {
|
|
||||||
Object.assign(this.localPagination, {
|
|
||||||
pageSize: val
|
|
||||||
})
|
|
||||||
},
|
|
||||||
showSizeChanger (val) {
|
|
||||||
Object.assign(this.localPagination, {
|
|
||||||
showSizeChanger: val
|
|
||||||
})
|
|
||||||
}
|
|
||||||
},
|
|
||||||
created () {
|
|
||||||
this.localPagination = ['auto', true].includes(this.showPagination) && Object.assign({}, this.localPagination, {
|
|
||||||
current: this.pageNum,
|
|
||||||
pageSize: this.pageSize,
|
|
||||||
showSizeChanger: this.showSizeChanger
|
|
||||||
})
|
|
||||||
this.needTotalList = this.initTotalList(this.columns)
|
|
||||||
this.loadData()
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
refresh (bool = false) {
|
|
||||||
bool && (this.localPagination = Object.assign({}, {
|
|
||||||
current: 1, pageSize: this.pageSize
|
|
||||||
}))
|
|
||||||
this.loadData()
|
|
||||||
},
|
|
||||||
loadData (pagination, filters, sorter) {
|
|
||||||
this.localLoading = true
|
|
||||||
const parameter = Object.assign({
|
|
||||||
pageNo: (pagination && pagination.current) ||
|
|
||||||
this.localPagination.current,
|
|
||||||
pageSize: (pagination && pagination.pageSize) ||
|
|
||||||
this.localPagination.pageSize
|
|
||||||
},
|
|
||||||
(sorter && sorter.field && {
|
|
||||||
sortField: sorter.field
|
|
||||||
}) || {},
|
|
||||||
(sorter && sorter.order && {
|
|
||||||
sortOrder: sorter.order
|
|
||||||
}) || {}, {
|
|
||||||
...filters
|
|
||||||
}
|
|
||||||
)
|
|
||||||
const result = this.data(parameter)
|
|
||||||
// eslint-disable-next-line
|
|
||||||
if (result instanceof Promise || '[object Promise]' === result.toString()) {
|
|
||||||
result.then(r => {
|
|
||||||
this.localPagination = Object.assign({}, this.localPagination, {
|
|
||||||
current: r.pageNo, // 返回结果中的当前分页数
|
|
||||||
total: r.totalCount, // 返回结果中的总记录数
|
|
||||||
showSizeChanger: this.showSizeChanger,
|
|
||||||
pageSize: (pagination && pagination.pageSize) ||
|
|
||||||
this.localPagination.pageSize
|
|
||||||
})
|
|
||||||
if (r.data.length === 0 && this.localPagination.current !== 1) {
|
|
||||||
this.localPagination.current--
|
|
||||||
this.loadData()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
!r.totalCount && ['auto', false].includes(this.showPagination) && (this.localPagination = false)
|
|
||||||
this.localDataSource = r.data
|
|
||||||
this.localLoading = false
|
|
||||||
})
|
|
||||||
}
|
|
||||||
},
|
|
||||||
initTotalList (columns) {
|
|
||||||
const totalList = []
|
|
||||||
columns && columns instanceof Array && columns.forEach(column => {
|
|
||||||
if (column.needTotal) {
|
|
||||||
totalList.push({
|
|
||||||
...column,
|
|
||||||
total: 0
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
return totalList
|
|
||||||
},
|
|
||||||
updateSelect (selectedRowKeys, selectedRows) {
|
|
||||||
this.selectedRows = selectedRows
|
|
||||||
this.selectedRowKeys = selectedRowKeys
|
|
||||||
const list = this.needTotalList
|
|
||||||
this.needTotalList = list.map(item => {
|
|
||||||
return {
|
|
||||||
...item,
|
|
||||||
total: selectedRows.reduce((sum, val) => {
|
|
||||||
const total = sum + parseInt(get(val, item.dataIndex))
|
|
||||||
return isNaN(total) ? 0 : total
|
|
||||||
}, 0)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
},
|
|
||||||
clearSelected () {
|
|
||||||
if (this.rowSelection) {
|
|
||||||
this.rowSelection.onChange([], [])
|
|
||||||
this.updateSelect([], [])
|
|
||||||
}
|
|
||||||
},
|
|
||||||
renderClear (callback) {
|
|
||||||
if (this.selectedRowKeys.length <= 0) return null
|
|
||||||
return (
|
|
||||||
<a style="margin-left: 24px" onClick={() => {
|
|
||||||
callback()
|
|
||||||
this.clearSelected()
|
|
||||||
}}>清空</a>
|
|
||||||
)
|
|
||||||
},
|
|
||||||
renderAlert () {
|
|
||||||
const needTotalItems = this.needTotalList.map((item) => {
|
|
||||||
return (<span style="margin-right: 12px">
|
|
||||||
{item.title}总计 <a style="font-weight: 600">{!item.customRender ? item.total : item.customRender(item.total)}</a>
|
|
||||||
</span>)
|
|
||||||
})
|
|
||||||
|
|
||||||
const clearItem = (typeof this.alert.clear === 'boolean' && this.alert.clear) ? (
|
|
||||||
this.renderClear(this.clearSelected)
|
|
||||||
) : (this.alert !== null && typeof this.alert.clear === 'function') ? (
|
|
||||||
this.renderClear(this.alert.clear)
|
|
||||||
) : null
|
|
||||||
|
|
||||||
return (
|
|
||||||
<a-alert showIcon={true} style="margin-bottom: 16px">
|
|
||||||
<template slot="message">
|
|
||||||
<span style="margin-right: 12px">已选择: <a style="font-weight: 600">{this.selectedRows.length}</a></span>
|
|
||||||
{needTotalItems}
|
|
||||||
{clearItem}
|
|
||||||
</template>
|
|
||||||
</a-alert>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
render () {
|
|
||||||
const props = {}
|
|
||||||
const localKeys = Object.keys(this.$data)
|
|
||||||
const showAlert = (typeof this.alert === 'object' && this.alert !== null && this.alert.show) && typeof this.rowSelection.selectedRowKeys !== 'undefined' || this.alert
|
|
||||||
|
|
||||||
Object.keys(T.props).forEach(k => {
|
|
||||||
const localKey = `local${k.substring(0, 1).toUpperCase()}${k.substring(1)}`
|
|
||||||
if (localKeys.includes(localKey)) {
|
|
||||||
props[k] = this[localKey]
|
|
||||||
return props[k]
|
|
||||||
}
|
|
||||||
if (k === 'rowSelection') {
|
|
||||||
if (showAlert && this.rowSelection) {
|
|
||||||
props[k] = {
|
|
||||||
selectedRows: this.selectedRows,
|
|
||||||
selectedRowKeys: this.selectedRowKeys,
|
|
||||||
onChange: (selectedRowKeys, selectedRows) => {
|
|
||||||
this.updateSelect(selectedRowKeys, selectedRows)
|
|
||||||
typeof this[k].onChange !== 'undefined' && this[k].onChange(selectedRowKeys, selectedRows)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return props[k]
|
|
||||||
} else if (!this.rowSelection) {
|
|
||||||
props[k] = null
|
|
||||||
return props[k]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
props[k] = this[k]
|
|
||||||
return props[k]
|
|
||||||
})
|
|
||||||
const table = (
|
|
||||||
<a-table {...{ props, scopedSlots: { ...this.$scopedSlots } }} onChange={this.loadData}>
|
|
||||||
{ Object.keys(this.$slots).map(name => (<template slot={name}>{this.$slots[name]}</template>)) }
|
|
||||||
</a-table>
|
|
||||||
)
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div class="table-wrapper">
|
|
||||||
{ showAlert ? this.renderAlert() : null }
|
|
||||||
{ table }
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,153 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div :class="['detail-list', size, layout === 'vertical' ? 'vertical': 'horizontal']">
|
|
||||||
<div v-if="title" class="title">{{ title }}</div>
|
|
||||||
<a-row>
|
|
||||||
<slot></slot>
|
|
||||||
</a-row>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import { Col } from 'ant-design-vue/es/grid/'
|
|
||||||
|
|
||||||
const Item = {
|
|
||||||
name: 'DetailListItem',
|
|
||||||
props: {
|
|
||||||
term: {
|
|
||||||
type: String,
|
|
||||||
default: '',
|
|
||||||
required: false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
inject: {
|
|
||||||
col: {
|
|
||||||
type: Number
|
|
||||||
}
|
|
||||||
},
|
|
||||||
render () {
|
|
||||||
return (
|
|
||||||
<Col {...{ props: responsive[this.col] }}>
|
|
||||||
<div class="term">{this.$props.term}</div>
|
|
||||||
<div class="content">{this.$slots.default}</div>
|
|
||||||
</Col>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const responsive = {
|
|
||||||
1: { xs: 24 },
|
|
||||||
2: { xs: 24, sm: 12 },
|
|
||||||
3: { xs: 24, sm: 12, md: 8 },
|
|
||||||
4: { xs: 24, sm: 12, md: 6 }
|
|
||||||
}
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: 'DetailList',
|
|
||||||
Item: Item,
|
|
||||||
components: {
|
|
||||||
Col
|
|
||||||
},
|
|
||||||
props: {
|
|
||||||
title: {
|
|
||||||
type: String,
|
|
||||||
default: '',
|
|
||||||
required: false
|
|
||||||
},
|
|
||||||
col: {
|
|
||||||
type: Number,
|
|
||||||
required: false,
|
|
||||||
default: 3
|
|
||||||
},
|
|
||||||
size: {
|
|
||||||
type: String,
|
|
||||||
required: false,
|
|
||||||
default: 'large'
|
|
||||||
},
|
|
||||||
layout: {
|
|
||||||
type: String,
|
|
||||||
required: false,
|
|
||||||
default: 'horizontal'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
provide () {
|
|
||||||
return {
|
|
||||||
col: this.col > 4 ? 4 : this.col
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="less" scoped>
|
|
||||||
|
|
||||||
.detail-list {
|
|
||||||
|
|
||||||
.title {
|
|
||||||
color: rgba(0,0,0,.85);
|
|
||||||
font-size: 14px;
|
|
||||||
font-weight: 500;
|
|
||||||
margin-bottom: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/deep/ .term {
|
|
||||||
color: rgba(0,0,0,.85);
|
|
||||||
display: table-cell;
|
|
||||||
line-height: 20px;
|
|
||||||
margin-right: 8px;
|
|
||||||
padding-bottom: 16px;
|
|
||||||
white-space: nowrap;
|
|
||||||
|
|
||||||
&:not(:empty):after {
|
|
||||||
content: ":";
|
|
||||||
margin: 0 8px 0 2px;
|
|
||||||
position: relative;
|
|
||||||
top: -.5px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/deep/ .content {
|
|
||||||
color: rgba(0,0,0,.65);
|
|
||||||
display: table-cell;
|
|
||||||
min-height: 22px;
|
|
||||||
line-height: 22px;
|
|
||||||
padding-bottom: 16px;
|
|
||||||
width: 100%;
|
|
||||||
&:empty {
|
|
||||||
content: ' ';
|
|
||||||
height: 38px;
|
|
||||||
padding-bottom: 16px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.small {
|
|
||||||
|
|
||||||
.title {
|
|
||||||
font-size: 14px;
|
|
||||||
color: rgba(0, 0, 0, .65);
|
|
||||||
font-weight: normal;
|
|
||||||
margin-bottom: 12px;
|
|
||||||
}
|
|
||||||
/deep/ .term, .content {
|
|
||||||
padding-bottom: 8px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.large {
|
|
||||||
/deep/ .term, .content {
|
|
||||||
padding-bottom: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.title {
|
|
||||||
font-size: 16px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.vertical {
|
|
||||||
.term {
|
|
||||||
padding-bottom: 8px;
|
|
||||||
}
|
|
||||||
/deep/ .term, .content {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@ -1,69 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="head-info" :class="center && 'center'">
|
|
||||||
<span class="head-info-title">{{ title }}</span>
|
|
||||||
<p class="head-info-content">{{ content }}</p>
|
|
||||||
<em class="head-info-border" v-if="bordered"/>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
export default {
|
|
||||||
name: 'HeadInfo',
|
|
||||||
props: {
|
|
||||||
title: {
|
|
||||||
type: String,
|
|
||||||
default: ''
|
|
||||||
},
|
|
||||||
content: {
|
|
||||||
type: String,
|
|
||||||
default: ''
|
|
||||||
},
|
|
||||||
bordered: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false
|
|
||||||
},
|
|
||||||
center: {
|
|
||||||
type: Boolean,
|
|
||||||
default: true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="less" scoped>
|
|
||||||
.head-info {
|
|
||||||
position: relative;
|
|
||||||
text-align: left;
|
|
||||||
padding: 0 32px 0 0;
|
|
||||||
min-width: 125px;
|
|
||||||
|
|
||||||
&.center {
|
|
||||||
text-align: center;
|
|
||||||
padding: 0 32px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&-title {
|
|
||||||
color: rgba(0, 0, 0, .45);
|
|
||||||
display: inline-block;
|
|
||||||
font-size: 14px;
|
|
||||||
line-height: 22px;
|
|
||||||
margin-bottom: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&-content {
|
|
||||||
color: rgba(0, 0, 0, .85);
|
|
||||||
font-size: 24px;
|
|
||||||
line-height: 32px;
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
&-border {
|
|
||||||
background-color: #e8e8e8;
|
|
||||||
position: absolute;
|
|
||||||
height: 56px;
|
|
||||||
width: 1px;
|
|
||||||
top: 0;
|
|
||||||
right: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@ -1,89 +0,0 @@
|
|||||||
<template>
|
|
||||||
<!-- 两步验证 -->
|
|
||||||
<a-modal
|
|
||||||
centered
|
|
||||||
v-model="visible"
|
|
||||||
@cancel="handleCancel"
|
|
||||||
:maskClosable="false"
|
|
||||||
>
|
|
||||||
<div slot="title" :style="{ textAlign: 'center' }">两步验证</div>
|
|
||||||
<template slot="footer">
|
|
||||||
<div :style="{ textAlign: 'center' }">
|
|
||||||
<a-button key="back" @click="handleCancel">返回</a-button>
|
|
||||||
<a-button key="submit" type="primary" :loading="stepLoading" @click="handleStepOk">
|
|
||||||
继续
|
|
||||||
</a-button>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<a-spin :spinning="stepLoading">
|
|
||||||
<a-form layout="vertical" :auto-form-create="(form)=>{this.form = form}">
|
|
||||||
<div class="step-form-wrapper">
|
|
||||||
<p style="text-align: center" v-if="!stepLoading">请在手机中打开 Google Authenticator 或两步验证 APP<br />输入 6 位动态码</p>
|
|
||||||
<p style="text-align: center" v-else>正在验证..<br/>请稍后</p>
|
|
||||||
<a-form-item
|
|
||||||
:style="{ textAlign: 'center' }"
|
|
||||||
hasFeedback
|
|
||||||
fieldDecoratorId="stepCode"
|
|
||||||
:fieldDecoratorOptions="{rules: [{ required: true, message: '请输入 6 位动态码!', pattern: /^\d{6}$/, len: 6 }]}"
|
|
||||||
>
|
|
||||||
<a-input :style="{ textAlign: 'center' }" @keyup.enter.native="handleStepOk" placeholder="000000" />
|
|
||||||
</a-form-item>
|
|
||||||
<p style="text-align: center">
|
|
||||||
<a @click="onForgeStepCode">遗失手机?</a>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</a-form>
|
|
||||||
</a-spin>
|
|
||||||
</a-modal>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
export default {
|
|
||||||
props: {
|
|
||||||
visible: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
data () {
|
|
||||||
return {
|
|
||||||
stepLoading: false,
|
|
||||||
|
|
||||||
form: null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
handleStepOk () {
|
|
||||||
const vm = this
|
|
||||||
this.stepLoading = true
|
|
||||||
this.form.validateFields((err, values) => {
|
|
||||||
if (!err) {
|
|
||||||
console.log('values', values)
|
|
||||||
setTimeout(() => {
|
|
||||||
vm.stepLoading = false
|
|
||||||
vm.$emit('success', { values })
|
|
||||||
}, 2000)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
this.stepLoading = false
|
|
||||||
this.$emit('error', { err })
|
|
||||||
})
|
|
||||||
},
|
|
||||||
handleCancel () {
|
|
||||||
this.visible = false
|
|
||||||
this.$emit('cancel')
|
|
||||||
},
|
|
||||||
onForgeStepCode () {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
<style lang="less" scoped>
|
|
||||||
.step-form-wrapper {
|
|
||||||
margin: 0 auto;
|
|
||||||
width: 80%;
|
|
||||||
max-width: 400px;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@ -1,94 +0,0 @@
|
|||||||
import { message } from 'ant-design-vue/es'
|
|
||||||
|
|
||||||
let lessNodesAppended
|
|
||||||
|
|
||||||
const colorList = [
|
|
||||||
{
|
|
||||||
key: '薄暮', color: '#F5222D'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: '火山', color: '#FA541C'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: '日暮', color: '#FAAD14'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: '明青', color: '#13C2C2'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: '极光绿', color: '#52C41A'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: '拂晓蓝(默认)', color: '#1890FF'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: '极客蓝', color: '#2F54EB'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: '酱紫', color: '#722ED1'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
const updateTheme = primaryColor => {
|
|
||||||
// Don't compile less in production!
|
|
||||||
/* if (process.env.NODE_ENV === 'production') {
|
|
||||||
return;
|
|
||||||
} */
|
|
||||||
// Determine if the component is remounted
|
|
||||||
if (!primaryColor) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
const hideMessage = message.loading('正在编译主题!', 0)
|
|
||||||
function buildIt () {
|
|
||||||
if (!window.less) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
setTimeout(() => {
|
|
||||||
window.less
|
|
||||||
.modifyVars({
|
|
||||||
'@primary-color': primaryColor
|
|
||||||
})
|
|
||||||
.then(() => {
|
|
||||||
hideMessage()
|
|
||||||
})
|
|
||||||
.catch(() => {
|
|
||||||
message.error('Failed to update theme')
|
|
||||||
hideMessage()
|
|
||||||
})
|
|
||||||
}, 200)
|
|
||||||
}
|
|
||||||
if (!lessNodesAppended) {
|
|
||||||
// insert less.js and color.less
|
|
||||||
const lessStyleNode = document.createElement('link')
|
|
||||||
const lessConfigNode = document.createElement('script')
|
|
||||||
const lessScriptNode = document.createElement('script')
|
|
||||||
lessStyleNode.setAttribute('rel', 'stylesheet/less')
|
|
||||||
lessStyleNode.setAttribute('href', '/color.less')
|
|
||||||
lessConfigNode.innerHTML = `
|
|
||||||
window.less = {
|
|
||||||
async: true,
|
|
||||||
env: 'production',
|
|
||||||
javascriptEnabled: true
|
|
||||||
};
|
|
||||||
`
|
|
||||||
lessScriptNode.src = 'https://gw.alipayobjects.com/os/lib/less.js/3.8.1/less.min.js'
|
|
||||||
lessScriptNode.async = true
|
|
||||||
lessScriptNode.onload = () => {
|
|
||||||
buildIt()
|
|
||||||
lessScriptNode.onload = null
|
|
||||||
}
|
|
||||||
document.body.appendChild(lessStyleNode)
|
|
||||||
document.body.appendChild(lessConfigNode)
|
|
||||||
document.body.appendChild(lessScriptNode)
|
|
||||||
lessNodesAppended = true
|
|
||||||
} else {
|
|
||||||
buildIt()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const updateInvertedMode = invertedMode => {
|
|
||||||
invertedMode = true
|
|
||||||
invertedMode ? document.body.classList.add('layout-inverted-mode') : document.body.classList.remove('layout-inverted-mode')
|
|
||||||
}
|
|
||||||
|
|
||||||
export { updateTheme, colorList, updateInvertedMode }
|
|
||||||
@ -67,7 +67,7 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|
||||||
import ChartCard from '@/components/chart/ChartCard'
|
import ChartCard from '@/components/widgets/ChartCard'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'FormView',
|
name: 'FormView',
|
||||||
|
|||||||
@ -13,14 +13,7 @@
|
|||||||
<slot name="name">
|
<slot name="name">
|
||||||
<h4>
|
<h4>
|
||||||
{{ resource.displayname || resource.name }}
|
{{ resource.displayname || resource.name }}
|
||||||
<a
|
<console :resource="resource" size="default" />
|
||||||
v-if="['vm', 'systemvm', 'router'].includes($route.meta.name)"
|
|
||||||
:href="'/client/console?cmd=access&vm=' + resource.id"
|
|
||||||
target="_blank">
|
|
||||||
<a-button shape="circle" >
|
|
||||||
<a-icon type="code" />
|
|
||||||
</a-button>
|
|
||||||
</a>
|
|
||||||
</h4>
|
</h4>
|
||||||
<a-tag v-if="resource.instancename">
|
<a-tag v-if="resource.instancename">
|
||||||
{{ resource.instancename }}
|
{{ resource.instancename }}
|
||||||
@ -372,12 +365,14 @@
|
|||||||
<script>
|
<script>
|
||||||
|
|
||||||
import { api } from '@/api'
|
import { api } from '@/api'
|
||||||
|
import Console from '@/components/widgets/Console'
|
||||||
import OsLogo from '@/components/widgets/OsLogo'
|
import OsLogo from '@/components/widgets/OsLogo'
|
||||||
import Status from '@/components/widgets/Status'
|
import Status from '@/components/widgets/Status'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'InfoCard',
|
name: 'InfoCard',
|
||||||
components: {
|
components: {
|
||||||
|
Console,
|
||||||
OsLogo,
|
OsLogo,
|
||||||
Status
|
Status
|
||||||
},
|
},
|
||||||
|
|||||||
@ -19,6 +19,7 @@
|
|||||||
<a slot="name" slot-scope="text, record" href="javascript:;">
|
<a slot="name" slot-scope="text, record" href="javascript:;">
|
||||||
<router-link :to="{ path: $route.path + '/' + record.id }" v-if="record.id">{{ text }}</router-link>
|
<router-link :to="{ path: $route.path + '/' + record.id }" v-if="record.id">{{ text }}</router-link>
|
||||||
<router-link :to="{ path: $route.path + '/' + record.name }" v-else>{{ text }}</router-link>
|
<router-link :to="{ path: $route.path + '/' + record.name }" v-else>{{ text }}</router-link>
|
||||||
|
<console :resource="record" size="small" style="float: right" />
|
||||||
</a>
|
</a>
|
||||||
<a slot="displayname" slot-scope="text, record" href="javascript:;">
|
<a slot="displayname" slot-scope="text, record" href="javascript:;">
|
||||||
<router-link :to="{ path: $route.path + '/' + record.id }">{{ text }}</router-link>
|
<router-link :to="{ path: $route.path + '/' + record.id }">{{ text }}</router-link>
|
||||||
@ -56,11 +57,13 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import Console from '@/components/widgets/Console'
|
||||||
import Status from '@/components/widgets/Status'
|
import Status from '@/components/widgets/Status'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'ListView',
|
name: 'ListView',
|
||||||
components: {
|
components: {
|
||||||
|
Console,
|
||||||
Status
|
Status
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
|
|||||||
26
ui/src/components/widgets/Console.vue
Normal file
26
ui/src/components/widgets/Console.vue
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
<template>
|
||||||
|
<a
|
||||||
|
v-if="['vm', 'systemvm', 'router'].includes($route.meta.name) && !['Stopped', 'Error', 'Destroyed'].includes(resource.state)"
|
||||||
|
:href="'/client/console?cmd=access&vm=' + resource.id"
|
||||||
|
target="_blank">
|
||||||
|
<a-button shape="circle" type="dashed" :size="size" >
|
||||||
|
<a-icon type="code" />
|
||||||
|
</a-button>
|
||||||
|
</a>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'Console',
|
||||||
|
props: {
|
||||||
|
resource: {
|
||||||
|
type: Object,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
size: {
|
||||||
|
type: String,
|
||||||
|
default: 'small'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import RouteView from '@/layouts/RouteView'
|
import RouteView from '@/layouts/RouteView'
|
||||||
import MultiTab from '@/components/MultiTab'
|
import MultiTab from '@/components/multitab'
|
||||||
import GlobalLayout from '@/components/page/GlobalLayout'
|
import GlobalLayout from '@/components/page/GlobalLayout'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
|||||||
@ -200,8 +200,8 @@ import { mixinDevice } from '@/utils/mixin.js'
|
|||||||
import store from '@/store'
|
import store from '@/store'
|
||||||
|
|
||||||
import Breadcrumb from '@/components/widgets/Breadcrumb'
|
import Breadcrumb from '@/components/widgets/Breadcrumb'
|
||||||
|
import ChartCard from '@/components/widgets/ChartCard'
|
||||||
import Status from '@/components/widgets/Status'
|
import Status from '@/components/widgets/Status'
|
||||||
import ChartCard from '@/components/chart/ChartCard'
|
|
||||||
import ListView from '@/components/view/ListView'
|
import ListView from '@/components/view/ListView'
|
||||||
import ResourceView from '@/components/view/ResourceView'
|
import ResourceView from '@/components/view/ResourceView'
|
||||||
|
|
||||||
|
|||||||
@ -105,13 +105,11 @@
|
|||||||
<script>
|
<script>
|
||||||
import { api } from '@/api'
|
import { api } from '@/api'
|
||||||
|
|
||||||
import ChartCard from '@/components/chart/ChartCard'
|
import ChartCard from '@/components/widgets/ChartCard'
|
||||||
import ACol from 'ant-design-vue/es/grid/Col'
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'CapacityDashboard',
|
name: 'CapacityDashboard',
|
||||||
components: {
|
components: {
|
||||||
ACol,
|
|
||||||
ChartCard
|
ChartCard
|
||||||
},
|
},
|
||||||
data () {
|
data () {
|
||||||
|
|||||||
@ -48,13 +48,11 @@
|
|||||||
<script>
|
<script>
|
||||||
import { api } from '@/api'
|
import { api } from '@/api'
|
||||||
|
|
||||||
import ChartCard from '@/components/chart/ChartCard'
|
import ChartCard from '@/components/widgets/ChartCard'
|
||||||
import ACol from 'ant-design-vue/es/grid/Col'
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'UsageDashboard',
|
name: 'UsageDashboard',
|
||||||
components: {
|
components: {
|
||||||
ACol,
|
|
||||||
ChartCard
|
ChartCard
|
||||||
},
|
},
|
||||||
data () {
|
data () {
|
||||||
|
|||||||
@ -46,7 +46,7 @@
|
|||||||
import { api } from '@/api'
|
import { api } from '@/api'
|
||||||
import router from '@/router'
|
import router from '@/router'
|
||||||
|
|
||||||
import ChartCard from '@/components/chart/ChartCard'
|
import ChartCard from '@/components/widgets/ChartCard'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'InfraSummary',
|
name: 'InfraSummary',
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user