feat: restore learning feedback and knowledge capabilities
This commit is contained in:
@@ -22,22 +22,42 @@
|
||||
<view>
|
||||
<text class="panel-title">岗位身份</text>
|
||||
<text class="position-title">{{ positionProfile.value }} · {{ positionProfile.heroTitle }}</text>
|
||||
<text class="position-source">岗位来自人力系统组织同步,如需调整请联系 HR。</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="position-actions">
|
||||
<button
|
||||
v-for="item in positionCards"
|
||||
:key="item.value"
|
||||
class="position-chip"
|
||||
:class="{ active: item.value === positionProfile.value }"
|
||||
@click="changePosition(item.value)"
|
||||
>
|
||||
{{ item.value }}
|
||||
</button>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view v-if="profile" class="panel profile-summary">
|
||||
<view v-if="supervisorLearning" class="panel supervisor-mode-panel">
|
||||
<view>
|
||||
<text class="panel-title">当前为学员模式</text>
|
||||
<text class="position-source">主管组织身份未改变,仅切换到个人学习与训练界面。</text>
|
||||
</view>
|
||||
<button class="secondary-button account-action" @click="returnToSupervisor">返回主管工作台</button>
|
||||
</view>
|
||||
|
||||
<view class="panel display-panel">
|
||||
<view class="display-heading">
|
||||
<view>
|
||||
<text class="panel-title">显示与辅助</text>
|
||||
<text class="display-current">字体大小 · {{ currentFontSizeLabel }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="font-size-options" role="group" aria-label="字体大小">
|
||||
<button
|
||||
v-for="option in appFontSizeOptions"
|
||||
:key="option.value"
|
||||
class="font-size-option"
|
||||
:class="{ active: fontSize === option.value }"
|
||||
:aria-pressed="fontSize === option.value"
|
||||
@click="changeFontSize(option.value)"
|
||||
>
|
||||
{{ option.label }}
|
||||
</button>
|
||||
</view>
|
||||
<text class="display-note">选择后会同步到今日、练、问、我等全部页面,并保留你的设置。</text>
|
||||
</view>
|
||||
|
||||
<view v-if="loggedIn && profile" class="panel profile-summary">
|
||||
<text class="panel-title">成长摘要</text>
|
||||
<text class="ai-score-disclaimer">AI训练综合分仅作训练参考,不等于BRD五维绩效总分,人可复核/否决</text>
|
||||
<view class="score-row">
|
||||
@@ -92,7 +112,15 @@
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view v-if="evidence" class="panel evidence-panel">
|
||||
<button v-if="loggedIn" class="panel points-entry" @click="openPoints">
|
||||
<view>
|
||||
<text class="panel-title">我的积分</text>
|
||||
<text class="points-entry-desc">查看问题榜奖励积分与学习学分明细</text>
|
||||
</view>
|
||||
<text class="points-entry-arrow">›</text>
|
||||
</button>
|
||||
|
||||
<view v-if="loggedIn && evidence" class="panel evidence-panel">
|
||||
<text class="panel-title">成长证据包(待人工复核)</text>
|
||||
<view class="evidence-grid">
|
||||
<view class="evidence-metric">
|
||||
@@ -153,20 +181,24 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue';
|
||||
import { computed, ref } from 'vue';
|
||||
import { onShow } from '@dcloudio/uni-app';
|
||||
import type { CompetencyProfile, PracticeRecord, PromotionEvidence } from '@/types/api';
|
||||
import {
|
||||
clearAuth,
|
||||
getAuth,
|
||||
getPositionProfile,
|
||||
getSelectedPositionProfile,
|
||||
isLoggedIn,
|
||||
rememberLoginRedirect,
|
||||
saveSelectedPosition,
|
||||
userPositionOptions,
|
||||
type UserPosition
|
||||
isSupervisorLearnerMode,
|
||||
leaveSupervisorLearnerMode,
|
||||
rememberLoginRedirect
|
||||
} from '@/services/auth';
|
||||
import {
|
||||
appFontSizeOptions,
|
||||
getAppFontSize,
|
||||
setAppFontSize,
|
||||
type AppFontSize
|
||||
} from '@/services/accessibility';
|
||||
import { getCompetencyProfile, getPracticeHistory, getPromotionEvidence } from '@/services/practice';
|
||||
import { resetPageScroll } from '@/services/navigation';
|
||||
import { ensureEmployeePosition } from '@/services/position';
|
||||
@@ -179,31 +211,62 @@ const profile = ref<CompetencyProfile | null>(null);
|
||||
const history = ref<PracticeRecord[]>([]);
|
||||
const evidence = ref<PromotionEvidence | null>(null);
|
||||
const positionProfile = ref(getSelectedPositionProfile());
|
||||
const positionCards = userPositionOptions.map((item) => getPositionProfile(item));
|
||||
const supervisorLearning = ref(false);
|
||||
const fontSize = ref<AppFontSize>(getAppFontSize());
|
||||
const currentFontSizeLabel = computed(() =>
|
||||
appFontSizeOptions.find((item) => item.value === fontSize.value)?.label || '标准'
|
||||
);
|
||||
let profileLoadGeneration = 0;
|
||||
let profileAccountPhone = '';
|
||||
|
||||
const refreshAuth = () => {
|
||||
const auth = getAuth();
|
||||
loggedIn.value = isLoggedIn();
|
||||
phone.value = auth.phone;
|
||||
positionProfile.value = getSelectedPositionProfile();
|
||||
supervisorLearning.value = isSupervisorLearnerMode();
|
||||
fontSize.value = getAppFontSize();
|
||||
};
|
||||
|
||||
const changeFontSize = (value: AppFontSize) => {
|
||||
fontSize.value = setAppFontSize(value);
|
||||
uni.showToast({ title: `已切换为${currentFontSizeLabel.value}`, icon: 'none' });
|
||||
};
|
||||
|
||||
const returnToSupervisor = () => {
|
||||
leaveSupervisorLearnerMode();
|
||||
supervisorLearning.value = false;
|
||||
uni.redirectTo({ url: '/pages/supervisor/index/index' });
|
||||
};
|
||||
|
||||
const openPoints = () => {
|
||||
uni.navigateTo({ url: '/pages/user/points/index' });
|
||||
};
|
||||
|
||||
const clearProfileData = () => {
|
||||
profile.value = null;
|
||||
history.value = [];
|
||||
evidence.value = null;
|
||||
profileAccountPhone = '';
|
||||
};
|
||||
|
||||
const loadData = async () => {
|
||||
const generation = ++profileLoadGeneration;
|
||||
refreshAuth();
|
||||
if (!loggedIn.value) {
|
||||
clearProfileData();
|
||||
return;
|
||||
}
|
||||
const requestedPhone = getAuth().phone;
|
||||
if (profileAccountPhone && profileAccountPhone !== requestedPhone) {
|
||||
clearProfileData();
|
||||
}
|
||||
if (!(await ensureEmployeePosition('/pages/user/profile/index'))) {
|
||||
return;
|
||||
}
|
||||
refreshAuth();
|
||||
if (generation !== profileLoadGeneration || !loggedIn.value) return;
|
||||
const accountPhone = getAuth().phone;
|
||||
loading.value = true;
|
||||
message.value = '';
|
||||
try {
|
||||
@@ -212,19 +275,27 @@ const loadData = async () => {
|
||||
getCompetencyProfile(),
|
||||
getPromotionEvidence()
|
||||
]);
|
||||
refreshAuth();
|
||||
if (generation !== profileLoadGeneration) return;
|
||||
if (!loggedIn.value || getAuth().phone !== accountPhone) {
|
||||
clearProfileData();
|
||||
return;
|
||||
}
|
||||
history.value = nextHistory || [];
|
||||
profile.value = nextProfile || null;
|
||||
evidence.value = nextEvidence || null;
|
||||
profileAccountPhone = accountPhone;
|
||||
} catch (error) {
|
||||
refreshAuth();
|
||||
if (!loggedIn.value) {
|
||||
if (generation !== profileLoadGeneration) return;
|
||||
if (!loggedIn.value || getAuth().phone !== accountPhone) {
|
||||
clearProfileData();
|
||||
message.value = '登录已过期,请重新登录';
|
||||
message.value = loggedIn.value ? '账号已切换,请刷新' : '登录已过期,请重新登录';
|
||||
return;
|
||||
}
|
||||
message.value = error instanceof Error ? error.message : '我的数据加载失败';
|
||||
} finally {
|
||||
loading.value = false;
|
||||
if (generation === profileLoadGeneration) loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -234,19 +305,14 @@ const goLogin = () => {
|
||||
};
|
||||
|
||||
const logout = () => {
|
||||
profileLoadGeneration += 1;
|
||||
loading.value = false;
|
||||
clearAuth();
|
||||
clearProfileData();
|
||||
refreshAuth();
|
||||
uni.showToast({ title: '已退出', icon: 'none' });
|
||||
};
|
||||
|
||||
const changePosition = (position: UserPosition) => {
|
||||
const saved = saveSelectedPosition(position);
|
||||
if (!saved) return;
|
||||
positionProfile.value = getSelectedPositionProfile();
|
||||
uni.showToast({ title: '岗位已更新', icon: 'none' });
|
||||
};
|
||||
|
||||
const openHistory = (id?: number) => {
|
||||
if (!id) {
|
||||
message.value = '这条训练记录暂不支持查看详情';
|
||||
@@ -313,13 +379,58 @@ onShow(() => {
|
||||
}
|
||||
|
||||
.account-card,
|
||||
.history-head {
|
||||
.history-head,
|
||||
.supervisor-mode-panel,
|
||||
.display-heading {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.display-panel {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 14px;
|
||||
}
|
||||
|
||||
.display-current,
|
||||
.display-note {
|
||||
display: block;
|
||||
margin-top: 7px;
|
||||
color: var(--employee-muted);
|
||||
font-size: 12px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.font-size-options {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
gap: 8px;
|
||||
padding: 4px;
|
||||
border-radius: 14px;
|
||||
background: #f0f3f8;
|
||||
}
|
||||
|
||||
.font-size-option {
|
||||
min-width: 0;
|
||||
min-height: 42px;
|
||||
padding: 0 2px;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 11px;
|
||||
background: transparent;
|
||||
color: var(--employee-text);
|
||||
font-size: 13px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.font-size-option.active {
|
||||
border-color: #f0c8cc;
|
||||
background: #ffffff;
|
||||
color: var(--employee-primary);
|
||||
box-shadow: 0 4px 12px rgba(24, 34, 48, 0.08);
|
||||
}
|
||||
|
||||
.account-card {
|
||||
margin-top: 16px;
|
||||
border-left: 4px solid var(--employee-primary);
|
||||
@@ -352,31 +463,12 @@ onShow(() => {
|
||||
font-weight: 900;
|
||||
}
|
||||
|
||||
.position-actions {
|
||||
display: grid;
|
||||
margin-top: 14px;
|
||||
grid-template-columns: repeat(5, minmax(0, 1fr));
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.position-chip {
|
||||
display: flex;
|
||||
min-height: 38px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border: 1px solid #dce5f2;
|
||||
border-radius: var(--employee-chip-radius);
|
||||
background: #f8fbff;
|
||||
color: #526176;
|
||||
font-size: 13px;
|
||||
font-weight: 900;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.position-chip.active {
|
||||
border-color: var(--employee-primary);
|
||||
background: var(--employee-primary-soft);
|
||||
color: var(--employee-primary);
|
||||
.position-source {
|
||||
display: block;
|
||||
margin-top: 7px;
|
||||
color: var(--employee-muted);
|
||||
font-size: 12px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.profile-summary {
|
||||
@@ -572,6 +664,28 @@ onShow(() => {
|
||||
background: var(--employee-primary);
|
||||
}
|
||||
|
||||
.points-entry {
|
||||
display: flex;
|
||||
width: calc(100% - 0px);
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
color: var(--ink);
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.points-entry-desc {
|
||||
display: block;
|
||||
margin-top: 5px;
|
||||
color: var(--muted);
|
||||
font-size: 13px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.points-entry-arrow {
|
||||
color: var(--muted);
|
||||
font-size: 28px;
|
||||
}
|
||||
|
||||
.dimension-row,
|
||||
.history-row {
|
||||
display: flex;
|
||||
|
||||
Reference in New Issue
Block a user