mirror of
https://github.com/Tencent/tdesign-vue-next-starter.git
synced 2024-11-10 07:28: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">
|
||||
<template #logo>
|
||||
<span v-if="showLogo" class="header-logo-container" @click="handleNav('/dashboard/base')">
|
||||
<tLogoFull class="t-logo" />
|
||||
<LogoFull class="t-logo" />
|
||||
</span>
|
||||
<div v-else class="header-operate-left">
|
||||
<t-button theme="default" shape="square" variant="text" @click="changeCollapsed">
|
||||
|
@ -69,7 +69,7 @@ import { useRouter } from 'vue-router';
|
|||
import { useSettingStore } from '@/store';
|
||||
import { getActive } from '@/router';
|
||||
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 Notice from './Notice.vue';
|
||||
|
@ -161,24 +161,6 @@ const navToHelper = () => {
|
|||
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 {
|
||||
cursor: pointer;
|
||||
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,
|
||||
colKey: 'productName',
|
||||
title: '客户名称',
|
||||
minWidth: 200,
|
||||
width: 150,
|
||||
},
|
||||
{
|
||||
align: 'center',
|
||||
|
@ -174,8 +174,8 @@ export const BUY_COLUMNS: TdBaseTableProps['columns'] = [
|
|||
align: 'left',
|
||||
ellipsis: true,
|
||||
colKey: 'productName',
|
||||
width: 150,
|
||||
title: '供应商名称',
|
||||
minWidth: 200,
|
||||
},
|
||||
{
|
||||
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>
|
||||
<div>
|
||||
<t-row :gutter="[16, 16]">
|
||||
<t-col v-for="(item, index) in PANE_LIST" :key="item.title" :xs="6" :xl="3">
|
||||
<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>
|
||||
|
||||
<!-- 顶部 card -->
|
||||
<top-panel class="row-container" />
|
||||
<!-- 中部图表 -->
|
||||
<t-row :gutter="16" 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>
|
||||
|
||||
<middle-chart class="row-container" />
|
||||
<!-- 列表排名 -->
|
||||
<t-row :gutter="16" 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>
|
||||
|
||||
<rank-list class="row-container" />
|
||||
<!-- 出入库概览 -->
|
||||
<div class="row-container overview-panel">
|
||||
<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>
|
||||
<over-view class="row-container" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -210,214 +18,14 @@ export default {
|
|||
</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 { 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 }];
|
||||
};
|
||||
import TopPanel from './components/top-panel.vue';
|
||||
import MiddleChart from './components/middle-chart.vue';
|
||||
import RankList from './components/rank-list.vue';
|
||||
import OverView from './components/overview.vue';
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
@import './index.less';
|
||||
</style>
|
||||
|
||||
<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 scoped>
|
||||
.row-container {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
</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>
|
||||
<div class="dashboard-panel-detail">
|
||||
<card title="本月采购申请情况">
|
||||
<t-card title="本月采购申请情况" class="dashboard-detail-card">
|
||||
<t-row :gutter="[16, 16]">
|
||||
<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">
|
||||
<div class="number">{{ item.number }}</div>
|
||||
<div class="dashboard-detail-container-item-text">
|
||||
<div class="dashboard-detail-container-item-text-left">
|
||||
<t-card class="dashboard-list-card" :description="item.title">
|
||||
<div class="dashboard-list-card__number">{{ item.number }}</div>
|
||||
<div class="dashboard-list-card__text">
|
||||
<div class="dashboard-list-card__text-left">
|
||||
环比
|
||||
<trend class="icon" :type="item.upTrend ? 'up' : 'down'" :describe="item.upTrend || item.downTrend" />
|
||||
</div>
|
||||
<t-icon name="chevron-right" />
|
||||
</div>
|
||||
</card>
|
||||
</t-card>
|
||||
</t-col>
|
||||
</t-row>
|
||||
</card>
|
||||
<t-row :gutter="[16, 16]" class="card-container-margin">
|
||||
</t-card>
|
||||
<t-row :gutter="[16, 16]" class="row-margin">
|
||||
<t-col :xs="12" :xl="9">
|
||||
<card title="采购商品申请趋势" describe="(件)">
|
||||
<template #option>
|
||||
<t-card class="dashboard-detail-card" title="采购商品申请趋势" subtitle="(件)">
|
||||
<template #actions>
|
||||
<t-date-picker
|
||||
class="card-date-picker-container"
|
||||
:default-value="LAST_7_DAYS"
|
||||
theme="primary"
|
||||
mode="date"
|
||||
range
|
||||
style="width: 240px"
|
||||
@change="onMaterialChange"
|
||||
/>
|
||||
</template>
|
||||
<div id="lineContainer" style="width: 100%; height: 406px" />
|
||||
</card>
|
||||
<div id="lineContainer" style="width: 100%; height: 410px" />
|
||||
</t-card>
|
||||
</t-col>
|
||||
<t-col :xs="12" :xl="3">
|
||||
<product-card
|
||||
v-for="(item, index) in PRODUCT_LIST"
|
||||
:key="index"
|
||||
:product="item"
|
||||
:class="{ 'card-container-margin': index !== 0 }"
|
||||
:class="{ 'row-margin': index !== 0 }"
|
||||
/>
|
||||
</t-col>
|
||||
</t-row>
|
||||
<card title="采购商品满意度分布" class="card-container-margin">
|
||||
<template #option>
|
||||
<t-card :class="['dashboard-detail-card', 'row-margin']" title="采购商品满意度分布">
|
||||
<template #actions>
|
||||
<t-date-picker
|
||||
class="card-date-picker-container"
|
||||
:default-value="LAST_7_DAYS"
|
||||
theme="primary"
|
||||
mode="date"
|
||||
range
|
||||
style="display: inline-block; margin-right: 8px; width: 240px"
|
||||
@change="onSatisfyChange"
|
||||
/>
|
||||
<t-button class="card-date-button"> 导出数据 </t-button>
|
||||
</template>
|
||||
<div id="scatterContainer" style="width: 100%; height: 330px" />
|
||||
</card>
|
||||
</t-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -71,7 +73,7 @@ import * as echarts from 'echarts/core';
|
|||
import { GridComponent, TooltipComponent, LegendComponent } from 'echarts/components';
|
||||
import { LineChart, ScatterChart } from 'echarts/charts';
|
||||
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 { PANE_LIST_DATA, PRODUCT_LIST } from './constants';
|
||||
|
@ -80,7 +82,6 @@ import { useSettingStore } from '@/store';
|
|||
import { changeChartsTheme } from '@/utils/color';
|
||||
|
||||
import Trend from '@/components/trend/index.vue';
|
||||
import Card from '@/components/card/index.vue';
|
||||
|
||||
echarts.use([GridComponent, LegendComponent, TooltipComponent, LineChart, ScatterChart, CanvasRenderer]);
|
||||
|
||||
|
@ -159,5 +160,82 @@ const onMaterialChange = (value: string[]) => {
|
|||
</script>
|
||||
|
||||
<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>
|
||||
|
|
|
@ -1,5 +1,23 @@
|
|||
@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 {
|
||||
.t-col-xl-4 + .t-col-xl-4 {
|
||||
@media (max-width: @screen-lg-max) {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<template>
|
||||
<div>
|
||||
<card title="基本信息">
|
||||
<div class="detail-advanced">
|
||||
<t-card title="基本信息">
|
||||
<div class="info-block">
|
||||
<div v-for="(item, index) in BASE_INFO_DATA" :key="index" class="info-item">
|
||||
<h1>{{ item.name }}</h1>
|
||||
|
@ -15,10 +15,10 @@
|
|||
</span>
|
||||
</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-steps :current="updateCurrent">
|
||||
<t-step-item title="申请提交" content="已于12月21日提交" />
|
||||
|
@ -27,10 +27,10 @@
|
|||
<t-step-item title="完成" content />
|
||||
</t-steps>
|
||||
</t-row>
|
||||
</card>
|
||||
</t-card>
|
||||
|
||||
<!-- 产品目录 -->
|
||||
<card title="产品目录" class="container-base-margin-top">
|
||||
<t-card title="产品目录" class="container-base-margin-top">
|
||||
<template #option>
|
||||
<t-radio-group default-value="dateVal">
|
||||
<t-radio-button value="dateVal"> 季度 </t-radio-button>
|
||||
|
@ -50,10 +50,10 @@
|
|||
<product :data="item" />
|
||||
</t-col>
|
||||
</t-row>
|
||||
</card>
|
||||
</t-card>
|
||||
|
||||
<!-- 产品采购明细 -->
|
||||
<card title="产品采购明细" class="container-base-margin-top">
|
||||
<t-card title="产品采购明细" class="container-base-margin-top">
|
||||
<t-table
|
||||
:columns="columns"
|
||||
:data="data"
|
||||
|
@ -87,7 +87,7 @@
|
|||
<t-icon name="descending-order" />
|
||||
</template>
|
||||
</t-table>
|
||||
</card>
|
||||
</t-card>
|
||||
|
||||
<t-dialog v-model:visible="visible" header="基本信息" @confirm="onConfirm">
|
||||
<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 { ResDataType } from '@/interface';
|
||||
|
||||
import Card from '@/components/card/index.vue';
|
||||
import Product from './components/Product.vue';
|
||||
|
||||
const data = ref([]);
|
||||
|
|
|
@ -1,7 +1,18 @@
|
|||
@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;
|
||||
}
|
||||
}
|
||||
|
||||
.info-block {
|
||||
|
@ -59,7 +70,6 @@
|
|||
}
|
||||
|
||||
.dialog-info-block {
|
||||
|
||||
.info-item {
|
||||
padding: 12px 0;
|
||||
display: flex;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<template>
|
||||
<div>
|
||||
<card title="基本信息">
|
||||
<div class="detail-base">
|
||||
<t-card title="基本信息">
|
||||
<div class="info-block">
|
||||
<div v-for="(item, index) in BASE_INFO_DATA" :key="index" class="info-item">
|
||||
<h1>{{ item.name }}</h1>
|
||||
|
@ -15,15 +15,15 @@
|
|||
</span>
|
||||
</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-step-item title="上传合同附件" content="这里是提示文字" />
|
||||
<t-step-item title="修改合同金额" content="这里是提示文字" />
|
||||
<t-step-item title="新建合同" content="2020-12-01 15:00:00 管理员-李川操作" />
|
||||
</t-steps>
|
||||
</card>
|
||||
</t-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -34,8 +34,6 @@ export default {
|
|||
</script>
|
||||
|
||||
<script setup lang="ts">
|
||||
import Card from '@/components/card/index.vue';
|
||||
|
||||
const BASE_INFO_DATA = [
|
||||
{
|
||||
name: '合同名称',
|
||||
|
|
|
@ -83,7 +83,7 @@ export const BASE_INFO_DATA = [
|
|||
|
||||
export const TABLE_COLUMNS = [
|
||||
{
|
||||
minWidth: '448',
|
||||
width: '448',
|
||||
ellipsis: true,
|
||||
colKey: 'name',
|
||||
title: '项目名称',
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
<template>
|
||||
<div>
|
||||
<div class="detail-deploy">
|
||||
<t-row :gutter="16">
|
||||
<t-col :span="6">
|
||||
<card title="部署趋势">
|
||||
<t-col :lg="6" :xs="12">
|
||||
<t-card title="部署趋势">
|
||||
<div class="deploy-panel-left">
|
||||
<div id="monitorContainer" style="width: 100%; height: 265px" />
|
||||
</div>
|
||||
</card>
|
||||
</t-card>
|
||||
</t-col>
|
||||
<t-col :span="6">
|
||||
<card title="告警情况">
|
||||
<t-col :lg="6" :xs="12">
|
||||
<t-card title="告警情况">
|
||||
<template #option>
|
||||
<t-radio-group default-value="dateVal" @change="onAlertChange">
|
||||
<t-radio-button value="dateVal"> 本周 </t-radio-button>
|
||||
|
@ -17,12 +17,12 @@
|
|||
</t-radio-group>
|
||||
</template>
|
||||
<div id="dataContainer" style="width: 100%; height: 265px" />
|
||||
</card>
|
||||
</t-card>
|
||||
</t-col>
|
||||
</t-row>
|
||||
|
||||
<!-- 项目列表 -->
|
||||
<card title="项目列表" class="container-base-margin-top">
|
||||
<t-card title="项目列表" class="container-base-margin-top">
|
||||
<t-table
|
||||
:columns="columns"
|
||||
:data="data"
|
||||
|
@ -46,7 +46,7 @@
|
|||
<t-icon name="descending-order" />
|
||||
</template>
|
||||
</t-table>
|
||||
</card>
|
||||
</t-card>
|
||||
|
||||
<t-dialog v-model:visible="visible" header="基本信息" @confirm="onConfirm">
|
||||
<template #body>
|
||||
|
@ -89,7 +89,6 @@ import { BASE_INFO_DATA, TABLE_COLUMNS as columns } from './constants';
|
|||
import { changeChartsTheme } from '@/utils/color';
|
||||
|
||||
import { prefix } from '@/config/global';
|
||||
import Card from '@/components/card/index.vue';
|
||||
import { ResDataType } from '@/interface';
|
||||
import request from '@/utils/request';
|
||||
|
||||
|
@ -205,5 +204,14 @@ const deleteClickOp = (e) => {
|
|||
</script>
|
||||
|
||||
<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>
|
||||
|
|
|
@ -2,6 +2,10 @@
|
|||
|
||||
.form-step-container {
|
||||
background-color: @bg-color-container;
|
||||
|
||||
.t-card {
|
||||
padding: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
.rule-tips {
|
||||
|
@ -15,3 +19,19 @@
|
|||
.step-form {
|
||||
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 class="form-step-container">
|
||||
<!-- 简单步骤条 -->
|
||||
<card title="基本信息">
|
||||
<t-card :bordered="false">
|
||||
<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-steps>
|
||||
</card>
|
||||
</t-card>
|
||||
|
||||
<!-- 分步表单1 -->
|
||||
<div v-show="activeForm === 0" class="rule-tips">
|
||||
|
@ -150,7 +150,6 @@ export default {
|
|||
import { ref, computed } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { ValidateResultContext } from 'tdesign-vue-next';
|
||||
import Card from '@/components/card/index.vue';
|
||||
|
||||
import {
|
||||
FORM_RULES,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<template>
|
||||
<div>
|
||||
<card class="list-card-container">
|
||||
<t-card class="list-card-container">
|
||||
<t-row justify="space-between">
|
||||
<div class="left-operation-container">
|
||||
<t-button @click="handleSetupContract"> 新建合同 </t-button>
|
||||
|
@ -15,7 +15,7 @@
|
|||
</t-input>
|
||||
</div>
|
||||
</t-row>
|
||||
|
||||
<!-- 如果开启多标签tab页 请修改offsetTop的配置 -->
|
||||
<t-table
|
||||
:data="data"
|
||||
:columns="COLUMNS"
|
||||
|
@ -25,6 +25,8 @@
|
|||
:pagination="pagination"
|
||||
:selected-row-keys="selectedRowKeys"
|
||||
:loading="dataLoading"
|
||||
:header-affixed-top="true"
|
||||
:header-affix-props="{ offsetTop: 0, container: getContainer }"
|
||||
@page-change="rehandlePageChange"
|
||||
@change="rehandleChange"
|
||||
@select-change="rehandleSelectChange"
|
||||
|
@ -55,7 +57,7 @@
|
|||
<a class="t-button-link" @click="handleClickDelete(slotProps)">删除</a>
|
||||
</template>
|
||||
</t-table>
|
||||
</card>
|
||||
</t-card>
|
||||
|
||||
<t-dialog
|
||||
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 Trend from '@/components/trend/index.vue';
|
||||
import Card from '@/components/card/index.vue';
|
||||
import { ResDataType } from '@/interface';
|
||||
import request from '@/utils/request';
|
||||
|
||||
|
@ -177,6 +178,10 @@ const handleClickDelete = (row: { rowIndex: any }) => {
|
|||
deleteIdx.value = row.rowIndex;
|
||||
confirmVisible.value = true;
|
||||
};
|
||||
|
||||
const getContainer = () => {
|
||||
return document.querySelector('.tdesign-starter-layout');
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
:xs="6"
|
||||
:xl="3"
|
||||
>
|
||||
<card
|
||||
<product-card
|
||||
class="list-card-item"
|
||||
:product="product"
|
||||
@delete-item="handleDeleteItem"
|
||||
|
@ -71,7 +71,7 @@ export default {
|
|||
import { ref, computed, onMounted } from 'vue';
|
||||
import { SearchIcon } from 'tdesign-icons-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 request from '@/utils/request';
|
||||
import { ResDataType } from '@/interface';
|
||||
|
|
|
@ -121,7 +121,8 @@ const COLUMNS = [
|
|||
{
|
||||
title: '合同名称',
|
||||
fixed: 'left',
|
||||
minWidth: '300',
|
||||
width: 200,
|
||||
ellipsis: true,
|
||||
align: 'left',
|
||||
colKey: 'name',
|
||||
},
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
@import '@/style/variables';
|
||||
|
||||
.card-padding-no {
|
||||
padding-left: 0;
|
||||
padding-right: 0;
|
||||
/deep/ .t-card__title {
|
||||
font-size: 20px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.user-left-greeting {
|
||||
|
@ -66,7 +66,7 @@
|
|||
}
|
||||
|
||||
.user-intro {
|
||||
padding: 48px;
|
||||
padding: 32px 24px;
|
||||
background: @brand-color;
|
||||
border-radius: @border-radius;
|
||||
color: @text-color-primary;
|
||||
|
@ -123,7 +123,6 @@
|
|||
|
||||
.content-container {
|
||||
margin-top: 16px;
|
||||
padding: 28px 32px;
|
||||
background: @bg-color-container;
|
||||
border-radius: @border-radius;
|
||||
}
|
||||
|
|
|
@ -9,8 +9,8 @@
|
|||
<img src="@/assets/assets-tencent-logo.png" class="logo" />
|
||||
</div>
|
||||
|
||||
<card class="user-info-list" size="small" title="个人信息">
|
||||
<template #option>
|
||||
<t-card class="user-info-list" title="个人信息">
|
||||
<template #actions>
|
||||
<t-button theme="default" shape="square" variant="text">
|
||||
<t-icon name="edit" size="18" />
|
||||
</t-button>
|
||||
|
@ -25,16 +25,16 @@
|
|||
</div>
|
||||
</t-col>
|
||||
</t-row>
|
||||
</card>
|
||||
</t-card>
|
||||
|
||||
<card class="content-container">
|
||||
<t-card class="content-container">
|
||||
<t-tabs value="second">
|
||||
<t-tab-panel value="first" label="内容列表">
|
||||
<p>内容列表</p>
|
||||
</t-tab-panel>
|
||||
<t-tab-panel value="second" label="内容列表">
|
||||
<card class="card-padding-no" title="主页访问数据" describe="(次)">
|
||||
<template #option>
|
||||
<t-card :bordered="false" class="card-padding-no" title="主页访问数据" describe="(次)">
|
||||
<template #actions>
|
||||
<t-date-picker
|
||||
class="card-date-picker-container"
|
||||
:default-value="LAST_7_DAYS"
|
||||
|
@ -45,24 +45,24 @@
|
|||
/>
|
||||
</template>
|
||||
<div id="lineContainer" style="width: 100%; height: 330px" />
|
||||
</card>
|
||||
</t-card>
|
||||
</t-tab-panel>
|
||||
<t-tab-panel value="third" label="内容列表">
|
||||
<p>内容列表</p>
|
||||
</t-tab-panel>
|
||||
</t-tabs>
|
||||
</card>
|
||||
</t-card>
|
||||
</t-col>
|
||||
|
||||
<t-col :flex="1">
|
||||
<card class="user-intro">
|
||||
<t-card class="user-intro">
|
||||
<t-avatar size="90px">T</t-avatar>
|
||||
<div class="name">My Account</div>
|
||||
<div class="position">XXG 港澳业务拓展组员工 直客销售</div>
|
||||
</card>
|
||||
</t-card>
|
||||
|
||||
<card title="团队成员" class="user-team" size="small">
|
||||
<template #option>
|
||||
<t-card title="团队成员" class="user-team">
|
||||
<template #actions>
|
||||
<t-button theme="default" shape="square" variant="text">
|
||||
<t-icon name="edit" size="18" />
|
||||
</t-button>
|
||||
|
@ -72,10 +72,10 @@
|
|||
<t-list-item-meta :image="item.avatar" :title="item.title" :description="item.description" />
|
||||
</t-list-item>
|
||||
</t-list>
|
||||
</card>
|
||||
</t-card>
|
||||
|
||||
<card title="服务产品" class="product-container" size="small">
|
||||
<template #option>
|
||||
<t-card title="服务产品" class="product-container">
|
||||
<template #actions>
|
||||
<t-button theme="default" shape="square" variant="text">
|
||||
<t-icon name="edit" size="18" />
|
||||
</t-button>
|
||||
|
@ -85,7 +85,7 @@
|
|||
<component :is="getIcon(item)"></component>
|
||||
</t-col>
|
||||
</t-row>
|
||||
</card>
|
||||
</t-card>
|
||||
</t-col>
|
||||
</t-row>
|
||||
</template>
|
||||
|
@ -111,8 +111,6 @@ import ProductCIcon from '@/assets/assets-product-3.svg';
|
|||
import ProductDIcon from '@/assets/assets-product-4.svg';
|
||||
import { changeChartsTheme } from '@/utils/color';
|
||||
|
||||
import Card from '@/components/card/index.vue';
|
||||
|
||||
echarts.use([GridComponent, TooltipComponent, LineChart, CanvasRenderer, LegendComponent]);
|
||||
|
||||
let lineContainer: HTMLElement;
|
||||
|
|
|
@ -75,7 +75,3 @@ p {
|
|||
.container-base-margin-top {
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
.card-date-picker-container {
|
||||
width: 240px;
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
@import './variables.less';
|
||||
@import './font-family.less';
|
||||
|
||||
|
||||
// layout rewrite
|
||||
|
||||
.t-layout__sider {
|
||||
|
@ -20,7 +19,7 @@
|
|||
}
|
||||
|
||||
.t-menu--dark .t-menu__operations .t-icon {
|
||||
color: rgba(255, 255, 255, .55);
|
||||
color: rgba(255, 255, 255, 0.55);
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
@ -37,7 +36,6 @@
|
|||
}
|
||||
|
||||
.@{prefix} {
|
||||
|
||||
// 布局元素调整
|
||||
&-wrapper {
|
||||
height: 100vh;
|
||||
|
@ -45,7 +43,7 @@
|
|||
flex-direction: column;
|
||||
}
|
||||
|
||||
&-main-wrapper{
|
||||
&-main-wrapper {
|
||||
height: 500px;
|
||||
overflow: scroll;
|
||||
}
|
||||
|
@ -60,7 +58,7 @@
|
|||
padding: @spacer-3;
|
||||
}
|
||||
|
||||
&-layout{
|
||||
&-layout {
|
||||
height: calc(100vh - 64px);
|
||||
overflow-y: scroll;
|
||||
&-tabs-nav {
|
||||
|
@ -177,3 +175,7 @@
|
|||
color: @text-color-primary;
|
||||
opacity: 0.4;
|
||||
}
|
||||
|
||||
.t-menu__popup {
|
||||
z-index: 1000;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user