Files
klp-mono/apps/hand-factory/components/klp-shutdown-statistic/klp-shutdown-statistic.vue

463 lines
12 KiB
Vue
Raw Normal View History

2025-10-27 13:21:43 +08:00
<template>
<view>
<!-- 日月年汇总单选 -->
<view class="tab-container">
<view
v-for="item in timeTabs"
:key="item.value"
class="tab-item"
:class="{ active: activeTab === item.value }"
@click="handleTabChange(item.value)"
>
{{ item.label }}
</view>
</view>
<!-- 日期选择器 -->
<view class="date-picker">
<!-- 日模式 -->
<view v-if="activeTab === 'day'" class="date-item">
<picker mode="date" :value="startDate" @change="handleDateChange">
<view class="picker-text">选择日期{{ startDate }}</view>
</picker>
</view>
<!-- 月模式 -->
<view v-else-if="activeTab === 'month'" class="date-range">
<view class="date-item">
<picker
mode="date"
fields="month"
:value="startDate"
@change="handleStartMonthChange"
>
<view class="picker-text">开始月份{{ startDate }}</view>
</picker>
</view>
<view class="date-item">
<picker
mode="date"
fields="month"
:value="endDate"
:start="startDate"
:end="maxMonthEnd"
@change="handleEndMonthChange"
>
<view class="picker-text">结束月份{{ endDate }}</view>
</picker>
</view>
</view>
<!-- 年模式 -->
<view v-else class="date-range">
<view class="date-item">
<picker
mode="date"
fields="year"
:value="startDate"
@change="handleStartYearChange"
>
<view class="picker-text">开始年份{{ startDate }}</view>
</picker>
</view>
<view class="date-item">
<picker
mode="date"
fields="year"
:value="endDate"
@change="handleEndYearChange"
>
<view class="picker-text">结束年份{{ endDate }}</view>
</picker>
</view>
</view>
</view>
<!-- 停机时间作业率统计图表 -->
<view v-if="activeTab != 'day'">
<qiun-data-charts type="mix" :chartData="chartData" :opts="opts" />
</view>
<view>
<klp-collapse-panel :title="'汇总(' + displayDateRange + ')'">
<k-metric-card
:items="summaryData"
></k-metric-card>
</klp-collapse-panel>
</view>
<view v-if="activeTab == 'day'">
<klp-collapse-panel title="详细信息">
<k-table :columns="columns" :data="tableData"></k-table>
</klp-collapse-panel>
</view>
<view style="margin-top: 30rpx;">
<qiun-data-charts type="pie" :chartData="pieChartData" :opts="pieOpts" />
</view>
</view>
</template>
<script>
// 2. 独立工具函数避免data初始化时调用this.methods的问题
/**
* 获取默认日期根据视图类型
* @param {string} type - 视图类型day/month/year
* @returns {string} 格式化后的日期
*/
function getDefaultDate(type = "day") {
const date = new Date();
const year = date.getFullYear();
const month = (date.getMonth() + 1).toString().padStart(2, "0");
const day = date.getDate().toString().padStart(2, "0");
switch (type) {
case "day":
return `${year}-${month}-${day}`;
case "month":
return `${year}-${month}`;
case "year":
return `${year}`;
default:
return `${year}-${month}-${day}`;
}
}
/**
* 格式化日期
* @param {Date} date - 日期对象
* @param {string} type - 视图类型day/month/year
* @returns {string} 格式化后的日期
*/
function formatDate(date, type) {
const year = date.getFullYear();
const month = (date.getMonth() + 1).toString().padStart(2, "0");
const day = date.getDate().toString().padStart(2, "0");
switch (type) {
case "day":
return `${year}-${month}-${day}`;
case "month":
return `${year}-${month}`;
case "year":
return `${year}`;
default:
return `${year}-${month}-${day}`;
}
}
export default {
// 4. 响应式数据(替代 Vue3 的 ref
data() {
return {
// 激活的视图类型(日/月/年)
activeTab: "day",
// 开始日期/月份/年份
startDate: getDefaultDate(),
// 结束日期/月份/年份
endDate: getDefaultDate(),
// 视图切换选项
timeTabs: [
{ label: "日视图", value: "day" },
{ label: "月视图", value: "month" },
{ label: "年视图", value: "year" }
],
// 混合图表数据
chartData: {
categories: ["2018", "2019", "2020", "2021", "2022", "2023"],
series: [
{
name: "曲面",
type: "area",
style: "curve",
data: [70, 50, 85, 130, 64, 88]
},
{
name: "柱1",
index: 1,
type: "column",
data: [40, { value: 30, color: "#f04864" }, 55, 110, 24, 58]
},
{
name: "柱2",
index: 1,
type: "column",
data: [50, 20, 75, 60, 34, 38]
},
{
name: "曲线",
type: "line",
style: "curve",
color: "#1890ff",
disableLegend: true,
data: [70, 50, 85, 130, 64, 88]
},
{
name: "折线",
type: "line",
color: "#2fc25b",
data: [120, 140, 105, 170, 95, 160]
},
{
name: "点",
index: 2,
type: "point",
color: "#f04864",
data: [100, 80, 125, 150, 112, 132]
}
]
},
// 混合图表配置
opts: {
color: [
"#1890FF",
"#91CB74",
"#FAC858",
"#EE6666",
"#73C0DE",
"#3CA272",
"#FC8452",
"#9A60B4",
"#ea7ccc"
],
padding: [15, 15, 0, 15],
enableScroll: false,
legend: {},
xAxis: {
disableGrid: true,
title: "单位:年"
},
yAxis: {
disabled: false,
disableGrid: false,
splitNumber: 5,
gridType: "dash",
dashLength: 4,
gridColor: "#CCCCCC",
padding: 10,
showTitle: true,
data: [
{ position: "left", title: "折线" },
{ position: "right", min: 0, max: 200, title: "柱状图", textAlign: "left" },
{ position: "right", min: 0, max: 200, title: "点", textAlign: "left" }
]
},
extra: { mix: { column: { width: 20 } } }
},
// 汇总数据(供 k-metric-card 使用)
summaryData: [
{ label: "停机时间", value: 730, unit: "min" },
{ label: "停机次数", value: 9 },
{ label: "作业率", value: 49.31, unit: "%" }
],
// 表格列配置(日视图详细信息)
columns: [
{ title: "起止时间", key: "time" },
{ title: "持续时间", key: "duration" },
{ title: "备注", key: "remark" },
{ title: "机组", key: "machine" }
],
// 表格数据(日视图详细信息)
tableData: [
{
time: "2022-01-01 08:00:00",
duration: "30min",
remark: "设备维护",
machine: "1号机"
},
{
time: "2022-01-01 10:00:00",
duration: "20min",
remark: "设备故障",
machine: "2号机"
},
{
time: "2022-01-01 12:00:00",
duration: "40min",
remark: "设备维护",
machine: "3号机"
}
],
// 饼图数据
pieChartData: {
series: [
{
data: [
{ name: "一班", value: 50 },
{ name: "二班", value: 30 },
{ name: "三班", value: 20 },
{ name: "四班", value: 18, labelText: "四班:18人" },
{ name: "五班", value: 8 }
]
}
]
},
// 饼图配置
pieOpts: {
color: [
"#1890FF",
"#91CB74",
"#FAC858",
"#EE6666",
"#73C0DE",
"#3CA272",
"#FC8452",
"#9A60B4",
"#ea7ccc"
],
padding: [5, 5, 5, 5],
enableScroll: false,
extra: {
pie: {
activeOpacity: 0.5,
activeRadius: 10,
offsetAngle: 0,
labelWidth: 15,
border: true,
borderWidth: 3,
borderColor: "#FFFFFF"
}
}
}
};
},
// 5. 计算属性(替代 Vue3 的 computed 函数)
computed: {
// 月模式:最大结束月份(开始月份+1年
maxMonthEnd() {
if (!this.startDate) return "";
const date = new Date(this.startDate);
date.setFullYear(date.getFullYear() + 1);
return formatDate(date, "month");
},
// 日期范围展示文本(汇总标题用)
displayDateRange() {
switch (this.activeTab) {
case "day":
return this.startDate;
case "month":
return `${this.startDate}${this.endDate}`;
case "year":
return `${this.startDate}${this.endDate}`;
default:
return "";
}
}
},
// 6. 方法定义(所有交互逻辑放这里)
methods: {
// 切换视图(日/月/年)
handleTabChange(tab) {
this.activeTab = tab;
// 重置日期:日视图首尾日期相同,月/年视图首尾默认当前
const defaultDate = getDefaultDate();
this.startDate = defaultDate;
this.endDate = tab === "day" ? defaultDate : getDefaultDate(tab);
},
// 日模式:日期选择器变更
handleDateChange(e) {
this.startDate = e.detail.value;
this.endDate = e.detail.value; // 日模式首尾日期一致
},
// 月模式:开始月份变更
handleStartMonthChange(e) {
this.startDate = e.detail.value;
// 自动调整结束月份:不超过开始月份+1年
const maxEndDate = new Date(this.startDate);
maxEndDate.setFullYear(maxEndDate.getFullYear() + 1);
const maxEndStr = formatDate(maxEndDate, "month");
if (new Date(this.endDate) > maxEndDate) {
this.endDate = maxEndStr;
}
},
// 月模式:结束月份变更
handleEndMonthChange(e) {
this.endDate = e.detail.value;
},
// 年模式:开始年份变更
handleStartYearChange(e) {
this.startDate = e.detail.value;
},
// 年模式:结束年份变更
handleEndYearChange(e) {
this.endDate = e.detail.value;
}
}
};
</script>
<style scoped>
2025-10-29 15:38:20 +08:00
/* 简洁Tab容器 */
2025-10-27 13:21:43 +08:00
.tab-container {
display: flex;
box-sizing: border-box;
2025-10-29 15:38:20 +08:00
background: #fff;
margin: 20rpx;
margin-bottom: 20rpx;
border-radius: 12rpx;
2025-10-27 13:21:43 +08:00
overflow: hidden;
2025-10-29 15:38:20 +08:00
border: 1rpx solid #e8e8e8;
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.04);
2025-10-27 13:21:43 +08:00
}
.tab-item {
2025-10-29 15:38:20 +08:00
flex: 1;
2025-10-27 13:21:43 +08:00
text-align: center;
2025-10-29 15:38:20 +08:00
padding: 24rpx 20rpx;
color: #666;
font-size: 28rpx;
font-weight: 500;
transition: all 0.3s ease;
position: relative;
&:not(:last-child)::after {
content: '';
position: absolute;
right: 0;
top: 50%;
transform: translateY(-50%);
width: 1rpx;
height: 40rpx;
background: #e8e8e8;
}
2025-10-27 13:21:43 +08:00
}
.tab-item.active {
2025-10-29 15:38:20 +08:00
color: #fff;
background: #1a73e8;
font-weight: 600;
2025-10-27 13:21:43 +08:00
}
2025-10-29 15:38:20 +08:00
/* 日期选择器 */
2025-10-27 13:21:43 +08:00
.date-picker {
2025-10-29 15:38:20 +08:00
padding: 20rpx;
margin: 0 20rpx 20rpx;
background: #fff;
border-radius: 12rpx;
border: 1rpx solid #e8e8e8;
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.04);
2025-10-27 13:21:43 +08:00
}
.date-range {
display: flex;
gap: 20rpx;
}
.date-item {
flex: 1;
}
.picker-text {
2025-10-29 15:38:20 +08:00
padding: 20rpx;
background: #f8f9fa;
border-radius: 10rpx;
color: #333;
font-size: 28rpx;
border: 1rpx solid #e8e8e8;
transition: all 0.2s ease;
&:active {
background: #f0f2f5;
}
2025-10-27 13:21:43 +08:00
}
</style>