Merge branch 'dev' of github.com:jetlinks/jetlinks-ui-vue into dev

This commit is contained in:
easy 2023-02-03 18:15:42 +08:00
commit 3d22650763
5 changed files with 493 additions and 132 deletions

View File

@ -13,21 +13,24 @@
<a-card>
<a-descriptions size="small" :column="3" bordered>
<template #title>
<span key="1">基本信息</span>
<a-button
key="2"
type="link"
@click="
() => {
visible = true;
current = detail;
saveType = 'edit';
}
"
>
<AIcon type="EditOutlined"></AIcon>
编辑
</a-button>
<Guide>
<template #title>
<span>基本信息</span>
<a-button
type="link"
@click="
() => {
visible = true;
current = detail;
saveType = 'edit';
}
"
>
<AIcon type="EditOutlined"></AIcon>
编辑
</a-button>
</template>
</Guide>
</template>
<a-descriptions-item label="卡号">{{
@ -91,27 +94,82 @@
</a-col>
<a-col :span="24">
<!-- 流量统计 -->
<a-row :gutter="40">
<a-row :gutter="24">
<a-col :span="16">
<div class="card">
<Guide title="流量统计">
<template #extra></template>
<template #extra>
<TimeSelect
:type="'week'"
:quickBtnList="quickBtnList"
@change="getEcharts"
/>
</template>
</Guide>
<LineChart
:showX="true"
:showY="true"
style="min-height: 450px"
style="min-height: 490px"
:chartData="flowData"
/>
</div>
</a-col>
<a-col :span="8">
<div class="card">
<a-row :gutter="20">
<a-col :span="24">
<Guide title="数据统计" />
</a-col>
</a-row>
<Guide title="数据统计" />
<div class="static-info" style="min-height: 490px">
<div class="data-statistics-item">
<div class="info" style="width: 100%">
<div class="label">昨日流量消耗</div>
<a-tooltip placement="bottomLeft">
<template #title>
<span>{{ dayTotal }} M</span>
</template>
<div class="value">
{{ dayTotal }}
<span class="unit">M</span>
</div>
</a-tooltip>
</div>
<LineChart
color="#FBA500"
:chartData="dayOptions"
/>
</div>
<div class="data-statistics-item">
<div class="info" style="width: 100%">
<div class="label">当月流量消耗</div>
<a-tooltip placement="bottomLeft">
<template #title>
<span>{{ monthTotal }} M</span>
</template>
<div class="value">
{{ monthTotal }}
<span class="unit">M</span>
</div>
</a-tooltip>
</div>
<LineChart :chartData="monthOptions" />
</div>
<div class="data-statistics-item">
<div class="info" style="width: 100%">
<div class="label">本年流量消耗</div>
<a-tooltip placement="bottomLeft">
<template #title>
<span>{{ yearTotal }} M</span>
</template>
<div class="value">
{{ yearTotal }}
<span class="unit">M</span>
</div>
</a-tooltip>
</div>
<LineChart
color="#58E1D3"
:chartData="yearOptions"
/>
</div>
</div>
</div>
</a-col>
</a-row>
@ -127,6 +185,8 @@ import { queryDetail } from '@/api/iot-card/cardManagement';
import Save from '../Save.vue';
import Guide from '@/views/iot-card/components/Guide.vue';
import LineChart from '@/views/iot-card/components/LineChart.vue';
import { queryFlow } from '@/api/iot-card/home';
import TimeSelect from '@/views/iot-card/components/TimeSelect.vue';
const route = useRoute();
@ -136,6 +196,19 @@ const saveType = ref<string>('');
const detail = ref<any>({});
const flowData = ref<any[]>([]);
const dayTotal = ref(0);
const monthTotal = ref(0);
const yearTotal = ref(0);
const dayOptions = ref<any[]>([]);
const monthOptions = ref<any[]>([]);
const yearOptions = ref<any[]>([]);
const quickBtnList = [
{ label: '昨日', value: 'yesterday' },
{ label: '近一周', value: 'week' },
{ label: '近一月', value: 'month' },
{ label: '近一年', value: 'year' },
];
const getDetail = () => {
queryDetail(route.params.id).then((resp: any) => {
@ -157,11 +230,123 @@ const saveChange = (val: any) => {
}
};
const getData = (
start: number,
end: number,
): Promise<{ sortArray: any[]; data: any[] }> => {
return new Promise((resolve) => {
queryFlow(start, end, {
orderBy: 'date',
}).then((resp: any) => {
if (resp.status === 200) {
const sortArray = resp.result.sort(
(a: any, b: any) =>
new Date(a.date).getTime() - new Date(b.date).getTime(),
);
resolve({
sortArray,
data: sortArray.map(
(item: any) => item.value && item.value.toFixed(2),
),
});
}
});
});
};
/**
* 查询今日当月本年数据
*/
const getDataTotal = () => {
const dTime = [
moment(new Date()).startOf('day').valueOf(),
moment(new Date()).endOf('day').valueOf(),
];
const mTime = [
moment().startOf('month').valueOf(),
moment().endOf('month').valueOf(),
];
const yTime = [
moment().startOf('year').valueOf(),
moment().endOf('year').valueOf(),
];
getData(dTime[0], dTime[1]).then((resp) => {
dayTotal.value = resp.data
.reduce((r, n) => r + Number(n), 0)
.toFixed(2);
dayOptions.value = resp.sortArray;
});
getData(mTime[0], mTime[1]).then((resp) => {
monthTotal.value = resp.data
.reduce((r, n) => r + Number(n), 0)
.toFixed(2);
monthOptions.value = resp.sortArray;
});
getData(yTime[0], yTime[1]).then((resp) => {
yearTotal.value = resp.data
.reduce((r, n) => r + Number(n), 0)
.toFixed(2);
yearOptions.value = resp.sortArray;
});
};
/**
* 流量统计
* @param data
*/
const getEcharts = (data: any) => {
let startTime = data.start;
let endTime = data.end;
if (data.type === 'week' || data.type === 'month') {
startTime = moment(data.start).startOf('days').valueOf();
endTime = moment(data.end).startOf('days').valueOf();
}
getData(startTime, endTime).then((resp) => {
flowData.value = resp.sortArray;
});
};
getDetail();
getDataTotal();
</script>
<style scoped lang="less">
.card {
padding: 24px;
background-color: #fff;
}
.static-info {
display: flex;
flex-direction: column;
justify-content: space-around;
.data-statistics-item {
height: 140px;
background: #fcfcfc;
border: 1px solid #e0e4e8;
display: flex;
justify-content: space-between;
align-items: center;
padding: 20px;
.info {
// width: 180px;
width: 28%;
.label {
font-size: 14px;
color: rgba(0, 0, 0, 0.64);
}
.value {
font-size: 32px;
font-weight: bold;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
.unit {
font-size: 20px;
font-weight: normal;
}
}
}
}
}
</style>

View File

@ -1,109 +1,145 @@
<!-- 物联卡-仪表盘 -->
<template>
<page-container class="container">
<a-card>
<a-row :gutter="20" :style="{ marginBottom: '20px' }">
<a-col :span="24"><Guide title="数据统计" /></a-col>
<a-col :span="8">
<div class="data-statistics-item">
<div class="info" style="width: 100%">
<div class="label">昨日流量消耗</div>
<a-tooltip placement="bottomLeft">
<template #title>
<span>{{ dayTotal }} M</span>
</template>
<div class="value">
{{ dayTotal }}
<span class="unit">M</span>
</div>
</a-tooltip>
<page-container>
<div class="card-dashboard-container">
<a-card style="margin-bottom: 24px">
<a-row :gutter="24">
<a-col :span="24"><Guide title="数据统计" /></a-col>
<a-col :span="8">
<div class="data-statistics-item">
<div class="info" style="width: 100%">
<div class="label">昨日流量消耗</div>
<a-tooltip placement="bottomLeft">
<template #title>
<span>{{ dayTotal }} M</span>
</template>
<div class="value">
{{ dayTotal }}
<span class="unit">M</span>
</div>
</a-tooltip>
</div>
<LineChart
color="#FBA500"
:chartData="dayOptions"
/>
</div>
<LineChart color="#FBA500" :chartData="dayOptions" />
</div>
</a-col>
<a-col :span="8">
<div class="data-statistics-item">
<div class="info" style="width: 100%">
<div class="label">当月流量消耗</div>
<a-tooltip placement="bottomLeft">
<template #title>
<span>{{ monthTotal }} M</span>
</template>
<div class="value">
{{ monthTotal }}
<span class="unit">M</span>
</div>
</a-tooltip>
</a-col>
<a-col :span="8">
<div class="data-statistics-item">
<div class="info" style="width: 100%">
<div class="label">当月流量消耗</div>
<a-tooltip placement="bottomLeft">
<template #title>
<span>{{ monthTotal }} M</span>
</template>
<div class="value">
{{ monthTotal }}
<span class="unit">M</span>
</div>
</a-tooltip>
</div>
<LineChart :chartData="monthOptions" />
</div>
<LineChart :chartData="monthOptions" />
</div>
</a-col>
<a-col :span="8">
<div class="data-statistics-item">
<div class="info" style="width: 100%">
<div class="label">本年流量消耗</div>
<a-tooltip placement="bottomLeft">
<template #title>
<span>{{ yearTotal }} M</span>
</template>
<div class="value">
{{ yearTotal }}
<span class="unit">M</span>
</div>
</a-tooltip>
</a-col>
<a-col :span="8">
<div class="data-statistics-item">
<div class="info" style="width: 100%">
<div class="label">本年流量消耗</div>
<a-tooltip placement="bottomLeft">
<template #title>
<span>{{ yearTotal }} M</span>
</template>
<div class="value">
{{ yearTotal }}
<span class="unit">M</span>
</div>
</a-tooltip>
</div>
<LineChart
color="#58E1D3"
:chartData="yearOptions"
/>
</div>
<LineChart color="#58E1D3" :chartData="yearOptions" />
</div>
</a-col>
</a-row>
<a-row :gutter="20">
</a-col>
</a-row>
</a-card>
<a-row :gutter="24">
<a-col :span="16">
<Guide title="流量统计">
<template #extra></template>
</Guide>
<LineChart
:showX="true"
:showY="true"
style="min-height: 450px"
:chartData="yearOptions"
/>
<div class="static-card">
<Guide title="流量统计">
<template #extra>
<TimeSelect
:type="'week'"
:quickBtnList="quickBtnList"
@change="getEcharts"
/>
</template>
</Guide>
<LineChart
v-if="flowData.length !== 0"
:showX="true"
:showY="true"
style="min-height: 490px"
:chartData="flowData"
/>
<div class="empty-body" v-else>
<a-empty :image="Empty.PRESENTED_IMAGE_SIMPLE" />
</div>
</div>
</a-col>
<a-col :span="8">
<Guide title="流量使用TOP10">
<template #extra></template>
</Guide>
<div class="rankingList" style="height: 400px">
<div class="static-card">
<Guide title="流量使用TOP10">
<template #extra>
<TimeSelect
:quickBtn="false"
:type="'week'"
@change="getTopRang"
/></template>
</Guide>
<div
v-for="(item, index) in topList"
:key="item.cardNum"
class="rankItem"
v-if="topList.length !== 0"
class="rankingList"
style="min-height: 490px"
>
<div
class="number"
:class="`number-item-${index + 1}`"
v-for="(item, index) in topList"
:key="item.cardNum"
class="rankItem"
>
{{ index + 1 }}
</div>
<div class="cardNum">{{ item.cardNum }}</div>
<div class="progress">
<a-progress
:strokeColor="'#ADC6FF'"
:trailColor="'#E0E4E8'"
:strokeLinecap="'butt'"
:showInfo="false"
:percent="
Math.ceil((item.value / topTotal) * 100)
"
></a-progress>
</div>
<div class="total">
{{ item?.value?.toFixed(2) }} M
<div
class="number"
:class="`number-item-${index + 1}`"
>
{{ index + 1 }}
</div>
<div class="cardNum">{{ item.cardNum }}</div>
<div class="progress">
<a-progress
:strokeColor="'#ADC6FF'"
:trailColor="'#E0E4E8'"
:strokeLinecap="'butt'"
:showInfo="false"
:percent="
Math.ceil(
(item.value / topTotal) * 100,
)
"
></a-progress>
</div>
<div class="total">
{{ item?.value?.toFixed(2) }} M
</div>
</div>
</div>
<div class="empty-body" v-else>
<a-empty :image="Empty.PRESENTED_IMAGE_SIMPLE" />
</div>
</div>
</a-col>
</a-row>
</a-card>
</div>
</page-container>
</template>
@ -112,6 +148,8 @@ import Guide from '../components/Guide.vue';
import LineChart from '../components/LineChart.vue';
import moment from 'moment';
import { queryFlow } from '@/api/iot-card/home';
import TimeSelect from '@/views/iot-card/components/TimeSelect.vue';
import { Empty } from 'ant-design-vue';
const dayTotal = ref(0);
const monthTotal = ref(0);
@ -124,6 +162,13 @@ const flowData = ref<any[]>([]);
const topList = ref<any[]>([]);
const topTotal = ref(0);
const quickBtnList = [
{ label: '昨日', value: 'yesterday' },
{ label: '近一周', value: 'week' },
{ label: '近一月', value: 'month' },
{ label: '近一年', value: 'year' },
];
const getData = (
start: number,
end: number,
@ -189,12 +234,11 @@ const getDataTotal = () => {
* @param data
*/
const getEcharts = (data: any) => {
console.log(data);
let startTime = data.time.start;
let endTime = data.time.end;
if (data.time.type === 'week' || data.time.type === 'month') {
startTime = moment(data.time.start).startOf('days').valueOf();
endTime = moment(data.time.end).startOf('days').valueOf();
let startTime = data.start;
let endTime = data.end;
if (data.type === 'week' || data.type === 'month') {
startTime = moment(data.start).startOf('days').valueOf();
endTime = moment(data.end).startOf('days').valueOf();
}
getData(startTime, endTime).then((resp) => {
flowData.value = resp.sortArray;
@ -206,8 +250,10 @@ const getEcharts = (data: any) => {
* @param star 开始时间
* @param end 结束时间
*/
const getTopRang = (star: number, end: number) => {
queryFlow(star, end, { orderBy: 'usage' }).then((resp: any) => {
const getTopRang = (data: any) => {
let startTime = data.start;
let endTime = data.end;
queryFlow(startTime, endTime, { orderBy: 'usage' }).then((resp: any) => {
if (resp.status === 200) {
const arr = resp.result
.slice(0, 10)
@ -219,17 +265,9 @@ const getTopRang = (star: number, end: number) => {
};
getDataTotal();
// getEcharts(data);
const dTime = [
moment().subtract(6, 'days').startOf('day').valueOf(),
moment().endOf('day').valueOf(),
];
getTopRang(dTime[0], dTime[1]);
</script>
<style scoped lang="less">
.container {
.card-dashboard-container {
.data-statistics-item {
height: 140px;
background: #fcfcfc;
@ -260,6 +298,21 @@ getTopRang(dTime[0], dTime[1]);
}
}
.static-card {
background-color: #fff;
padding: 24px;
}
.empty-body {
height: 490px;
display: flex;
flex-direction: column;
align-content: center;
justify-content: center;
width: 100%;
// height: 100%;
}
.rankingList {
padding: 0;
overflow-y: auto;

View File

@ -1,6 +1,9 @@
<template>
<div class="home-title">
<div>{{ title }}</div>
<div v-if="title">{{ title }}</div>
<div v-else>
<slot name="title"></slot>
</div>
<div class="extra-text">
<slot name="extra"></slot>
</div>
@ -10,7 +13,7 @@
<script setup lang="ts" name="Guide">
interface guideProps {
title: string;
title?: string;
english?: string;
}

View File

@ -39,7 +39,7 @@ const createChart = () => {
const options = {
grid: {
left: '7%',
left: '5%',
right: '5%',
top: '5%',
bottom: '5%',

View File

@ -0,0 +1,120 @@
<template>
<div>
<a-radio-group
v-if="quickBtn"
default-value="today"
button-style="solid"
v-model:value="radioValue"
@change="(e) => handleBtnChange(e.target.value)"
>
<a-radio-button
v-for="item in quickBtnList"
:key="item.value"
:value="item.value"
>
{{ item.label }}
</a-radio-button>
</a-radio-group>
<a-range-picker
format="YYYY-MM-DD"
valueFormat="YYYY-MM-DD"
style="margin-left: 12px"
@change="rangeChange"
v-model:value="rangeVal"
:allowClear="false"
>
</a-range-picker>
</div>
</template>
<script setup lang="ts">
import moment from 'moment';
import { PropType } from 'vue';
interface BtnOptions {
label: string;
value: string;
}
interface EmitProps {
(e: 'change', data: Record<string, any>): void;
}
const emit = defineEmits<EmitProps>();
const props = defineProps({
//
quickBtn: {
type: Boolean,
default: true,
},
//
quickBtnList: {
type: Array as PropType<BtnOptions[]>,
default: [
{ label: '今日', value: 'today' },
{ label: '近一周', value: 'week' },
{ label: '近一月', value: 'month' },
{ label: '近一年', value: 'year' },
],
},
type: {
type: String,
default: 'today',
},
});
const radioValue = ref(props.type || 'week' || undefined);
const rangeVal = ref<[string, string]>();
const rangeChange = (val: any) => {
radioValue.value = undefined;
emit('change', {
start: moment(val[0]).valueOf(),
end: moment(val[1]).valueOf(),
type: undefined,
});
};
const getTimeByType = (type: string) => {
switch (type) {
case 'hour':
return moment().subtract(1, 'hours').valueOf();
case 'week':
return moment().subtract(6, 'days').valueOf();
case 'month':
return moment().subtract(29, 'days').valueOf();
case 'year':
return moment().subtract(365, 'days').valueOf();
default:
return moment().startOf('day').valueOf();
}
};
const handleBtnChange = (val: string) => {
radioValue.value = val;
let endTime = moment(new Date()).valueOf();
let startTime = getTimeByType(val);
if (val === 'yesterday') {
startTime = moment().subtract(1, 'days').startOf('day').valueOf();
endTime = moment().subtract(1, 'days').endOf('day').valueOf();
}
rangeVal.value = [
moment(startTime).format('YYYY-MM-DD'),
moment(endTime).format('YYYY-MM-DD'),
];
emit('change', {
start: startTime,
end: endTime,
type: val,
});
};
watch(
() => radioValue.value,
(val) => {
handleBtnChange(val);
},
{ deep: true, immediate: true },
);
</script>