feat(aihr): align figma pages for release

This commit is contained in:
2026-07-14 02:04:36 +08:00
parent 922fe7ff29
commit 87360a25d3
51 changed files with 3575 additions and 629 deletions
+343
View File
@@ -0,0 +1,343 @@
<template>
<view class="page history-detail-page">
<view class="subpage-header">
<button class="subpage-back-button" aria-label="返回我的页面" title="返回我的页面" @click="goBack">←</button>
<view class="subpage-heading">
<text class="page-title">训练详情</text>
<text class="page-subtitle">{{ detail ? `${detail.scene} · ${detail.time}` : '训练记录' }}</text>
</view>
<button class="ghost-button refresh-button" :disabled="loading" @click="loadDetail">
{{ loading ? '加载中' : '刷新' }}
</button>
</view>
<view v-if="message" class="status-message">{{ message }}</view>
<view v-if="!loggedIn" class="panel login-panel">
<text class="panel-title">需要登录</text>
<text class="muted block">登录后查看训练详情。</text>
<button class="primary-button login-button" @click="goLogin">去登录</button>
</view>
<template v-else-if="detail">
<view class="panel summary-panel">
<view class="summary-head">
<view>
<text class="detail-title">{{ detail.scene }}</text>
<text class="detail-meta">{{ detail.status }} · {{ detail.score }}分</text>
</view>
<text class="score-pill">{{ detail.score }}</text>
</view>
<text class="detail-desc">{{ detail.summary || detail.aiComment || '暂无训练总结' }}</text>
</view>
<view v-if="detail.scoreItems?.length" class="panel">
<text class="panel-title">评分明细</text>
<view v-for="item in detail.scoreItems" :key="item.label" class="score-row">
<view>
<text class="score-label">{{ item.label }}</text>
<text class="score-note">{{ item.note }}</text>
</view>
<text class="score-value">{{ item.value }}</text>
</view>
</view>
<view v-if="detail.dialogue?.length" class="panel">
<text class="panel-title">对话记录</text>
<view v-for="(turn, index) in detail.dialogue" :key="`${turn.role}-${index}`" class="dialogue-row">
<text class="dialogue-label">{{ turn.label }}</text>
<text class="dialogue-text">{{ turn.text }}</text>
<view v-if="hasAudio(turn)" class="audio-block">
<audio v-if="audioSrc(turn, index)" class="audio-player" controls :src="audioSrc(turn, index)" />
<button v-else class="secondary-button" :disabled="audioLoading[index]" @click="loadAudio(turn, index)">
{{ audioLoading[index] ? '加载中' : '加载录音' }}
</button>
<text v-if="audioErrors[index]" class="audio-error">{{ audioErrors[index] }}</text>
</view>
</view>
</view>
<view v-if="detail.annotations?.length || detail.mentorRewrite" class="panel">
<text class="panel-title">复盘建议</text>
<view v-for="item in detail.annotations" :key="`${item.turnIndex}-${item.issue}`" class="annotation-row">
<text class="annotation-issue">{{ item.issue }}</text>
<text class="annotation-rewrite">建议:{{ item.rewrite }}</text>
<text class="annotation-sop">依据:{{ item.sopPoint }}</text>
</view>
<view v-if="detail.mentorRewrite" class="mentor-block">
<text class="subsection-title">推荐话术</text>
<text class="mentor-text">{{ detail.mentorRewrite }}</text>
</view>
</view>
</template>
<view v-else-if="loggedIn && !loading" class="panel empty-panel">
<text class="empty">{{ message || '训练记录不存在或不属于当前账号' }}</text>
<button class="secondary-button" @click="goBack">返回我的页面</button>
</view>
</view>
</template>
<script setup lang="ts">
import { onLoad, onUnload } from '@dcloudio/uni-app';
import { ref } from 'vue';
import type { ReviewDetail, ReviewDialogue } from '@/types/api';
import { authenticatedFileUrl, releaseAuthenticatedFileUrl } from '@/services/api';
import { isLoggedIn, rememberLoginRedirect } from '@/services/auth';
import { getPracticeHistoryDetail } from '@/services/practice';
import { resetPageScroll } from '@/services/navigation';
const detail = ref<ReviewDetail | null>(null);
const reviewId = ref(0);
const loggedIn = ref(isLoggedIn());
const loading = ref(false);
const message = ref('');
const audioSources = ref<Record<number, string>>({});
const audioLoading = ref<Record<number, boolean>>({});
const audioErrors = ref<Record<number, string>>({});
const audioSrc = (turn: ReviewDialogue, index: number) => audioSources.value[index] || turn.audioUrl || '';
const hasAudio = (turn: ReviewDialogue) => Boolean(turn.audioOssId || turn.audioUrl);
const releaseAudio = () => {
Object.values(audioSources.value).forEach(releaseAuthenticatedFileUrl);
audioSources.value = {};
};
const loadAudio = async (turn: ReviewDialogue, index: number) => {
if (!turn.audioOssId || audioLoading.value[index]) return;
audioLoading.value = { ...audioLoading.value, [index]: true };
audioErrors.value = { ...audioErrors.value, [index]: '' };
try {
audioSources.value = {
...audioSources.value,
[index]: await authenticatedFileUrl(`/api/aihr/mobile/oss/${turn.audioOssId}`)
};
} catch {
audioErrors.value = { ...audioErrors.value, [index]: '录音加载失败,请稍后重试' };
} finally {
audioLoading.value = { ...audioLoading.value, [index]: false };
}
};
const loadDetail = async () => {
loggedIn.value = isLoggedIn();
if (!loggedIn.value) return;
if (!reviewId.value) {
message.value = '缺少有效的训练记录ID';
return;
}
loading.value = true;
message.value = '';
releaseAudio();
try {
detail.value = await getPracticeHistoryDetail(reviewId.value);
} catch (error) {
detail.value = null;
message.value = error instanceof Error ? error.message : '训练详情加载失败';
} finally {
loading.value = false;
}
};
const goBack = () => uni.navigateBack({ delta: 1 });
const goLogin = () => {
rememberLoginRedirect(`/pages/user/history/index?id=${reviewId.value}`);
uni.navigateTo({ url: '/pages/auth/login/index' });
};
onLoad((query) => {
reviewId.value = Number(query?.id || 0);
resetPageScroll();
void loadDetail();
});
onUnload(releaseAudio);
</script>
<style scoped>
.history-detail-page {
padding: 0 18px 96px;
}
.subpage-header,
.summary-head {
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
}
.subpage-header {
padding: 20px 0 16px;
}
.subpage-back-button {
width: 36px;
min-width: 36px;
height: 36px;
padding: 0;
border: 1px solid #e1e2e5;
border-radius: 8px;
background: #fff;
color: #25282d;
font-size: 20px;
line-height: 34px;
}
.subpage-heading {
flex: 1;
min-width: 0;
}
.page-title,
.detail-title,
.panel-title,
.score-label,
.dialogue-label,
.annotation-issue,
.subsection-title {
display: block;
color: #25282d;
font-weight: 900;
}
.page-title {
font-size: 22px;
}
.page-subtitle,
.detail-meta,
.detail-desc,
.score-note,
.dialogue-text,
.annotation-rewrite,
.annotation-sop,
.mentor-text,
.muted,
.audio-error {
display: block;
color: #73767c;
font-size: 13px;
line-height: 1.5;
}
.page-subtitle,
.detail-meta {
margin-top: 4px;
}
.panel {
margin-bottom: 12px;
padding: 16px;
border: 1px solid #e1e2e5;
border-radius: 8px;
background: #fff;
}
.summary-panel {
border-top: 3px solid #e60012;
}
.score-pill {
color: #e60012;
font-size: 24px;
font-weight: 900;
}
.detail-desc {
margin-top: 14px;
}
.score-row,
.dialogue-row,
.annotation-row {
padding: 12px 0;
border-top: 1px solid #ececee;
}
.score-row {
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
}
.score-note,
.dialogue-text,
.annotation-rewrite,
.annotation-sop {
margin-top: 4px;
}
.score-value {
color: #e60012;
font-size: 20px;
font-weight: 900;
}
.dialogue-row:first-of-type,
.annotation-row:first-of-type {
margin-top: 8px;
}
.dialogue-text,
.mentor-text {
color: #34373c;
}
.audio-block {
margin-top: 10px;
}
.audio-player {
width: 100%;
}
.audio-error {
margin-top: 6px;
color: #c43b3b;
}
.mentor-block {
margin-top: 12px;
padding-top: 12px;
border-top: 1px solid #ececee;
}
.mentor-text {
margin-top: 6px;
}
.refresh-button,
.secondary-button,
.primary-button {
min-height: 36px;
padding: 0 12px;
border-radius: 8px;
font-size: 13px;
}
.refresh-button,
.secondary-button {
border: 1px solid #dedee1;
background: #fff;
color: #66696f;
}
.primary-button {
border: 0;
background: #e60012;
color: #fff;
}
.login-panel,
.empty-panel {
text-align: center;
}
.login-button,
.empty-panel button {
margin-top: 14px;
}
</style>
+95 -68
View File
@@ -774,11 +774,12 @@ onShow(() => {
.practice-head::after {
position: absolute;
right: 28px;
bottom: 24px;
width: 56px;
height: 3px;
background: #e70014;
right: 20px;
bottom: 20px;
width: 42px;
height: 4px;
border-radius: 4px;
background: var(--employee-primary);
content: '';
}
@@ -1058,7 +1059,7 @@ onShow(() => {
}
.dialogue-card {
border-color: #f0dfe0;
border-color: #dbe7ff;
box-shadow: var(--employee-card-shadow);
}
@@ -1120,19 +1121,19 @@ onShow(() => {
}
.emotion-fill {
background: #e45757;
background: #6f9cff;
}
.trust-fill {
background: #d51b2b;
background: #2f6bff;
}
.red-flag {
padding: 9px 10px;
border-left: 3px solid #e70014;
border-left: 3px solid #f59e0b;
border-radius: 4px;
background: #fff2f3;
color: #bd0010;
background: #fff7e6;
color: #a15c00;
font-size: 13px;
font-weight: 800;
line-height: 1.45;
@@ -1162,19 +1163,19 @@ onShow(() => {
}
.turn-row.trainee {
border-left-color: #e70014;
background: #fff6f6;
border-left-color: #2f6bff;
background: #eef4ff;
}
.turn-row.coach {
border-left-color: #d98282;
background: #fff5f5;
border-left-color: #8bb1ff;
background: #f4f7ff;
}
.reply-actions button.recording-active {
border-color: #e70014;
background: #fff5f5;
color: #e70014;
border-color: #2f6bff;
background: #eef4ff;
color: #2f6bff;
}
.turn-role {
@@ -1198,9 +1199,9 @@ onShow(() => {
.style-chip {
width: auto;
border-color: #f0c8ca;
border-color: #c9d9ff;
background: #ffffff;
color: #d51b2b;
color: #2f6bff;
}
.reply-card {
@@ -1210,7 +1211,7 @@ onShow(() => {
.practice-textarea {
min-height: 124px;
border-color: #f0dfe0;
border-color: #dbe7ff;
border-radius: 18px;
background: #f9fbff;
}
@@ -1230,8 +1231,8 @@ onShow(() => {
.help-ref {
padding: 5px 8px;
border-radius: 5px;
background: #fff1f2;
color: #d51b2b;
background: #eef4ff;
color: #2f6bff;
font-size: 12px;
font-weight: 800;
}
@@ -1243,7 +1244,7 @@ onShow(() => {
}
.result-score {
color: #e52323;
color: #2f6bff;
font-size: 44px;
font-weight: 900;
line-height: 1;
@@ -1261,55 +1262,56 @@ onShow(() => {
flex-direction: column;
gap: 6px;
padding: 12px;
border-left: 3px solid #e52323;
border-left: 3px solid #2f6bff;
border-radius: 6px;
background: #fff6f6;
background: #eef4ff;
}
.mentor-rewrite text:first-child {
color: #c71927;
color: #2f6bff;
font-weight: 900;
}
/* 练页入口态:对应高保真原型,真实对话状态仍沿用下方业务面板 */
/* 练页入口态:与员工端蓝白轻卡片体系保持一致 */
.practice-page {
padding: 0 18px 104px;
background: #fafafa;
padding: 0 16px 108px;
background: linear-gradient(180deg, var(--employee-bg-soft) 0%, var(--employee-bg) 100%);
}
.practice-head {
margin: 0 -18px;
padding: 36px 18px 26px;
background: #ffffff;
text-align: center;
margin: 0 -16px;
padding: 30px 20px 24px;
border-bottom: 1px solid var(--employee-line);
background: linear-gradient(180deg, #eef4ff 0%, #f5f8fd 100%);
text-align: left;
}
.practice-head::after,
.practice-eyebrow,
.practice-tip {
display: none;
display: block;
}
.practice-head .page-title {
color: #111111;
font-size: 38px;
color: var(--employee-text);
font-size: 30px;
font-weight: 900;
}
.practice-head .page-subtitle {
max-width: none;
margin-top: 8px;
color: #858991;
font-size: 16px;
color: var(--employee-muted);
font-size: 14px;
}
.scenario-card {
position: relative;
overflow: hidden;
margin-top: 18px;
margin-top: 16px;
padding: 22px 18px 18px;
border: 0;
border-radius: 20px;
border-radius: var(--employee-card-radius);
border-left: 0;
background: #ffffff;
box-shadow: 0 8px 24px rgba(24, 28, 36, 0.06);
@@ -1323,13 +1325,13 @@ onShow(() => {
}
.scenario-title {
color: #111111;
color: var(--employee-text);
font-size: 30px;
font-weight: 900;
}
.scenario-desc {
color: #858991;
color: var(--employee-muted);
font-size: 17px;
}
@@ -1340,7 +1342,7 @@ onShow(() => {
width: 42%;
height: 108px;
border-radius: 50%;
background: #fff1f2;
background: var(--employee-primary-soft);
opacity: 0.9;
}
@@ -1352,7 +1354,7 @@ onShow(() => {
height: 76px;
border-radius: 12px;
background: #ffffff;
box-shadow: 0 8px 16px rgba(231, 0, 20, 0.08);
box-shadow: 0 8px 16px rgba(47, 107, 255, 0.08);
transform: rotate(7deg);
}
@@ -1363,7 +1365,7 @@ onShow(() => {
width: 48px;
height: 6px;
border-radius: 6px;
background: #f5dfe1;
background: #dce8ff;
content: '';
}
@@ -1386,11 +1388,11 @@ onShow(() => {
align-items: center;
justify-content: center;
border-radius: 14px;
background: #ef5b61;
background: #7ba4ff;
color: #ffffff;
font-size: 19px;
letter-spacing: 3px;
box-shadow: 0 8px 14px rgba(231, 0, 20, 0.16);
box-shadow: 0 8px 14px rgba(47, 107, 255, 0.16);
}
.visual-bubble::after {
@@ -1399,7 +1401,7 @@ onShow(() => {
bottom: -7px;
width: 14px;
height: 14px;
background: #ef5b61;
background: #7ba4ff;
content: '';
transform: rotate(35deg);
}
@@ -1421,27 +1423,47 @@ onShow(() => {
justify-content: center;
gap: 4px;
padding: 8px;
border: 1px solid #f4d9da;
border: 1px solid #dce8ff;
border-radius: 12px;
background: #fffafa;
background: #f8fbff;
}
.prep-mini .prep-label {
color: #e70014;
color: var(--employee-primary);
font-size: 15px;
font-weight: 800;
}
.prep-mini text:last-child {
color: #8c8f96;
color: var(--employee-muted);
font-size: 11px;
line-height: 1.3;
}
.scenario-card .primary-button {
margin-top: 18px;
background: #e70014;
box-shadow: 0 8px 16px rgba(231, 0, 20, 0.18);
background: linear-gradient(135deg, #2f6bff, #5a8cff);
box-shadow: 0 8px 16px rgba(47, 107, 255, 0.18);
}
.login-panel {
border-left-color: var(--employee-primary);
}
.assignment-row {
border-color: #dbe7ff;
}
.assignment-row.highlighted {
border-color: #9bbaff;
background: #f4f7ff;
}
.assignment-badge,
.assignment-badge.daily,
.scenario-badge {
background: var(--employee-primary-soft);
color: var(--employee-primary);
}
.recent-panel,
@@ -1449,14 +1471,14 @@ onShow(() => {
margin-top: 14px;
padding: 18px;
border: 0;
border-radius: 20px;
border-radius: var(--employee-card-radius);
background: #ffffff;
box-shadow: 0 8px 24px rgba(24, 28, 36, 0.05);
}
.recent-link,
.daily-action-label {
color: #858991;
color: var(--employee-muted);
font-size: 14px;
}
@@ -1481,8 +1503,8 @@ onShow(() => {
justify-content: center;
margin-right: 12px;
border-radius: 50%;
background: #fff1f2;
color: #e52323;
background: var(--employee-primary-soft);
color: var(--employee-primary);
font-size: 24px;
font-weight: 800;
}
@@ -1502,7 +1524,7 @@ onShow(() => {
.recent-row .assignment-desc {
margin-top: 4px;
color: #858991;
color: var(--employee-muted);
}
.recent-arrow {
@@ -1517,7 +1539,7 @@ onShow(() => {
.daily-subtitle {
display: block;
margin-top: 4px;
color: #858991;
color: var(--employee-muted);
font-size: 14px;
}
@@ -1529,17 +1551,17 @@ onShow(() => {
gap: 5px;
margin-top: 14px;
padding: 0 14px;
border: 1px dashed #f0c8ca;
border: 1px dashed #cfe0ff;
border-radius: 14px;
background: #fffafa;
color: #858991;
background: #f8fbff;
color: var(--employee-muted);
font-size: 13px;
line-height: 1.45;
text-align: center;
}
.daily-empty text:first-child {
color: #d51b2b;
color: var(--employee-primary);
font-size: 15px;
font-weight: 800;
}
@@ -1556,13 +1578,18 @@ onShow(() => {
margin-top: 8px;
}
.daily-row .small-button {
background: linear-gradient(135deg, #2f6bff, #5a8cff);
box-shadow: 0 6px 12px rgba(47, 107, 255, 0.16);
}
.capability-strip {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 0;
margin-top: 14px;
padding: 16px 8px;
border-radius: 18px;
border-radius: var(--employee-card-radius);
background: #ffffff;
box-shadow: 0 8px 24px rgba(24, 28, 36, 0.05);
}
@@ -1580,13 +1607,13 @@ onShow(() => {
}
.capability-strip text:first-child {
color: #1a1a1a;
color: var(--employee-text);
font-size: 16px;
font-weight: 800;
}
.capability-strip text:last-child {
color: #8a8d93;
color: var(--employee-muted);
font-size: 11px;
}
</style>
+92 -60
View File
@@ -1,5 +1,5 @@
<template>
<view class="page profile-page">
<view class="page profile-page employee-page-shell">
<view class="profile-head">
<text class="profile-eyebrow">银城物业 · 员工成长</text>
<text class="page-title">我的成长</text>
@@ -120,7 +120,12 @@
<button class="ghost-button refresh-button" :disabled="loading" @click="loadData">刷新</button>
</view>
<view v-if="history.length" class="history-list">
<view v-for="item in history" :key="item.id || item.sessionId || item.time" class="history-row">
<view
v-for="item in history"
:key="item.id || item.sessionId || item.time"
class="history-row history-row-clickable"
@click="openHistory(item.id)"
>
<view>
<text class="history-title">{{ item.scene }}</text>
<text class="history-desc">{{ item.time }} · {{ item.summary }}</text>
@@ -231,6 +236,14 @@ const changePosition = (position: UserPosition) => {
uni.showToast({ title: '岗位已更新', icon: 'none' });
};
const openHistory = (id?: number) => {
if (!id) {
message.value = '这条训练记录暂不支持查看详情';
return;
}
uni.navigateTo({ url: `/pages/user/history/index?id=${id}` });
};
onShow(() => {
resetPageScroll();
void loadData();
@@ -239,45 +252,52 @@ onShow(() => {
<style scoped>
.profile-page {
padding: 0 18px 96px;
background: #f7f7f8;
padding: 0 16px 108px;
}
.profile-page .panel {
border-radius: var(--employee-card-radius);
box-shadow: var(--employee-card-shadow);
}
.profile-head {
position: relative;
margin: 0 -18px;
padding: 34px 28px 26px;
background: #f0f1ee;
margin: 0 -16px;
padding: 30px 20px 26px;
border-bottom: 1px solid rgba(47, 74, 117, 0.08);
background: linear-gradient(180deg, #f8fbff 0%, #edf4ff 100%);
}
.profile-head::after {
position: absolute;
right: 28px;
bottom: 24px;
width: 56px;
height: 3px;
background: #e70014;
right: 20px;
bottom: 20px;
width: 42px;
height: 4px;
border-radius: 4px;
background: var(--employee-primary);
content: '';
}
.profile-eyebrow {
display: block;
margin-bottom: 12px;
color: #168243;
margin-bottom: 10px;
color: var(--employee-primary);
font-size: 13px;
font-weight: 800;
line-height: 1;
letter-spacing: 0.04em;
line-height: 1.2;
}
.profile-head .page-title {
color: #25282d;
font-size: 32px;
line-height: 1.16;
color: var(--employee-text);
font-size: 28px;
line-height: 1.2;
}
.profile-head .page-subtitle {
margin-top: 10px;
color: #696c72;
color: var(--employee-muted);
font-size: 14px;
}
@@ -290,15 +310,14 @@ onShow(() => {
}
.account-card {
margin-top: 22px;
border-left: 4px solid #e70014;
box-shadow: 0 8px 22px rgba(37, 40, 45, 0.08);
margin-top: 16px;
border-left: 4px solid var(--employee-primary);
}
.account-phone {
display: block;
margin-top: 8px;
color: #676a70;
color: var(--employee-muted);
font-size: 14px;
}
@@ -317,7 +336,7 @@ onShow(() => {
.position-title {
display: block;
margin-top: 8px;
color: #168243;
color: var(--employee-primary);
font-size: 16px;
font-weight: 900;
}
@@ -334,24 +353,24 @@ onShow(() => {
min-height: 38px;
align-items: center;
justify-content: center;
border: 1px solid #dedfe2;
border-radius: 6px;
background: #fbfbfb;
color: #5e6167;
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: #168243;
background: #edf7f0;
color: #168243;
border-color: var(--employee-primary);
background: var(--employee-primary-soft);
color: var(--employee-primary);
}
.profile-summary {
border-color: #d9e7de;
border-top: 3px solid #168243;
border-color: var(--employee-line);
border-top: 3px solid var(--employee-primary);
}
.score-row {
@@ -367,12 +386,12 @@ onShow(() => {
flex-direction: column;
align-items: center;
justify-content: center;
border-radius: 8px;
background: #edf7f0;
border-radius: 18px;
background: var(--employee-primary-soft);
}
.score-value {
color: #168243;
color: var(--employee-primary);
font-size: 42px;
font-weight: 900;
line-height: 1;
@@ -380,7 +399,7 @@ onShow(() => {
.score-label {
margin-top: 8px;
color: #5f6268;
color: var(--employee-muted);
font-size: 13px;
}
@@ -396,26 +415,27 @@ onShow(() => {
flex-direction: column;
justify-content: center;
padding: 8px 10px;
border-radius: 6px;
background: #f4f4f5;
border: 1px solid var(--employee-line);
border-radius: 14px;
background: #fbfdff;
}
.metric text:first-child {
color: #303338;
color: var(--employee-text);
font-size: 18px;
font-weight: 900;
}
.metric text:last-child {
margin-top: 4px;
color: #73767c;
color: var(--employee-muted);
font-size: 12px;
}
.evidence-panel {
border-color: #eadfbd;
border-left: 4px solid #d98200;
background: #fffdf7;
border-color: #f4e4c4;
border-left: 4px solid var(--employee-warning);
background: #fffaf2;
}
.evidence-grid {
@@ -431,19 +451,20 @@ onShow(() => {
flex-direction: column;
justify-content: center;
padding: 8px 10px;
border-radius: 6px;
border: 1px solid #f4e7ce;
border-radius: 14px;
background: #ffffff;
}
.evidence-metric text:first-child {
color: #a86100;
color: #b56b14;
font-size: 18px;
font-weight: 900;
}
.evidence-metric text:last-child {
margin-top: 4px;
color: #73767c;
color: var(--employee-muted);
font-size: 12px;
}
@@ -494,14 +515,14 @@ onShow(() => {
}
.growth-title {
color: #34373c;
color: var(--employee-text);
font-size: 14px;
font-weight: 900;
}
.growth-desc {
margin-top: 5px;
color: #73767c;
color: var(--employee-muted);
font-size: 12px;
line-height: 1.4;
}
@@ -513,7 +534,7 @@ onShow(() => {
align-items: flex-end;
justify-content: center;
gap: 6px;
color: #168243;
color: var(--employee-primary);
font-size: 12px;
font-weight: 900;
}
@@ -523,13 +544,13 @@ onShow(() => {
height: 6px;
overflow: hidden;
border-radius: 4px;
background: #dce8e0;
background: #dce8fb;
}
.growth-fill {
height: 100%;
border-radius: inherit;
background: #168243;
background: var(--employee-primary);
}
.dimension-row,
@@ -545,7 +566,7 @@ onShow(() => {
.dimension-title,
.history-title {
display: block;
color: #34373c;
color: var(--employee-text);
font-weight: 900;
}
@@ -553,13 +574,13 @@ onShow(() => {
.history-desc {
display: block;
margin-top: 5px;
color: #73767c;
color: var(--employee-muted);
font-size: 13px;
line-height: 1.4;
}
.dimension-score {
color: #168243;
color: var(--employee-primary);
font-size: 20px;
font-weight: 900;
}
@@ -567,14 +588,25 @@ onShow(() => {
.refresh-button {
min-height: 36px;
padding: 0 12px;
border: 1px solid #dedee1;
border: 1px solid #dce5f2;
border-radius: var(--employee-chip-radius);
background: #ffffff;
color: #66696f;
color: #526176;
font-size: 13px;
}
.history-panel {
border-color: #e1e2e5;
border-color: var(--employee-line);
}
.history-row-clickable {
min-height: 68px;
padding: 14px 4px;
cursor: pointer;
}
.history-row-clickable:active {
opacity: 0.72;
}
.history-score {
@@ -585,14 +617,14 @@ onShow(() => {
}
.history-score text:first-child {
color: #168243;
color: var(--employee-primary);
font-size: 20px;
font-weight: 900;
}
.history-score text:last-child {
margin-top: 4px;
color: #73767c;
color: var(--employee-muted);
font-size: 12px;
}
</style>
+139 -83
View File
@@ -61,8 +61,14 @@
</view>
<view v-if="result" class="panel answer-panel employee-card">
<text class="panel-title">直给答案</text>
<text class="answer-text">{{ result.answer || '未生成直接答案,请查看下方引用。' }}</text>
<text class="panel-title">师傅回答</text>
<view class="question-card">
<text class="question-label">我的问题</text>
<text class="question-text">{{ query }}</text>
</view>
<view class="answer-copy-card">
<text class="answer-text">{{ result.answer || '未生成直接答案,请查看下方引用。' }}</text>
</view>
<view v-if="result.keyPoints?.length" class="keypoints">
<text v-for="(point, index) in result.keyPoints" :key="point" class="keypoint">
@@ -81,7 +87,7 @@
:disabled="feedbackSubmitting || Boolean(feedbackVerdict)"
@click="feedback('up')"
>
有用
有帮助
</button>
<button
class="secondary-button"
@@ -89,9 +95,12 @@
:disabled="feedbackSubmitting || Boolean(feedbackVerdict)"
@click="feedback('down')"
>
需要复核
没解决
</button>
</view>
<text v-if="feedbackVerdict" class="feedback-status">
{{ feedbackVerdict === 'up' ? '已记录为有帮助' : '已提交未解决反馈,后续会继续优化这条答案' }}
</text>
</view>
<view v-if="result?.snippets?.length" class="panel sources-panel">
@@ -115,7 +124,7 @@
<view class="modal-card" @click.stop>
<view class="modal-header">
<text class="modal-title">{{ summaryCard.title }}</text>
<button class="modal-close" @click="closeSummary">×</button>
<button class="modal-close" aria-label="关闭总结卡" title="关闭总结卡" @click="closeSummary">×</button>
</view>
<scroll-view scroll-y class="modal-body">
<view v-if="summaryCard.steps?.length" class="info-section">
@@ -378,24 +387,26 @@ onShow(() => {
<style scoped>
.sop-page {
padding: 0 18px 96px;
padding: 0 16px 108px;
background: linear-gradient(180deg, var(--employee-bg-soft) 0%, var(--employee-bg) 100%);
}
.sop-head {
position: relative;
margin: 0 -18px;
padding: 30px 28px 24px;
margin: 0 -16px;
padding: 30px 20px 24px;
border-bottom: 1px solid var(--employee-line);
background: linear-gradient(180deg, #eef4ff 0%, #f5f8fd 100%);
}
.sop-head::after {
position: absolute;
right: 28px;
bottom: 24px;
width: 56px;
height: 3px;
background: #e70014;
right: 20px;
bottom: 20px;
width: 42px;
height: 4px;
border-radius: 4px;
background: var(--employee-primary);
content: '';
}
@@ -436,7 +447,7 @@ onShow(() => {
}
.query-panel {
margin-top: 22px;
margin-top: 16px;
padding: 20px;
border-top: 0;
box-shadow: var(--employee-card-shadow);
@@ -523,13 +534,43 @@ onShow(() => {
}
.answer-panel {
border-color: #d9e7de;
border-left: 4px solid #168243;
border-color: var(--employee-line);
border-left: 4px solid var(--employee-primary);
box-shadow: var(--employee-card-shadow);
}
.answer-panel .panel-title {
color: #168243;
color: var(--employee-primary);
}
.question-card,
.answer-copy-card {
display: flex;
flex-direction: column;
gap: 6px;
margin-top: 12px;
padding: 14px 16px;
border-radius: 14px;
}
.question-card {
background: #fff1f1;
}
.question-label {
color: #e34b4b;
font-size: 13px;
font-weight: 700;
}
.question-text {
color: #25282d;
font-size: 16px;
line-height: 1.55;
}
.answer-copy-card {
background: #fff;
}
.keypoints {
@@ -568,15 +609,25 @@ onShow(() => {
}
.feedback-actions .active {
border-color: #168243;
background: #edf7f0;
color: #168243;
border-color: var(--employee-primary);
background: var(--employee-primary-soft);
color: var(--employee-primary);
}
.feedback-actions .negative {
border-color: #e70014;
background: #fff1f2;
color: #bd0010;
border-color: var(--employee-danger);
background: #fff1f0;
color: #c34d45;
}
.feedback-status {
display: block;
padding: 10px 12px;
border-radius: 12px;
background: var(--employee-primary-soft);
color: var(--employee-primary);
font-size: 13px;
line-height: 1.5;
}
.sources-panel {
@@ -600,7 +651,8 @@ onShow(() => {
gap: 6px;
padding: 14px;
border: 1px solid #e3e4e7;
border-radius: 8px;
border-color: var(--employee-line);
border-radius: 18px;
background: #ffffff;
box-shadow: 0 5px 14px rgba(37, 40, 45, 0.04);
}
@@ -629,8 +681,8 @@ onShow(() => {
}
.summary-panel {
border-color: #eadfbd;
background: #fffdf7;
border-color: #f4e4c4;
background: #fffaf2;
box-shadow: var(--employee-card-shadow);
}
@@ -719,7 +771,8 @@ onShow(() => {
.footer-btn {
width: 100%;
background: #168243;
background: var(--employee-primary);
box-shadow: 0 8px 18px rgba(47, 107, 255, 0.18);
color: #ffffff;
}
@@ -915,55 +968,55 @@ onShow(() => {
line-height: 1.45;
}
/* 视觉稿对齐:与练页统一的红白卡片体系 */
/* 视觉稿对齐:与员工端练页统一的蓝白轻卡片体系 */
.sop-page {
padding: 0 18px 96px;
background: #fafafa;
padding: 0 16px 108px;
background: linear-gradient(180deg, var(--employee-bg-soft) 0%, var(--employee-bg) 100%);
}
.sop-head {
margin: 0 -18px;
padding: 34px 18px 24px;
background: #ffffff;
text-align: center;
margin: 0 -16px;
padding: 30px 20px 24px;
border-bottom: 1px solid var(--employee-line);
background: linear-gradient(180deg, #eef4ff 0%, #f5f8fd 100%);
text-align: left;
}
.sop-head::after,
.sop-eyebrow,
.toolbar-tip {
display: none;
display: block;
}
.sop-head .page-title {
color: #111111;
font-size: 38px;
color: var(--employee-text);
font-size: 30px;
font-weight: 900;
}
.sop-head .page-subtitle {
max-width: none;
margin-top: 10px;
color: #858991;
font-size: 16px;
color: var(--employee-muted);
font-size: 14px;
}
.sop-context {
display: inline-flex;
margin-top: 14px;
padding: 7px 14px;
border: 1px solid #f8d7d8;
border: 1px solid #cfe0ff;
border-radius: 999px;
background: #fff7f7;
color: #d51b2b;
background: var(--employee-primary-soft);
color: var(--employee-primary);
font-size: 13px;
font-weight: 800;
}
.query-panel {
margin-top: 18px;
margin-top: 16px;
padding: 22px 18px 18px;
border: 0;
border-radius: 20px;
border-radius: var(--employee-card-radius);
background: #ffffff;
box-shadow: 0 8px 24px rgba(24, 28, 36, 0.06);
}
@@ -979,18 +1032,18 @@ onShow(() => {
.query-panel .chip {
min-height: 40px;
border-color: #e52323;
border-color: #cfe0ff;
border-radius: 999px;
background: #ffffff;
color: #e52323;
color: var(--employee-primary);
}
.query-submit {
min-height: 54px;
margin-top: 8px;
border-radius: 18px;
background: #e52323;
box-shadow: 0 8px 16px rgba(229, 35, 35, 0.18);
background: linear-gradient(135deg, #2f6bff, #5a8cff);
box-shadow: 0 8px 18px rgba(47, 107, 255, 0.2);
}
.knowledge-tip-card {
@@ -1001,8 +1054,10 @@ onShow(() => {
padding: 16px;
border: 0;
border-radius: 18px;
border: 1px solid var(--employee-line);
border-radius: var(--employee-card-radius);
background: #ffffff;
box-shadow: 0 8px 24px rgba(24, 28, 36, 0.05);
box-shadow: var(--employee-card-shadow);
}
.knowledge-tip-icon {
@@ -1012,8 +1067,8 @@ onShow(() => {
align-items: center;
justify-content: center;
border-radius: 14px;
background: #fff0f1;
color: #e52323;
background: var(--employee-primary-soft);
color: var(--employee-primary);
font-size: 28px;
font-weight: 900;
}
@@ -1050,7 +1105,7 @@ onShow(() => {
padding: 28px 18px;
flex-direction: column;
border: 0;
border-radius: 20px;
border-radius: var(--employee-card-radius);
background: #ffffff;
box-shadow: 0 8px 24px rgba(24, 28, 36, 0.04);
}
@@ -1075,67 +1130,68 @@ onShow(() => {
}
.answer-panel {
border-color: #f0dfe0;
border-left-color: #e52323;
border-color: var(--employee-line);
border-left-color: var(--employee-primary);
}
.answer-panel .panel-title,
.result-score {
color: #e52323;
color: var(--employee-primary);
}
.keypoint,
.speech-bubble {
border-left-color: #e52323;
background: #fff5f5;
border-left-color: var(--employee-primary);
background: var(--employee-primary-soft);
}
.cautions,
.reminder-item {
border-left-color: #e52323;
background: #fff5f5;
color: #b71925;
border-left-color: var(--employee-warning);
background: #fff8ec;
color: #8b5a1d;
}
.feedback-actions .active {
border-color: #e52323;
background: #fff0f1;
color: #e52323;
border-color: var(--employee-primary);
background: var(--employee-primary-soft);
color: var(--employee-primary);
}
.feedback-actions .negative {
border-color: #e52323;
background: #fff0f1;
color: #b71925;
border-color: var(--employee-danger);
background: #fff1f0;
color: #c34d45;
}
.summary-panel {
border-color: #f0dfe0;
border-color: #f4e4c4;
border-radius: var(--employee-card-radius);
background: #ffffff;
}
.summary-panel .ghost-button {
border-color: #e52323;
background: #ffffff;
color: #e52323;
border-color: #cfe0ff;
background: var(--employee-primary-soft);
color: var(--employee-primary);
}
.modal-card {
border-top-color: #e52323;
border-top-color: var(--employee-primary);
}
.badge-num,
.timeline-node {
background: #e52323;
background: var(--employee-primary);
}
.a-badge {
background: #fff0f1;
color: #e52323;
background: var(--employee-primary-soft);
color: var(--employee-primary);
}
.reminder-text {
color: #b71925;
color: #8b5a1d;
}
/* 原型对齐:问师傅主卡的标题与对话插画 */
@@ -1155,14 +1211,14 @@ onShow(() => {
}
.query-title {
color: #111111;
color: var(--employee-text);
font-size: 30px;
font-weight: 900;
line-height: 1.1;
}
.query-subtitle {
color: #858991;
color: var(--employee-muted);
font-size: 15px;
line-height: 1.45;
}
@@ -1174,7 +1230,7 @@ onShow(() => {
width: 42%;
height: 96px;
border-radius: 50%;
background: #fff3f3;
background: var(--employee-primary-soft);
}
.query-bubble {
@@ -1192,7 +1248,7 @@ onShow(() => {
width: 92px;
height: 56px;
border-radius: 28px 28px 28px 10px;
background: #f58d91;
background: #7ba4ff;
color: #ffffff;
font-size: 18px;
}
@@ -1203,7 +1259,7 @@ onShow(() => {
left: 18px;
width: 16px;
height: 16px;
background: #f58d91;
background: #7ba4ff;
content: '';
transform: rotate(28deg);
}
@@ -1215,8 +1271,8 @@ onShow(() => {
height: 42px;
border-radius: 22px 22px 8px 22px;
background: #ffffff;
box-shadow: 0 5px 14px rgba(229, 35, 35, 0.08);
color: #f3b7b9;
box-shadow: 0 5px 14px rgba(47, 107, 255, 0.1);
color: #9bb8ff;
font-size: 13px;
}
+3 -1
View File
@@ -106,7 +106,9 @@
</view>
<text class="schedule-desc">{{ primaryScheduleDesc }}</text>
</view>
<button class="schedule-action" @click="openPrimarySchedule">开始</button>
<button class="schedule-action" @click="openPrimarySchedule">
{{ primaryAssignment?.source === 'daily' ? '去作答' : '开始练习' }}
</button>
</view>
<view class="schedule-row" v-if="home?.review">