This commit is contained in:
Zyronon
2025-12-30 20:10:13 +08:00
committed by GitHub
parent 8d778a8b44
commit 7b9be69838
22 changed files with 2188 additions and 1126 deletions

View File

@@ -8,7 +8,6 @@
--color-item-border: rgb(226, 226, 226);
--color-tooltip-bg: white;
--color-tooltip-shadow: #d9d9d9;
--color-font-2: rgb(46, 46, 46);
--color-font-3: rgb(102, 116, 135);
--color-font-active-1: white;
@@ -70,6 +69,8 @@
--bg-card-secend: rgb(247, 247, 247);
--bg-book: rgb(226 232 240);
--color-line: rgb(226, 226, 226);
}
html.dark {
@@ -91,8 +92,7 @@ html.dark {
--bg-history: rgb(43, 45, 48);
--color-item-border: rgb(41, 41, 41);
--color-tooltip-bg: #252525;
--color-tooltip-shadow: #3b3b3b;
--color-tooltip-bg: #35373a;
--color-font-2: rgba(255, 255, 255, 0.5);
--color-font-3: rgba(255, 255, 255, 0.3);
@@ -116,6 +116,7 @@ html.dark {
--bg-book: #35373a;
--color-line: rgb(66, 66, 66);
}
@media (max-width: 1720px) {
@@ -403,7 +404,7 @@ a {
.line {
width: 100%;
border-bottom: 1px solid var(--color-item-border);
border-bottom: 1px solid var(--color-line);
@apply hover:text-blue-700;
}

View File

@@ -7,7 +7,7 @@ interface IProps {
disabled?: boolean
loading?: boolean
size?: 'small' | 'normal' | 'large'
type?: 'primary' | 'link' | 'info' | 'orange'
type?: 'primary' | 'info' | 'orange'
}
withDefaults(defineProps<IProps>(), {
@@ -27,12 +27,7 @@ defineEmits(['click'])
:class="[active && 'active', size, type, (disabled || loading) && 'disabled']"
>
<span :style="{ opacity: loading ? 0 : 1 }"><slot></slot></span>
<IconEosIconsLoading
v-if="loading"
class="loading"
width="18"
:color="type === 'info' ? '#000000' : '#ffffff'"
/>
<IconEosIconsLoading v-if="loading" class="loading" width="18" :color="type === 'info' ? '#000000' : '#ffffff'" />
</div>
</Tooltip>
</template>
@@ -45,7 +40,7 @@ defineEmits(['click'])
--btn-info: white;
--btn-info-hover: #eaeaea;
--btn-orange: #facc15;
--btn-orange-hover: #fbe27e;
--btn-orange-hover: #bfac61;
}
html.dark {
@@ -124,15 +119,6 @@ html.dark {
}
}
&.link {
border-radius: 0;
border-bottom: 2px solid transparent;
&:hover:not(.disabled) {
border-bottom: 2px solid var(--color-font-2);
}
}
&.info {
background: var(--btn-info);
border: 1px solid var(--color-main-text);

View File

@@ -18,9 +18,9 @@ export default {
validator(value) {
// Validate that array items have the correct structure
if (Array.isArray(value)) {
return value.every(item =>
typeof item === 'object' &&
item !== null &&
return value.every(item =>
typeof item === 'object' &&
item !== null &&
typeof item.text === 'string' &&
['normal', 'bold', 'red', 'redBold'].includes(item.type)
)
@@ -114,8 +114,8 @@ export default {
<div ref="tip" class="pop-confirm-content shadow-2xl">
<div class="w-52 title-content">
{this.titleItems.map((item, index) => (
<div
key={index}
<div
key={index}
style={this.getTextStyle(item.type)}
class="title-item"
>
@@ -140,17 +140,14 @@ export default {
</script>
<style lang="scss" scoped>
.pop-confirm-content {
position: fixed;
background: var(--color-tooltip-bg);
padding: 1rem;
border-radius: .6rem;
transform: translate(-50%, calc(-100% - .6rem));
z-index: 999;
@apply fixed z-9999 shadow-2xl rounded-lg p-3;
.title-content {
.title-item {
margin-bottom: 0.25rem;
&:last-child {
margin-bottom: 0;
}

View File

@@ -6,9 +6,7 @@
<slot></slot>
</div>
<div class="relative group">
<div
class="more w-10 rounded-r-lg h-full center border-solid border-1 border-l-gray/50 border-transparent box-border transition-all duration-300"
>
<div class="more w-10 rounded-r-lg h-full center box-border transition-all duration-300">
<IconFluentChevronDown20Regular />
</div>
<div
@@ -34,6 +32,8 @@
.primary-btn {
.more {
background: var(--btn-primary);
border: 1.5px solid transparent;
border-left-color: #69788e;
&:hover {
background: var(--btn-primary-hover);
}
@@ -44,7 +44,8 @@
.more {
background: var(--btn-orange);
color: black;
border-left-color: black;
border: 1px solid transparent;
border-left-color: #cfb752;
&:hover {
background: var(--btn-orange-hover);
}

View File

@@ -72,14 +72,8 @@ export default {
</script>
<style lang="scss" scoped>
.tip {
position: fixed;
font-size: 1rem;
z-index: 9999;
border-radius: .3rem;
padding: 0.4rem .8rem;
color: var(--color-font-1);
background: var(--color-tooltip-bg);
max-width: 22rem;
box-shadow: 0 0 6px 1px var(--color-tooltip-shadow);
@apply fixed z-9999 shadow-xl border-item-solid rounded-md px-2.5 py-1.5;
}
</style>

View File

@@ -245,7 +245,8 @@ $time: 0.3s;
}
.modal {
@apply relative bg-second overflow-hidden flex flex-col transition-all duration-300;
@apply relative overflow-hidden flex flex-col transition-all duration-300;
background: var(--color-card-bg);
.close {
@apply absolute right-1.2rem top-1.2rem z-999;

View File

@@ -1,66 +0,0 @@
<script setup lang="ts">
import { Word } from "@/types/types.ts";
import VolumeIcon from "@/components/icon/VolumeIcon.vue";
import BaseList from "@/components/list/BaseList.vue";
import { usePlayWordAudio } from "@/hooks/sound.ts";
import Tooltip from "@/components/base/Tooltip.vue";
import WordItem from "@/components/WordItem.vue";
withDefaults(defineProps<{
list: Word[],
showTranslate?: boolean
showWord?: boolean
}>(), {
list: [],
showTranslate: true,
showWord: true
})
const emit = defineEmits<{
click: [val: { item: Word, index: number }],
title: [val: { item: Word, index: number }],
}>()
const listRef: any = $ref(null as any)
function scrollToBottom() {
listRef?.scrollToBottom()
}
function scrollToItem(index: number) {
listRef?.scrollToItem(index)
}
const playWordAudio = usePlayWordAudio()
defineExpose({ scrollToBottom, scrollToItem })
</script>
<template>
<BaseList ref="listRef" @click="(e: any) => emit('click', e)" :list="list" v-bind="$attrs">
<template v-slot:prefix="{ item, index }">
<slot name="prefix" :item="item" :index="index"></slot>
</template>
<template v-slot="{ item, index }">
<div class="item-title">
<span class="text-sm">{{ index + 1 }}.</span>
<span class="word" :class="!showWord && 'word-shadow'">{{ item.word }}</span>
<span class="phonetic" :class="!showWord && 'word-shadow'">{{ item.phonetic0 }}</span>
<VolumeIcon class="volume" @click="playWordAudio(item.word)"></VolumeIcon>
</div>
<div class="item-sub-title flex flex-col gap-2" v-if="item.trans.length && showTranslate">
<div v-for="v in item.trans">
<Tooltip v-if="v.cn.length > 30" :key="item.word" :title="v.pos + ' ' + v.cn">
<span>{{ v.pos + ' ' + v.cn.slice(0, 30) + '...' }}</span>
</Tooltip>
<span v-else>{{ v.pos + ' ' + v.cn }}</span>
</div>
</div>
</template>
<template v-slot:suffix="{ item, index }">
<slot name="suffix" :item="item" :index="index"></slot>
</template>
</BaseList>
</template>

View File

@@ -58,7 +58,7 @@ let show = $ref(false)
flex-direction: column;
justify-content: space-between;
align-items: center;
border-right: 1px solid gainsboro;
border-right: 2px solid var(--color-line);
.tabs {
padding: 1rem;

View File

@@ -544,8 +544,8 @@ provide('currentPractice', currentPractice)
<div class="name">记录</div>
</div>
<div class="row">
<div class="num">{{statStore.spend }}分钟</div>
<!-- <div class="num">{{ Math.floor(statStore.spend / 1000 / 60) }}分钟</div> -->
<!-- <div class="num">{{statStore.spend }}分钟</div>-->
<div class="num">{{ Math.floor(statStore.spend / 1000 / 60) }}分钟</div>
<div class="line"></div>
<div class="name">时间</div>
</div>

View File

@@ -223,9 +223,9 @@ function handleChange(e: any) {
return v.map((w, j) => {
for (let k = 0; k < lrcList.length; k++) {
let s = lrcList[k]
let d = Comparison.default.cosine.similarity(w.text, s.text)
d = Comparison.default.levenshtein.similarity(w.text, s.text)
d = Comparison.default.longestCommonSubsequence.similarity(w.text, s.text)
// let d = Comparison.default.cosine.similarity(w.text, s.text)
// d = Comparison.default.levenshtein.similarity(w.text, s.text)
let d = Comparison.default.longestCommonSubsequence.similarity(w.text, s.text)
// d = Comparison.default.metricLcs.similarity(w.text, s.text)
// console.log(w.text, s.text, d)
if (d >= 0.8) {

View File

@@ -2,6 +2,10 @@
let logList = [
{
date: '2025/12/30',
content: '移除“继续默写”选项',
},
{
date: '2025/12/29',
content: '单词练习界面,底部工具栏新增音频设置按钮',
},
{

View File

@@ -457,7 +457,7 @@ function transferOk() {
<style scoped lang="scss">
.col-line {
border-right: 2px solid gainsboro;
border-right: 2px solid var(--color-line);
}
.setting {

View File

@@ -16,22 +16,10 @@ import {
WordPracticeStage,
WordPracticeType,
} from '@/types/types.ts'
import {
useDisableEventListener,
useOnKeyboardEventListener,
useStartKeyboardEventListener,
} from '@/hooks/event.ts'
import { useDisableEventListener, useOnKeyboardEventListener, useStartKeyboardEventListener } from '@/hooks/event.ts'
import useTheme from '@/hooks/theme.ts'
import { getCurrentStudyWord, useWordOptions } from '@/hooks/dict.ts'
import {
_getDictDataByUrl,
_nextTick,
cloneDeep,
isMobile,
loadJsLib,
resourceWrap,
shuffle,
} from '@/utils'
import { _getDictDataByUrl, _nextTick, cloneDeep, isMobile, loadJsLib, resourceWrap, shuffle } from '@/utils'
import { useRoute, useRouter } from 'vue-router'
import Footer from '@/pages/word/components/Footer.vue'
import Panel from '@/components/Panel.vue'
@@ -385,14 +373,16 @@ function wordLoop() {
let toastInstance: ToastInstance = null
function nextStage(originList, log) {
function nextStage(originList: Word[], log: string = '', toast: boolean = false) {
//每次都判断,因为每次都可能新增已掌握的单词
let list = originList.filter(v => !data.excludeWords.includes(v.word))
console.log(log)
statStore.stage = statStore.nextStage
if (list.length) {
if (toastInstance) toastInstance.close()
toastInstance = Toast.info('输入完成后按空格键切换下一个', { duration: 5000 })
if (toast) {
if (toastInstance) toastInstance.close()
toastInstance = Toast.info('输入完成后按空格键切换下一个', { duration: 5000 })
}
data.words = list
data.index = 0
} else {
@@ -426,10 +416,7 @@ async function next(isTyping: boolean = true) {
} else {
if (data.index === data.words.length - 1) {
//如果手动敲的,才轮询
if (
(statStore.stage === WordPracticeStage.FollowWriteNewWord || isTypingWrongWord.value) &&
isTyping
) {
if ((statStore.stage === WordPracticeStage.FollowWriteNewWord || isTypingWrongWord.value) && isTyping) {
if (settingStore.wordPracticeType !== WordPracticeType.Spell) {
//回到最后一组的开始位置
data.index = Math.floor(data.index / groupSize) * groupSize
@@ -461,19 +448,19 @@ async function next(isTyping: boolean = true) {
if (settingStore.wordPracticeMode === WordPracticeMode.System) {
if (statStore.stage === WordPracticeStage.FollowWriteNewWord) {
nextStage(shuffle(taskWords.new), '开始听写新词')
nextStage(shuffle(taskWords.new), '开始听写新词', true)
} else if (statStore.stage === WordPracticeStage.ListenNewWord) {
nextStage(shuffle(taskWords.new), '开始默写新词')
} else if (statStore.stage === WordPracticeStage.DictationNewWord) {
nextStage(taskWords.review, '开始自测昨日')
} else if (statStore.stage === WordPracticeStage.IdentifyReview) {
nextStage(shuffle(taskWords.review), '开始听写上次')
nextStage(shuffle(taskWords.review), '开始听写上次', true)
} else if (statStore.stage === WordPracticeStage.ListenReview) {
nextStage(shuffle(taskWords.review), '开始默写上次')
} else if (statStore.stage === WordPracticeStage.DictationReview) {
nextStage(taskWords.write, '开始自测之前')
} else if (statStore.stage === WordPracticeStage.IdentifyReviewAll) {
nextStage(shuffle(taskWords.write), '开始听写之前')
nextStage(shuffle(taskWords.write), '开始听写之前', true)
} else if (statStore.stage === WordPracticeStage.ListenReviewAll) {
nextStage(shuffle(taskWords.write), '开始默写之前')
} else if (statStore.stage === WordPracticeStage.DictationReviewAll) {
@@ -481,13 +468,13 @@ async function next(isTyping: boolean = true) {
}
} else if (settingStore.wordPracticeMode === WordPracticeMode.ListenOnly) {
if (statStore.stage === WordPracticeStage.ListenNewWord) {
nextStage(taskWords.review, '开始听写昨日')
nextStage(taskWords.review, '开始听写昨日',true)
} else if (statStore.stage === WordPracticeStage.ListenReview) {
nextStage(taskWords.write, '开始听写之前')
} else if (statStore.stage === WordPracticeStage.ListenReviewAll) complete()
} else if (settingStore.wordPracticeMode === WordPracticeMode.DictationOnly) {
if (statStore.stage === WordPracticeStage.DictationNewWord) {
nextStage(taskWords.review, '开始默写昨日')
nextStage(taskWords.review, '开始默写昨日',true)
} else if (statStore.stage === WordPracticeStage.DictationReview) {
nextStage(taskWords.write, '开始默写之前')
} else if (statStore.stage === WordPracticeStage.DictationReviewAll) complete()
@@ -501,13 +488,13 @@ async function next(isTyping: boolean = true) {
if (statStore.stage === WordPracticeStage.Shuffle) complete()
} else if (settingStore.wordPracticeMode === WordPracticeMode.Review) {
if (statStore.stage === WordPracticeStage.IdentifyReview) {
nextStage(shuffle(taskWords.review), '开始听写昨日')
nextStage(shuffle(taskWords.review), '开始听写昨日',true)
} else if (statStore.stage === WordPracticeStage.ListenReview) {
nextStage(shuffle(taskWords.review), '开始默写昨日')
} else if (statStore.stage === WordPracticeStage.DictationReview) {
nextStage(taskWords.write, '开始自测之前')
} else if (statStore.stage === WordPracticeStage.IdentifyReviewAll) {
nextStage(shuffle(taskWords.write), '开始听写之前')
nextStage(shuffle(taskWords.write), '开始听写之前',true)
} else if (statStore.stage === WordPracticeStage.ListenReviewAll) {
nextStage(shuffle(taskWords.write), '开始默写之前')
} else if (statStore.stage === WordPracticeStage.DictationReviewAll) complete()
@@ -677,9 +664,7 @@ async function continueStudy() {
console.log('没学完,强行跳过')
store.sdict.lastLearnIndex = store.sdict.lastLearnIndex + statStore.newWordNumber
// 忽略单词数
const ignoreCount = ignoreList.filter(word =>
store.sdict.words.some(w => w.word.toLowerCase() === word)
).length
const ignoreCount = ignoreList.filter(word => store.sdict.words.some(w => w.word.toLowerCase() === word)).length
// 如果lastLearnIndex已经超过可学单词数则判定完成
if (store.sdict.lastLearnIndex + ignoreCount >= store.sdict.length) {
store.sdict.complete = true
@@ -725,18 +710,9 @@ function randomWrite() {
settingStore.dictation = true
}
function nextRandomWrite() {
setPracticeWordCache(null)
console.log('继续随机默写')
initData(getCurrentStudyWord())
randomWrite()
showStatDialog = false
}
useEvents([
[EventKey.repeatStudy, repeat],
[EventKey.continueStudy, continueStudy],
[EventKey.randomWrite, nextRandomWrite],
[ShortcutKey.ShowWord, show],
[ShortcutKey.Previous, prev],
[ShortcutKey.Next, skip],
@@ -752,7 +728,6 @@ useEvents([
[ShortcutKey.ToggleConciseMode, toggleConciseMode],
[ShortcutKey.TogglePanel, togglePanel],
[ShortcutKey.RandomWrite, randomWrite],
[ShortcutKey.NextRandomWrite, nextRandomWrite],
])
</script>
@@ -767,11 +742,7 @@ useEvents([
<div class="word">{{ prevWord.word }}</div>
</Tooltip>
</div>
<div
class="center gap-2 cursor-pointer float-right mr-3"
@click="next(false)"
v-if="nextWord"
>
<div class="center gap-2 cursor-pointer float-right mr-3" @click="next(false)" v-if="nextWord">
<Tooltip :title="`下一个(${settingStore.shortcutKeyMap[ShortcutKey.Next]})`">
<div class="word" :class="settingStore.dictation && 'word-shadow'">
{{ nextWord.word }}
@@ -780,13 +751,7 @@ useEvents([
<IconFluentArrowRight16Regular class="arrow" width="22" />
</div>
</div>
<TypeWord
ref="typingRef"
:word="word"
@wrong="onTypeWrong"
@complete="next"
@know="onWordKnow"
/>
<TypeWord ref="typingRef" :word="word" @wrong="onTypeWrong" @complete="next" @know="onWordKnow" />
</div>
</template>
{{ Math.ceil(store.sdict.length / store.sdict.perDayStudyNumber) }}
@@ -798,16 +763,12 @@ useEvents([
<GroupList
@click="jumpToGroup"
v-if="
taskWords.new.length && settingStore.wordPracticeMode !== WordPracticeMode.Shuffle
"
v-if="taskWords.new.length && settingStore.wordPracticeMode !== WordPracticeMode.Shuffle"
/>
<BaseIcon
v-if="
taskWords.new.length &&
![WordPracticeMode.Review, WordPracticeMode.Shuffle].includes(
settingStore.wordPracticeMode
)
![WordPracticeMode.Review, WordPracticeMode.Shuffle].includes(settingStore.wordPracticeMode)
"
@click="continueStudy"
:title="`下一组(${settingStore.shortcutKeyMap[ShortcutKey.NextChapter]})`"
@@ -815,10 +776,7 @@ useEvents([
<IconFluentArrowRight16Regular class="arrow" width="22" />
</BaseIcon>
<BaseIcon
@click="randomWrite"
:title="`随机默写(${settingStore.shortcutKeyMap[ShortcutKey.RandomWrite]})`"
>
<BaseIcon @click="randomWrite" :title="`随机默写(${settingStore.shortcutKeyMap[ShortcutKey.RandomWrite]})`">
<IconFluentArrowShuffle16Regular class="arrow" width="22" />
</BaseIcon>
</div>

View File

@@ -142,16 +142,11 @@ function startPractice(practiceMode: WordPracticeMode, resetCache: boolean = fal
}
function freePractice() {
startPractice(
WordPracticeMode.Free,
settingStore.wordPracticeMode !== WordPracticeMode.Free && isSaveData
)
startPractice(WordPracticeMode.Free, settingStore.wordPracticeMode !== WordPracticeMode.Free && isSaveData)
}
function systemPractice() {
startPractice(
settingStore.wordPracticeMode === WordPracticeMode.Free
? WordPracticeMode.System
: settingStore.wordPracticeMode,
settingStore.wordPracticeMode === WordPracticeMode.Free ? WordPracticeMode.System : settingStore.wordPracticeMode,
settingStore.wordPracticeMode === WordPracticeMode.Free && isSaveData
)
}
@@ -264,9 +259,7 @@ async function saveLastPracticeIndex(e) {
currentStudy = getCurrentStudyWord()
}
const { data: recommendDictList, isFetching } = useFetch(
resourceWrap(DICT_LIST.WORD.RECOMMENDED)
).json()
const { data: recommendDictList, isFetching } = useFetch(resourceWrap(DICT_LIST.WORD.RECOMMENDED)).json()
let isNewHost = $ref(window.location.host === Host)
@@ -312,11 +305,7 @@ const systemPracticeText = $computed(() => {
}}
</span>
</div>
<Progress
size="large"
:percentage="store.currentStudyProgress"
:show-text="false"
></Progress>
<Progress size="large" :percentage="store.currentStudyProgress" :show-text="false"></Progress>
<div class="text-sm flex justify-between">
<span>{{ progressTextLeft }}</span>
@@ -356,10 +345,7 @@ const systemPracticeText = $computed(() => {
</div>
</div>
<div
class="flex-1 w-full mt-4 md:mt-0"
:class="!store.sdict.id && 'opacity-30 cursor-not-allowed'"
>
<div class="flex-1 w-full mt-4 md:mt-0" :class="!store.sdict.id && 'opacity-30 cursor-not-allowed'">
<div class="flex justify-between">
<div class="flex items-center gap-2">
<div class="p-2 center rounded-full bg-white">
@@ -368,10 +354,7 @@ const systemPracticeText = $computed(() => {
<div class="text-xl font-bold">
{{ isSaveData ? '上次任务' : '今日任务' }}
</div>
<span
class="color-link cursor-pointer"
v-if="store.sdict.id"
@click="showPracticeWordListDialog = true"
<span class="color-link cursor-pointer" v-if="store.sdict.id" @click="showPracticeWordListDialog = true"
>词表</span
>
</div>
@@ -406,11 +389,7 @@ const systemPracticeText = $computed(() => {
</div>
<div class="flex items-end mt-4 gap-4 btn-no-margin">
<OptionButton
:class="
settingStore.wordPracticeMode !== WordPracticeMode.Free
? 'flex-1 orange-btn'
: 'primary-btn'
"
:class="settingStore.wordPracticeMode !== WordPracticeMode.Free ? 'flex-1 orange-btn' : 'primary-btn'"
>
<BaseButton
size="large"
@@ -431,7 +410,7 @@ const systemPracticeText = $computed(() => {
settingStore.wordPracticeMode !== WordPracticeMode.System &&
settingStore.wordPracticeMode !== WordPracticeMode.Free
"
@click="startPractice(WordPracticeMode.System,true)"
@click="startPractice(WordPracticeMode.System, true)"
>
智能学习
</BaseButton>
@@ -440,14 +419,14 @@ const systemPracticeText = $computed(() => {
class="w-full"
v-if="settingStore.wordPracticeMode !== WordPracticeMode.Review"
:disabled="!currentStudy.review.length && !currentStudy.write.length"
@click="startPractice(WordPracticeMode.Review,true)"
@click="startPractice(WordPracticeMode.Review, true)"
>
复习
</BaseButton>
<BaseButton
class="w-full"
v-if="settingStore.wordPracticeMode !== WordPracticeMode.Shuffle"
:disabled="store.sdict.lastLearnIndex < 10"
:disabled="store.sdict.lastLearnIndex < 10 && !store.sdict.complete"
@click="check(() => (showShufflePracticeSettingDialog = true))"
>
随机复习
@@ -456,21 +435,21 @@ const systemPracticeText = $computed(() => {
<BaseButton
class="w-full"
v-if="settingStore.wordPracticeMode !== WordPracticeMode.IdentifyOnly"
@click="startPractice(WordPracticeMode.IdentifyOnly,true)"
@click="startPractice(WordPracticeMode.IdentifyOnly, true)"
>
{{ WordPracticeModeNameMap[WordPracticeMode.IdentifyOnly] }}
</BaseButton>
<BaseButton
class="w-full"
v-if="settingStore.wordPracticeMode !== WordPracticeMode.ListenOnly"
@click="startPractice(WordPracticeMode.ListenOnly,true)"
@click="startPractice(WordPracticeMode.ListenOnly, true)"
>
{{ WordPracticeModeNameMap[WordPracticeMode.ListenOnly] }}
</BaseButton>
<BaseButton
class="w-full"
v-if="settingStore.wordPracticeMode !== WordPracticeMode.DictationOnly"
@click="startPractice(WordPracticeMode.DictationOnly,true)"
@click="startPractice(WordPracticeMode.DictationOnly, true)"
>
{{ WordPracticeModeNameMap[WordPracticeMode.DictationOnly] }}
</BaseButton>
@@ -487,9 +466,7 @@ const systemPracticeText = $computed(() => {
<div class="flex items-center gap-2">
<span class="line-height-[2]">
{{
settingStore.wordPracticeMode === WordPracticeMode.Free && isSaveData
? '继续自由练习'
: '自由练习'
settingStore.wordPracticeMode === WordPracticeMode.Free && isSaveData ? '继续自由练习' : '自由练习'
}}
</span>
<IconStreamlineColorPenDrawFlat class="text-xl" />
@@ -503,11 +480,7 @@ const systemPracticeText = $computed(() => {
<div class="flex justify-between">
<div class="title">我的词典</div>
<div class="flex gap-4 items-center">
<PopConfirm
title="确认删除所有选中词典?"
@confirm="handleBatchDel"
v-if="selectIds.length"
>
<PopConfirm title="确认删除所有选中词典?" @confirm="handleBatchDel" v-if="selectIds.length">
<BaseIcon class="del" title="删除">
<DeleteIcon />
</BaseIcon>
@@ -525,9 +498,7 @@ const systemPracticeText = $computed(() => {
>
{{ isManageDict ? '取消' : '管理词典' }}
</div>
<div class="color-link cursor-pointer" @click="nav('dict-detail', { isAdd: true })">
创建个人词典
</div>
<div class="color-link cursor-pointer" @click="nav('dict-detail', { isAdd: true })">创建个人词典</div>
</div>
</div>
<div class="flex gap-4 flex-wrap mt-4">
@@ -565,23 +536,13 @@ const systemPracticeText = $computed(() => {
</div>
</BasePage>
<PracticeSettingDialog
:show-left-option="false"
v-model="showPracticeSettingDialog"
@ok="savePracticeSetting"
/>
<PracticeSettingDialog :show-left-option="false" v-model="showPracticeSettingDialog" @ok="savePracticeSetting" />
<ChangeLastPracticeIndexDialog
v-model="showChangeLastPracticeIndexDialog"
@ok="saveLastPracticeIndex"
/>
<ChangeLastPracticeIndexDialog v-model="showChangeLastPracticeIndexDialog" @ok="saveLastPracticeIndex" />
<PracticeWordListDialog :data="currentStudy" v-model="showPracticeWordListDialog" />
<ShufflePracticeSettingDialog
v-model="showShufflePracticeSettingDialog"
@ok="onShufflePracticeSettingOk"
/>
<ShufflePracticeSettingDialog v-model="showShufflePracticeSettingDialog" @ok="onShufflePracticeSettingOk" />
</template>
<style scoped lang="scss">

View File

@@ -318,7 +318,7 @@ const stages = $computed(() => {
</div>
<div class="progress-wrap flex gap-3 items-center color-gray">
<span class="shrink-0">{{ status }}</span>
<Progress :percentage="progress" :stroke-width="8" color="#69b1ff" :show-text="false" />
<StageProgress :stages="stages" />
<div class="num">{{ `${practiceData.index + 1}/${practiceData.words.length}` }}</div>
</div>
</div>

View File

@@ -262,17 +262,6 @@ calcWeekList() // 新增:计算本周学习记录
{{ dictIsEnd ? '从头开始练习' : '再来一组' }}
</div>
</BaseButton>
<!-- todo 感觉这里的继续默写有问题应该是当前组而不是下一组-->
<BaseButton
v-if="settingStore.wordPracticeMode !== WordPracticeMode.Review"
:keyboard="settingStore.shortcutKeyMap[ShortcutKey.NextRandomWrite]"
@click="options(EventKey.randomWrite)"
>
<div class="center gap-2">
<IconFluentPen20Regular />
继续默写
</div>
</BaseButton>
<BaseButton @click="$router.back">
<div class="center gap-2">
<IconFluentHome20Regular />

View File

@@ -120,7 +120,6 @@ export enum ShortcutKey {
ToggleConciseMode = 'ToggleConciseMode',
TogglePanel = 'TogglePanel',
RandomWrite = 'RandomWrite',
NextRandomWrite = 'NextRandomWrite',
KnowWord = 'KnowWord',
UnknownWord = 'UnknownWord',
}
@@ -143,7 +142,6 @@ export const DefaultShortcutKeyMap = {
[ShortcutKey.ToggleConciseMode]: 'Ctrl+M',
[ShortcutKey.TogglePanel]: 'Ctrl+L',
[ShortcutKey.RandomWrite]: 'Ctrl+R',
[ShortcutKey.NextRandomWrite]: 'Ctrl+Shift+R',
[ShortcutKey.KnowWord]: '1',
[ShortcutKey.UnknownWord]: '2',
}

View File

@@ -16,7 +16,6 @@ export const EventKey = {
editDict: 'editDict',
openMyDictDialog: 'openMyDictDialog',
stateInitEnd: 'stateInitEnd',
randomWrite: 'randomWrite',
}
export function useEvent(key: string, func: any) {