feat(mobile): learning page APP-ification (fold long content, batch 2 of app-like)
学习中心页(全站最长,实测 5452px)按「折叠不删减」治理: - 岗位 SOP 长答案默认收起为 140 字预览+「展开全文/收起全文」 (短答案不出现开关;切换主题自动复位) - 学习资料段落(snippet)默认只显示标题行,点标题展开/收起正文; 超长文档标题两行截断 - 错题本默认 3 条,「展开全部 N 条」可切换(随归因筛选联动) 实测页面高度 5452 → 3834(-30%),其余为八个功能面板固有高度, 继续压缩需删减面板,违背不影响功能原则,不做。 本地+生产复核:高度、段落默认收起、点击展开均通过。 发布备份 h5-before-$TS。 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -98,7 +98,7 @@
|
|||||||
</button>
|
</button>
|
||||||
</view>
|
</view>
|
||||||
<view v-if="visibleMistakes.length" class="mistake-list">
|
<view v-if="visibleMistakes.length" class="mistake-list">
|
||||||
<view v-for="item in visibleMistakes" :key="item.id" class="mistake-row">
|
<view v-for="item in displayedMistakes" :key="item.id" class="mistake-row">
|
||||||
<view class="mistake-copy">
|
<view class="mistake-copy">
|
||||||
<view class="mistake-meta">
|
<view class="mistake-meta">
|
||||||
<text class="mistake-cause">{{ item.cause }}</text>
|
<text class="mistake-cause">{{ item.cause }}</text>
|
||||||
@@ -117,6 +117,9 @@
|
|||||||
</button>
|
</button>
|
||||||
<text v-else-if="item.retryAssignmentId" class="mistake-completed">已完成</text>
|
<text v-else-if="item.retryAssignmentId" class="mistake-completed">已完成</text>
|
||||||
</view>
|
</view>
|
||||||
|
<button v-if="visibleMistakes.length > 3" class="fold-toggle" @click="showAllMistakes = !showAllMistakes">
|
||||||
|
{{ showAllMistakes ? '收起 ▲' : `展开全部 ${visibleMistakes.length} 条 ▼` }}
|
||||||
|
</button>
|
||||||
</view>
|
</view>
|
||||||
<view v-else-if="!mistakeLoading" class="empty">
|
<view v-else-if="!mistakeLoading" class="empty">
|
||||||
{{ mistakes.length ? '当前归因筛选暂无错题' : '完成训练后,低分和红线回合会自动出现在这里' }}
|
{{ mistakes.length ? '当前归因筛选暂无错题' : '完成训练后,低分和红线回合会自动出现在这里' }}
|
||||||
@@ -224,16 +227,26 @@
|
|||||||
{{ topic }}
|
{{ topic }}
|
||||||
</button>
|
</button>
|
||||||
</view>
|
</view>
|
||||||
<text v-if="knowledgeResult?.answer" class="answer-text">{{ knowledgeResult.answer }}</text>
|
<text v-if="knowledgeResult?.answer" class="answer-text">{{ displayedAnswer }}</text>
|
||||||
|
<button v-if="answerIsLong" class="fold-toggle" @click="showFullAnswer = !showFullAnswer">
|
||||||
|
{{ showFullAnswer ? '收起全文 ▲' : '展开全文 ▼' }}
|
||||||
|
</button>
|
||||||
<view v-if="knowledgeResult?.keyPoints?.length" class="keypoints">
|
<view v-if="knowledgeResult?.keyPoints?.length" class="keypoints">
|
||||||
<text v-for="(point, index) in knowledgeResult.keyPoints" :key="point" class="keypoint">
|
<text v-for="(point, index) in knowledgeResult.keyPoints" :key="point" class="keypoint">
|
||||||
{{ index + 1 }}. {{ cleanOrderedText(point) }}
|
{{ index + 1 }}. {{ cleanOrderedText(point) }}
|
||||||
</text>
|
</text>
|
||||||
</view>
|
</view>
|
||||||
<view v-if="knowledgeResult?.snippets?.length" class="snippet-list">
|
<view v-if="knowledgeResult?.snippets?.length" class="snippet-list">
|
||||||
<view v-for="(snippet, index) in knowledgeResult.snippets?.slice(0, 3)" :key="`${snippet.docTitle}-${index}`" class="snippet-row">
|
<view
|
||||||
<text class="snippet-title">{{ snippet.docTitle || '知识片段' }}</text>
|
v-for="(snippet, index) in knowledgeResult.snippets?.slice(0, 3)"
|
||||||
<text class="snippet-content">{{ snippetExcerpt(snippet.content) }}</text>
|
:key="`${snippet.docTitle}-${index}`"
|
||||||
|
class="snippet-row"
|
||||||
|
>
|
||||||
|
<button class="snippet-head" @click="toggleSnippet(index)">
|
||||||
|
<text class="snippet-title">{{ snippet.docTitle || '知识片段' }}</text>
|
||||||
|
<text class="snippet-arrow">{{ expandedSnippets[index] ? '▲' : '▼' }}</text>
|
||||||
|
</button>
|
||||||
|
<text v-if="expandedSnippets[index]" class="snippet-content">{{ snippetExcerpt(snippet.content) }}</text>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
<view v-else-if="!knowledgeLoading" class="empty">知识库暂未命中可引用内容</view>
|
<view v-else-if="!knowledgeLoading" class="empty">知识库暂未命中可引用内容</view>
|
||||||
@@ -348,6 +361,22 @@ const visibleMistakes = computed(() => activeMistakeCause.value === '全部'
|
|||||||
? mistakes.value
|
? mistakes.value
|
||||||
: mistakes.value.filter((item) => item.cause === activeMistakeCause.value));
|
: mistakes.value.filter((item) => item.cause === activeMistakeCause.value));
|
||||||
|
|
||||||
|
/* APP-like folding: long content collapsed by default, nothing removed. */
|
||||||
|
const ANSWER_PREVIEW_CHARS = 140;
|
||||||
|
const showAllMistakes = ref(false);
|
||||||
|
const showFullAnswer = ref(false);
|
||||||
|
const expandedSnippets = ref<Record<number, boolean>>({});
|
||||||
|
const displayedMistakes = computed(() => (showAllMistakes.value ? visibleMistakes.value : visibleMistakes.value.slice(0, 3)));
|
||||||
|
const answerIsLong = computed(() => (knowledgeResult.value?.answer || '').length > ANSWER_PREVIEW_CHARS);
|
||||||
|
const displayedAnswer = computed(() => {
|
||||||
|
const answer = knowledgeResult.value?.answer || '';
|
||||||
|
if (showFullAnswer.value || answer.length <= ANSWER_PREVIEW_CHARS) return answer;
|
||||||
|
return `${answer.slice(0, ANSWER_PREVIEW_CHARS)}…`;
|
||||||
|
});
|
||||||
|
const toggleSnippet = (index: number) => {
|
||||||
|
expandedSnippets.value = { ...expandedSnippets.value, [index]: !expandedSnippets.value[index] };
|
||||||
|
};
|
||||||
|
|
||||||
const qualificationStatusLabel = computed(() => {
|
const qualificationStatusLabel = computed(() => {
|
||||||
switch (qualification.value?.status) {
|
switch (qualification.value?.status) {
|
||||||
case 'PASSED': return '已通过';
|
case 'PASSED': return '已通过';
|
||||||
@@ -554,6 +583,8 @@ const loadKnowledge = async (topic: string, request: RequestScopeTicket = reques
|
|||||||
const nextKnowledge = await searchKnowledge(topic);
|
const nextKnowledge = await searchKnowledge(topic);
|
||||||
if (!requests.isCurrent(request)) return;
|
if (!requests.isCurrent(request)) return;
|
||||||
knowledgeResult.value = nextKnowledge;
|
knowledgeResult.value = nextKnowledge;
|
||||||
|
showFullAnswer.value = false;
|
||||||
|
expandedSnippets.value = {};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (!requests.isCurrent(request)) return;
|
if (!requests.isCurrent(request)) return;
|
||||||
knowledgeResult.value = null;
|
knowledgeResult.value = null;
|
||||||
@@ -1157,4 +1188,53 @@ onUnload(invalidateRequests);
|
|||||||
.action-button {
|
.action-button {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.fold-toggle {
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
margin: 10px 0 0;
|
||||||
|
padding: 8px 0;
|
||||||
|
border: none;
|
||||||
|
border-top: 1px dashed #eceff2;
|
||||||
|
background: transparent;
|
||||||
|
color: #6b7480;
|
||||||
|
font-size: 13px;
|
||||||
|
text-align: center;
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fold-toggle::after {
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.snippet-head {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 8px;
|
||||||
|
width: 100%;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
border: none;
|
||||||
|
background: transparent;
|
||||||
|
text-align: left;
|
||||||
|
line-height: 1.4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.snippet-head::after {
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.snippet-arrow {
|
||||||
|
flex-shrink: 0;
|
||||||
|
color: #98a1ad;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.snippet-head .snippet-title {
|
||||||
|
display: -webkit-box;
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
-webkit-line-clamp: 2;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
Reference in New Issue
Block a user