refactor(card): replace all card with t-card

This commit is contained in:
Uyarn 2022-04-28 14:19:32 +08:00 committed by PY
parent 991f0588e2
commit 915a6bd118
28 changed files with 1104 additions and 1032 deletions

View File

@ -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>

View File

@ -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>

View 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>

View File

@ -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;

View 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>

View 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>

View 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>

View 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>

View File

@ -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',

View File

@ -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;
}

View File

@ -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>

View File

@ -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;
}

View File

@ -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>

View File

@ -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) {

View File

@ -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([]);

View File

@ -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;

View File

@ -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: '合同名称',

View File

@ -83,7 +83,7 @@ export const BASE_INFO_DATA = [
export const TABLE_COLUMNS = [
{
minWidth: '448',
width: '448',
ellipsis: true,
colKey: 'name',
title: '项目名称',

View File

@ -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>

View File

@ -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;
}
}

View File

@ -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,

View File

@ -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>

View File

@ -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';

View File

@ -121,7 +121,8 @@ const COLUMNS = [
{
title: '合同名称',
fixed: 'left',
minWidth: '300',
width: 200,
ellipsis: true,
align: 'left',
colKey: 'name',
},

View File

@ -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;
}

View File

@ -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;

View File

@ -75,7 +75,3 @@ p {
.container-base-margin-top {
margin-top: 16px;
}
.card-date-picker-container {
width: 240px;
}

View File

@ -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;
}