mirror of
https://github.com/Tencent/tdesign-vue-next-starter.git
synced 2024-09-20 02:34:24 +08:00
refactor(card): replace all card with t-card
This commit is contained in:
parent
991f0588e2
commit
915a6bd118
|
@ -1,183 +0,0 @@
|
||||||
<template>
|
|
||||||
<div :class="cardClass">
|
|
||||||
<div class="list-card-item_detail">
|
|
||||||
<t-row justify="space-between">
|
|
||||||
<div :class="cardLogoClass">
|
|
||||||
<shop-icon v-if="product.type === 1" />
|
|
||||||
<calendar-icon v-if="product.type === 2" />
|
|
||||||
<service-icon v-if="product.type === 3" />
|
|
||||||
<user-avatar-icon v-if="product.type === 4" />
|
|
||||||
<laptop-icon v-if="product.type === 5" />
|
|
||||||
</div>
|
|
||||||
<t-tag :theme="product.isSetup ? 'success' : 'default'" :disabled="!product.isSetup">
|
|
||||||
{{ product.isSetup ? '已启用' : '已停用' }}
|
|
||||||
</t-tag>
|
|
||||||
</t-row>
|
|
||||||
<p class="list-card-item_detail--name">{{ product.name }}</p>
|
|
||||||
<p class="list-card-item_detail--desc">{{ product.description }}</p>
|
|
||||||
<t-row justify="space-between" align="middle" :class="cardControlClass">
|
|
||||||
<div>
|
|
||||||
<t-button shape="circle" :disabled="!product.isSetup">{{ typeMap[product.type - 1] }}</t-button>
|
|
||||||
<t-button shape="circle" :disabled="!product.isSetup">
|
|
||||||
<add-icon />
|
|
||||||
</t-button>
|
|
||||||
</div>
|
|
||||||
<t-dropdown
|
|
||||||
:disabled="!product.isSetup"
|
|
||||||
trigger="click"
|
|
||||||
:options="[
|
|
||||||
{
|
|
||||||
content: '管理',
|
|
||||||
value: 'manage',
|
|
||||||
onClick: () => handleClickManage(product),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
content: '删除',
|
|
||||||
value: 'delete',
|
|
||||||
onClick: () => handleClickDelete(product),
|
|
||||||
},
|
|
||||||
]"
|
|
||||||
>
|
|
||||||
<t-button theme="default" :disabled="!product.isSetup" shape="square" variant="text">
|
|
||||||
<more-icon />
|
|
||||||
</t-button>
|
|
||||||
</t-dropdown>
|
|
||||||
</t-row>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<script setup lang="ts">
|
|
||||||
import { computed, PropType } from 'vue';
|
|
||||||
import {
|
|
||||||
ShopIcon,
|
|
||||||
CalendarIcon,
|
|
||||||
ServiceIcon,
|
|
||||||
UserAvatarIcon,
|
|
||||||
LaptopIcon,
|
|
||||||
MoreIcon,
|
|
||||||
AddIcon,
|
|
||||||
} from 'tdesign-icons-vue-next';
|
|
||||||
|
|
||||||
export interface CardProductType {
|
|
||||||
type: number;
|
|
||||||
isSetup: boolean;
|
|
||||||
description: string;
|
|
||||||
name: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
const props = defineProps({
|
|
||||||
product: {
|
|
||||||
type: Object as PropType<CardProductType>,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const emit = defineEmits(['manage-product', 'delete-item']);
|
|
||||||
|
|
||||||
const cardClass = computed(() => ['list-card-item', { 'list-card-item__disabled': !props.product.isSetup }]);
|
|
||||||
|
|
||||||
const cardLogoClass = computed(() => [
|
|
||||||
'list-card-item_detail--logo',
|
|
||||||
{ 'list-card-item_detail--logo__disabled': !props.product.isSetup },
|
|
||||||
]);
|
|
||||||
|
|
||||||
const cardControlClass = computed(() => [
|
|
||||||
'list-card-item_detail--control',
|
|
||||||
{ 'list-card-item_detail--control__disabled': !props.product.isSetup },
|
|
||||||
]);
|
|
||||||
|
|
||||||
const typeMap = ['A', 'B', 'C', 'D', 'E'];
|
|
||||||
|
|
||||||
const handleClickManage = (product: CardProductType) => {
|
|
||||||
emit('manage-product', product);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleClickDelete = (product: CardProductType) => {
|
|
||||||
emit('delete-item', product);
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="less" scoped>
|
|
||||||
@import '@/style/variables';
|
|
||||||
|
|
||||||
.list-card-item {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
border-radius: @border-radius;
|
|
||||||
overflow: hidden;
|
|
||||||
cursor: pointer;
|
|
||||||
color: @text-color-secondary;
|
|
||||||
|
|
||||||
&_detail {
|
|
||||||
flex: 1;
|
|
||||||
background: @bg-color-container;
|
|
||||||
padding: 24px 32px;
|
|
||||||
min-height: 140px;
|
|
||||||
|
|
||||||
&--logo {
|
|
||||||
width: 56px;
|
|
||||||
height: 56px;
|
|
||||||
border-radius: 50%;
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
background: @brand-color-1;
|
|
||||||
font-size: 32px;
|
|
||||||
color: @brand-color;
|
|
||||||
|
|
||||||
&__disabled {
|
|
||||||
color: @brand-color-3;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&--name {
|
|
||||||
margin: 24px 0 8px 0;
|
|
||||||
font-size: 16px;
|
|
||||||
font-weight: 400;
|
|
||||||
color: @text-color-primary;
|
|
||||||
}
|
|
||||||
|
|
||||||
&--desc {
|
|
||||||
font-size: 12px;
|
|
||||||
line-height: 20px;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
display: -webkit-box;
|
|
||||||
-webkit-line-clamp: 2;
|
|
||||||
-webkit-box-orient: vertical;
|
|
||||||
margin-bottom: 24px;
|
|
||||||
height: 40px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&--control {
|
|
||||||
> div:first-child {
|
|
||||||
position: relative;
|
|
||||||
|
|
||||||
> button:last-child {
|
|
||||||
position: absolute;
|
|
||||||
left: 18px;
|
|
||||||
background-color: @brand-color-2;
|
|
||||||
--ripple-color: @brand-color-2;
|
|
||||||
color: @brand-color;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.t-icon-more {
|
|
||||||
font-size: 24px;
|
|
||||||
color: @text-color-primary;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__disabled {
|
|
||||||
color: @text-color-disabled;
|
|
||||||
|
|
||||||
.list-card-item_detail--name {
|
|
||||||
color: @text-color-disabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
.t-icon-more {
|
|
||||||
color: @text-color-disabled;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
|
@ -1,160 +0,0 @@
|
||||||
<template>
|
|
||||||
<div :class="containerCls">
|
|
||||||
<div v-if="title || $slots.title || $slots.option || subtitle || describe" :class="titleCls">
|
|
||||||
<div :class="titleTextCls">
|
|
||||||
{{ title }}
|
|
||||||
<span v-if="describe" class="card-describe">{{ describe }}</span>
|
|
||||||
<span v-if="subtitle" class="card-subtitle">{{ subtitle }}</span>
|
|
||||||
</div>
|
|
||||||
<span class="card-option">
|
|
||||||
<slot name="option" />
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<div class="card-content">
|
|
||||||
<slot />
|
|
||||||
</div>
|
|
||||||
<div v-if="size !== 'small'" class="card-spacer-bottom" />
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<script setup lang="ts">
|
|
||||||
import { computed } from 'vue';
|
|
||||||
|
|
||||||
const props = defineProps({
|
|
||||||
title: String,
|
|
||||||
subtitle: String,
|
|
||||||
describe: String,
|
|
||||||
compact: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false,
|
|
||||||
},
|
|
||||||
size: {
|
|
||||||
type: String,
|
|
||||||
default: 'default',
|
|
||||||
},
|
|
||||||
border: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const containerCls = computed(() => {
|
|
||||||
const { compact, border } = props;
|
|
||||||
return ['card-container', { 'card-container-compact': compact, 'card-container--border': border }];
|
|
||||||
});
|
|
||||||
|
|
||||||
const titleCls = computed(() => {
|
|
||||||
const { size } = props;
|
|
||||||
return [
|
|
||||||
'card-title',
|
|
||||||
{
|
|
||||||
'card-title--small': size === 'small',
|
|
||||||
'card-title--default': size !== 'small',
|
|
||||||
},
|
|
||||||
];
|
|
||||||
});
|
|
||||||
|
|
||||||
const titleTextCls = computed(() => {
|
|
||||||
const { size } = props;
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
'card-title__text--small': size === 'small',
|
|
||||||
'card-title__text--default': size !== 'small',
|
|
||||||
},
|
|
||||||
];
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
<style lang="less">
|
|
||||||
@import '@/style/variables';
|
|
||||||
|
|
||||||
.t-col-lg-6 + .t-col-lg-6 {
|
|
||||||
@media (max-width: @screen-md-max) {
|
|
||||||
.card-container {
|
|
||||||
margin-top: 16px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.card {
|
|
||||||
&-option {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
&-container {
|
|
||||||
padding: 24px 32px;
|
|
||||||
background: @bg-color-container;
|
|
||||||
border-radius: @border-radius;
|
|
||||||
width: 100%;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
|
|
||||||
&-compact {
|
|
||||||
padding: 16px 16px 0;
|
|
||||||
margin-top: 24px;
|
|
||||||
margin-bottom: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&--border {
|
|
||||||
border: solid 1px @component-border;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&-title {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
font-size: 20px;
|
|
||||||
line-height: 24px;
|
|
||||||
font-family: PingFangSC-Regular;
|
|
||||||
font-weight: 500;
|
|
||||||
color: @text-color-primary;
|
|
||||||
|
|
||||||
&--small {
|
|
||||||
margin-bottom: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&--default {
|
|
||||||
margin-bottom: 24px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__text {
|
|
||||||
display: inline-flex;
|
|
||||||
|
|
||||||
&--default {
|
|
||||||
margin: @spacer 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
&--small {
|
|
||||||
display: inline-block;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&-describe {
|
|
||||||
font-size: 14px;
|
|
||||||
color: @brand-color;
|
|
||||||
color: @text-color-placeholder;
|
|
||||||
line-height: 22px;
|
|
||||||
margin-left: 4px;
|
|
||||||
}
|
|
||||||
&-subtitle {
|
|
||||||
font-size: 14px;
|
|
||||||
color: @brand-color;
|
|
||||||
color: @text-color-secondary;
|
|
||||||
line-height: 22px;
|
|
||||||
margin-left: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&-content {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
flex-direction: column;
|
|
||||||
flex: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
&-spacer-bottom {
|
|
||||||
height: @spacer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
127
src/components/product-card/index.vue
Normal file
127
src/components/product-card/index.vue
Normal file
|
@ -0,0 +1,127 @@
|
||||||
|
<template>
|
||||||
|
<t-card theme="poster2">
|
||||||
|
<template #avatar>
|
||||||
|
<t-avatar size="56px">
|
||||||
|
<template #icon>
|
||||||
|
<shop-icon v-if="product.type === 1" />
|
||||||
|
<calendar-icon v-if="product.type === 2" />
|
||||||
|
<service-icon v-if="product.type === 3" />
|
||||||
|
<user-avatar-icon v-if="product.type === 4" />
|
||||||
|
<laptop-icon v-if="product.type === 5" />
|
||||||
|
</template>
|
||||||
|
</t-avatar>
|
||||||
|
</template>
|
||||||
|
<template #status>
|
||||||
|
<t-tag :theme="product.isSetup ? 'success' : 'default'" :disabled="!product.isSetup">{{
|
||||||
|
product.isSetup ? '已启用' : '已停用'
|
||||||
|
}}</t-tag>
|
||||||
|
</template>
|
||||||
|
<template #content>
|
||||||
|
<p class="list-card-item_detail--name">{{ product.name }}</p>
|
||||||
|
<p class="list-card-item_detail--desc">{{ product.description }}</p>
|
||||||
|
</template>
|
||||||
|
<template #footer>
|
||||||
|
<t-avatar-group cascading="left-up" :max="2">
|
||||||
|
<t-avatar>{{ typeMap[product.type - 1] }}</t-avatar>
|
||||||
|
<t-avatar
|
||||||
|
><template #icon>
|
||||||
|
<add-icon />
|
||||||
|
</template>
|
||||||
|
</t-avatar>
|
||||||
|
</t-avatar-group>
|
||||||
|
</template>
|
||||||
|
<template #actions>
|
||||||
|
<t-dropdown
|
||||||
|
:disabled="!product.isSetup"
|
||||||
|
trigger="click"
|
||||||
|
:options="[
|
||||||
|
{
|
||||||
|
content: '管理',
|
||||||
|
value: 'manage',
|
||||||
|
onClick: () => handleClickManage(product),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
content: '删除',
|
||||||
|
value: 'delete',
|
||||||
|
onClick: () => handleClickDelete(product),
|
||||||
|
},
|
||||||
|
]"
|
||||||
|
>
|
||||||
|
<t-button theme="default" :disabled="!product.isSetup" shape="square" variant="text">
|
||||||
|
<more-icon />
|
||||||
|
</t-button>
|
||||||
|
</t-dropdown>
|
||||||
|
</template>
|
||||||
|
</t-card>
|
||||||
|
</template>
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { PropType } from 'vue';
|
||||||
|
import {
|
||||||
|
ShopIcon,
|
||||||
|
CalendarIcon,
|
||||||
|
ServiceIcon,
|
||||||
|
UserAvatarIcon,
|
||||||
|
LaptopIcon,
|
||||||
|
MoreIcon,
|
||||||
|
AddIcon,
|
||||||
|
} from 'tdesign-icons-vue-next';
|
||||||
|
|
||||||
|
export interface CardProductType {
|
||||||
|
type: number;
|
||||||
|
isSetup: boolean;
|
||||||
|
description: string;
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line
|
||||||
|
const props = defineProps({
|
||||||
|
product: {
|
||||||
|
type: Object as PropType<CardProductType>,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const emit = defineEmits(['manage-product', 'delete-item']);
|
||||||
|
|
||||||
|
const typeMap = ['A', 'B', 'C', 'D', 'E'];
|
||||||
|
|
||||||
|
const handleClickManage = (product: CardProductType) => {
|
||||||
|
emit('manage-product', product);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleClickDelete = (product: CardProductType) => {
|
||||||
|
emit('delete-item', product);
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
@import '@/style/variables';
|
||||||
|
|
||||||
|
.list-card-item {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&_detail {
|
||||||
|
min-height: 140px;
|
||||||
|
|
||||||
|
&--name {
|
||||||
|
margin-bottom: 8px;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 400;
|
||||||
|
color: @text-color-primary;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--desc {
|
||||||
|
color: @text-color-secondary;
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 20px;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
display: -webkit-box;
|
||||||
|
-webkit-line-clamp: 2;
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
height: 40px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -3,7 +3,7 @@
|
||||||
<t-head-menu :class="menuCls" :theme="theme" expand-type="popup" :value="active">
|
<t-head-menu :class="menuCls" :theme="theme" expand-type="popup" :value="active">
|
||||||
<template #logo>
|
<template #logo>
|
||||||
<span v-if="showLogo" class="header-logo-container" @click="handleNav('/dashboard/base')">
|
<span v-if="showLogo" class="header-logo-container" @click="handleNav('/dashboard/base')">
|
||||||
<tLogoFull class="t-logo" />
|
<LogoFull class="t-logo" />
|
||||||
</span>
|
</span>
|
||||||
<div v-else class="header-operate-left">
|
<div v-else class="header-operate-left">
|
||||||
<t-button theme="default" shape="square" variant="text" @click="changeCollapsed">
|
<t-button theme="default" shape="square" variant="text" @click="changeCollapsed">
|
||||||
|
@ -69,7 +69,7 @@ import { useRouter } from 'vue-router';
|
||||||
import { useSettingStore } from '@/store';
|
import { useSettingStore } from '@/store';
|
||||||
import { getActive } from '@/router';
|
import { getActive } from '@/router';
|
||||||
import { prefix } from '@/config/global';
|
import { prefix } from '@/config/global';
|
||||||
import tLogoFull from '@/assets/assets-logo-full.svg?component';
|
import LogoFull from '@/assets/assets-logo-full.svg?component';
|
||||||
import { MenuRoute } from '@/interface';
|
import { MenuRoute } from '@/interface';
|
||||||
|
|
||||||
import Notice from './Notice.vue';
|
import Notice from './Notice.vue';
|
||||||
|
@ -161,24 +161,6 @@ const navToHelper = () => {
|
||||||
height: 64px;
|
height: 64px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&-menu-fixed {
|
|
||||||
position: fixed;
|
|
||||||
top: 0;
|
|
||||||
z-index: 10;
|
|
||||||
|
|
||||||
&-side {
|
|
||||||
left: 232px;
|
|
||||||
right: 0;
|
|
||||||
z-index: 10;
|
|
||||||
width: auto;
|
|
||||||
transition: all 0.3s;
|
|
||||||
|
|
||||||
&-compact {
|
|
||||||
left: 64px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&-logo-container {
|
&-logo-container {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
|
|
170
src/pages/dashboard/base/components/middle-chart.vue
Normal file
170
src/pages/dashboard/base/components/middle-chart.vue
Normal file
|
@ -0,0 +1,170 @@
|
||||||
|
<template>
|
||||||
|
<t-row :gutter="16" class="row-container">
|
||||||
|
<t-col :xs="12" :xl="9">
|
||||||
|
<t-card title="统计数据" :subtitle="`(万元)${currentMonth}`" class="dashboard-chart-card">
|
||||||
|
<template #option>
|
||||||
|
<div class="dashboard-chart-title-container">
|
||||||
|
<t-date-picker
|
||||||
|
class="card-date-picker-container"
|
||||||
|
theme="primary"
|
||||||
|
mode="date"
|
||||||
|
range
|
||||||
|
:default-value="LAST_7_DAYS"
|
||||||
|
@change="onCurrencyChange"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<div
|
||||||
|
id="monitorContainer"
|
||||||
|
ref="monitorContainer"
|
||||||
|
class="dashboard-chart-container"
|
||||||
|
:style="{ width: '100%', height: `${resizeTime * 326}px` }"
|
||||||
|
/>
|
||||||
|
</t-card>
|
||||||
|
</t-col>
|
||||||
|
<t-col :xs="12" :xl="3">
|
||||||
|
<t-card title="销售渠道" :subtitle="currentMonth" class="dashboard-chart-card">
|
||||||
|
<div
|
||||||
|
id="countContainer"
|
||||||
|
ref="countContainer"
|
||||||
|
:style="{ width: `${resizeTime * 326}px`, height: `${resizeTime * 326}px`, margin: '0 auto' }"
|
||||||
|
class="dashboard-chart-container"
|
||||||
|
/>
|
||||||
|
</t-card>
|
||||||
|
</t-col>
|
||||||
|
</t-row>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { onMounted, watch, ref, onUnmounted, nextTick, computed } from 'vue';
|
||||||
|
|
||||||
|
import * as echarts from 'echarts/core';
|
||||||
|
import { TooltipComponent, LegendComponent, GridComponent } from 'echarts/components';
|
||||||
|
import { PieChart, LineChart } from 'echarts/charts';
|
||||||
|
import { CanvasRenderer } from 'echarts/renderers';
|
||||||
|
import { useSettingStore } from '@/store';
|
||||||
|
import { LAST_7_DAYS } from '@/utils/date';
|
||||||
|
import { changeChartsTheme } from '@/utils/color';
|
||||||
|
|
||||||
|
import { getPieChartDataSet, getLineChartDataSet } from '../index';
|
||||||
|
|
||||||
|
echarts.use([TooltipComponent, LegendComponent, PieChart, GridComponent, LineChart, CanvasRenderer]);
|
||||||
|
|
||||||
|
const getThisMonth = (checkedValues?: string[]) => {
|
||||||
|
let date: Date;
|
||||||
|
if (!checkedValues || checkedValues.length === 0) {
|
||||||
|
date = new Date();
|
||||||
|
return `${date.getFullYear()}-${date.getMonth() + 1}`;
|
||||||
|
}
|
||||||
|
date = new Date(checkedValues[0]);
|
||||||
|
const date2 = new Date(checkedValues[1]);
|
||||||
|
|
||||||
|
const startMonth = date.getMonth() + 1 > 9 ? date.getMonth() + 1 : `0${date.getMonth() + 1}`;
|
||||||
|
const endMonth = date2.getMonth() + 1 > 9 ? date2.getMonth() + 1 : `0${date2.getMonth() + 1}`;
|
||||||
|
return `${date.getFullYear()}-${startMonth} 至 ${date2.getFullYear()}-${endMonth}`;
|
||||||
|
};
|
||||||
|
|
||||||
|
const store = useSettingStore();
|
||||||
|
const resizeTime = ref(1);
|
||||||
|
|
||||||
|
const chartColors = computed(() => store.chartColors);
|
||||||
|
|
||||||
|
// monitorChart
|
||||||
|
let monitorContainer: HTMLElement;
|
||||||
|
let monitorChart: echarts.ECharts;
|
||||||
|
const renderMonitorChart = () => {
|
||||||
|
if (!monitorContainer) {
|
||||||
|
monitorContainer = document.getElementById('monitorContainer');
|
||||||
|
}
|
||||||
|
monitorChart = echarts.init(monitorContainer);
|
||||||
|
monitorChart.setOption(getLineChartDataSet({ ...chartColors.value }));
|
||||||
|
};
|
||||||
|
|
||||||
|
// monitorChart
|
||||||
|
let countContainer: HTMLElement;
|
||||||
|
let countChart: echarts.ECharts;
|
||||||
|
const renderCountChart = () => {
|
||||||
|
if (!countContainer) {
|
||||||
|
countContainer = document.getElementById('countContainer');
|
||||||
|
}
|
||||||
|
countChart = echarts.init(countContainer);
|
||||||
|
countChart.setOption(getPieChartDataSet(chartColors.value));
|
||||||
|
};
|
||||||
|
|
||||||
|
const renderCharts = () => {
|
||||||
|
renderMonitorChart();
|
||||||
|
renderCountChart();
|
||||||
|
};
|
||||||
|
|
||||||
|
// chartSize update
|
||||||
|
const updateContainer = () => {
|
||||||
|
if (document.documentElement.clientWidth >= 1400 && document.documentElement.clientWidth < 1920) {
|
||||||
|
resizeTime.value = Number((document.documentElement.clientWidth / 2080).toFixed(2));
|
||||||
|
} else if (document.documentElement.clientWidth < 1080) {
|
||||||
|
resizeTime.value = Number((document.documentElement.clientWidth / 1080).toFixed(2));
|
||||||
|
} else {
|
||||||
|
resizeTime.value = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
monitorChart.resize({
|
||||||
|
width: monitorContainer.clientWidth,
|
||||||
|
height: resizeTime.value * 326,
|
||||||
|
});
|
||||||
|
countChart.resize({
|
||||||
|
width: resizeTime.value * 326,
|
||||||
|
height: resizeTime.value * 326,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
renderCharts();
|
||||||
|
nextTick(() => {
|
||||||
|
updateContainer();
|
||||||
|
});
|
||||||
|
window.addEventListener('resize', updateContainer, false);
|
||||||
|
});
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
|
window.removeEventListener('resize', updateContainer);
|
||||||
|
});
|
||||||
|
|
||||||
|
const currentMonth = ref(getThisMonth());
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => store.brandTheme,
|
||||||
|
() => {
|
||||||
|
changeChartsTheme([monitorChart, countChart]);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => store.mode,
|
||||||
|
() => {
|
||||||
|
[monitorChart, countChart].forEach((item) => {
|
||||||
|
item.dispose();
|
||||||
|
});
|
||||||
|
|
||||||
|
renderCharts();
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
const onCurrencyChange = (checkedValues: string[]) => {
|
||||||
|
currentMonth.value = getThisMonth(checkedValues);
|
||||||
|
monitorChart.setOption(getLineChartDataSet({ dateTime: checkedValues, ...chartColors.value }));
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.dashboard-chart-card {
|
||||||
|
padding: 8px;
|
||||||
|
|
||||||
|
:deep(.t-card__header) {
|
||||||
|
padding-bottom: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.t-card__title) {
|
||||||
|
font-size: 20px;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
205
src/pages/dashboard/base/components/overview.vue
Normal file
205
src/pages/dashboard/base/components/overview.vue
Normal file
|
@ -0,0 +1,205 @@
|
||||||
|
<template>
|
||||||
|
<t-card>
|
||||||
|
<t-row>
|
||||||
|
<t-col :xs="12" :xl="9">
|
||||||
|
<t-card
|
||||||
|
:bordered="false"
|
||||||
|
title="出入库概览"
|
||||||
|
subtitle="(件)"
|
||||||
|
:class="{ 'dashboard-overview-card': true, 'overview-panel': true }"
|
||||||
|
>
|
||||||
|
<template #actions>
|
||||||
|
<t-date-picker
|
||||||
|
class="card-date-picker-container"
|
||||||
|
theme="primary"
|
||||||
|
mode="date"
|
||||||
|
range
|
||||||
|
:default-value="LAST_7_DAYS"
|
||||||
|
@change="onStokeDataChange"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
<div
|
||||||
|
id="stokeContainer"
|
||||||
|
ref="stokeContainer"
|
||||||
|
style="width: 100%; height: 351px"
|
||||||
|
class="dashboard-chart-container"
|
||||||
|
></div>
|
||||||
|
</t-card>
|
||||||
|
</t-col>
|
||||||
|
<t-col :xs="12" :xl="3">
|
||||||
|
<t-card :bordered="false" :class="{ 'dashboard-overview-card': true, 'export-panel': true }">
|
||||||
|
<template #actions>
|
||||||
|
<t-button>导出数据</t-button>
|
||||||
|
</template>
|
||||||
|
<t-row>
|
||||||
|
<t-col :xs="6" :xl="12">
|
||||||
|
<t-card :bordered="false" subtitle="本月出库总计(件)" class="inner-card">
|
||||||
|
<div class="inner-card__content">
|
||||||
|
<div class="inner-card__content-title">1726</div>
|
||||||
|
<div class="inner-card__content-footer">
|
||||||
|
自从上周以来
|
||||||
|
<trend class="trend-tag" type="down" :is-reverse-color="false" describe="20.3%" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</t-card>
|
||||||
|
</t-col>
|
||||||
|
<t-col :xs="6" :xl="12">
|
||||||
|
<t-card :bordered="false" subtitle="本月入库总计(件)" class="inner-card">
|
||||||
|
<div class="inner-card__content">
|
||||||
|
<div class="inner-card__content-title">226</div>
|
||||||
|
<div class="inner-card__content-footer">
|
||||||
|
自从上周以来
|
||||||
|
<trend class="trend-tag" type="down" :is-reverse-color="false" describe="20.3%" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</t-card>
|
||||||
|
</t-col>
|
||||||
|
</t-row>
|
||||||
|
</t-card>
|
||||||
|
</t-col>
|
||||||
|
</t-row>
|
||||||
|
</t-card>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
export default {
|
||||||
|
name: 'DashboardBase',
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { onMounted, watch, ref, onUnmounted, nextTick, computed } from 'vue';
|
||||||
|
|
||||||
|
import * as echarts from 'echarts/core';
|
||||||
|
import { TooltipComponent, LegendComponent, GridComponent } from 'echarts/components';
|
||||||
|
import { LineChart } from 'echarts/charts';
|
||||||
|
import { CanvasRenderer } from 'echarts/renderers';
|
||||||
|
import { useSettingStore } from '@/store';
|
||||||
|
import { LAST_7_DAYS } from '@/utils/date';
|
||||||
|
import { changeChartsTheme } from '@/utils/color';
|
||||||
|
|
||||||
|
// 导入样式
|
||||||
|
import Trend from '@/components/trend/index.vue';
|
||||||
|
import { constructInitDataset } from '../index';
|
||||||
|
|
||||||
|
echarts.use([TooltipComponent, LegendComponent, GridComponent, LineChart, CanvasRenderer]);
|
||||||
|
|
||||||
|
const store = useSettingStore();
|
||||||
|
const resizeTime = ref(1);
|
||||||
|
|
||||||
|
const chartColors = computed(() => store.chartColors);
|
||||||
|
|
||||||
|
// stokeCharts
|
||||||
|
let stokeContainer: HTMLElement;
|
||||||
|
let stokeChart: echarts.ECharts;
|
||||||
|
const renderStokeChart = () => {
|
||||||
|
if (!stokeContainer) {
|
||||||
|
stokeContainer = document.getElementById('stokeContainer');
|
||||||
|
}
|
||||||
|
stokeChart = echarts.init(stokeContainer);
|
||||||
|
stokeChart.setOption(constructInitDataset({ dateTime: LAST_7_DAYS, ...chartColors.value }));
|
||||||
|
};
|
||||||
|
|
||||||
|
const renderCharts = () => {
|
||||||
|
renderStokeChart();
|
||||||
|
};
|
||||||
|
|
||||||
|
// chartSize update
|
||||||
|
const updateContainer = () => {
|
||||||
|
if (document.documentElement.clientWidth >= 1400 && document.documentElement.clientWidth < 1920) {
|
||||||
|
resizeTime.value = Number((document.documentElement.clientWidth / 2080).toFixed(2));
|
||||||
|
} else if (document.documentElement.clientWidth < 1080) {
|
||||||
|
resizeTime.value = Number((document.documentElement.clientWidth / 1080).toFixed(2));
|
||||||
|
} else {
|
||||||
|
resizeTime.value = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
stokeChart.resize({
|
||||||
|
width: stokeContainer.clientWidth,
|
||||||
|
height: stokeContainer.clientHeight,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
renderCharts();
|
||||||
|
nextTick(() => {
|
||||||
|
updateContainer();
|
||||||
|
});
|
||||||
|
window.addEventListener('resize', updateContainer, false);
|
||||||
|
});
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
|
window.removeEventListener('resize', updateContainer);
|
||||||
|
});
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => store.brandTheme,
|
||||||
|
() => {
|
||||||
|
changeChartsTheme([stokeChart]);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => store.mode,
|
||||||
|
() => {
|
||||||
|
[stokeChart].forEach((item) => {
|
||||||
|
item.dispose();
|
||||||
|
});
|
||||||
|
|
||||||
|
renderCharts();
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
const onStokeDataChange = (checkedValues: string[]) => {
|
||||||
|
stokeChart.setOption(constructInitDataset({ dateTime: checkedValues, ...chartColors.value }));
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
@import '@/style/variables.less';
|
||||||
|
|
||||||
|
.dashboard-overview-card {
|
||||||
|
:deep(.t-card__header) {
|
||||||
|
padding-bottom: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.t-card__title) {
|
||||||
|
font-size: 20px;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.overview-panel {
|
||||||
|
border-right: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.export-panel {
|
||||||
|
border-left: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.inner-card {
|
||||||
|
padding: 24px 0;
|
||||||
|
|
||||||
|
:deep(.t-card__header) {
|
||||||
|
padding-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__content {
|
||||||
|
&-title {
|
||||||
|
font-size: 36px;
|
||||||
|
line-height: 44px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-footer {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
line-height: 22px;
|
||||||
|
color: @text-color-placeholder;
|
||||||
|
|
||||||
|
.trend-tag {
|
||||||
|
margin-left: 4px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
100
src/pages/dashboard/base/components/rank-list.vue
Normal file
100
src/pages/dashboard/base/components/rank-list.vue
Normal file
|
@ -0,0 +1,100 @@
|
||||||
|
<template>
|
||||||
|
<t-row :gutter="16" class="row-container">
|
||||||
|
<t-col :xs="12" :xl="6">
|
||||||
|
<t-card title="销售订单排名" class="dashboard-rank-card">
|
||||||
|
<template #actions>
|
||||||
|
<t-radio-group default-value="dateVal">
|
||||||
|
<t-radio-button value="dateVal">本周</t-radio-button>
|
||||||
|
<t-radio-button value="monthVal">近三个月</t-radio-button>
|
||||||
|
</t-radio-group>
|
||||||
|
</template>
|
||||||
|
<t-table :data="SALE_TEND_LIST" :columns="SALE_COLUMNS" row-key="productName">
|
||||||
|
<template #index="{ rowIndex }">
|
||||||
|
<span :class="getRankClass(rowIndex)">
|
||||||
|
{{ rowIndex + 1 }}
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
<template #growUp="{ row }">
|
||||||
|
<span>
|
||||||
|
<trend :type="row.growUp > 0 ? 'up' : 'down'" :describe="Math.abs(row.growUp)" />
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
<template #operation="slotProps">
|
||||||
|
<a class="t-button-link" @click="rehandleClickOp(slotProps)">详情</a>
|
||||||
|
</template>
|
||||||
|
</t-table>
|
||||||
|
</t-card>
|
||||||
|
</t-col>
|
||||||
|
<t-col :xs="12" :xl="6">
|
||||||
|
<t-card title="销售订单排名" class="dashboard-rank-card">
|
||||||
|
<template #actions>
|
||||||
|
<t-radio-group default-value="dateVal">
|
||||||
|
<t-radio-button value="dateVal">本周</t-radio-button>
|
||||||
|
<t-radio-button value="monthVal">近三个月</t-radio-button>
|
||||||
|
</t-radio-group>
|
||||||
|
</template>
|
||||||
|
<t-table :data="BUY_TEND_LIST" :columns="BUY_COLUMNS" row-key="productName">
|
||||||
|
<template #index="{ rowIndex }">
|
||||||
|
<span :class="getRankClass(rowIndex)">
|
||||||
|
{{ rowIndex + 1 }}
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
<template #growUp="{ row }">
|
||||||
|
<trend :type="row.growUp > 0 ? 'up' : 'down'" :describe="Math.abs(row.growUp)" />
|
||||||
|
</template>
|
||||||
|
<template #operation="slotProps">
|
||||||
|
<a class="t-button-link" @click="rehandleClickOp(slotProps)">详情</a>
|
||||||
|
</template>
|
||||||
|
</t-table>
|
||||||
|
</t-card>
|
||||||
|
</t-col>
|
||||||
|
</t-row>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
// 导入样式
|
||||||
|
import Trend from '@/components/trend/index.vue';
|
||||||
|
|
||||||
|
import { SALE_TEND_LIST, BUY_TEND_LIST, SALE_COLUMNS, BUY_COLUMNS } from '../constants';
|
||||||
|
|
||||||
|
const rehandleClickOp = (val: MouseEvent) => {
|
||||||
|
console.log(val);
|
||||||
|
};
|
||||||
|
const getRankClass = (index: number) => {
|
||||||
|
return ['dashboard-rank', { 'dashboard-rank__top': index < 3 }];
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
@import '@/style/variables.less';
|
||||||
|
|
||||||
|
.dashboard-rank-card {
|
||||||
|
padding: 8px;
|
||||||
|
|
||||||
|
:deep(.t-card__header) {
|
||||||
|
padding-bottom: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.t-card__title) {
|
||||||
|
font-size: 20px;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.dashboard-rank__cell {
|
||||||
|
display: inline-flex;
|
||||||
|
width: 24px;
|
||||||
|
height: 24px;
|
||||||
|
border-radius: 50%;
|
||||||
|
color: white;
|
||||||
|
font-size: 14px;
|
||||||
|
background-color: @gray-color-5;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-weight: 700;
|
||||||
|
|
||||||
|
&--top {
|
||||||
|
background: @brand-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
260
src/pages/dashboard/base/components/top-panel.vue
Normal file
260
src/pages/dashboard/base/components/top-panel.vue
Normal file
|
@ -0,0 +1,260 @@
|
||||||
|
<template>
|
||||||
|
<t-row :gutter="[16, 16]">
|
||||||
|
<t-col v-for="(item, index) in PANE_LIST" :key="item.title" :xs="6" :xl="3">
|
||||||
|
<t-card
|
||||||
|
:title="item.title"
|
||||||
|
:style="{ height: '168px' }"
|
||||||
|
:class="{ 'dashboard-item': true, 'dashboard-item--main-color': index == 0 }"
|
||||||
|
>
|
||||||
|
<div class="dashboard-item-top">
|
||||||
|
<span :style="{ fontSize: `${resizeTime * 36}px` }">{{ item.number }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="dashboard-item-left">
|
||||||
|
<div
|
||||||
|
v-if="index === 0"
|
||||||
|
id="moneyContainer"
|
||||||
|
class="dashboard-chart-container"
|
||||||
|
:style="{ width: `${resizeTime * 120}px`, height: `${resizeTime * 66}px` }"
|
||||||
|
></div>
|
||||||
|
<div
|
||||||
|
v-else-if="index === 1"
|
||||||
|
id="refundContainer"
|
||||||
|
class="dashboard-chart-container"
|
||||||
|
:style="{ width: `${resizeTime * 120}px`, height: `${resizeTime * 42}px` }"
|
||||||
|
></div>
|
||||||
|
<span v-else-if="index === 2" :style="{ marginTop: `-24px` }">
|
||||||
|
<usergroup-icon />
|
||||||
|
</span>
|
||||||
|
<span v-else :style="{ marginTop: '-24px' }">
|
||||||
|
<file-icon />
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<template #footer>
|
||||||
|
<div class="dashboard-item-bottom">
|
||||||
|
<div class="dashboard-item-block">
|
||||||
|
自从上周以来
|
||||||
|
<trend
|
||||||
|
class="dashboard-item-trend"
|
||||||
|
:type="item.upTrend ? 'up' : 'down'"
|
||||||
|
:is-reverse-color="index === 0"
|
||||||
|
:describe="item.upTrend || item.downTrend"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<t-icon name="chevron-right" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</t-card>
|
||||||
|
</t-col>
|
||||||
|
</t-row>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
export default {
|
||||||
|
name: 'DashboardBase',
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { onMounted, watch, ref, onUnmounted, nextTick } from 'vue';
|
||||||
|
|
||||||
|
import * as echarts from 'echarts/core';
|
||||||
|
import { LineChart, BarChart } from 'echarts/charts';
|
||||||
|
import { CanvasRenderer } from 'echarts/renderers';
|
||||||
|
import { UsergroupIcon, FileIcon } from 'tdesign-icons-vue-next';
|
||||||
|
import { useSettingStore } from '@/store';
|
||||||
|
import { changeChartsTheme } from '@/utils/color';
|
||||||
|
|
||||||
|
// 导入样式
|
||||||
|
import Trend from '@/components/trend/index.vue';
|
||||||
|
import { constructInitDashboardDataset } from '../index';
|
||||||
|
|
||||||
|
import { PANE_LIST } from '../constants';
|
||||||
|
|
||||||
|
echarts.use([LineChart, BarChart, CanvasRenderer]);
|
||||||
|
|
||||||
|
const store = useSettingStore();
|
||||||
|
const resizeTime = ref(1);
|
||||||
|
|
||||||
|
// moneyCharts
|
||||||
|
let moneyContainer: HTMLElement;
|
||||||
|
let moneyChart: echarts.ECharts;
|
||||||
|
const renderMoneyChart = () => {
|
||||||
|
if (!moneyContainer) {
|
||||||
|
moneyContainer = document.getElementById('moneyContainer');
|
||||||
|
}
|
||||||
|
moneyChart = echarts.init(moneyContainer);
|
||||||
|
moneyChart.setOption(constructInitDashboardDataset('line'));
|
||||||
|
};
|
||||||
|
|
||||||
|
// refundCharts
|
||||||
|
let refundContainer: HTMLElement;
|
||||||
|
let refundChart: echarts.ECharts;
|
||||||
|
const renderRefundChart = () => {
|
||||||
|
if (!refundContainer) {
|
||||||
|
refundContainer = document.getElementById('refundContainer');
|
||||||
|
}
|
||||||
|
refundChart = echarts.init(refundContainer);
|
||||||
|
refundChart.setOption(constructInitDashboardDataset('bar'));
|
||||||
|
};
|
||||||
|
|
||||||
|
const renderCharts = () => {
|
||||||
|
renderMoneyChart();
|
||||||
|
renderRefundChart();
|
||||||
|
};
|
||||||
|
|
||||||
|
// chartSize update
|
||||||
|
const updateContainer = () => {
|
||||||
|
if (document.documentElement.clientWidth >= 1400 && document.documentElement.clientWidth < 1920) {
|
||||||
|
resizeTime.value = Number((document.documentElement.clientWidth / 2080).toFixed(2));
|
||||||
|
} else if (document.documentElement.clientWidth < 1080) {
|
||||||
|
resizeTime.value = Number((document.documentElement.clientWidth / 1080).toFixed(2));
|
||||||
|
} else {
|
||||||
|
resizeTime.value = 1;
|
||||||
|
}
|
||||||
|
moneyChart.resize({
|
||||||
|
width: resizeTime.value * 120,
|
||||||
|
height: resizeTime.value * 66,
|
||||||
|
});
|
||||||
|
refundChart.resize({
|
||||||
|
width: resizeTime.value * 120,
|
||||||
|
height: resizeTime.value * 42,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
renderCharts();
|
||||||
|
nextTick(() => {
|
||||||
|
updateContainer();
|
||||||
|
});
|
||||||
|
window.addEventListener('resize', updateContainer, false);
|
||||||
|
});
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
|
window.removeEventListener('resize', updateContainer);
|
||||||
|
});
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => store.brandTheme,
|
||||||
|
() => {
|
||||||
|
changeChartsTheme([refundChart]);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => store.mode,
|
||||||
|
() => {
|
||||||
|
[moneyChart, refundChart].forEach((item) => {
|
||||||
|
item.dispose();
|
||||||
|
});
|
||||||
|
|
||||||
|
renderCharts();
|
||||||
|
},
|
||||||
|
);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
@import '@/style/variables.less';
|
||||||
|
|
||||||
|
.dashboard-item {
|
||||||
|
padding: 8px;
|
||||||
|
|
||||||
|
:deep(.t-card__footer) {
|
||||||
|
padding-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.t-card__title) {
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.t-card__body) {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: space-between;
|
||||||
|
flex: 1;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-top {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: flex-start;
|
||||||
|
|
||||||
|
> span {
|
||||||
|
display: inline-block;
|
||||||
|
color: @text-color-primary;
|
||||||
|
font-size: 36px;
|
||||||
|
line-height: 44px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&-bottom {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
> .t-icon {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&-block {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
line-height: 22px;
|
||||||
|
color: @text-color-placeholder;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-trend {
|
||||||
|
margin-left: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-left {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 32px;
|
||||||
|
|
||||||
|
> span {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
width: 56px;
|
||||||
|
height: 56px;
|
||||||
|
background: @brand-color-1;
|
||||||
|
border-radius: 50%;
|
||||||
|
|
||||||
|
.t-icon {
|
||||||
|
font-size: 24px;
|
||||||
|
color: @brand-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 针对第一个卡片需要反色处理
|
||||||
|
&--main-color {
|
||||||
|
background: @brand-color;
|
||||||
|
color: @text-color-primary;
|
||||||
|
|
||||||
|
:deep(.t-card__title),
|
||||||
|
.dashboard-item-top span,
|
||||||
|
.dashboard-item-bottom {
|
||||||
|
color: @text-color-anti;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dashboard-item-block {
|
||||||
|
color: @text-color-anti;
|
||||||
|
opacity: 0.6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dashboard-item-bottom {
|
||||||
|
color: @text-color-anti;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -133,7 +133,7 @@ export const SALE_COLUMNS: TdBaseTableProps['columns'] = [
|
||||||
ellipsis: true,
|
ellipsis: true,
|
||||||
colKey: 'productName',
|
colKey: 'productName',
|
||||||
title: '客户名称',
|
title: '客户名称',
|
||||||
minWidth: 200,
|
width: 150,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
align: 'center',
|
align: 'center',
|
||||||
|
@ -174,8 +174,8 @@ export const BUY_COLUMNS: TdBaseTableProps['columns'] = [
|
||||||
align: 'left',
|
align: 'left',
|
||||||
ellipsis: true,
|
ellipsis: true,
|
||||||
colKey: 'productName',
|
colKey: 'productName',
|
||||||
|
width: 150,
|
||||||
title: '供应商名称',
|
title: '供应商名称',
|
||||||
minWidth: 200,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
align: 'center',
|
align: 'center',
|
||||||
|
|
|
@ -1,95 +0,0 @@
|
||||||
@import '@/style/variables.less';
|
|
||||||
|
|
||||||
.dashboard-item {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
justify-content: space-between;
|
|
||||||
flex: 1;
|
|
||||||
|
|
||||||
.dashboard-item-top {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
align-items: flex-start;
|
|
||||||
|
|
||||||
> span {
|
|
||||||
display: inline-block;
|
|
||||||
color: @text-color-primary;
|
|
||||||
font-size: 36px;
|
|
||||||
line-height: 44px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.dashboard-item-bottom {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
|
|
||||||
> .t-icon {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.dashboard-item-block {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
line-height: 22px;
|
|
||||||
color: @text-color-placeholder;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dashboard-item-trend {
|
|
||||||
margin-left: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dashboard-item-left {
|
|
||||||
position: absolute;
|
|
||||||
top: 32px;
|
|
||||||
right: 32px;
|
|
||||||
|
|
||||||
> span {
|
|
||||||
display: inline-flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
width: 56px;
|
|
||||||
height: 56px;
|
|
||||||
background: @brand-color-1;
|
|
||||||
border-radius: 50%;
|
|
||||||
|
|
||||||
.t-icon {
|
|
||||||
font-size: 24px;
|
|
||||||
color: @brand-color;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.dashboard-rank {
|
|
||||||
display: inline-flex;
|
|
||||||
width: 24px;
|
|
||||||
height: 24px;
|
|
||||||
border-radius: 50%;
|
|
||||||
color: white;
|
|
||||||
font-size: 14px;
|
|
||||||
background-color: @gray-color-5;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
font-weight: 700;
|
|
||||||
|
|
||||||
&__top {
|
|
||||||
background: @brand-color;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.overview-panel {
|
|
||||||
background-color: @bg-color-container;
|
|
||||||
border-radius: 3px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.row-container {
|
|
||||||
margin-top: 16px;
|
|
||||||
}
|
|
|
@ -1,205 +1,13 @@
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<t-row :gutter="[16, 16]">
|
<!-- 顶部 card -->
|
||||||
<t-col v-for="(item, index) in PANE_LIST" :key="item.title" :xs="6" :xl="3">
|
<top-panel class="row-container" />
|
||||||
<card :subtitle="item.title" size="small" :style="{ height: '168px' }" :class="{ 'main-color': index == 0 }">
|
|
||||||
<div class="dashboard-item">
|
|
||||||
<div class="dashboard-item-top">
|
|
||||||
<span :style="{ fontSize: `${resizeTime * 36}px` }">{{ item.number }}</span>
|
|
||||||
</div>
|
|
||||||
<div class="dashboard-item-left">
|
|
||||||
<div v-if="index === 0">
|
|
||||||
<div
|
|
||||||
id="moneyContainer"
|
|
||||||
class="dashboard-chart-container"
|
|
||||||
:style="{ width: `${resizeTime * 120}px`, height: `${resizeTime * 66}px`, marginTop: '22px' }"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div v-else-if="index === 1">
|
|
||||||
<div
|
|
||||||
id="refundContainer"
|
|
||||||
class="dashboard-chart-container"
|
|
||||||
:style="{ width: `${resizeTime * 120}px`, height: `${resizeTime * 42}px`, marginTop: '24px' }"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<span v-else-if="index === 2">
|
|
||||||
<t-icon name="usergroup" />
|
|
||||||
</span>
|
|
||||||
<span v-else>
|
|
||||||
<t-icon name="file" />
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<div class="dashboard-item-bottom">
|
|
||||||
<div class="dashboard-item-block">
|
|
||||||
自从上周以来
|
|
||||||
<trend
|
|
||||||
class="dashboard-item-trend"
|
|
||||||
:type="item.upTrend ? 'up' : 'down'"
|
|
||||||
:is-reverse-color="index === 0"
|
|
||||||
:describe="item.upTrend || item.downTrend"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<t-icon name="chevron-right" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</card>
|
|
||||||
</t-col>
|
|
||||||
</t-row>
|
|
||||||
|
|
||||||
<!-- 中部图表 -->
|
<!-- 中部图表 -->
|
||||||
<t-row :gutter="16" class="row-container">
|
<middle-chart class="row-container" />
|
||||||
<t-col :xs="12" :xl="9">
|
|
||||||
<card title="统计数据" :describe="`(万元)${currentMonth}`">
|
|
||||||
<template #option>
|
|
||||||
<div class="dashboard-chart-title-container">
|
|
||||||
<t-date-picker
|
|
||||||
class="card-date-picker-container"
|
|
||||||
theme="primary"
|
|
||||||
mode="date"
|
|
||||||
range
|
|
||||||
:default-value="LAST_7_DAYS"
|
|
||||||
@change="onCurrencyChange"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<div
|
|
||||||
id="monitorContainer"
|
|
||||||
ref="monitorContainer"
|
|
||||||
class="dashboard-chart-container"
|
|
||||||
:style="{ width: '100%', height: `${resizeTime * 326}px` }"
|
|
||||||
/>
|
|
||||||
</card>
|
|
||||||
</t-col>
|
|
||||||
<t-col :xs="12" :xl="3">
|
|
||||||
<card title="销售渠道" :describe="currentMonth">
|
|
||||||
<div
|
|
||||||
id="countContainer"
|
|
||||||
ref="countContainer"
|
|
||||||
:style="{ width: `${resizeTime * 326}px`, height: `${resizeTime * 326}px`, margin: '0 auto' }"
|
|
||||||
class="dashboard-chart-container"
|
|
||||||
/>
|
|
||||||
</card>
|
|
||||||
</t-col>
|
|
||||||
</t-row>
|
|
||||||
|
|
||||||
<!-- 列表排名 -->
|
<!-- 列表排名 -->
|
||||||
<t-row :gutter="16" class="row-container">
|
<rank-list class="row-container" />
|
||||||
<t-col :xs="12" :xl="6">
|
|
||||||
<card title="销售订单排名">
|
|
||||||
<template #option>
|
|
||||||
<t-radio-group default-value="dateVal">
|
|
||||||
<t-radio-button value="dateVal">本周</t-radio-button>
|
|
||||||
<t-radio-button value="monthVal">近三个月</t-radio-button>
|
|
||||||
</t-radio-group>
|
|
||||||
</template>
|
|
||||||
<t-table :data="SALE_TEND_LIST" :columns="SALE_COLUMNS" row-key="productName">
|
|
||||||
<template #index="{ rowIndex }">
|
|
||||||
<span :class="getRankClass(rowIndex)">
|
|
||||||
{{ rowIndex + 1 }}
|
|
||||||
</span>
|
|
||||||
</template>
|
|
||||||
<template #growUp="{ row }">
|
|
||||||
<span>
|
|
||||||
<trend :type="row.growUp > 0 ? 'up' : 'down'" :describe="Math.abs(row.growUp)" />
|
|
||||||
</span>
|
|
||||||
</template>
|
|
||||||
<template #operation="slotProps">
|
|
||||||
<a class="t-button-link" @click="rehandleClickOp(slotProps)">详情</a>
|
|
||||||
</template>
|
|
||||||
</t-table>
|
|
||||||
</card>
|
|
||||||
</t-col>
|
|
||||||
<t-col :xs="12" :xl="6">
|
|
||||||
<card title="采购订单排名">
|
|
||||||
<template #option>
|
|
||||||
<t-radio-group default-value="dateVal">
|
|
||||||
<t-radio-button value="dateVal">本周</t-radio-button>
|
|
||||||
<t-radio-button value="monthVal">近三个月</t-radio-button>
|
|
||||||
</t-radio-group>
|
|
||||||
</template>
|
|
||||||
<t-table :data="BUY_TEND_LIST" :columns="BUY_COLUMNS" row-key="productName">
|
|
||||||
<template #index="{ rowIndex }">
|
|
||||||
<span :class="getRankClass(rowIndex)">
|
|
||||||
{{ rowIndex + 1 }}
|
|
||||||
</span>
|
|
||||||
</template>
|
|
||||||
<template #growUp="{ row }">
|
|
||||||
<trend :type="row.growUp > 0 ? 'up' : 'down'" :describe="Math.abs(row.growUp)" />
|
|
||||||
</template>
|
|
||||||
<template #operation="slotProps">
|
|
||||||
<a class="t-button-link" @click="rehandleClickOp(slotProps)">详情</a>
|
|
||||||
</template>
|
|
||||||
</t-table>
|
|
||||||
</card>
|
|
||||||
</t-col>
|
|
||||||
</t-row>
|
|
||||||
|
|
||||||
<!-- 出入库概览 -->
|
<!-- 出入库概览 -->
|
||||||
<div class="row-container overview-panel">
|
<over-view class="row-container" />
|
||||||
<t-row>
|
|
||||||
<t-col :xs="12" :xl="9">
|
|
||||||
<card title="出入库概览" describe="(件)">
|
|
||||||
<template #option>
|
|
||||||
<t-date-picker
|
|
||||||
class="card-date-picker-container"
|
|
||||||
theme="primary"
|
|
||||||
mode="date"
|
|
||||||
range
|
|
||||||
:default-value="LAST_7_DAYS"
|
|
||||||
@change="onStokeDataChange"
|
|
||||||
/>
|
|
||||||
</template>
|
|
||||||
<div
|
|
||||||
id="stokeContainer"
|
|
||||||
ref="stokeContainer"
|
|
||||||
style="width: 100%; height: 351px"
|
|
||||||
class="dashboard-chart-container"
|
|
||||||
/>
|
|
||||||
</card>
|
|
||||||
</t-col>
|
|
||||||
<t-col :xs="12" :xl="3">
|
|
||||||
<card>
|
|
||||||
<template #option>
|
|
||||||
<t-button>导出数据</t-button>
|
|
||||||
</template>
|
|
||||||
<t-row>
|
|
||||||
<t-col :xs="6" :xl="12">
|
|
||||||
<card describe="本月出库总计(件)" class="inner-card" size="small">
|
|
||||||
<div class="dashboard-item">
|
|
||||||
<div class="dashboard-item-top">
|
|
||||||
<span>1726</span>
|
|
||||||
</div>
|
|
||||||
<div class="dashboard-item-bottom">
|
|
||||||
<div class="dashboard-item-block">
|
|
||||||
自从上周以来
|
|
||||||
<trend class="dashboard-item-trend" type="down" :is-reverse-color="false" describe="20.3%" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</card>
|
|
||||||
</t-col>
|
|
||||||
|
|
||||||
<t-col :xs="6" :xl="12">
|
|
||||||
<card describe="本月入库总计(件)" class="inner-card" size="small">
|
|
||||||
<div class="dashboard-item">
|
|
||||||
<div class="dashboard-item-top">
|
|
||||||
<span>226</span>
|
|
||||||
</div>
|
|
||||||
<div class="dashboard-item-bottom">
|
|
||||||
<div class="dashboard-item-block">
|
|
||||||
自从上周以来
|
|
||||||
<trend class="dashboard-item-trend" type="down" :is-reverse-color="false" describe="20.3%" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</card>
|
|
||||||
</t-col>
|
|
||||||
</t-row>
|
|
||||||
</card>
|
|
||||||
</t-col>
|
|
||||||
</t-row>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -210,214 +18,14 @@ export default {
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { onMounted, watch, ref, onUnmounted, nextTick, computed } from 'vue';
|
import TopPanel from './components/top-panel.vue';
|
||||||
|
import MiddleChart from './components/middle-chart.vue';
|
||||||
import * as echarts from 'echarts/core';
|
import RankList from './components/rank-list.vue';
|
||||||
import { TooltipComponent, LegendComponent, GridComponent } from 'echarts/components';
|
import OverView from './components/overview.vue';
|
||||||
import { PieChart, LineChart, BarChart } from 'echarts/charts';
|
|
||||||
import { CanvasRenderer } from 'echarts/renderers';
|
|
||||||
import { useSettingStore } from '@/store';
|
|
||||||
import { LAST_7_DAYS } from '@/utils/date';
|
|
||||||
import { changeChartsTheme } from '@/utils/color';
|
|
||||||
|
|
||||||
// 导入样式
|
|
||||||
import Trend from '@/components/trend/index.vue';
|
|
||||||
import Card from '@/components/card/index.vue';
|
|
||||||
import { constructInitDataset, getPieChartDataSet, getLineChartDataSet, constructInitDashboardDataset } from './index';
|
|
||||||
|
|
||||||
import { PANE_LIST, SALE_TEND_LIST, BUY_TEND_LIST, SALE_COLUMNS, BUY_COLUMNS } from './constants';
|
|
||||||
|
|
||||||
echarts.use([TooltipComponent, LegendComponent, PieChart, GridComponent, LineChart, BarChart, CanvasRenderer]);
|
|
||||||
|
|
||||||
const getThisMonth = (checkedValues?: string[]) => {
|
|
||||||
let date: Date;
|
|
||||||
if (!checkedValues || checkedValues.length === 0) {
|
|
||||||
date = new Date();
|
|
||||||
return `${date.getFullYear()}-${date.getMonth() + 1}`;
|
|
||||||
}
|
|
||||||
date = new Date(checkedValues[0]);
|
|
||||||
const date2 = new Date(checkedValues[1]);
|
|
||||||
|
|
||||||
const startMonth = date.getMonth() + 1 > 9 ? date.getMonth() + 1 : `0${date.getMonth() + 1}`;
|
|
||||||
const endMonth = date2.getMonth() + 1 > 9 ? date2.getMonth() + 1 : `0${date2.getMonth() + 1}`;
|
|
||||||
return `${date.getFullYear()}-${startMonth} 至 ${date2.getFullYear()}-${endMonth}`;
|
|
||||||
};
|
|
||||||
|
|
||||||
const store = useSettingStore();
|
|
||||||
const resizeTime = ref(1);
|
|
||||||
|
|
||||||
const chartColors = computed(() => store.chartColors);
|
|
||||||
|
|
||||||
// moneyCharts
|
|
||||||
let moneyContainer: HTMLElement;
|
|
||||||
let moneyChart: echarts.ECharts;
|
|
||||||
const renderMoneyChart = () => {
|
|
||||||
if (!moneyContainer) {
|
|
||||||
moneyContainer = document.getElementById('moneyContainer');
|
|
||||||
}
|
|
||||||
moneyChart = echarts.init(moneyContainer);
|
|
||||||
moneyChart.setOption(constructInitDashboardDataset('line'));
|
|
||||||
};
|
|
||||||
|
|
||||||
// refundCharts
|
|
||||||
let refundContainer: HTMLElement;
|
|
||||||
let refundChart: echarts.ECharts;
|
|
||||||
const renderRefundChart = () => {
|
|
||||||
if (!refundContainer) {
|
|
||||||
refundContainer = document.getElementById('refundContainer');
|
|
||||||
}
|
|
||||||
refundChart = echarts.init(refundContainer);
|
|
||||||
refundChart.setOption(constructInitDashboardDataset('bar'));
|
|
||||||
};
|
|
||||||
|
|
||||||
// stokeCharts
|
|
||||||
let stokeContainer: HTMLElement;
|
|
||||||
let stokeChart: echarts.ECharts;
|
|
||||||
const renderStokeChart = () => {
|
|
||||||
if (!stokeContainer) {
|
|
||||||
stokeContainer = document.getElementById('stokeContainer');
|
|
||||||
}
|
|
||||||
stokeChart = echarts.init(stokeContainer);
|
|
||||||
stokeChart.setOption(constructInitDataset({ dateTime: LAST_7_DAYS, ...chartColors.value }));
|
|
||||||
};
|
|
||||||
|
|
||||||
// monitorChart
|
|
||||||
let monitorContainer: HTMLElement;
|
|
||||||
let monitorChart: echarts.ECharts;
|
|
||||||
const renderMonitorChart = () => {
|
|
||||||
if (!monitorContainer) {
|
|
||||||
monitorContainer = document.getElementById('monitorContainer');
|
|
||||||
}
|
|
||||||
monitorChart = echarts.init(monitorContainer);
|
|
||||||
monitorChart.setOption(getLineChartDataSet({ ...chartColors.value }));
|
|
||||||
};
|
|
||||||
|
|
||||||
// monitorChart
|
|
||||||
let countContainer: HTMLElement;
|
|
||||||
let countChart: echarts.ECharts;
|
|
||||||
const renderCountChart = () => {
|
|
||||||
if (!countContainer) {
|
|
||||||
countContainer = document.getElementById('countContainer');
|
|
||||||
}
|
|
||||||
countChart = echarts.init(countContainer);
|
|
||||||
countChart.setOption(getPieChartDataSet(chartColors.value));
|
|
||||||
};
|
|
||||||
|
|
||||||
const renderCharts = () => {
|
|
||||||
renderMoneyChart();
|
|
||||||
renderRefundChart();
|
|
||||||
renderStokeChart();
|
|
||||||
renderMonitorChart();
|
|
||||||
renderCountChart();
|
|
||||||
};
|
|
||||||
|
|
||||||
// chartSize update
|
|
||||||
const updateContainer = () => {
|
|
||||||
if (document.documentElement.clientWidth >= 1400 && document.documentElement.clientWidth < 1920) {
|
|
||||||
resizeTime.value = Number((document.documentElement.clientWidth / 2080).toFixed(2));
|
|
||||||
} else if (document.documentElement.clientWidth < 1080) {
|
|
||||||
resizeTime.value = Number((document.documentElement.clientWidth / 1080).toFixed(2));
|
|
||||||
} else {
|
|
||||||
resizeTime.value = 1;
|
|
||||||
}
|
|
||||||
moneyChart.resize({
|
|
||||||
width: resizeTime.value * 120,
|
|
||||||
height: resizeTime.value * 66,
|
|
||||||
});
|
|
||||||
refundChart.resize({
|
|
||||||
width: resizeTime.value * 120,
|
|
||||||
height: resizeTime.value * 42,
|
|
||||||
});
|
|
||||||
stokeChart.resize({
|
|
||||||
width: stokeContainer.clientWidth,
|
|
||||||
height: stokeContainer.clientHeight,
|
|
||||||
});
|
|
||||||
monitorChart.resize({
|
|
||||||
width: monitorContainer.clientWidth,
|
|
||||||
height: resizeTime.value * 326,
|
|
||||||
});
|
|
||||||
countChart.resize({
|
|
||||||
width: resizeTime.value * 326,
|
|
||||||
height: resizeTime.value * 326,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
renderCharts();
|
|
||||||
nextTick(() => {
|
|
||||||
updateContainer();
|
|
||||||
});
|
|
||||||
window.addEventListener('resize', updateContainer, false);
|
|
||||||
});
|
|
||||||
|
|
||||||
onUnmounted(() => {
|
|
||||||
window.removeEventListener('resize', updateContainer);
|
|
||||||
});
|
|
||||||
|
|
||||||
const currentMonth = ref(getThisMonth());
|
|
||||||
|
|
||||||
watch(
|
|
||||||
() => store.brandTheme,
|
|
||||||
() => {
|
|
||||||
changeChartsTheme([refundChart, stokeChart, monitorChart, countChart]);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
watch(
|
|
||||||
() => store.mode,
|
|
||||||
() => {
|
|
||||||
[moneyChart, refundChart, stokeChart, monitorChart, countChart].forEach((item) => {
|
|
||||||
item.dispose();
|
|
||||||
});
|
|
||||||
|
|
||||||
renderCharts();
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
const onCurrencyChange = (checkedValues: string[]) => {
|
|
||||||
currentMonth.value = getThisMonth(checkedValues);
|
|
||||||
monitorChart.setOption(getLineChartDataSet({ dateTime: checkedValues, ...chartColors.value }));
|
|
||||||
};
|
|
||||||
const onStokeDataChange = (checkedValues: string[]) => {
|
|
||||||
stokeChart.setOption(constructInitDataset({ dateTime: checkedValues, ...chartColors.value }));
|
|
||||||
};
|
|
||||||
const rehandleClickOp = (val: MouseEvent) => {
|
|
||||||
console.log(val);
|
|
||||||
};
|
|
||||||
const getRankClass = (index: number) => {
|
|
||||||
return ['dashboard-rank', { 'dashboard-rank__top': index < 3 }];
|
|
||||||
};
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less" scoped>
|
<style scoped>
|
||||||
@import './index.less';
|
.row-container {
|
||||||
</style>
|
margin-bottom: 16px;
|
||||||
|
|
||||||
<style lang="less">
|
|
||||||
@import '@/style/variables.less';
|
|
||||||
|
|
||||||
.card-container.main-color {
|
|
||||||
background: @brand-color;
|
|
||||||
color: @text-color-primary;
|
|
||||||
|
|
||||||
.card-subtitle {
|
|
||||||
color: @text-color-anti;
|
|
||||||
}
|
|
||||||
.card-describe {
|
|
||||||
color: @text-color-anti;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dashboard-item-top span {
|
|
||||||
color: @text-color-anti;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dashboard-item-block {
|
|
||||||
color: @text-color-anti;
|
|
||||||
opacity: 0.6;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dashboard-item-bottom {
|
|
||||||
color: @text-color-anti;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -1,73 +0,0 @@
|
||||||
@import '@/style/variables.less';
|
|
||||||
|
|
||||||
.card-container-margin {
|
|
||||||
margin-top: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.card-date-button {
|
|
||||||
margin-left: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dark {
|
|
||||||
.dashboard-detail-container-item {
|
|
||||||
&:hover {
|
|
||||||
background: @gray-color-14;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.light {
|
|
||||||
.dashboard-detail-container-item {
|
|
||||||
&:hover {
|
|
||||||
background: @gray-color-1;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.dashboard-detail-container-item {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
justify-content: space-between;
|
|
||||||
flex: 1;
|
|
||||||
height: 170px;
|
|
||||||
|
|
||||||
.title {
|
|
||||||
color: @text-color-secondary;
|
|
||||||
}
|
|
||||||
|
|
||||||
.number {
|
|
||||||
font-size: 36px;
|
|
||||||
line-height: 44px;
|
|
||||||
color: @text-color-primary;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dashboard-detail-container-item-text {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: space-between;
|
|
||||||
font-size: 14px;
|
|
||||||
color: @text-color-placeholder;
|
|
||||||
text-align: left;
|
|
||||||
line-height: 18px;
|
|
||||||
|
|
||||||
&-left {
|
|
||||||
display: flex;
|
|
||||||
|
|
||||||
.icon {
|
|
||||||
margin: 0 8px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.dashboard-chart-title-left {
|
|
||||||
display: flex;
|
|
||||||
width: 100%;
|
|
||||||
color: @text-color-placeholder;
|
|
||||||
justify-content: left;
|
|
||||||
font-size: 15px;
|
|
||||||
padding-left: 8px;
|
|
||||||
}
|
|
|
@ -1,60 +1,62 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="dashboard-panel-detail">
|
<div class="dashboard-panel-detail">
|
||||||
<card title="本月采购申请情况">
|
<t-card title="本月采购申请情况" class="dashboard-detail-card">
|
||||||
<t-row :gutter="[16, 16]">
|
<t-row :gutter="[16, 16]">
|
||||||
<t-col v-for="(item, index) in PANE_LIST_DATA" :key="index" :xs="6" :xl="3">
|
<t-col v-for="(item, index) in PANE_LIST_DATA" :key="index" :xs="6" :xl="3">
|
||||||
<card border class="dashboard-detail-container-item" size="small" :subtitle="item.title">
|
<t-card class="dashboard-list-card" :description="item.title">
|
||||||
<div class="number">{{ item.number }}</div>
|
<div class="dashboard-list-card__number">{{ item.number }}</div>
|
||||||
<div class="dashboard-detail-container-item-text">
|
<div class="dashboard-list-card__text">
|
||||||
<div class="dashboard-detail-container-item-text-left">
|
<div class="dashboard-list-card__text-left">
|
||||||
环比
|
环比
|
||||||
<trend class="icon" :type="item.upTrend ? 'up' : 'down'" :describe="item.upTrend || item.downTrend" />
|
<trend class="icon" :type="item.upTrend ? 'up' : 'down'" :describe="item.upTrend || item.downTrend" />
|
||||||
</div>
|
</div>
|
||||||
<t-icon name="chevron-right" />
|
<t-icon name="chevron-right" />
|
||||||
</div>
|
</div>
|
||||||
</card>
|
</t-card>
|
||||||
</t-col>
|
</t-col>
|
||||||
</t-row>
|
</t-row>
|
||||||
</card>
|
</t-card>
|
||||||
<t-row :gutter="[16, 16]" class="card-container-margin">
|
<t-row :gutter="[16, 16]" class="row-margin">
|
||||||
<t-col :xs="12" :xl="9">
|
<t-col :xs="12" :xl="9">
|
||||||
<card title="采购商品申请趋势" describe="(件)">
|
<t-card class="dashboard-detail-card" title="采购商品申请趋势" subtitle="(件)">
|
||||||
<template #option>
|
<template #actions>
|
||||||
<t-date-picker
|
<t-date-picker
|
||||||
class="card-date-picker-container"
|
class="card-date-picker-container"
|
||||||
:default-value="LAST_7_DAYS"
|
:default-value="LAST_7_DAYS"
|
||||||
theme="primary"
|
theme="primary"
|
||||||
mode="date"
|
mode="date"
|
||||||
range
|
range
|
||||||
|
style="width: 240px"
|
||||||
@change="onMaterialChange"
|
@change="onMaterialChange"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
<div id="lineContainer" style="width: 100%; height: 406px" />
|
<div id="lineContainer" style="width: 100%; height: 410px" />
|
||||||
</card>
|
</t-card>
|
||||||
</t-col>
|
</t-col>
|
||||||
<t-col :xs="12" :xl="3">
|
<t-col :xs="12" :xl="3">
|
||||||
<product-card
|
<product-card
|
||||||
v-for="(item, index) in PRODUCT_LIST"
|
v-for="(item, index) in PRODUCT_LIST"
|
||||||
:key="index"
|
:key="index"
|
||||||
:product="item"
|
:product="item"
|
||||||
:class="{ 'card-container-margin': index !== 0 }"
|
:class="{ 'row-margin': index !== 0 }"
|
||||||
/>
|
/>
|
||||||
</t-col>
|
</t-col>
|
||||||
</t-row>
|
</t-row>
|
||||||
<card title="采购商品满意度分布" class="card-container-margin">
|
<t-card :class="['dashboard-detail-card', 'row-margin']" title="采购商品满意度分布">
|
||||||
<template #option>
|
<template #actions>
|
||||||
<t-date-picker
|
<t-date-picker
|
||||||
class="card-date-picker-container"
|
class="card-date-picker-container"
|
||||||
:default-value="LAST_7_DAYS"
|
:default-value="LAST_7_DAYS"
|
||||||
theme="primary"
|
theme="primary"
|
||||||
mode="date"
|
mode="date"
|
||||||
range
|
range
|
||||||
|
style="display: inline-block; margin-right: 8px; width: 240px"
|
||||||
@change="onSatisfyChange"
|
@change="onSatisfyChange"
|
||||||
/>
|
/>
|
||||||
<t-button class="card-date-button"> 导出数据 </t-button>
|
<t-button class="card-date-button"> 导出数据 </t-button>
|
||||||
</template>
|
</template>
|
||||||
<div id="scatterContainer" style="width: 100%; height: 330px" />
|
<div id="scatterContainer" style="width: 100%; height: 330px" />
|
||||||
</card>
|
</t-card>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -71,7 +73,7 @@ import * as echarts from 'echarts/core';
|
||||||
import { GridComponent, TooltipComponent, LegendComponent } from 'echarts/components';
|
import { GridComponent, TooltipComponent, LegendComponent } from 'echarts/components';
|
||||||
import { LineChart, ScatterChart } from 'echarts/charts';
|
import { LineChart, ScatterChart } from 'echarts/charts';
|
||||||
import { CanvasRenderer } from 'echarts/renderers';
|
import { CanvasRenderer } from 'echarts/renderers';
|
||||||
import ProductCard from '@/components/card/Card.vue';
|
import ProductCard from '@/components/product-card/index.vue';
|
||||||
|
|
||||||
import { getFolderLineDataSet, getScatterDataSet } from './index';
|
import { getFolderLineDataSet, getScatterDataSet } from './index';
|
||||||
import { PANE_LIST_DATA, PRODUCT_LIST } from './constants';
|
import { PANE_LIST_DATA, PRODUCT_LIST } from './constants';
|
||||||
|
@ -80,7 +82,6 @@ import { useSettingStore } from '@/store';
|
||||||
import { changeChartsTheme } from '@/utils/color';
|
import { changeChartsTheme } from '@/utils/color';
|
||||||
|
|
||||||
import Trend from '@/components/trend/index.vue';
|
import Trend from '@/components/trend/index.vue';
|
||||||
import Card from '@/components/card/index.vue';
|
|
||||||
|
|
||||||
echarts.use([GridComponent, LegendComponent, TooltipComponent, LineChart, ScatterChart, CanvasRenderer]);
|
echarts.use([GridComponent, LegendComponent, TooltipComponent, LineChart, ScatterChart, CanvasRenderer]);
|
||||||
|
|
||||||
|
@ -159,5 +160,82 @@ const onMaterialChange = (value: string[]) => {
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
@import url('./index.less');
|
@import '@/style/variables.less';
|
||||||
|
|
||||||
|
.row-margin {
|
||||||
|
margin-top: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 统一增加8px;
|
||||||
|
.dashboard-detail-card {
|
||||||
|
padding: 8px;
|
||||||
|
|
||||||
|
:deep(.t-card__title) {
|
||||||
|
font-size: 20px;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.t-card__actions) {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.dashboard-list-card {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
flex: 1;
|
||||||
|
height: 170px;
|
||||||
|
padding: 8px;
|
||||||
|
|
||||||
|
:deep(.t-card__header) {
|
||||||
|
padding-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.t-card__body) {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.dark {
|
||||||
|
&:hover {
|
||||||
|
background: @gray-color-14;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.light {
|
||||||
|
&:hover {
|
||||||
|
background: @gray-color-14;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__number {
|
||||||
|
font-size: 36px;
|
||||||
|
line-height: 44px;
|
||||||
|
color: @text-color-primary;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__text {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
font-size: 14px;
|
||||||
|
color: @text-color-placeholder;
|
||||||
|
text-align: left;
|
||||||
|
line-height: 18px;
|
||||||
|
|
||||||
|
&-left {
|
||||||
|
display: flex;
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
margin: 0 8px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -1,5 +1,23 @@
|
||||||
@import '../base/index.less';
|
@import '../base/index.less';
|
||||||
|
|
||||||
|
.detail-advanced {
|
||||||
|
:deep(.t-card) {
|
||||||
|
padding: 8px;
|
||||||
|
}
|
||||||
|
:deep(.t-card__title) {
|
||||||
|
font-size: 20px;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.advanced-card {
|
||||||
|
margin-top: 0 !important;
|
||||||
|
|
||||||
|
.card-title-default {
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.product-block-container {
|
.product-block-container {
|
||||||
.t-col-xl-4 + .t-col-xl-4 {
|
.t-col-xl-4 + .t-col-xl-4 {
|
||||||
@media (max-width: @screen-lg-max) {
|
@media (max-width: @screen-lg-max) {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div class="detail-advanced">
|
||||||
<card title="基本信息">
|
<t-card title="基本信息">
|
||||||
<div class="info-block">
|
<div class="info-block">
|
||||||
<div v-for="(item, index) in BASE_INFO_DATA" :key="index" class="info-item">
|
<div v-for="(item, index) in BASE_INFO_DATA" :key="index" class="info-item">
|
||||||
<h1>{{ item.name }}</h1>
|
<h1>{{ item.name }}</h1>
|
||||||
|
@ -15,10 +15,10 @@
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</card>
|
</t-card>
|
||||||
|
|
||||||
<!-- 发票进度 -->
|
<!-- 发票进度 -->
|
||||||
<card title="发票进度" class="container-base-margin-top">
|
<t-card title="发票进度" class="container-base-margin-top">
|
||||||
<t-row justify="space-between">
|
<t-row justify="space-between">
|
||||||
<t-steps :current="updateCurrent">
|
<t-steps :current="updateCurrent">
|
||||||
<t-step-item title="申请提交" content="已于12月21日提交" />
|
<t-step-item title="申请提交" content="已于12月21日提交" />
|
||||||
|
@ -27,10 +27,10 @@
|
||||||
<t-step-item title="完成" content />
|
<t-step-item title="完成" content />
|
||||||
</t-steps>
|
</t-steps>
|
||||||
</t-row>
|
</t-row>
|
||||||
</card>
|
</t-card>
|
||||||
|
|
||||||
<!-- 产品目录 -->
|
<!-- 产品目录 -->
|
||||||
<card title="产品目录" class="container-base-margin-top">
|
<t-card title="产品目录" class="container-base-margin-top">
|
||||||
<template #option>
|
<template #option>
|
||||||
<t-radio-group default-value="dateVal">
|
<t-radio-group default-value="dateVal">
|
||||||
<t-radio-button value="dateVal"> 季度 </t-radio-button>
|
<t-radio-button value="dateVal"> 季度 </t-radio-button>
|
||||||
|
@ -50,10 +50,10 @@
|
||||||
<product :data="item" />
|
<product :data="item" />
|
||||||
</t-col>
|
</t-col>
|
||||||
</t-row>
|
</t-row>
|
||||||
</card>
|
</t-card>
|
||||||
|
|
||||||
<!-- 产品采购明细 -->
|
<!-- 产品采购明细 -->
|
||||||
<card title="产品采购明细" class="container-base-margin-top">
|
<t-card title="产品采购明细" class="container-base-margin-top">
|
||||||
<t-table
|
<t-table
|
||||||
:columns="columns"
|
:columns="columns"
|
||||||
:data="data"
|
:data="data"
|
||||||
|
@ -87,7 +87,7 @@
|
||||||
<t-icon name="descending-order" />
|
<t-icon name="descending-order" />
|
||||||
</template>
|
</template>
|
||||||
</t-table>
|
</t-table>
|
||||||
</card>
|
</t-card>
|
||||||
|
|
||||||
<t-dialog v-model:visible="visible" header="基本信息" @confirm="onConfirm">
|
<t-dialog v-model:visible="visible" header="基本信息" @confirm="onConfirm">
|
||||||
<template #body>
|
<template #body>
|
||||||
|
@ -123,7 +123,6 @@ import { BASE_INFO_DATA, TABLE_COLUMNS_DATA as columns, PRODUCT_LIST } from './c
|
||||||
import request from '@/utils/request';
|
import request from '@/utils/request';
|
||||||
import { ResDataType } from '@/interface';
|
import { ResDataType } from '@/interface';
|
||||||
|
|
||||||
import Card from '@/components/card/index.vue';
|
|
||||||
import Product from './components/Product.vue';
|
import Product from './components/Product.vue';
|
||||||
|
|
||||||
const data = ref([]);
|
const data = ref([]);
|
||||||
|
|
|
@ -1,7 +1,18 @@
|
||||||
@import '@/style/variables.less';
|
@import '@/style/variables.less';
|
||||||
|
|
||||||
.detail-base-info-steps {
|
.detail-base {
|
||||||
|
:deep(.t-card) {
|
||||||
|
padding: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.t-card__title) {
|
||||||
|
font-size: 20px;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-info-steps {
|
||||||
padding-top: 12px;
|
padding-top: 12px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.info-block {
|
.info-block {
|
||||||
|
@ -59,7 +70,6 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.dialog-info-block {
|
.dialog-info-block {
|
||||||
|
|
||||||
.info-item {
|
.info-item {
|
||||||
padding: 12px 0;
|
padding: 12px 0;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div class="detail-base">
|
||||||
<card title="基本信息">
|
<t-card title="基本信息">
|
||||||
<div class="info-block">
|
<div class="info-block">
|
||||||
<div v-for="(item, index) in BASE_INFO_DATA" :key="index" class="info-item">
|
<div v-for="(item, index) in BASE_INFO_DATA" :key="index" class="info-item">
|
||||||
<h1>{{ item.name }}</h1>
|
<h1>{{ item.name }}</h1>
|
||||||
|
@ -15,15 +15,15 @@
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</card>
|
</t-card>
|
||||||
|
|
||||||
<card title="变更记录" class="container-base-margin-top">
|
<t-card title="变更记录" class="container-base-margin-top">
|
||||||
<t-steps class="detail-base-info-steps" layout="vertical" theme="dot" :current="1">
|
<t-steps class="detail-base-info-steps" layout="vertical" theme="dot" :current="1">
|
||||||
<t-step-item title="上传合同附件" content="这里是提示文字" />
|
<t-step-item title="上传合同附件" content="这里是提示文字" />
|
||||||
<t-step-item title="修改合同金额" content="这里是提示文字" />
|
<t-step-item title="修改合同金额" content="这里是提示文字" />
|
||||||
<t-step-item title="新建合同" content="2020-12-01 15:00:00 管理员-李川操作" />
|
<t-step-item title="新建合同" content="2020-12-01 15:00:00 管理员-李川操作" />
|
||||||
</t-steps>
|
</t-steps>
|
||||||
</card>
|
</t-card>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -34,8 +34,6 @@ export default {
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import Card from '@/components/card/index.vue';
|
|
||||||
|
|
||||||
const BASE_INFO_DATA = [
|
const BASE_INFO_DATA = [
|
||||||
{
|
{
|
||||||
name: '合同名称',
|
name: '合同名称',
|
||||||
|
|
|
@ -83,7 +83,7 @@ export const BASE_INFO_DATA = [
|
||||||
|
|
||||||
export const TABLE_COLUMNS = [
|
export const TABLE_COLUMNS = [
|
||||||
{
|
{
|
||||||
minWidth: '448',
|
width: '448',
|
||||||
ellipsis: true,
|
ellipsis: true,
|
||||||
colKey: 'name',
|
colKey: 'name',
|
||||||
title: '项目名称',
|
title: '项目名称',
|
||||||
|
|
|
@ -1,15 +1,15 @@
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div class="detail-deploy">
|
||||||
<t-row :gutter="16">
|
<t-row :gutter="16">
|
||||||
<t-col :span="6">
|
<t-col :lg="6" :xs="12">
|
||||||
<card title="部署趋势">
|
<t-card title="部署趋势">
|
||||||
<div class="deploy-panel-left">
|
<div class="deploy-panel-left">
|
||||||
<div id="monitorContainer" style="width: 100%; height: 265px" />
|
<div id="monitorContainer" style="width: 100%; height: 265px" />
|
||||||
</div>
|
</div>
|
||||||
</card>
|
</t-card>
|
||||||
</t-col>
|
</t-col>
|
||||||
<t-col :span="6">
|
<t-col :lg="6" :xs="12">
|
||||||
<card title="告警情况">
|
<t-card title="告警情况">
|
||||||
<template #option>
|
<template #option>
|
||||||
<t-radio-group default-value="dateVal" @change="onAlertChange">
|
<t-radio-group default-value="dateVal" @change="onAlertChange">
|
||||||
<t-radio-button value="dateVal"> 本周 </t-radio-button>
|
<t-radio-button value="dateVal"> 本周 </t-radio-button>
|
||||||
|
@ -17,12 +17,12 @@
|
||||||
</t-radio-group>
|
</t-radio-group>
|
||||||
</template>
|
</template>
|
||||||
<div id="dataContainer" style="width: 100%; height: 265px" />
|
<div id="dataContainer" style="width: 100%; height: 265px" />
|
||||||
</card>
|
</t-card>
|
||||||
</t-col>
|
</t-col>
|
||||||
</t-row>
|
</t-row>
|
||||||
|
|
||||||
<!-- 项目列表 -->
|
<!-- 项目列表 -->
|
||||||
<card title="项目列表" class="container-base-margin-top">
|
<t-card title="项目列表" class="container-base-margin-top">
|
||||||
<t-table
|
<t-table
|
||||||
:columns="columns"
|
:columns="columns"
|
||||||
:data="data"
|
:data="data"
|
||||||
|
@ -46,7 +46,7 @@
|
||||||
<t-icon name="descending-order" />
|
<t-icon name="descending-order" />
|
||||||
</template>
|
</template>
|
||||||
</t-table>
|
</t-table>
|
||||||
</card>
|
</t-card>
|
||||||
|
|
||||||
<t-dialog v-model:visible="visible" header="基本信息" @confirm="onConfirm">
|
<t-dialog v-model:visible="visible" header="基本信息" @confirm="onConfirm">
|
||||||
<template #body>
|
<template #body>
|
||||||
|
@ -89,7 +89,6 @@ import { BASE_INFO_DATA, TABLE_COLUMNS as columns } from './constants';
|
||||||
import { changeChartsTheme } from '@/utils/color';
|
import { changeChartsTheme } from '@/utils/color';
|
||||||
|
|
||||||
import { prefix } from '@/config/global';
|
import { prefix } from '@/config/global';
|
||||||
import Card from '@/components/card/index.vue';
|
|
||||||
import { ResDataType } from '@/interface';
|
import { ResDataType } from '@/interface';
|
||||||
import request from '@/utils/request';
|
import request from '@/utils/request';
|
||||||
|
|
||||||
|
@ -205,5 +204,14 @@ const deleteClickOp = (e) => {
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
@import url('../base/index.less');
|
.detail-deploy {
|
||||||
|
:deep(.t-card) {
|
||||||
|
padding: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.t-card__title) {
|
||||||
|
font-size: 20px;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -2,6 +2,10 @@
|
||||||
|
|
||||||
.form-step-container {
|
.form-step-container {
|
||||||
background-color: @bg-color-container;
|
background-color: @bg-color-container;
|
||||||
|
|
||||||
|
.t-card {
|
||||||
|
padding: 8px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.rule-tips {
|
.rule-tips {
|
||||||
|
@ -15,3 +19,19 @@
|
||||||
.step-form {
|
.step-form {
|
||||||
padding: 24px;
|
padding: 24px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.step-form-4 {
|
||||||
|
padding: 66px 0 90px 0;
|
||||||
|
text-align: center;
|
||||||
|
> .t-icon {
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
> .text {
|
||||||
|
font-size: 20px;
|
||||||
|
font-weight: 500;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
> .button-group {
|
||||||
|
margin-top: 32px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -2,14 +2,14 @@
|
||||||
<div>
|
<div>
|
||||||
<div class="form-step-container">
|
<div class="form-step-container">
|
||||||
<!-- 简单步骤条 -->
|
<!-- 简单步骤条 -->
|
||||||
<card title="基本信息">
|
<t-card :bordered="false">
|
||||||
<t-steps class="step-container" :current="activeForm" status="process">
|
<t-steps class="step-container" :current="activeForm" status="process">
|
||||||
<t-step-item title="提交开票申请" />
|
<t-step-item title="提交开票申请" />
|
||||||
<t-step-item title="填写发票信息" />
|
<t-step-item title="填写发票信息" />
|
||||||
<t-step-item title="确认邮寄地址" />
|
<t-step-item title="确认邮寄地址" />
|
||||||
<t-step-item title="完成" />
|
<t-step-item title="完成" />
|
||||||
</t-steps>
|
</t-steps>
|
||||||
</card>
|
</t-card>
|
||||||
|
|
||||||
<!-- 分步表单1 -->
|
<!-- 分步表单1 -->
|
||||||
<div v-show="activeForm === 0" class="rule-tips">
|
<div v-show="activeForm === 0" class="rule-tips">
|
||||||
|
@ -150,7 +150,6 @@ export default {
|
||||||
import { ref, computed } from 'vue';
|
import { ref, computed } from 'vue';
|
||||||
import { useRouter } from 'vue-router';
|
import { useRouter } from 'vue-router';
|
||||||
import { ValidateResultContext } from 'tdesign-vue-next';
|
import { ValidateResultContext } from 'tdesign-vue-next';
|
||||||
import Card from '@/components/card/index.vue';
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
FORM_RULES,
|
FORM_RULES,
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<card class="list-card-container">
|
<t-card class="list-card-container">
|
||||||
<t-row justify="space-between">
|
<t-row justify="space-between">
|
||||||
<div class="left-operation-container">
|
<div class="left-operation-container">
|
||||||
<t-button @click="handleSetupContract"> 新建合同 </t-button>
|
<t-button @click="handleSetupContract"> 新建合同 </t-button>
|
||||||
|
@ -15,7 +15,7 @@
|
||||||
</t-input>
|
</t-input>
|
||||||
</div>
|
</div>
|
||||||
</t-row>
|
</t-row>
|
||||||
|
<!-- 如果开启多标签tab页 请修改offsetTop的配置 -->
|
||||||
<t-table
|
<t-table
|
||||||
:data="data"
|
:data="data"
|
||||||
:columns="COLUMNS"
|
:columns="COLUMNS"
|
||||||
|
@ -25,6 +25,8 @@
|
||||||
:pagination="pagination"
|
:pagination="pagination"
|
||||||
:selected-row-keys="selectedRowKeys"
|
:selected-row-keys="selectedRowKeys"
|
||||||
:loading="dataLoading"
|
:loading="dataLoading"
|
||||||
|
:header-affixed-top="true"
|
||||||
|
:header-affix-props="{ offsetTop: 0, container: getContainer }"
|
||||||
@page-change="rehandlePageChange"
|
@page-change="rehandlePageChange"
|
||||||
@change="rehandleChange"
|
@change="rehandleChange"
|
||||||
@select-change="rehandleSelectChange"
|
@select-change="rehandleSelectChange"
|
||||||
|
@ -55,7 +57,7 @@
|
||||||
<a class="t-button-link" @click="handleClickDelete(slotProps)">删除</a>
|
<a class="t-button-link" @click="handleClickDelete(slotProps)">删除</a>
|
||||||
</template>
|
</template>
|
||||||
</t-table>
|
</t-table>
|
||||||
</card>
|
</t-card>
|
||||||
|
|
||||||
<t-dialog
|
<t-dialog
|
||||||
v-model:visible="confirmVisible"
|
v-model:visible="confirmVisible"
|
||||||
|
@ -81,7 +83,6 @@ import { MessagePlugin } from 'tdesign-vue-next';
|
||||||
|
|
||||||
import { CONTRACT_STATUS, CONTRACT_TYPES, CONTRACT_PAYMENT_TYPES } from '@/constants';
|
import { CONTRACT_STATUS, CONTRACT_TYPES, CONTRACT_PAYMENT_TYPES } from '@/constants';
|
||||||
import Trend from '@/components/trend/index.vue';
|
import Trend from '@/components/trend/index.vue';
|
||||||
import Card from '@/components/card/index.vue';
|
|
||||||
import { ResDataType } from '@/interface';
|
import { ResDataType } from '@/interface';
|
||||||
import request from '@/utils/request';
|
import request from '@/utils/request';
|
||||||
|
|
||||||
|
@ -177,6 +178,10 @@ const handleClickDelete = (row: { rowIndex: any }) => {
|
||||||
deleteIdx.value = row.rowIndex;
|
deleteIdx.value = row.rowIndex;
|
||||||
confirmVisible.value = true;
|
confirmVisible.value = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const getContainer = () => {
|
||||||
|
return document.querySelector('.tdesign-starter-layout');
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
:xs="6"
|
:xs="6"
|
||||||
:xl="3"
|
:xl="3"
|
||||||
>
|
>
|
||||||
<card
|
<product-card
|
||||||
class="list-card-item"
|
class="list-card-item"
|
||||||
:product="product"
|
:product="product"
|
||||||
@delete-item="handleDeleteItem"
|
@delete-item="handleDeleteItem"
|
||||||
|
@ -71,7 +71,7 @@ export default {
|
||||||
import { ref, computed, onMounted } from 'vue';
|
import { ref, computed, onMounted } from 'vue';
|
||||||
import { SearchIcon } from 'tdesign-icons-vue-next';
|
import { SearchIcon } from 'tdesign-icons-vue-next';
|
||||||
import { MessagePlugin } from 'tdesign-vue-next';
|
import { MessagePlugin } from 'tdesign-vue-next';
|
||||||
import Card from '@/components/card/Card.vue';
|
import ProductCard from '@/components/product-card/index.vue';
|
||||||
import DialogForm from './components/DialogForm.vue';
|
import DialogForm from './components/DialogForm.vue';
|
||||||
import request from '@/utils/request';
|
import request from '@/utils/request';
|
||||||
import { ResDataType } from '@/interface';
|
import { ResDataType } from '@/interface';
|
||||||
|
|
|
@ -121,7 +121,8 @@ const COLUMNS = [
|
||||||
{
|
{
|
||||||
title: '合同名称',
|
title: '合同名称',
|
||||||
fixed: 'left',
|
fixed: 'left',
|
||||||
minWidth: '300',
|
width: 200,
|
||||||
|
ellipsis: true,
|
||||||
align: 'left',
|
align: 'left',
|
||||||
colKey: 'name',
|
colKey: 'name',
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
@import '@/style/variables';
|
@import '@/style/variables';
|
||||||
|
|
||||||
.card-padding-no {
|
/deep/ .t-card__title {
|
||||||
padding-left: 0;
|
font-size: 20px;
|
||||||
padding-right: 0;
|
font-weight: 500;
|
||||||
}
|
}
|
||||||
|
|
||||||
.user-left-greeting {
|
.user-left-greeting {
|
||||||
|
@ -66,7 +66,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.user-intro {
|
.user-intro {
|
||||||
padding: 48px;
|
padding: 32px 24px;
|
||||||
background: @brand-color;
|
background: @brand-color;
|
||||||
border-radius: @border-radius;
|
border-radius: @border-radius;
|
||||||
color: @text-color-primary;
|
color: @text-color-primary;
|
||||||
|
@ -123,7 +123,6 @@
|
||||||
|
|
||||||
.content-container {
|
.content-container {
|
||||||
margin-top: 16px;
|
margin-top: 16px;
|
||||||
padding: 28px 32px;
|
|
||||||
background: @bg-color-container;
|
background: @bg-color-container;
|
||||||
border-radius: @border-radius;
|
border-radius: @border-radius;
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,8 +9,8 @@
|
||||||
<img src="@/assets/assets-tencent-logo.png" class="logo" />
|
<img src="@/assets/assets-tencent-logo.png" class="logo" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<card class="user-info-list" size="small" title="个人信息">
|
<t-card class="user-info-list" title="个人信息">
|
||||||
<template #option>
|
<template #actions>
|
||||||
<t-button theme="default" shape="square" variant="text">
|
<t-button theme="default" shape="square" variant="text">
|
||||||
<t-icon name="edit" size="18" />
|
<t-icon name="edit" size="18" />
|
||||||
</t-button>
|
</t-button>
|
||||||
|
@ -25,16 +25,16 @@
|
||||||
</div>
|
</div>
|
||||||
</t-col>
|
</t-col>
|
||||||
</t-row>
|
</t-row>
|
||||||
</card>
|
</t-card>
|
||||||
|
|
||||||
<card class="content-container">
|
<t-card class="content-container">
|
||||||
<t-tabs value="second">
|
<t-tabs value="second">
|
||||||
<t-tab-panel value="first" label="内容列表">
|
<t-tab-panel value="first" label="内容列表">
|
||||||
<p>内容列表</p>
|
<p>内容列表</p>
|
||||||
</t-tab-panel>
|
</t-tab-panel>
|
||||||
<t-tab-panel value="second" label="内容列表">
|
<t-tab-panel value="second" label="内容列表">
|
||||||
<card class="card-padding-no" title="主页访问数据" describe="(次)">
|
<t-card :bordered="false" class="card-padding-no" title="主页访问数据" describe="(次)">
|
||||||
<template #option>
|
<template #actions>
|
||||||
<t-date-picker
|
<t-date-picker
|
||||||
class="card-date-picker-container"
|
class="card-date-picker-container"
|
||||||
:default-value="LAST_7_DAYS"
|
:default-value="LAST_7_DAYS"
|
||||||
|
@ -45,24 +45,24 @@
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
<div id="lineContainer" style="width: 100%; height: 330px" />
|
<div id="lineContainer" style="width: 100%; height: 330px" />
|
||||||
</card>
|
</t-card>
|
||||||
</t-tab-panel>
|
</t-tab-panel>
|
||||||
<t-tab-panel value="third" label="内容列表">
|
<t-tab-panel value="third" label="内容列表">
|
||||||
<p>内容列表</p>
|
<p>内容列表</p>
|
||||||
</t-tab-panel>
|
</t-tab-panel>
|
||||||
</t-tabs>
|
</t-tabs>
|
||||||
</card>
|
</t-card>
|
||||||
</t-col>
|
</t-col>
|
||||||
|
|
||||||
<t-col :flex="1">
|
<t-col :flex="1">
|
||||||
<card class="user-intro">
|
<t-card class="user-intro">
|
||||||
<t-avatar size="90px">T</t-avatar>
|
<t-avatar size="90px">T</t-avatar>
|
||||||
<div class="name">My Account</div>
|
<div class="name">My Account</div>
|
||||||
<div class="position">XXG 港澳业务拓展组员工 直客销售</div>
|
<div class="position">XXG 港澳业务拓展组员工 直客销售</div>
|
||||||
</card>
|
</t-card>
|
||||||
|
|
||||||
<card title="团队成员" class="user-team" size="small">
|
<t-card title="团队成员" class="user-team">
|
||||||
<template #option>
|
<template #actions>
|
||||||
<t-button theme="default" shape="square" variant="text">
|
<t-button theme="default" shape="square" variant="text">
|
||||||
<t-icon name="edit" size="18" />
|
<t-icon name="edit" size="18" />
|
||||||
</t-button>
|
</t-button>
|
||||||
|
@ -72,10 +72,10 @@
|
||||||
<t-list-item-meta :image="item.avatar" :title="item.title" :description="item.description" />
|
<t-list-item-meta :image="item.avatar" :title="item.title" :description="item.description" />
|
||||||
</t-list-item>
|
</t-list-item>
|
||||||
</t-list>
|
</t-list>
|
||||||
</card>
|
</t-card>
|
||||||
|
|
||||||
<card title="服务产品" class="product-container" size="small">
|
<t-card title="服务产品" class="product-container">
|
||||||
<template #option>
|
<template #actions>
|
||||||
<t-button theme="default" shape="square" variant="text">
|
<t-button theme="default" shape="square" variant="text">
|
||||||
<t-icon name="edit" size="18" />
|
<t-icon name="edit" size="18" />
|
||||||
</t-button>
|
</t-button>
|
||||||
|
@ -85,7 +85,7 @@
|
||||||
<component :is="getIcon(item)"></component>
|
<component :is="getIcon(item)"></component>
|
||||||
</t-col>
|
</t-col>
|
||||||
</t-row>
|
</t-row>
|
||||||
</card>
|
</t-card>
|
||||||
</t-col>
|
</t-col>
|
||||||
</t-row>
|
</t-row>
|
||||||
</template>
|
</template>
|
||||||
|
@ -111,8 +111,6 @@ import ProductCIcon from '@/assets/assets-product-3.svg';
|
||||||
import ProductDIcon from '@/assets/assets-product-4.svg';
|
import ProductDIcon from '@/assets/assets-product-4.svg';
|
||||||
import { changeChartsTheme } from '@/utils/color';
|
import { changeChartsTheme } from '@/utils/color';
|
||||||
|
|
||||||
import Card from '@/components/card/index.vue';
|
|
||||||
|
|
||||||
echarts.use([GridComponent, TooltipComponent, LineChart, CanvasRenderer, LegendComponent]);
|
echarts.use([GridComponent, TooltipComponent, LineChart, CanvasRenderer, LegendComponent]);
|
||||||
|
|
||||||
let lineContainer: HTMLElement;
|
let lineContainer: HTMLElement;
|
||||||
|
|
|
@ -75,7 +75,3 @@ p {
|
||||||
.container-base-margin-top {
|
.container-base-margin-top {
|
||||||
margin-top: 16px;
|
margin-top: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.card-date-picker-container {
|
|
||||||
width: 240px;
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
@import './variables.less';
|
@import './variables.less';
|
||||||
@import './font-family.less';
|
@import './font-family.less';
|
||||||
|
|
||||||
|
|
||||||
// layout rewrite
|
// layout rewrite
|
||||||
|
|
||||||
.t-layout__sider {
|
.t-layout__sider {
|
||||||
|
@ -20,7 +19,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.t-menu--dark .t-menu__operations .t-icon {
|
.t-menu--dark .t-menu__operations .t-icon {
|
||||||
color: rgba(255, 255, 255, .55);
|
color: rgba(255, 255, 255, 0.55);
|
||||||
&:hover {
|
&:hover {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
@ -37,7 +36,6 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.@{prefix} {
|
.@{prefix} {
|
||||||
|
|
||||||
// 布局元素调整
|
// 布局元素调整
|
||||||
&-wrapper {
|
&-wrapper {
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
|
@ -45,7 +43,7 @@
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
|
|
||||||
&-main-wrapper{
|
&-main-wrapper {
|
||||||
height: 500px;
|
height: 500px;
|
||||||
overflow: scroll;
|
overflow: scroll;
|
||||||
}
|
}
|
||||||
|
@ -60,7 +58,7 @@
|
||||||
padding: @spacer-3;
|
padding: @spacer-3;
|
||||||
}
|
}
|
||||||
|
|
||||||
&-layout{
|
&-layout {
|
||||||
height: calc(100vh - 64px);
|
height: calc(100vh - 64px);
|
||||||
overflow-y: scroll;
|
overflow-y: scroll;
|
||||||
&-tabs-nav {
|
&-tabs-nav {
|
||||||
|
@ -177,3 +175,7 @@
|
||||||
color: @text-color-primary;
|
color: @text-color-primary;
|
||||||
opacity: 0.4;
|
opacity: 0.4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.t-menu__popup {
|
||||||
|
z-index: 1000;
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user