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

912 lines
24 KiB
Vue
Raw Normal View History

2025-10-27 13:21:43 +08:00
<template>
<view class="page-container">
<!-- 时间维度切换 -->
<view class="time-tab-bar">
2025-10-27 13:21:43 +08:00
<view
v-for="item in timeTabs"
:key="item.value"
class="time-tab-item"
:class="{ 'time-tab-active': activeTab === item.value }"
2025-10-27 13:21:43 +08:00
@click="handleTabChange(item.value)"
>
{{ item.label }}
</view>
</view>
<!-- 日期选择区 -->
<view class="date-selector">
2025-10-27 13:21:43 +08:00
<!-- 日模式 -->
<picker v-if="activeTab === 'day'" mode="date" :value="startDate" @change="handleDateChange">
<view class="date-input">
<text class="date-label">日期</text>
<text class="date-value">{{ startDate }}</text>
</view>
</picker>
<!-- 月模式 -->
<view v-else-if="activeTab === 'month'" class="date-range-group">
<picker mode="date" fields="month" :value="startDate" @change="handleStartMonthChange">
<view class="date-input">
<text class="date-label"></text>
<text class="date-value">{{ startDate }}</text>
</view>
</picker>
<view class="date-separator"></view>
<picker mode="date" fields="month" :value="endDate" :start="startDate" :end="maxMonthEnd" @change="handleEndMonthChange">
<view class="date-input">
<text class="date-label"></text>
<text class="date-value">{{ endDate }}</text>
</view>
2025-10-27 13:21:43 +08:00
</picker>
</view>
<!-- 年模式 -->
<view v-else class="date-range-group">
<picker mode="date" fields="year" :value="startDate" @change="handleStartYearChange">
<view class="date-input">
<text class="date-label"></text>
<text class="date-value">{{ startDate }}</text>
</view>
2025-10-27 13:21:43 +08:00
</picker>
<view class="date-separator"></view>
<picker mode="date" fields="year" :value="endDate" @change="handleEndYearChange">
<view class="date-input">
<text class="date-label"></text>
<text class="date-value">{{ endDate }}</text>
2025-10-27 13:21:43 +08:00
</view>
</picker>
</view>
</view>
<!-- 停机汇总 -->
<view class="summary-section">
<view class="section-header">
<text class="section-title">停机汇总</text>
<text class="section-date">{{ displayDateRange }}</text>
</view>
<view class="summary-grid">
<view class="summary-card" v-for="(item, index) in summaryData" :key="index">
<text class="summary-label">{{ item.label }}</text>
<view class="summary-value-box">
<text class="summary-value">{{ item.value }}</text>
<text v-if="item.unit" class="summary-unit">{{ item.unit }}</text>
2025-10-27 13:21:43 +08:00
</view>
</view>
</view>
</view>
<!-- 停机趋势图/年视图 -->
<view class="chart-section" v-if="activeTab !== 'day' && trendChartData.categories && trendChartData.categories.length > 0">
<view class="section-header">
<text class="section-title">停机趋势</text>
</view>
<view class="chart-wrapper trend-chart">
<qiun-data-charts type="mix" :chartData="trendChartData" :opts="trendChartOpts"/>
</view>
2025-10-27 13:21:43 +08:00
</view>
<!-- 停机分布 - 班组 -->
<view class="chart-section">
<view class="section-header">
<text class="section-title">班组停机分布</text>
</view>
<view class="pie-chart-single" v-if="crewPieData.series[0].data.length > 0">
<qiun-data-charts type="pie" :chartData="crewPieData" :opts="pieChartOpts"/>
</view>
<view class="empty-chart" v-else>
<text class="empty-icon">📊</text>
<text class="empty-text">此时间段未发生停机</text>
</view>
2025-10-27 13:21:43 +08:00
</view>
<!-- 停机分布 - 类型 -->
<view class="chart-section">
<view class="section-header">
<text class="section-title">停机类型分布</text>
</view>
<view class="pie-chart-single" v-if="typePieData.series[0].data.length > 0">
<qiun-data-charts type="pie" :chartData="typePieData" :opts="pieChartOpts"/>
</view>
<view class="empty-chart" v-else>
<text class="empty-icon">📊</text>
<text class="empty-text">此时间段未发生停机</text>
</view>
2025-10-27 13:21:43 +08:00
</view>
<!-- 停机详细列表日视图 -->
<view class="detail-section" v-if="activeTab === 'day'">
<view class="section-header">
<text class="section-title">停机详情</text>
</view>
<view class="detail-list">
<view class="detail-item" v-for="(item, index) in tableData" :key="index">
<view class="detail-header">
<text class="detail-time">{{ item.time }}</text>
<text class="detail-duration">{{ item.duration }}</text>
</view>
<view class="detail-info">
<text class="detail-label">机组</text>
<text class="detail-text">{{ item.machine }}</text>
</view>
<view class="detail-info">
<text class="detail-label">备注</text>
<text class="detail-text">{{ item.remark }}</text>
</view>
</view>
<view v-if="tableData.length === 0" class="empty-state">
<text class="empty-text">暂无停机记录</text>
</view>
</view>
2025-10-27 13:21:43 +08:00
</view>
</view>
</template>
<script>
2025-10-31 14:50:19 +08:00
import { listStoppage } from '@/api/pocket/plantState'
2025-10-27 13:21:43 +08:00
// 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}`;
}
}
// 获取上个月的年月
function getLastMonth() {
const date = new Date();
date.setMonth(date.getMonth() - 1); // 减1个月
const year = date.getFullYear();
const month = (date.getMonth() + 1).toString().padStart(2, "0");
return `${year}-${month}`;
}
2025-10-27 13:21:43 +08:00
/**
* 格式化日期
* @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(),
// 结束日期/月份/年份(默认)
2025-10-27 13:21:43 +08:00
endDate: getDefaultDate(),
// 视图切换选项
timeTabs: [
{ label: "日", value: "day" },
{ label: "月", value: "month" },
{ label: "年", value: "year" }
2025-10-27 13:21:43 +08:00
],
// 汇总数据
summaryData: [
{ label: "停机时间", value: 0, unit: "min" },
{ label: "停机次数", value: 0, unit: "次" },
{ label: "作业率", value: 0, unit: "%" }
],
// 停机趋势图(月/年视图)
trendChartData: {
categories: [],
series: []
2025-10-27 13:21:43 +08:00
},
trendChartOpts: {
color: ["#0066cc", "#f56c6c"],
2025-10-27 13:21:43 +08:00
padding: [15, 15, 0, 15],
enableScroll: false,
legend: { position: "top" },
xAxis: { disableGrid: true },
2025-10-27 13:21:43 +08:00
yAxis: {
gridType: "dash",
dashLength: 4,
gridColor: "#e4e7ed",
2025-10-27 13:21:43 +08:00
data: [
{ position: "left", title: "停机时间(min)" },
{ position: "right", title: "作业率(%)" }
2025-10-27 13:21:43 +08:00
]
},
extra: {
mix: {
column: { width: 20 }
2025-10-27 13:21:43 +08:00
}
}
2025-10-27 13:21:43 +08:00
},
// 饼图配置
pieChartOpts: {
color: ["#0066cc", "#409eff", "#66b1ff", "#a0cfff", "#d9ecff"],
padding: [15, 15, 15, 15],
2025-10-27 13:21:43 +08:00
enableScroll: false,
legend: {
show: true,
position: "bottom",
lineHeight: 16,
fontSize: 10,
fontColor: "#666",
margin: 5,
itemGap: 8
},
2025-10-27 13:21:43 +08:00
extra: {
pie: {
activeOpacity: 0.5,
activeRadius: 10,
labelWidth: 15,
border: false,
ringWidth: 0,
offsetAngle: 0,
disablePieStroke: true
2025-10-27 13:21:43 +08:00
}
}
},
// 班组停机分布
crewPieData: {
series: [{ data: [] }]
},
// 停机类型分布
typePieData: {
series: [{ data: [] }]
},
// 停机详细列表
tableData: []
2025-10-27 13:21:43 +08:00
};
},
// 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;
// 重置日期
if (tab === "day") {
// 日视图:首尾日期相同(今天)
const today = getDefaultDate();
this.startDate = today;
this.endDate = today;
} else if (tab === "month") {
// 月视图:上个月到这个月
this.startDate = getLastMonth();
this.endDate = getDefaultDate("month");
} else {
// 年视图:今年
const currentYear = getDefaultDate("year");
this.startDate = currentYear;
this.endDate = currentYear;
}
2025-10-31 14:50:19 +08:00
// 切换视图时重新加载数据
this.loadStoppageData();
2025-10-27 13:21:43 +08:00
},
// 日模式:日期选择器变更
handleDateChange(e) {
this.startDate = e.detail.value;
this.endDate = e.detail.value; // 日模式首尾日期一致
2025-10-31 14:50:19 +08:00
this.loadStoppageData();
2025-10-27 13:21:43 +08:00
},
// 月模式:开始月份变更
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;
}
2025-10-31 14:50:19 +08:00
this.loadStoppageData();
2025-10-27 13:21:43 +08:00
},
// 月模式:结束月份变更
handleEndMonthChange(e) {
this.endDate = e.detail.value;
2025-10-31 14:50:19 +08:00
this.loadStoppageData();
2025-10-27 13:21:43 +08:00
},
// 年模式:开始年份变更
handleStartYearChange(e) {
this.startDate = e.detail.value;
2025-10-31 14:50:19 +08:00
this.loadStoppageData();
2025-10-27 13:21:43 +08:00
},
// 年模式:结束年份变更
handleEndYearChange(e) {
this.endDate = e.detail.value;
2025-10-31 14:50:19 +08:00
this.loadStoppageData();
},
// 加载停机数据
loadStoppageData() {
uni.showLoading({ title: '加载中' })
// 转换为完整日期格式
const start = this.formatFullDate(this.startDate, true)
const end = this.formatFullDate(this.endDate, false)
2025-10-31 14:50:19 +08:00
const queryParams = {
pageNum: 1,
pageSize: 100,
startDate: start,
endDate: end
2025-10-31 14:50:19 +08:00
}
console.log('停机查询参数:', queryParams)
2025-10-31 14:50:19 +08:00
listStoppage(queryParams).then(response => {
uni.hideLoading()
console.log('停机统计响应:', response)
2025-10-31 14:50:19 +08:00
if (response.code === 200 && response.rows && response.rows.length > 0) {
// 处理停机数据
console.log('停机数据:', response.rows)
2025-10-31 14:50:19 +08:00
// 更新表格数据(日视图)
this.tableData = response.rows.map(item => ({
time: this.formatDateTime(item.startDate) + ' - ' + this.formatDateTime(item.endDate),
duration: this.secondsToMinutes(item.duration) + 'min',
2025-10-31 14:50:19 +08:00
remark: item.remark || '-',
machine: item.unit || '-'
}))
// 计算汇总数据(秒转分钟)
const totalDurationSeconds = response.rows.reduce((sum, item) => sum + (Number(item.duration) || 0), 0)
const totalDurationMinutes = this.secondsToMinutes(totalDurationSeconds)
2025-10-31 14:50:19 +08:00
const totalCount = response.rows.length
// 计算作业率(需要知道总可用时间)
const totalAvailableMinutes = this.getTotalAvailableMinutes()
const workRate = this.calculateWorkRate(totalDurationMinutes, totalAvailableMinutes)
2025-10-31 14:50:19 +08:00
this.summaryData = [
{ label: '停机时间', value: totalDurationMinutes, unit: 'min' },
{ label: '停机次数', value: totalCount, unit: '次' },
{ label: '作业率', value: workRate, unit: '%' }
2025-10-31 14:50:19 +08:00
]
2025-10-31 14:50:19 +08:00
// 更新饼图数据(按班组统计)
const crewMap = {}
const typeMap = {}
2025-10-31 14:50:19 +08:00
response.rows.forEach(item => {
const crew = item.crew || '未知班组'
const type = item.stopType || '未知类型'
const durationMinutes = this.secondsToMinutes(item.duration)
crewMap[crew] = (crewMap[crew] || 0) + durationMinutes
typeMap[type] = (typeMap[type] || 0) + durationMinutes
2025-10-31 14:50:19 +08:00
})
this.crewPieData = {
2025-10-31 14:50:19 +08:00
series: [{
data: Object.keys(crewMap).map(crew => ({
name: crew,
value: crewMap[crew]
}))
}]
}
this.typePieData = {
series: [{
data: Object.keys(typeMap).map(type => ({
name: type,
value: typeMap[type]
}))
}]
}
// 如果是月/年视图,构建趋势图
if (this.activeTab !== 'day' && response.rows.length > 0) {
this.buildTrendChart(response.rows)
}
2025-10-31 14:50:19 +08:00
} else {
// 没有数据时使用默认值
console.log('暂无停机数据')
// 清空数据
this.tableData = []
this.summaryData = [
{ label: '停机时间', value: 0, unit: 'min' },
{ label: '停机次数', value: 0, unit: '次' },
{ label: '作业率', value: 100, unit: '%' }
]
this.crewPieData = { series: [{ data: [] }] }
this.typePieData = { series: [{ data: [] }] }
// 清空趋势图
this.trendChartData = {
categories: [],
series: []
}
2025-10-31 14:50:19 +08:00
}
}).catch(error => {
uni.hideLoading()
console.error('加载停机数据失败:', error)
uni.showToast({
title: '加载失败',
icon: 'none'
})
2025-10-31 14:50:19 +08:00
})
},
// 格式化日期时间
formatDateTime(dateStr) {
if (!dateStr) return '-'
const date = new Date(dateStr)
const year = date.getFullYear()
const month = String(date.getMonth() + 1).padStart(2, '0')
const day = String(date.getDate()).padStart(2, '0')
const hours = String(date.getHours()).padStart(2, '0')
const minutes = String(date.getMinutes()).padStart(2, '0')
return `${year}-${month}-${day} ${hours}:${minutes}`
},
// 获取总可用时间(分钟)
getTotalAvailableMinutes() {
const start = new Date(this.formatFullDate(this.startDate, true))
const end = new Date(this.formatFullDate(this.endDate, false))
// 计算天数差
const diffTime = end - start
const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24)) + 1 // 包含结束日期
// 每天1440分钟24小时
return diffDays * 1440
},
2025-10-31 14:50:19 +08:00
// 计算作业率
calculateWorkRate(stopDuration, totalAvailableMinutes) {
if (!totalAvailableMinutes || totalAvailableMinutes === 0) {
return 100
}
const workRate = ((totalAvailableMinutes - stopDuration) / totalAvailableMinutes) * 100
2025-10-31 14:50:19 +08:00
return Math.max(0, Math.min(100, workRate)).toFixed(2)
},
// 构建趋势图(月/年视图)
buildTrendChart(stoppageData) {
if (!stoppageData || stoppageData.length === 0) {
console.log('无法构建趋势图:数据为空')
this.trendChartData = {
categories: [],
series: []
}
return
}
// 按日期分组统计
const dateMap = {}
stoppageData.forEach(item => {
if (!item.startDate) return
const date = this.formatDate(item.startDate)
if (!dateMap[date]) {
dateMap[date] = { duration: 0, count: 0 }
}
const durationMinutes = this.secondsToMinutes(item.duration)
dateMap[date].duration += durationMinutes
dateMap[date].count += 1
})
const categories = Object.keys(dateMap).sort()
if (categories.length === 0) {
console.log('无法构建趋势图:无有效日期')
this.trendChartData = {
categories: [],
series: []
}
return
}
const durationData = []
const rateData = []
categories.forEach(date => {
durationData.push(dateMap[date].duration)
// 趋势图中每个点是单天的作业率所以总时间是1440分钟
const rate = this.calculateWorkRate(dateMap[date].duration, 1440)
rateData.push(Number(rate))
})
console.log('趋势图数据构建成功:', { categories, durationData, rateData })
this.trendChartData = {
categories: categories,
series: [
{
name: "停机时间",
type: "column",
index: 0,
data: durationData
},
{
name: "作业率",
type: "line",
index: 1,
style: "curve",
data: rateData
}
]
}
},
// 格式化日期(简短格式)
formatDate(dateStr) {
if (!dateStr) return ''
const date = new Date(dateStr)
const month = date.getMonth() + 1
const day = date.getDate()
return `${month}/${day}`
},
// 秒转分钟(保留整数)
secondsToMinutes(seconds) {
if (!seconds || seconds === 0) return 0
return Math.round(Number(seconds) / 60)
},
// 格式化为完整日期(用于查询)
formatFullDate(dateStr, isStart) {
if (!dateStr) return ''
// 如果已经是完整日期格式 yyyy-MM-dd直接返回
if (dateStr.length === 10) {
return dateStr
}
// 月份格式 yyyy-MM
if (dateStr.length === 7) {
if (isStart) {
return `${dateStr}-01`
} else {
const [year, month] = dateStr.split('-')
const lastDay = new Date(year, month, 0).getDate()
return `${dateStr}-${String(lastDay).padStart(2, '0')}`
}
}
// 年份格式 yyyy
if (dateStr.length === 4) {
if (isStart) {
return `${dateStr}-01-01`
} else {
return `${dateStr}-12-31`
}
}
return dateStr
2025-10-27 13:21:43 +08:00
}
2025-10-31 14:50:19 +08:00
},
// 生命周期钩子
mounted() {
this.loadStoppageData()
2025-10-27 13:21:43 +08:00
}
};
</script>
<style scoped lang="scss">
/* 页面容器 */
.page-container {
background: #f5f7fa;
padding: 24rpx;
}
/* 时间维度切换 */
.time-tab-bar {
2025-10-27 13:21:43 +08:00
display: flex;
2025-10-29 15:38:20 +08:00
background: #fff;
border-radius: 8rpx;
padding: 8rpx;
margin-bottom: 24rpx;
border: 1rpx solid #e4e7ed;
2025-10-27 13:21:43 +08:00
}
.time-tab-item {
2025-10-29 15:38:20 +08:00
flex: 1;
2025-10-27 13:21:43 +08:00
text-align: center;
padding: 16rpx 0;
font-size: 26rpx;
color: #606266;
border-radius: 6rpx;
transition: all 0.2s;
}
.time-tab-active {
background: #0066cc;
color: #fff;
2025-10-29 15:38:20 +08:00
font-weight: 500;
}
/* 日期选择区 */
.date-selector {
background: #fff;
border-radius: 8rpx;
padding: 24rpx;
margin-bottom: 24rpx;
border: 1rpx solid #e4e7ed;
}
.date-range-group {
display: flex;
align-items: stretch;
gap: 0;
}
.date-input {
flex: 1;
display: flex;
align-items: center;
justify-content: space-between;
padding: 24rpx 32rpx;
background: #f5f7fa;
border: 1rpx solid #e4e7ed;
&:first-child {
border-radius: 6rpx 0 0 6rpx;
border-right: none;
}
&:last-child {
border-radius: 0 6rpx 6rpx 0;
border-left: none;
2025-10-29 15:38:20 +08:00
}
2025-10-27 13:21:43 +08:00
}
.date-label {
font-size: 26rpx;
color: #909399;
margin-right: 16rpx;
}
.date-value {
font-size: 28rpx;
color: #303133;
font-weight: 500;
flex: 1;
text-align: right;
}
.date-separator {
font-size: 28rpx;
2025-10-29 15:38:20 +08:00
color: #fff;
background: #0066cc;
padding: 24rpx 20rpx;
display: flex;
align-items: center;
justify-content: center;
min-width: 80rpx;
}
/* 区块样式 */
.summary-section,
.chart-section,
.detail-section {
margin-bottom: 24rpx;
}
.section-header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 20rpx;
padding-left: 16rpx;
border-left: 4rpx solid #0066cc;
}
.section-title {
font-size: 30rpx;
font-weight: 500;
color: #303133;
}
.section-date {
font-size: 24rpx;
color: #909399;
}
/* 汇总卡片网格 */
.summary-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 16rpx;
}
.summary-card {
background: #fff;
border: 1rpx solid #e4e7ed;
border-radius: 8rpx;
padding: 28rpx 20rpx;
text-align: center;
}
.summary-label {
display: block;
font-size: 24rpx;
color: #909399;
margin-bottom: 16rpx;
}
.summary-value-box {
display: flex;
align-items: baseline;
justify-content: center;
}
.summary-value {
font-size: 40rpx;
2025-10-29 15:38:20 +08:00
font-weight: 600;
color: #0066cc;
line-height: 1;
2025-10-27 13:21:43 +08:00
}
.summary-unit {
font-size: 22rpx;
color: #909399;
margin-left: 6rpx;
}
/* 图表容器 */
.chart-wrapper {
2025-10-29 15:38:20 +08:00
background: #fff;
border: 1rpx solid #e4e7ed;
border-radius: 8rpx;
padding: 24rpx 16rpx;
min-height: 450rpx;
}
/* 趋势图固定高度 */
.trend-chart {
height: 500rpx;
min-height: 500rpx;
2025-10-27 13:21:43 +08:00
}
/* 单个饼图容器 */
.pie-chart-single {
background: #fff;
border: 1rpx solid #e4e7ed;
border-radius: 8rpx;
padding: 32rpx 0;
min-height: 480rpx;
}
/* 空状态图表占位 */
.empty-chart {
background: #fff;
border: 1rpx solid #e4e7ed;
border-radius: 8rpx;
padding: 100rpx 0;
min-height: 480rpx;
2025-10-27 13:21:43 +08:00
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
2025-10-27 13:21:43 +08:00
gap: 20rpx;
}
.empty-icon {
font-size: 80rpx;
opacity: 0.3;
2025-10-27 13:21:43 +08:00
}
.empty-text {
2025-10-29 15:38:20 +08:00
font-size: 28rpx;
color: #909399;
}
/* 停机详情列表 */
.detail-list {
background: #fff;
border-radius: 8rpx;
border: 1rpx solid #e4e7ed;
overflow: hidden;
}
.detail-item {
padding: 24rpx;
border-bottom: 1rpx solid #f5f7fa;
&:last-child {
border-bottom: none;
}
}
.detail-header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 16rpx;
}
.detail-time {
font-size: 26rpx;
color: #606266;
}
.detail-duration {
font-size: 28rpx;
color: #0066cc;
font-weight: 600;
}
.detail-info {
display: flex;
align-items: baseline;
margin-bottom: 8rpx;
&:last-child {
margin-bottom: 0;
2025-10-29 15:38:20 +08:00
}
2025-10-27 13:21:43 +08:00
}
.detail-label {
font-size: 24rpx;
color: #909399;
min-width: 120rpx;
}
.detail-text {
font-size: 26rpx;
color: #303133;
flex: 1;
}
/* 空状态 */
.empty-state {
padding: 100rpx 0;
text-align: center;
}
.empty-text {
font-size: 28rpx;
color: #909399;
}
</style>