|
|
@@ -1,7 +1,7 @@
|
|
|
<template>
|
|
|
- <uni-navbar-lite :showLeft=false title="工分"></uni-navbar-lite>
|
|
|
+ <uni-navbar-lite :showLeft="false" title="工分" />
|
|
|
<view class="list-page">
|
|
|
- <!-- 搜索栏 -->
|
|
|
+ <!-- 搜索栏 -->
|
|
|
<view class="search-bar">
|
|
|
<view class="search-box">
|
|
|
<image class="search-icon" src="/static/images/workbench/list/1.png" mode="aspectFit"></image>
|
|
|
@@ -63,64 +63,102 @@
|
|
|
</text> -->
|
|
|
</view>
|
|
|
</view>
|
|
|
-
|
|
|
- <!-- 工分统计 -->
|
|
|
+
|
|
|
<view class="stats-section">
|
|
|
- <view class="stats-header">
|
|
|
- <text class="stats-title">{{ monthTitle }}月度工分</text>
|
|
|
- <view class="month-filters">
|
|
|
- <view class="month-tab">
|
|
|
- <text
|
|
|
- class="month-filter"
|
|
|
- :class="{ 'month-filter-sel': selectedMonth === 'prev' }"
|
|
|
- @click="changeMonth('prev')"
|
|
|
- >
|
|
|
- 上月
|
|
|
- </text>
|
|
|
- </view>
|
|
|
- <view class="month-tab">
|
|
|
- <text
|
|
|
- class="month-filter"
|
|
|
- :class="{ 'month-filter-sel': selectedMonth === 'current' }"
|
|
|
- @click="changeMonth('current')"
|
|
|
- >
|
|
|
- 本月
|
|
|
- </text>
|
|
|
+ <!-- 标签切换 -->
|
|
|
+ <view class="stats-tabs">
|
|
|
+ <text
|
|
|
+ class="tab-item"
|
|
|
+ :class="{ 'tab-active': activeTab === 'ranking' }"
|
|
|
+ @click="switchTab('ranking')"
|
|
|
+ >
|
|
|
+ 个人排名
|
|
|
+ </text>
|
|
|
+ <text
|
|
|
+ class="tab-item"
|
|
|
+ :class="{ 'tab-active': activeTab === 'score' }"
|
|
|
+ @click="switchTab('score')"
|
|
|
+ >
|
|
|
+ 月度工分
|
|
|
+ </text>
|
|
|
+ </view>
|
|
|
+ <!-- 个人排名内容 -->
|
|
|
+ <view v-if="activeTab === 'ranking'" class="ranking-content">
|
|
|
+ <!-- 排名模块 -->
|
|
|
+ <view v-if="rankingItems.length > 0">
|
|
|
+ <view class="ranking-item-wrapper" v-for="(item, index) in rankingItems" :key="index">
|
|
|
+ <view class="ranking-item">
|
|
|
+ <view class="ranking-circle-wrapper">
|
|
|
+ <view class="ranking-number" :class="getRankingSizeClass(index)">
|
|
|
+ <text class="ranking-number-text">{{ item.rank }}/{{ item.total }}</text>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ <text class="ranking-name">{{ item.name }}</text>
|
|
|
+ <text class="ranking-label">第{{ item.rank }}名</text>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
</view>
|
|
|
- <view class="month-tab">
|
|
|
- <text
|
|
|
- class="month-filter"
|
|
|
- :class="{ 'month-filter-sel': selectedMonth === 'custom' }"
|
|
|
- @click="showCustomDatePicker"
|
|
|
- >
|
|
|
- 自定义
|
|
|
- </text>
|
|
|
+ <view v-else class="no-data">
|
|
|
+ <text class="no-data-text">无排名数据</text>
|
|
|
</view>
|
|
|
- </view>
|
|
|
- </view>
|
|
|
-
|
|
|
- <!-- 统计数据 -->
|
|
|
- <view class="stats-content">
|
|
|
- <view class="total-score">
|
|
|
- <text class="score-value">{{ totalScore }}分</text>
|
|
|
- <text class="score-label">{{ monthTitle }}总工分</text>
|
|
|
- </view>
|
|
|
-
|
|
|
- <view class="score-breakdown">
|
|
|
- <view class="breakdown-item">
|
|
|
- <text class="breakdown-label">维保工分</text>
|
|
|
- <text class="breakdown-value">{{ maintenanceScore }}分</text>
|
|
|
- </view>
|
|
|
- <view class="breakdown-item">
|
|
|
- <text class="breakdown-label">维修工分</text>
|
|
|
- <text class="breakdown-value">{{ repairScore }}分</text>
|
|
|
- </view>
|
|
|
- <!-- <view v-if="rank !== null && totalRankingUsers !== null" class="breakdown-item">
|
|
|
- <text class="breakdown-label">排名</text>
|
|
|
- <text class="breakdown-value">{{ rank }}/{{ totalRankingUsers }}</text>
|
|
|
- </view> -->
|
|
|
- </view>
|
|
|
- </view>
|
|
|
+ </view>
|
|
|
+ <!-- 月度工分内容 -->
|
|
|
+ <view v-if="activeTab === 'score'" class="score-content">
|
|
|
+ <view class="stats-header">
|
|
|
+ <text class="stats-title">{{ monthTitle }}月度工分</text>
|
|
|
+ <view class="month-filters">
|
|
|
+ <view class="month-tab">
|
|
|
+ <text
|
|
|
+ class="month-filter"
|
|
|
+ :class="{ 'month-filter-sel': selectedMonth === 'prev' }"
|
|
|
+ @click="changeMonth('prev')"
|
|
|
+ >
|
|
|
+ 上月
|
|
|
+ </text>
|
|
|
+ </view>
|
|
|
+ <view class="month-tab">
|
|
|
+ <text
|
|
|
+ class="month-filter"
|
|
|
+ :class="{ 'month-filter-sel': selectedMonth === 'current' }"
|
|
|
+ @click="changeMonth('current')"
|
|
|
+ >
|
|
|
+ 本月
|
|
|
+ </text>
|
|
|
+ </view>
|
|
|
+ <view class="month-tab">
|
|
|
+ <text
|
|
|
+ class="month-filter"
|
|
|
+ :class="{ 'month-filter-sel': selectedMonth === 'custom' }"
|
|
|
+ @click="showCustomDatePicker"
|
|
|
+ >
|
|
|
+ 自定义
|
|
|
+ </text>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ <!-- 统计数据 -->
|
|
|
+ <view class="stats-content">
|
|
|
+ <view class="total-score">
|
|
|
+ <text class="score-value">{{ totalScore }}分</text>
|
|
|
+ <text class="score-label">{{ monthTitle }}总工分</text>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <view class="score-breakdown">
|
|
|
+ <view class="breakdown-item">
|
|
|
+ <text class="breakdown-label">维保工分</text>
|
|
|
+ <text class="breakdown-value">{{ maintenanceScore }}分</text>
|
|
|
+ </view>
|
|
|
+ <view class="breakdown-item">
|
|
|
+ <text class="breakdown-label">维修工分</text>
|
|
|
+ <text class="breakdown-value">{{ repairScore }}分</text>
|
|
|
+ </view>
|
|
|
+ <!-- <view v-if="rank !== null && totalRankingUsers !== null" class="breakdown-item">
|
|
|
+ <text class="breakdown-label">排名</text>
|
|
|
+ <text class="breakdown-value">{{ rank }}/{{ totalRankingUsers }}</text>
|
|
|
+ </view> -->
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
</view>
|
|
|
|
|
|
<!-- 工单评分列表 -->
|
|
|
@@ -197,13 +235,14 @@
|
|
|
|
|
|
<!-- 底部 TabBar -->
|
|
|
<custom-tabbar :current="3" :hide0="tabbar[0]" :hide1="tabbar[1]" :hide2="tabbar[2]" :hide3="tabbar[3]"/>
|
|
|
- </view>
|
|
|
+ </view>
|
|
|
</template>
|
|
|
|
|
|
<script setup lang="uts">
|
|
|
import { ref, computed, onMounted, onBeforeUnmount } from 'vue'
|
|
|
import { listOrderScores, getOrderScoreStatistics, listMobileOrderScores } from '@/api/score/index'
|
|
|
import { getDictDataByType } from '@/api/dict/index'
|
|
|
+ import { selectHomePageData } from '@/api/index/index'
|
|
|
import type { SysDictData } from '@/types/dict'
|
|
|
|
|
|
// 数据状态
|
|
|
@@ -221,6 +260,19 @@
|
|
|
const rank = ref<number | null>(null)
|
|
|
const totalRankingUsers = ref<number | null>(null)
|
|
|
const customDate = ref<string>('')
|
|
|
+
|
|
|
+ // 新增:标签切换相关
|
|
|
+ const activeTab = ref<string>('ranking') // 默认显示个人排名
|
|
|
+
|
|
|
+ // 用户数据类型定义
|
|
|
+ type RankingItem = {
|
|
|
+ name: string;
|
|
|
+ rank: number;
|
|
|
+ total: number;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 新增:个人排名相关数据
|
|
|
+ const rankingItems = ref<RankingItem[]>([])
|
|
|
|
|
|
// 防止重复请求的标志位
|
|
|
const isSearching = ref<boolean>(false)
|
|
|
@@ -261,6 +313,111 @@
|
|
|
}
|
|
|
})
|
|
|
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ // 根据索引获取排名圆圈的大小类(复制并修改自开屏页)
|
|
|
+ const getRankingSizeClass = (index: number): string => {
|
|
|
+ // size-1 对应最小的圆圈,size-3 对应最大的圆圈
|
|
|
+ const size = Math.min(index + 1, 3);
|
|
|
+ return `size-${size}`;
|
|
|
+ };
|
|
|
+
|
|
|
+ // 获取个人排名数据(复制并修改自开屏页)
|
|
|
+ const fetchRankingData = async (): Promise<void> => {
|
|
|
+ try {
|
|
|
+ // 调用后端API获取用户数据
|
|
|
+ const response = await selectHomePageData();
|
|
|
+
|
|
|
+ // 根据响应结果更新rankingItems
|
|
|
+ if (response != null) {
|
|
|
+ const respObj = response as UTSJSONObject;
|
|
|
+ const data = respObj['data'] as UTSJSONObject;
|
|
|
+
|
|
|
+ // 初始化默认值
|
|
|
+ let deptName = '未知部门';
|
|
|
+ let center = '未知中心';
|
|
|
+ let companyName = '未知公司';
|
|
|
+
|
|
|
+ // 从scoreDept中提取部门、中心和公司名称
|
|
|
+ if (data.hasOwnProperty('scoreDept') && Array.isArray(data['scoreDept']) && (data['scoreDept'] as any[]).length > 0) {
|
|
|
+ const scoreDept = data['scoreDept'] as UTSJSONObject[];
|
|
|
+ const firstItem = scoreDept[0];
|
|
|
+ if (firstItem.hasOwnProperty('deptName')) {
|
|
|
+ deptName = firstItem['deptName'] as string;
|
|
|
+ }
|
|
|
+ if (firstItem.hasOwnProperty('center')) {
|
|
|
+ center = firstItem['center'] as string;
|
|
|
+ }
|
|
|
+ if (firstItem.hasOwnProperty('companyName')) {
|
|
|
+ companyName = firstItem['companyName'] as string;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 更新排名信息
|
|
|
+ const items : RankingItem[] = [];
|
|
|
+
|
|
|
+ // 部门排名(东山电场)
|
|
|
+ if (data.hasOwnProperty('deptSort') && data.hasOwnProperty('scoreDept')) {
|
|
|
+ const deptSort = typeof data['deptSort'] === 'number' ? data['deptSort'] as number : 0;
|
|
|
+ const scoreDept = Array.isArray(data['scoreDept']) ? data['scoreDept'] as any[] : [];
|
|
|
+ // 只有当部门排序大于0且scoreDept数组不为空时才添加
|
|
|
+ if (deptSort > 0 && scoreDept.length > 0) {
|
|
|
+ items.push({
|
|
|
+ name: deptName,
|
|
|
+ rank: deptSort,
|
|
|
+ total: scoreDept.length
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 中心排名(陆上设备维护中心)
|
|
|
+ if (data.hasOwnProperty('centerSort') && data.hasOwnProperty('scoreCenter')) {
|
|
|
+ const centerSort = typeof data['centerSort'] === 'number' ? data['centerSort'] as number : 0;
|
|
|
+ const scoreCenter = Array.isArray(data['scoreCenter']) ? data['scoreCenter'] as any[] : [];
|
|
|
+ // 只有当中心排序大于0且scoreCenter数组不为空时才添加
|
|
|
+ if (centerSort > 0 && scoreCenter.length > 0) {
|
|
|
+ items.push({
|
|
|
+ name: center,
|
|
|
+ rank: centerSort,
|
|
|
+ total: scoreCenter.length
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 公司排名
|
|
|
+ if (data.hasOwnProperty('companySort') && data.hasOwnProperty('scoreCompany')) {
|
|
|
+ const companySort = typeof data['companySort'] === 'number' ? data['companySort'] as number : 0;
|
|
|
+ const scoreCompany = Array.isArray(data['scoreCompany']) ? data['scoreCompany'] as any[] : [];
|
|
|
+ // 只有当公司排序大于0且scoreCompany数组不为空时才添加
|
|
|
+ if (companySort > 0 && scoreCompany.length > 0) {
|
|
|
+ items.push({
|
|
|
+ name: companyName,
|
|
|
+ rank: companySort,
|
|
|
+ total: scoreCompany.length
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 更新rankingItems
|
|
|
+ rankingItems.value = items;
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.error('获取用户排名数据失败:', error);
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ // 新增:切换标签
|
|
|
+ function switchTab(tab: string) {
|
|
|
+ activeTab.value = tab;
|
|
|
+
|
|
|
+ // 当切换到个人排名标签时,获取排名数据
|
|
|
+ if (tab === 'ranking') {
|
|
|
+ fetchRankingData();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
// 打开自定义日期选择弹窗
|
|
|
function showCustomDatePicker() {
|
|
|
showDatePickerPopup.value = true
|
|
|
@@ -828,6 +985,9 @@
|
|
|
loadData(false)
|
|
|
getStatistics()
|
|
|
dictLoaded.value = true
|
|
|
+
|
|
|
+ // 获取初始排名数据
|
|
|
+ fetchRankingData();
|
|
|
})
|
|
|
|
|
|
// 组件销毁时清除定时器
|
|
|
@@ -921,6 +1081,37 @@
|
|
|
padding: 20rpx;
|
|
|
}
|
|
|
|
|
|
+/* 标签切换样式 */
|
|
|
+.stats-tabs {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: row;
|
|
|
+ border-bottom: 2rpx solid #f0f0f0;
|
|
|
+ margin-bottom: 20rpx;
|
|
|
+}
|
|
|
+
|
|
|
+.tab-item {
|
|
|
+ padding: 15rpx 30rpx;
|
|
|
+ font-size: 30rpx;
|
|
|
+ color: #666;
|
|
|
+ position: relative;
|
|
|
+}
|
|
|
+
|
|
|
+.tab-active {
|
|
|
+ color: #165dff;
|
|
|
+ font-weight: bold;
|
|
|
+}
|
|
|
+
|
|
|
+.tab-active::after {
|
|
|
+ content: '';
|
|
|
+ position: absolute;
|
|
|
+ bottom: -2rpx;
|
|
|
+ left: 0;
|
|
|
+ right: 0;
|
|
|
+ height: 6rpx;
|
|
|
+ background-color: #165dff;
|
|
|
+ border-radius: 3rpx;
|
|
|
+}
|
|
|
+
|
|
|
.stats-header {
|
|
|
flex-direction: row;
|
|
|
justify-content: space-between;
|
|
|
@@ -1209,4 +1400,116 @@
|
|
|
color: #ff0000;
|
|
|
border-color: #ff7446;
|
|
|
}
|
|
|
-</style>
|
|
|
+
|
|
|
+/* 个人排名模块样式 */
|
|
|
+.ranking-item-wrapper {
|
|
|
+ padding: 5rpx 30rpx;
|
|
|
+ margin-bottom: 5rpx;
|
|
|
+ background: transparent;
|
|
|
+}
|
|
|
+
|
|
|
+.ranking-item {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: row;
|
|
|
+ align-items: center;
|
|
|
+ width: 100%;
|
|
|
+ padding: 10rpx 0;
|
|
|
+}
|
|
|
+
|
|
|
+.module-title {
|
|
|
+ color: #ffffff;
|
|
|
+ font-size: 36rpx;
|
|
|
+ font-weight: bold;
|
|
|
+ margin-bottom: 0;
|
|
|
+ text-align: center;
|
|
|
+}
|
|
|
+
|
|
|
+.ranking-item {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: row;
|
|
|
+ align-items: center;
|
|
|
+ width: 100%;
|
|
|
+ padding-left: 0;
|
|
|
+ margin-left: 0;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+.ranking-name {
|
|
|
+ color: #000000;
|
|
|
+ font-size: 32rpx;
|
|
|
+ font-weight: normal;
|
|
|
+ flex: 1;
|
|
|
+ margin-left: 20rpx;
|
|
|
+}
|
|
|
+
|
|
|
+.ranking-number {
|
|
|
+ background: #38bdf8;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+}
|
|
|
+
|
|
|
+.ranking-circle-wrapper {
|
|
|
+ width: 100rpx;
|
|
|
+ display: flex;
|
|
|
+ justify-content: center;
|
|
|
+ align-items: center;
|
|
|
+}
|
|
|
+
|
|
|
+.ranking-number.size-1 {
|
|
|
+ width: 60rpx;
|
|
|
+ height: 60rpx;
|
|
|
+ border-radius: 30rpx;
|
|
|
+}
|
|
|
+
|
|
|
+.ranking-number.size-2 {
|
|
|
+ width: 70rpx;
|
|
|
+ height: 70rpx;
|
|
|
+ border-radius: 35rpx;
|
|
|
+}
|
|
|
+
|
|
|
+.ranking-number.size-3 {
|
|
|
+ width: 80rpx;
|
|
|
+ height: 80rpx;
|
|
|
+ border-radius: 40rpx;
|
|
|
+}
|
|
|
+
|
|
|
+.ranking-number-text {
|
|
|
+ color: #ffffff;
|
|
|
+ font-weight: normal;
|
|
|
+ text-align: center;
|
|
|
+ font-size: 28rpx;
|
|
|
+}
|
|
|
+
|
|
|
+.ranking-number.size-1 .ranking-number-text {
|
|
|
+ font-size: 18rpx;
|
|
|
+}
|
|
|
+
|
|
|
+.ranking-number.size-2 .ranking-number-text {
|
|
|
+ font-size: 20rpx;
|
|
|
+}
|
|
|
+
|
|
|
+.ranking-number.size-3 .ranking-number-text {
|
|
|
+ font-size: 22rpx;
|
|
|
+}
|
|
|
+
|
|
|
+.ranking-label {
|
|
|
+ color: #ff0000;
|
|
|
+ font-size: 32rpx;
|
|
|
+ white-space: nowrap;
|
|
|
+ margin-left: 20rpx;
|
|
|
+}
|
|
|
+
|
|
|
+.no-data {
|
|
|
+ display: flex;
|
|
|
+ justify-content: center;
|
|
|
+ align-items: center;
|
|
|
+ height: 200rpx;
|
|
|
+}
|
|
|
+
|
|
|
+.no-data-text {
|
|
|
+ font-size: 28rpx;
|
|
|
+ color: #999;
|
|
|
+}
|
|
|
+</style>
|