Files
klp-mono/apps/hand-factory/components/klp-team-performance/klp-team-performance.vue

484 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 class="page-container">
<!-- 月份选择器 -->
<view class="month-selector">
<view class="month-arrow" @click="changeMonth(-1)" :class="{ disabled: isMinMonth }">
<text></text>
</view>
<picker mode="date" fields="month" :value="selectedMonth" :start="startDate" :end="endDate" @change="handleMonthChange">
<view class="month-display">
<text class="month-text">{{ formattedMonth }}</text>
<text class="picker-icon"></text>
</view>
</picker>
<view class="month-arrow" @click="changeMonth(1)" :class="{ disabled: isMaxMonth }">
<text></text>
</view>
</view>
<!-- 班组绩效排名 -->
<view class="ranking-section">
<view class="section-header">
<text class="section-title">绩效排名</text>
</view>
<view class="ranking-list">
<view
class="ranking-item"
v-for="(item, index) in teamRankingData"
:key="index"
:class="'rank-' + (index + 1)"
>
<view class="rank-badge">{{ index + 1 }}</view>
<view class="rank-info">
<text class="team-name">{{ item.team }}</text>
<text class="team-shift">{{ item.shift }}</text>
</view>
<view class="rank-score">
<text class="score-value">{{ item.score }}</text>
<text class="score-label"></text>
</view>
</view>
</view>
</view>
<!-- 班组产量对比 -->
<view class="chart-section">
<view class="section-header">
<text class="section-title">产量对比</text>
</view>
<view class="chart-wrapper">
<qiun-data-charts type="column" :chartData="outputChartData" :opts="columnChartOpts"/>
</view>
</view>
<!-- 质量指标对比 -->
<view class="chart-section">
<view class="section-header">
<text class="section-title">质量指标</text>
</view>
<view class="chart-wrapper">
<qiun-data-charts type="radar" :chartData="qualityRadarData" :opts="radarChartOpts"/>
</view>
</view>
<!-- 班组详细数据 -->
<view class="detail-section">
<view class="section-header">
<text class="section-title">详细数据</text>
</view>
<view class="detail-table">
<view class="table-header">
<text class="table-cell header-cell" v-for="col in columns" :key="col.key">{{ col.title }}</text>
</view>
<view class="table-row" v-for="(row, index) in tableData" :key="index">
<text class="table-cell" v-for="col in columns" :key="col.key">{{ row[col.key] }}</text>
</view>
<view v-if="tableData.length === 0" class="empty-state">
<text class="empty-text">暂无数据</text>
</view>
</view>
</view>
</view>
</template>
<script>
import { getTeamPerformance } from '@/api/pocket/plantState'
// 工具函数
function getCurrentMonth() {
const date = new Date();
const year = date.getFullYear();
const month = (date.getMonth() + 1).toString().padStart(2, "0");
return `${year}-${month}`;
}
export default {
data() {
return {
selectedMonth: getCurrentMonth(),
startDate: "2020-01",
endDate: getCurrentMonth(),
// 表格列配置
columns: [
{ title: '班组', key: 'team' },
{ title: '产量(t)', key: 'output' },
{ title: '成材率', key: 'yieldRate' },
{ title: '合格率', key: 'passRate' },
{ title: '综合评分', key: 'score' }
],
// 表格数据
tableData: [],
// 班组排名数据
teamRankingData: [
{ team: '甲班', shift: '早班', score: 96.8 },
{ team: '乙班', shift: '中班', score: 95.5 },
{ team: '丙班', shift: '晚班', score: 94.2 },
{ team: '丁班', shift: '早班', score: 93.6 }
],
// 产量对比图
outputChartData: {},
columnChartOpts: {
color: ["#0066cc"],
padding: [15, 15, 0, 15],
enableScroll: false,
xAxis: { disableGrid: true },
yAxis: {
gridType: "dash",
dashLength: 4,
gridColor: "#e4e7ed",
data: [{ title: "产量(t)" }]
}
},
// 质量指标雷达图
qualityRadarData: {
categories: [],
series: []
},
radarChartOpts: {
color: ["#0066cc", "#409eff", "#66b1ff", "#a0cfff"],
padding: [15, 15, 15, 15],
enableScroll: false,
legend: {
show: true,
position: "bottom",
lineHeight: 16,
fontSize: 10,
fontColor: "#666"
},
extra: {
radar: {
gridType: "radar",
gridColor: "#e4e7ed",
gridCount: 5,
opacity: 0.2,
labelShow: true,
max: 100,
labelColor: "#666666",
labelFontSize: 10
}
}
}
};
},
computed: {
isMinMonth() {
return this.selectedMonth === this.startDate;
},
isMaxMonth() {
return this.selectedMonth === this.endDate;
},
formattedMonth() {
const [year, month] = this.selectedMonth.split("-");
return `${year}${month}`;
}
},
mounted() {
this.loadTeamPerformance();
},
methods: {
handleMonthChange(e) {
this.selectedMonth = e.detail.value;
this.loadTeamPerformance();
},
changeMonth(step) {
const [year, month] = this.selectedMonth.split("-").map(Number);
const targetDate = new Date(year, month - 1 + step);
const targetMonth = `${targetDate.getFullYear()}-${(targetDate.getMonth() + 1).toString().padStart(2, "0")}`;
if (this.compareMonths(targetMonth, this.startDate) < 0) return;
if (this.compareMonths(targetMonth, this.endDate) > 0) return;
this.selectedMonth = targetMonth;
this.loadTeamPerformance();
},
compareMonths(a, b) {
const [aYear, aMonth] = a.split("-").map(Number);
const [bYear, bMonth] = b.split("-").map(Number);
if (aYear !== bYear) return aYear - bYear;
return aMonth - bMonth;
},
// 加载班组绩效数据
loadTeamPerformance() {
uni.showLoading({ title: '加载中' })
// 转换月份为完整日期范围
const startDate = `${this.selectedMonth}-01`
const [year, month] = this.selectedMonth.split('-')
const lastDay = new Date(year, month, 0).getDate()
const endDate = `${this.selectedMonth}-${String(lastDay).padStart(2, '0')}`
console.log('查询班组绩效:', startDate, endDate)
getTeamPerformance(startDate, endDate).then(response => {
uni.hideLoading()
if (response.code === 200 && response.data && response.data.length > 0) {
const teamData = response.data
console.log('班组绩效数据:', teamData)
// 排名数据取前4名
this.teamRankingData = teamData.slice(0, 4).map(item => ({
team: item.crew,
shift: item.shift,
score: Number(item.score) || 0
}))
// 表格数据
this.tableData = teamData.map(item => ({
team: item.teamName,
output: Number(item.output) || 0,
yieldRate: `${Number(item.yieldRate) || 0}%`,
passRate: `${Number(item.passRate) || 0}%`,
score: Number(item.score) || 0
}))
// 产量对比柱状图
this.outputChartData = {
categories: teamData.map(item => item.teamName),
series: [
{ name: '产量', data: teamData.map(item => Number(item.output) || 0) }
]
}
// 质量指标雷达图
this.qualityRadarData = {
categories: ['产量指标', '成材率', '合格率', '厚度质量', '板形质量'],
series: teamData.map(item => ({
name: item.teamName,
data: [
Number(this.normalizeValue(item.output, 1500)), // 产量归一化到100
Number(item.yieldRate) || 0,
Number(item.passRate) || 0,
Number(item.avgThickQuality) || 0,
Number(item.avgShapeQuality) || 0
]
}))
}
} else {
console.log('暂无班组绩效数据')
}
}).catch(error => {
uni.hideLoading()
console.error('加载班组绩效失败:', error)
})
},
// 数值归一化到100用于雷达图
normalizeValue(value, max) {
return Math.min(100, (Number(value) / max) * 100).toFixed(2)
}
}
};
</script>
<style scoped lang="scss">
/* 页面容器 */
.page-container {
background: #f5f7fa;
padding: 24rpx;
}
/* 月份选择器 */
.month-selector {
display: flex;
align-items: center;
background: #fff;
border-radius: 8rpx;
padding: 20rpx 24rpx;
margin-bottom: 24rpx;
border: 1rpx solid #e4e7ed;
}
.month-arrow {
padding: 12rpx 20rpx;
font-size: 28rpx;
color: #0066cc;
font-weight: 600;
&.disabled {
color: #dcdfe6;
}
}
.month-display {
flex: 1;
display: flex;
align-items: center;
justify-content: center;
gap: 12rpx;
}
.month-text {
font-size: 32rpx;
color: #0066cc;
font-weight: 600;
}
.picker-icon {
font-size: 20rpx;
color: #909399;
}
/* 区块样式 */
.ranking-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;
}
/* 排名列表 */
.ranking-list {
background: #fff;
border-radius: 8rpx;
border: 1rpx solid #e4e7ed;
overflow: hidden;
}
.ranking-item {
display: flex;
align-items: center;
padding: 24rpx;
border-bottom: 1rpx solid #f5f7fa;
&:last-child {
border-bottom: none;
}
&.rank-1 .rank-badge {
background: #0066cc;
}
&.rank-2 .rank-badge {
background: #409eff;
}
&.rank-3 .rank-badge {
background: #66b1ff;
}
}
.rank-badge {
width: 56rpx;
height: 56rpx;
border-radius: 50%;
background: #a0cfff;
color: #fff;
font-size: 28rpx;
font-weight: 600;
display: flex;
align-items: center;
justify-content: center;
margin-right: 24rpx;
}
.rank-info {
flex: 1;
display: flex;
flex-direction: column;
gap: 8rpx;
}
.team-name {
font-size: 30rpx;
color: #303133;
font-weight: 500;
}
.team-shift {
font-size: 24rpx;
color: #909399;
}
.rank-score {
display: flex;
align-items: baseline;
gap: 4rpx;
}
.score-value {
font-size: 48rpx;
color: #0066cc;
font-weight: 600;
line-height: 1;
}
.score-label {
font-size: 22rpx;
color: #909399;
}
/* 图表容器 */
.chart-wrapper {
background: #fff;
border: 1rpx solid #e4e7ed;
border-radius: 8rpx;
padding: 24rpx 16rpx;
min-height: 450rpx;
}
/* 详细数据表格 */
.detail-table {
background: #fff;
border-radius: 8rpx;
border: 1rpx solid #e4e7ed;
overflow: hidden;
}
.table-header {
display: flex;
background: #0066cc;
color: #fff;
}
.header-cell {
color: #fff !important;
font-weight: 500;
}
.table-row {
display: flex;
border-bottom: 1rpx solid #f5f7fa;
&:last-child {
border-bottom: none;
}
}
.table-cell {
flex: 1;
padding: 24rpx 12rpx;
text-align: center;
font-size: 26rpx;
color: #303133;
}
/* 空状态 */
.empty-state {
padding: 100rpx 0;
text-align: center;
}
.empty-text {
font-size: 28rpx;
color: #909399;
}
</style>