- 主题(浅色/深色/跟随系统)与正文字号(标准/大/特大)按账号存在本机, 账号切换不串、退出回默认;深色走 html[data-theme] 与 Element Plus 的 html.dark - style.css 收敛为语义调色板::root 的 53 个变量是文件内仅有的颜色字面量, 其余规则全部走 var(),暗色只覆盖变量 - 字号经 --reader-font-scale 只作用于阅读面,不做全局缩放 - 阅读位置按账号+章节保存滚动比例与该章 content_sha256,正文换版本后不恢复 - 复习页键盘:空格/Enter 显示答案、1/2/3 评分;输入控件与聚焦按钮的按键不被劫持 - 站点头部新增「显示」控件,七个学习页面共用 - Playwright 新增 390×844 hasTouch 的 mobile 项目与移动用例(无溢出、可返回、 触摸滑动不误开面板、深色与字号持久化、账号隔离);新增主题变量回归用例 - Wiki 记录 Architecture、Business-Rules、Local-Development 与需求更新
100 lines
4.6 KiB
Vue
100 lines
4.6 KiB
Vue
<script setup lang="ts">
|
||
import { onMounted } from 'vue'
|
||
import { RouterLink, useRouter } from 'vue-router'
|
||
import { ElButton } from 'element-plus'
|
||
import { useProgressStore } from '../stores/progress'
|
||
import { useSessionStore } from '../stores/session'
|
||
import DisplaySettings from '../components/DisplaySettings.vue'
|
||
|
||
const session = useSessionStore()
|
||
const progress = useProgressStore()
|
||
const router = useRouter()
|
||
|
||
onMounted(() => { void progress.load() })
|
||
|
||
async function logout() {
|
||
try { await session.logout() }
|
||
catch { session.notice = '已退出此设备。服务器暂时无法连接,请稍后重试。' }
|
||
finally { await router.replace('/login') }
|
||
}
|
||
</script>
|
||
|
||
<template>
|
||
<div v-if="session.user">
|
||
<header class="site-header">
|
||
<RouterLink to="/" class="brand">LexGo<span class="brand-dot">.</span></RouterLink>
|
||
<nav aria-label="学习导航"><RouterLink to="/">我的书库</RouterLink> · <RouterLink to="/vocab">生词本</RouterLink> · <RouterLink to="/review">到期复习</RouterLink> · <RouterLink to="/progress">进度</RouterLink></nav>
|
||
<div class="account">
|
||
<DisplaySettings />
|
||
<span class="account-name">{{ session.user.username }}</span>
|
||
<ElButton text @click="logout">退出登录</ElButton>
|
||
</div>
|
||
</header>
|
||
<main class="page progress-page">
|
||
<div class="page-title">
|
||
<div>
|
||
<h1>我的进度</h1>
|
||
<p class="subtle">只统计你自己的记录,按当前学习语言(英语)汇总。</p>
|
||
</div>
|
||
<div class="page-actions">
|
||
<RouterLink to="/review" class="link-button">开始到期复习</RouterLink>
|
||
<ElButton :loading="progress.loading" data-testid="progress-reload" @click="progress.load()">刷新</ElButton>
|
||
</div>
|
||
</div>
|
||
|
||
<p v-if="progress.loading && !progress.loaded" role="status" class="loading">正在加载…</p>
|
||
<div v-else-if="progress.error && !progress.loaded" class="notice">
|
||
<p role="alert">{{ progress.error }}</p>
|
||
<ElButton data-testid="progress-retry" @click="progress.load()">重试</ElButton>
|
||
</div>
|
||
<template v-else>
|
||
<p v-if="progress.error" role="alert" class="notice">{{ progress.error }}</p>
|
||
<section class="progress-stats" aria-label="学习统计">
|
||
<article class="stat-card" data-testid="stat-read">
|
||
<h2>已读章节</h2>
|
||
<p class="stat-value">{{ progress.data.readChapters }} / {{ progress.data.totalChapters }}</p>
|
||
<p class="subtle">章(可阅读)</p>
|
||
</article>
|
||
<article class="stat-card" data-testid="stat-due">
|
||
<h2>待复习</h2>
|
||
<p class="stat-value">{{ progress.data.dueNow }}</p>
|
||
<p class="subtle">个词条现在到期</p>
|
||
</article>
|
||
<article class="stat-card" data-testid="stat-known">
|
||
<h2>已知词</h2>
|
||
<p class="stat-value">{{ progress.data.knownTerms }}</p>
|
||
<p class="subtle">标记为已认识</p>
|
||
</article>
|
||
<article class="stat-card" data-testid="stat-learning">
|
||
<h2>学习中</h2>
|
||
<p class="stat-value">{{ progress.data.learningTerms }}</p>
|
||
<p class="subtle">按间隔复习</p>
|
||
</article>
|
||
<article class="stat-card" data-testid="stat-new">
|
||
<h2>新词</h2>
|
||
<p class="stat-value">{{ progress.data.newTerms }}</p>
|
||
<p class="subtle">刚保存,还没作答</p>
|
||
</article>
|
||
<article class="stat-card" data-testid="stat-ignored">
|
||
<h2>忽略</h2>
|
||
<p class="stat-value">{{ progress.data.ignoredTerms }}</p>
|
||
<p class="subtle">单独统计,不计入已知</p>
|
||
</article>
|
||
</section>
|
||
|
||
<section class="progress-books" aria-label="每本书的阅读进度">
|
||
<h2>每本书的阅读</h2>
|
||
<ul v-if="progress.hasBooks" class="progress-book-list" data-testid="progress-books">
|
||
<li v-for="item in progress.data.books" :key="item.id" class="progress-book-row">
|
||
<RouterLink :to="`/books/${item.id}`" class="chapter-name">{{ item.title }}</RouterLink>
|
||
<span class="subtle">{{ item.readChapters }} / {{ item.totalChapters }} 章已读</span>
|
||
</li>
|
||
</ul>
|
||
<p v-else class="subtle" data-testid="progress-no-books">还没有书。导入或粘贴一段英语,读完后在这里看到进度。</p>
|
||
<p class="subtle" data-testid="progress-saved">已保存词条 {{ progress.data.savedTerms }} 个(含忽略)。</p>
|
||
</section>
|
||
</template>
|
||
</main>
|
||
</div>
|
||
</template>
|