Files
klp-mono/apps/hand-factory/components/klp-shutdown-statistic/klp-shutdown-statistic.vue
2025-10-29 15:38:20 +08:00

463 lines
12 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<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>
/* 简洁Tab容器 */
.tab-container {
display: flex;
box-sizing: border-box;
background: #fff;
margin: 20rpx;
margin-bottom: 20rpx;
border-radius: 12rpx;
overflow: hidden;
border: 1rpx solid #e8e8e8;
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.04);
}
.tab-item {
flex: 1;
text-align: center;
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;
}
}
.tab-item.active {
color: #fff;
background: #1a73e8;
font-weight: 600;
}
/* 日期选择器 */
.date-picker {
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);
}
.date-range {
display: flex;
gap: 20rpx;
}
.date-item {
flex: 1;
}
.picker-text {
padding: 20rpx;
background: #f8f9fa;
border-radius: 10rpx;
color: #333;
font-size: 28rpx;
border: 1rpx solid #e8e8e8;
transition: all 0.2s ease;
&:active {
background: #f0f2f5;
}
}
</style>