feat(aihr): add supervisor mistake aggregation
This commit is contained in:
@@ -46,6 +46,27 @@
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="panel mistake-panel">
|
||||
<view class="section-head">
|
||||
<text class="panel-title">团队错题本</text>
|
||||
<text class="muted">按项目范围聚合</text>
|
||||
</view>
|
||||
<view v-if="mistakes.length" class="mistake-list">
|
||||
<view v-for="item in mistakes" :key="`${item.scenarioId}-${item.cause}`" class="mistake-row">
|
||||
<view class="mistake-main">
|
||||
<view class="mistake-title-row">
|
||||
<text class="mistake-title">{{ item.scenarioName }}</text>
|
||||
<text class="mistake-count">{{ item.count }} 次</text>
|
||||
</view>
|
||||
<text class="mistake-cause">{{ item.cause }} · {{ item.affectedPeople }} 名成员 · 平均 {{ item.averageScore }} 分</text>
|
||||
<text class="mistake-time">最近发生 {{ item.latestTime || '暂无时间' }}</text>
|
||||
</view>
|
||||
<button class="secondary-button mistake-action" @click="openReviews">去待复盘</button>
|
||||
</view>
|
||||
</view>
|
||||
<view v-else class="empty compact-empty">暂无团队错题记录</view>
|
||||
</view>
|
||||
|
||||
<view class="panel team-panel">
|
||||
<view class="section-head">
|
||||
<text class="panel-title">成员列表</text>
|
||||
@@ -120,7 +141,7 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, ref } from 'vue';
|
||||
import { onShow } from '@dcloudio/uni-app';
|
||||
import type { PracticeAssignment, PracticeRecord, PracticeTeamMember } from '@/types/api';
|
||||
import type { PracticeAssignment, PracticeMistakeAggregate, PracticeRecord, PracticeTeamMember } from '@/types/api';
|
||||
import { clearAuth, isLoggedIn, rememberLoginRedirect } from '@/services/auth';
|
||||
import { resetPageScroll } from '@/services/navigation';
|
||||
import { getPracticeTeamSnapshot } from '@/services/practice';
|
||||
@@ -136,6 +157,7 @@ const currentPath = '/pages/supervisor/team/index';
|
||||
const records = ref<PracticeRecord[]>([]);
|
||||
const assignments = ref<PracticeAssignment[]>([]);
|
||||
const members = ref<PracticeTeamMember[]>([]);
|
||||
const mistakes = ref<PracticeMistakeAggregate[]>([]);
|
||||
const loggedIn = ref(false);
|
||||
const accessDenied = ref(false);
|
||||
const loading = ref(false);
|
||||
@@ -161,6 +183,7 @@ const clearData = () => {
|
||||
records.value = [];
|
||||
assignments.value = [];
|
||||
members.value = [];
|
||||
mistakes.value = [];
|
||||
selectedMember.value = null;
|
||||
};
|
||||
|
||||
@@ -201,6 +224,7 @@ const loadPage = async () => {
|
||||
records.value = snapshot.records;
|
||||
assignments.value = snapshot.assignments;
|
||||
members.value = snapshot.members;
|
||||
mistakes.value = snapshot.mistakes ?? [];
|
||||
} catch (error) {
|
||||
handleRequestError(error, '团队画像加载失败');
|
||||
} finally {
|
||||
@@ -223,6 +247,10 @@ const selectMember = (member: TeamProfile) => {
|
||||
selectedMember.value = selectedMember.value?.key === member.key ? null : member;
|
||||
};
|
||||
|
||||
const openReviews = () => {
|
||||
uni.navigateTo({ url: '/pages/supervisor/reviews/index' });
|
||||
};
|
||||
|
||||
const goLogin = () => {
|
||||
rememberLoginRedirect(currentPath);
|
||||
uni.redirectTo({ url: '/pages/auth/login/index' });
|
||||
@@ -340,6 +368,77 @@ onShow(() => {
|
||||
color: var(--employee-primary);
|
||||
}
|
||||
|
||||
.mistake-panel {
|
||||
margin-top: 14px;
|
||||
}
|
||||
|
||||
.mistake-list {
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.mistake-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 10px;
|
||||
padding: 12px 0;
|
||||
border-bottom: 1px solid #e5edf7;
|
||||
}
|
||||
|
||||
.mistake-row:last-child {
|
||||
border-bottom: 0;
|
||||
}
|
||||
|
||||
.mistake-main {
|
||||
min-width: 0;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.mistake-title-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.mistake-title,
|
||||
.mistake-cause,
|
||||
.mistake-time {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.mistake-title {
|
||||
overflow: hidden;
|
||||
color: var(--employee-text);
|
||||
font-size: 14px;
|
||||
font-weight: 900;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.mistake-count {
|
||||
flex: 0 0 auto;
|
||||
color: #b91c1c;
|
||||
font-size: 13px;
|
||||
font-weight: 900;
|
||||
}
|
||||
|
||||
.mistake-cause,
|
||||
.mistake-time {
|
||||
margin-top: 5px;
|
||||
color: var(--employee-muted);
|
||||
font-size: 11px;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.mistake-action {
|
||||
min-width: 64px;
|
||||
min-height: 34px;
|
||||
flex: 0 0 auto;
|
||||
padding: 0 8px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.team-list {
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
@@ -224,6 +224,16 @@ export interface PracticeMistake {
|
||||
summary: string;
|
||||
}
|
||||
|
||||
export interface PracticeMistakeAggregate {
|
||||
scenarioId: string;
|
||||
scenarioName: string;
|
||||
cause: string;
|
||||
count: number;
|
||||
affectedPeople: number;
|
||||
averageScore: number;
|
||||
latestTime: string;
|
||||
}
|
||||
|
||||
export interface PracticeTeamMember {
|
||||
extPartyId: string;
|
||||
name: string;
|
||||
@@ -233,6 +243,7 @@ export interface PracticeTeamSnapshot {
|
||||
members: PracticeTeamMember[];
|
||||
records: PracticeRecord[];
|
||||
assignments: PracticeAssignment[];
|
||||
mistakes: PracticeMistakeAggregate[];
|
||||
}
|
||||
|
||||
export interface ReviewDialogue {
|
||||
|
||||
Reference in New Issue
Block a user