巡检日,周,月完成,数据概况待修改

This commit is contained in:
Zy
2026-04-22 16:05:44 +08:00
parent 48852a33ec
commit 04eb40d0e4
55 changed files with 1583 additions and 422 deletions

View File

@@ -1,13 +1,367 @@
<template>
<div class="p-2 h-full flex flex-col">
<PageHeader></PageHeader>
<div class="flex-1 color-gray flex h-full font-size-6 flex-center">系统还在维护中敬请期待...</div>
<div class="h-full flex flex-col p-2">
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
<div v-show="showSearch" class="mb-[10px]">
<el-card shadow="hover">
<div>
<div class="flex flex-items-center justify-between">
<div>
<div class="line"></div>
<div class="metatitle">巡更数据概况</div>
</div>
<div class="rightSearch flex flex-items-center justify-around">
<div>选择日期</div>
<el-date-picker
v-model="statDate"
value-format="YYYY/MM/DD"
format="YYYY/MM/DD"
@update:model-value="handleStateDate"
type="date"
placeholder="选择日期"
:disabled-date="disabledDate"
/>
<i @click="handleQueryDay(0)">今日</i>
<i @click="handleQueryDay(1)">昨日</i>
<i @click="handleQueryDay(7)">近7天</i>
<i @click="handleQueryDay(30)">近30日</i>
</div>
</div>
<div class="overviewBox">
<el-card v-for="(item, index) in list" :key="index">
<div class="overviewitem">
<div class="overviewitem_name">{{ item.name }}</div>
<div class="overviewitem_value">{{ item.value }}</div>
</div>
</el-card>
</div>
</div>
</el-card>
</div>
</transition>
<el-card class="flex-1" shadow="never">
<template #header>
<span style="font-size: 1.2rem">数据统计 </span>
</template>
<el-row :gutter="10" class="h-full">
<el-col :span="10">
<div class="echartsbox flex h-full flex-col">
<div class="echartsactions">
<div
@click="handleEcartsData(item)"
:class="{ active: activeEchartsindex === item.key }"
class="echartsactions_item"
v-for="(item, index) in ecartslist"
:key="index"
>
{{ item.name }}
</div>
</div>
<div class="echartsbody flex-1">
<EchartsCompontent :options="options"></EchartsCompontent>
</div>
</div>
</el-col>
<el-col :span="14">
<el-table v-loading="loading" border :data="itemList">
<el-table-column label="日期" width="100" align="center" prop="statDate" />
<el-table-column label="计划巡检任务" width="120" align="center" prop="totalPlans" />
<el-table-column label="按时完成" align="center" prop="completedTasks" />
<el-table-column label="超时完成" align="center" prop="outCompletedTasks" />
<el-table-column label="超时未完成" align="center" prop="outUncompletedTasks" />
<el-table-column label="进行中" align="center" prop="activeTask" />
<el-table-column label="未开始" align="center" prop="pendingTask" />
</el-table>
<pagination
v-show="total > 0"
:total="total"
v-model:page="queryParams.pageNum"
v-model:limit="queryParams.pageSize"
@pagination="getList"
/>
</el-col>
</el-row>
</el-card>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import PageHeader from '@/components/Pageheader/index.vue';
<script setup name="Item" lang="ts">
import EchartsCompontent from '@/components/Echarts/index.vue';
import { listItem, type Request } from '@/api/system/Inspection/index';
import { getNaturalDayDiff, getLast7Days, getLastNDays, diffDays, formatDate } from '@/utils/time';
import { EChartsOption } from 'echarts';
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const itemList = ref<any[]>([]);
const loading = ref(true);
const showSearch = ref(true);
const total = ref(0);
const queryFormRef = ref<ElFormInstance>();
const disabledDate = (time: Date) => {
return time.getTime() > Date.now();
};
const statDate = ref('');
const data = reactive<{
queryParams: Request;
}>({
queryParams: {
pageNum: 1,
pageSize: 10,
statDate: '',
dataType: '0' // 0 总览 1 日报 3 月报
}
});
const list = ref([
{
name: '计划数量',
key: 'totalPlans',
value: 20
},
{
name: '任务数量',
key: 'totalPlans',
value: 200
},
{
name: '任务完成数量',
key: 'UncompletedTasks',
value: 40
},
{
name: ' 完成率',
key: 'onTimeRateDisplay',
value: '20%'
},
{
name: '未完成数量',
key: 'outUncompletedTasks',
value: 40
}
]);
// ! echarts =================================================================
const activeEchartsindex = ref('totalTasks');
const ecartslist = ref([
{
name: '全部任务',
key: 'totalTasks',
color: '#1a75ff',
offsetbottomColor: '#f2f9ff'
},
{
name: '按时完成',
key: 'completedTasks',
color: '#42b983',
offsetbottomColor: '#c6eada'
},
{
name: '超时未完成',
key: 'outUncompletedTasks',
color: '#f83333',
offsetbottomColor: '#fed6d6'
},
{
name: '进行中',
key: 'activeTask',
color: '#9d33f8',
offsetbottomColor: '#ebd6fe'
},
{
name: '未开始',
key: 'pendingTask',
color: '#909399',
offsetbottomColor: 'rgb(233, 233, 235)'
}
]);
const options = computed<EChartsOption>(() => ({
grid: {
left: '1%',
right: '1%',
top: '10%',
bottom: '1%',
containLabel: true
},
xAxis: { data: xAxislist.value },
yAxis: { type: 'value' as const },
tooltip: { trigger: 'axis' as const },
series: activeSeries.value // 动态系列
}));
//
const diffday = ref(0);
const activeSeries = ref();
const xAxislist = ref([]);
function handleEcartsOptions(data, name, colorlist = ['#1a75ff', '#f2f9ff']) {
const obj = {
data: data,
type: 'line' as const,
smooth: true,
name: name,
areaStyle: {
color: {
type: 'linear',
x: 0,
y: 0,
x2: 0,
y2: 1, // 从上到下渐变
colorStops: colorlist.map((item, index) => {
return {
offset: index / colorlist.length,
color: item
};
})
}
},
lineStyle: {
color: colorlist[0]
},
itemStyle: {
color: colorlist[0]
},
label: {
show: true,
color: colorlist[0],
position: 'top'
}
};
activeSeries.value = obj;
}
function handleEcartsData(row: (typeof ecartslist.value)[number]) {
if (row) {
xAxislist.value = [];
// 避免修改原数组,创建副本排序
const sortedList = [...itemList.value].sort((a, b) => new Date(a.statDate).getTime() - new Date(b.statDate).getTime());
console.log(sortedList);
// 创建日期到值的映射,标准化日期格式(假设 statDate 为 '2024-04-16 00:00:00'截取前10位
const dataMap = new Map<string, number>();
sortedList.forEach((item) => {
const dateKey = item.statDate.split(' ')[0]; // 截取 'YYYY-MM-DD'
dataMap.set(dateKey, Number(item[row.key]) || 0); // 确保为数字
});
// 根据 x 轴日期生成数据数组
console.log(diffday.value);
const xAxisDates = getLastNDays(diffday.value, undefined, 'YYYY.MM.DD'); // 确保格式为 ['2024-04-16', ...]
const arr = xAxisDates.map((date) => dataMap.get(date) || 0);
xAxislist.value = xAxisDates;
console.log('xAxisDates:', xAxisDates); // 调试
console.log('dataMap:', dataMap); // 调试
console.log('arr:', arr); // 调试
activeSeries.value = null;
handleEcartsOptions(arr, row.name, [row.color, row.offsetbottomColor]);
}
}
function handleStateDate(val) {
console.log(diffDays(val));
diffday.value = diffDays(val);
queryParams.value.statDate = `${formatDate(new Date(val), 'YYYY/MM/DD')}-${formatDate(new Date(), 'YYYY/MM/DD')}`;
getList();
}
// ! echarts =================================================================
const day = 1000 * 60 * 60 * 24;
function handleQueryDay(val: number) {
const newday = new Date(); // 当前日期
const time = new Date(newday.getTime() - val * day); // 指定日期
console.log(time, newday);
diffday.value = val; // 差值
diffday.value = getNaturalDayDiff(time, newday);
queryParams.value.statDate = formatDate(time, 'YYYY/MM/DD');
getList();
}
const { queryParams } = toRefs(data);
/** 查询巡检项目列表 */
const getList = async () => {
loading.value = true;
const res = await listItem(queryParams.value);
itemList.value = res.rows;
handleEcartsData(ecartslist.value[0]);
total.value = res.total;
loading.value = false;
};
onMounted(() => {
// getList();
handleQueryDay(7);
});
</script>
<style scoped lang="scss"></style>
<style lang="scss" scoped>
.el-table {
height: calc(100% - 80px);
}
.rightSearch {
div {
width: 60px;
}
i {
margin: 0 10px;
display: block;
padding: 5px 5px;
font-style: normal;
&:hover {
color: #409eff;
}
}
}
.overviewBox {
display: flex;
flex-wrap: nowrap;
align-items: center;
justify-content: space-between;
margin-top: 40px;
.overviewitem {
min-width: 150px;
padding: 5px -5px;
.overviewitem_name {
color: rgba(102, 102, 102, 1);
font-size: 12px;
}
.overviewitem_value {
color: rgba(51, 51, 51, 1);
font-size: 24px;
font-weight: 500;
margin-top: 10px;
}
}
}
.echartsbox {
.echartsactions {
display: flex;
align-items: center;
margin-bottom: 20px;
.echartsactions_item {
height: 40px;
line-height: 40px;
width: 100px;
text-align: center;
border: 1px solid rgba(220, 223, 230, 1);
color: rgba(16, 16, 16, 1);
border-left: none;
&:first-of-type {
border-radius: 4px 0px 0px 0px;
border-left: 1px solid rgba(220, 223, 230, 1);
}
&:last-of-type {
border-radius: 0px 4px 0px 0px;
}
&.active {
color: #fff;
background-color: rgba(26, 117, 255, 1);
}
}
}
}
</style>