bug: Ctrl + C copy function not working

This commit is contained in:
Zyronon
2025-12-05 18:52:02 +08:00
committed by GitHub
parent 63ca3ba29f
commit 7f05ec95d9
13 changed files with 301 additions and 515 deletions

View File

@@ -1,8 +1,8 @@
import { onDeactivated, onMounted, onUnmounted, watch } from "vue";
import { emitter, EventKey } from "@/utils/eventBus.ts";
import { useRuntimeStore } from "@/stores/runtime.ts";
import { useSettingStore } from "@/stores/setting.ts";
import { isMobile } from "@/utils";
import {onDeactivated, onMounted, onUnmounted, watch} from "vue";
import {emitter, EventKey} from "@/utils/eventBus.ts";
import {useRuntimeStore} from "@/stores/runtime.ts";
import {useSettingStore} from "@/stores/setting.ts";
import {isMobile} from "@/utils";
export function useWindowClick(cb: (e: PointerEvent) => void) {
onMounted(() => {
@@ -92,9 +92,12 @@ export function useEventListener(type: string, listener: EventListenerOrEventLis
repeat: false,
isComposing: false,
type,
preventDefault() {},
stopPropagation() {},
stopImmediatePropagation() {},
preventDefault() {
},
stopPropagation() {
},
stopImmediatePropagation() {
},
}
return base as unknown as KeyboardEvent
}
@@ -131,7 +134,7 @@ export function useEventListener(type: string, listener: EventListenerOrEventLis
const value = target?.value ?? ''
if (event.inputType === 'deleteContentBackward') {
dispatchSyntheticKey({ key: 'Backspace', code: 'Backspace', keyCode: 8 })
dispatchSyntheticKey({key: 'Backspace', code: 'Backspace', keyCode: 8})
if (target) target.value = ''
return
}
@@ -252,6 +255,8 @@ export function useStartKeyboardEventListener() {
const settingStore = useSettingStore()
useEventListener('keydown', (e: KeyboardEvent) => {
//解决无法复制、全选的问题
if ((e.ctrlKey || e.metaKey) && ['KeyC', 'KeyA'].includes(e.code)) return
if (!runtimeStore.disableEventListener) {
// 检查当前单词是否包含空格,如果包含,则空格键应该被视为输入

View File

@@ -280,7 +280,7 @@ let isNewHost = $ref(window.location.host === Host)
</div>
<BaseButton size="large" class="w-full md:w-auto"
@click="startStudy"
:disabled="!base.currentBook.name">
:disabled="!base.sbook.name">
<div class="flex items-center gap-2 justify-center w-full">
<span class="line-height-[2]">{{ isSaveData ? '继续学习' : '开始学习' }}</span>
<IconFluentArrowCircleRight16Regular class="text-xl"/>

View File

@@ -739,7 +739,7 @@ const currentPractice = inject('currentPractice', [])
@click="emit('replay')">重新练习
</BaseButton>
<BaseButton
v-if="store.currentBook.lastLearnIndex < store.currentBook.articles.length - 1"
v-if="store.sbook.lastLearnIndex < store.sbook.articles.length - 1"
@click="emit('next')">下一篇
</BaseButton>
</div>

237
src/pages/setting/Log.vue Normal file
View File

@@ -0,0 +1,237 @@
<script setup lang="ts">
</script>
<template>
<div>
<div class="log-item">
<div class="mb-2">
<div>
<div>日期2025/12/5</div>
<div>内容解决练习界面无法复制全选的问题</div>
</div>
</div>
</div>
<div class="log-item">
<div class="mb-2">
<div>
<div>日期2025/12/3</div>
<div>内容单词文章设置修改为弹框更方便</div>
</div>
</div>
</div>
<div class="log-item">
<div class="mb-2">
<div>
<div>日期2025/12/3</div>
<div>内容录入新概念部分音频优化文章相关功能</div>
</div>
</div>
</div>
<div class="log-item">
<div class="mb-2">
<div>
<div>日期2025/12/2</div>
<div>内容完成新概念音频优化文章管理页面</div>
</div>
</div>
</div>
<div class="log-item">
<div class="mb-2">
<div>
<div>日期2025/11/30</div>
<div>内容文章里的单词可点击播放</div>
</div>
</div>
</div>
<div class="log-item">
<div class="mb-2">
<div>
<div>日期2025/11/29</div>
<div>内容修改 Slider 组件显示bug新增 IE 浏览器检测提示</div>
</div>
</div>
</div>
<div class="log-item">
<div class="mb-2">
<div>
<div>日期2025/11/28</div>
<div>内容新增引导框 新增<a href="https://github.com/zyronon/TypeWords/pull/175" target="_blank">词典测试模式由大佬
hebeihang 开发</a></div>
</div>
</div>
</div>
<div class="log-item">
<div class="mb-2">
<div>
<div>日期2025/11/25</div>
<div>内容文章练习新增人名忽略功能新概念一已全部适配上传了新概念1-18 音频</div>
</div>
</div>
</div>
<div class="log-item">
<div class="mb-2">
<div>
<div>日期2025/11/23</div>
<div>内容优化练习完成结算界面新增分享功能</div>
</div>
</div>
</div>
<div class="log-item">
<div class="mb-2">
<div>
<div>日期2025/11/22</div>
<div>内容适配移动端</div>
</div>
</div>
</div>
<div class="log-item">
<div class="mb-2">
<div>
<div>日期2025/11/16</div>
<div>内容自测单词时不认识单词可以直接输入自动标识为错误单词无需按2</div>
</div>
</div>
</div>
<div class="log-item">
<div class="mb-2">
<div>
<div>日期2025/11/15</div>
<div>内容练习单词时底部工具栏新增跳到下一阶段按钮</div>
</div>
</div>
</div>
<div class="log-item">
<div class="mb-2">
<div>
<div>日期2025/11/14</div>
<div>内容新增文章练习时可跳过空格如果在单词的最后一位上不按空格直接输入下一个字母的话自动跳下一个单词
按空格也自动跳下一个单词
</div>
</div>
</div>
</div>
<div class="log-item">
<div class="mb-2">
<div>
<div>日期2025/11/13</div>
<div>内容新增文章练习时输入时忽略符号/数字选项</div>
</div>
</div>
</div>
<div class="log-item">
<div class="mb-2">
<div>
<div>日期2025/11/6</div>
<div>内容新增随机复习功能</div>
</div>
</div>
</div>
<div class="log-item">
<div class="mb-2">
<div>
<div>日期2025/10/30</div>
<div>内容集成PWA基础配置支持用户以类App形式打开项目</div>
</div>
</div>
</div>
<div class="log-item">
<div class="mb-2">
<div>
<div>日期2025/10/26</div>
<div>内容进一步完善单词练习解决复习数量太多的问题</div>
</div>
<div class="text-base mt-1">
<ol>
<li>
<div class="title"><b>智能模式优化</b></div>
<div class="desc">练习时新增四种练习模式学习自测听写默写</div>
</li>
<li>
<div class="title"><b>学习模式</b></div>
<div class="desc">
<ul>
<li>仅在练习新词时出现</li>
<li>采用跟写 / 拼写方式进行学习</li>
<li> 7 个单词会 <b>强制进行听写</b>解决原来一次练太多听写时已忘记的问题</li>
</ul>
</div>
</li>
<li>
<div class="title"><b>自测模式新增</b></div>
<div class="desc">
<ul>
<li>仅在复习已学单词时出现</li>
<li>不再强制拼写提供我认识不认识选项</li>
<li>选择我认识该单词在后续听写或默写中将不再出现<b>显著减少复习数量</b></li>
</ul>
</div>
</li>
<li>
<div class="title"><b>听写模式</b></div>
<div class="desc">原有逻辑保持不变</div>
</li>
<li>
<div class="title"><b>默写模式新增</b></div>
<div class="desc">
<ul>
<li>仅显示释义不自动发音不显示单词长度</li>
<li>适合强化拼写记忆的场景</li>
</ul>
</div>
</li>
</ol>
<b>说明</b>
<div>本次更新重点解决了复习单词数量过多效率偏低的问题</div>
<div>通过引入复习默写两种模式使复习流程更加灵活高效</div>
</div>
</div>
</div>
<div class="log-item">
<div class="mb-2">
<div>
<div>日期2025/10/8</div>
<div>内容文章支持自动播放下一篇</div>
</div>
</div>
</div>
<div class="log-item">
<div class="mb-2">
<div>
<div>日期2025/9/14</div>
<div>内容完善文章编辑导入导出等功能</div>
</div>
<div class="text-base mt-1">
<div>1文章的音频管理功能目前已可添加音频设置句子与音频的对应位置</div>
<div>2文章可导入导出</div>
<div>3单词可导入导出</div>
</div>
</div>
</div>
<div class="log-item">
<div class="mb-2">
<div>
<div>日期2025/8/10</div>
<div>内容2.0版本发布全新UI全新逻辑新增短语例句近义词等功能</div>
</div>
</div>
</div>
<div class="log-item">
<div class="mb-2">
<div>
<div>日期2025/7/19</div>
<div>内容1.0版本发布</div>
</div>
</div>
</div>
</div>
</template>
<style scoped lang="scss">
.log-item {
border-bottom: 1px solid var(--color-input-border);
margin-bottom: 1rem;
}
</style>

View File

@@ -41,6 +41,7 @@ import {useRuntimeStore} from "@/stores/runtime.ts";
import {useUserStore} from "@/stores/user.ts";
import {useExport} from "@/hooks/export.ts";
import MigrateDialog from "@/components/MigrateDialog.vue";
import Log from "@/pages/setting/Log.vue";
const emit = defineEmits<{
toggleDisabledDialogEscKey: [val: boolean]
@@ -231,7 +232,7 @@ function importJson(str: string, notice: boolean = true) {
notice && Toast.success('导入成功!')
} catch (err) {
return Toast.error('导入失败!')
}finally {
} finally {
importLoading = false
}
}
@@ -397,220 +398,7 @@ function transferOk() {
</div>
<!-- 日志-->
<div v-if="tabIndex === 5">
<div class="log-item">
<div class="mb-2">
<div>
<div>日期2025/12/3</div>
<div>内容单词文章设置修改为弹框更方便</div>
</div>
</div>
</div>
<div class="log-item">
<div class="mb-2">
<div>
<div>日期2025/12/3</div>
<div>内容录入新概念部分音频优化文章相关功能</div>
</div>
</div>
</div>
<div class="log-item">
<div class="mb-2">
<div>
<div>日期2025/12/2</div>
<div>内容完成新概念音频优化文章管理页面</div>
</div>
</div>
</div>
<div class="log-item">
<div class="mb-2">
<div>
<div>日期2025/11/30</div>
<div>内容文章里的单词可点击播放</div>
</div>
</div>
</div>
<div class="log-item">
<div class="mb-2">
<div>
<div>日期2025/11/29</div>
<div>内容修改 Slider 组件显示bug新增 IE 浏览器检测提示</div>
</div>
</div>
</div>
<div class="log-item">
<div class="mb-2">
<div>
<div>日期2025/11/28</div>
<div>内容新增引导框 新增<a href="https://github.com/zyronon/TypeWords/pull/175" target="_blank">词典测试模式由大佬
hebeihang 开发</a></div>
</div>
</div>
</div>
<div class="log-item">
<div class="mb-2">
<div>
<div>日期2025/11/25</div>
<div>内容文章练习新增人名忽略功能新概念一已全部适配上传了新概念1-18 音频</div>
</div>
</div>
</div>
<div class="log-item">
<div class="mb-2">
<div>
<div>日期2025/11/23</div>
<div>内容优化练习完成结算界面新增分享功能</div>
</div>
</div>
</div>
<div class="log-item">
<div class="mb-2">
<div>
<div>日期2025/11/22</div>
<div>内容适配移动端</div>
</div>
</div>
</div>
<div class="log-item">
<div class="mb-2">
<div>
<div>日期2025/11/16</div>
<div>内容自测单词时不认识单词可以直接输入自动标识为错误单词无需按2</div>
</div>
</div>
</div>
<div class="log-item">
<div class="mb-2">
<div>
<div>日期2025/11/15</div>
<div>内容练习单词时底部工具栏新增跳到下一阶段按钮</div>
</div>
</div>
</div>
<div class="log-item">
<div class="mb-2">
<div>
<div>日期2025/11/14</div>
<div>内容新增文章练习时可跳过空格如果在单词的最后一位上不按空格直接输入下一个字母的话自动跳下一个单词
按空格也自动跳下一个单词
</div>
</div>
</div>
</div>
<div class="log-item">
<div class="mb-2">
<div>
<div>日期2025/11/13</div>
<div>内容新增文章练习时输入时忽略符号/数字选项</div>
</div>
</div>
</div>
<div class="log-item">
<div class="mb-2">
<div>
<div>日期2025/11/6</div>
<div>内容新增随机复习功能</div>
</div>
</div>
</div>
<div class="log-item">
<div class="mb-2">
<div>
<div>日期2025/10/30</div>
<div>内容集成PWA基础配置支持用户以类App形式打开项目</div>
</div>
</div>
</div>
<div class="log-item">
<div class="mb-2">
<div>
<div>日期2025/10/26</div>
<div>内容进一步完善单词练习解决复习数量太多的问题</div>
</div>
<div class="text-base mt-1">
<ol>
<li>
<div class="title"><b>智能模式优化</b></div>
<div class="desc">练习时新增四种练习模式学习自测听写默写</div>
</li>
<li>
<div class="title"><b>学习模式</b></div>
<div class="desc">
<ul>
<li>仅在练习新词时出现</li>
<li>采用跟写 / 拼写方式进行学习</li>
<li> 7 个单词会 <b>强制进行听写</b>解决原来一次练太多听写时已忘记的问题</li>
</ul>
</div>
</li>
<li>
<div class="title"><b>自测模式新增</b></div>
<div class="desc">
<ul>
<li>仅在复习已学单词时出现</li>
<li>不再强制拼写提供我认识不认识选项</li>
<li>选择我认识该单词在后续听写或默写中将不再出现<b>显著减少复习数量</b></li>
</ul>
</div>
</li>
<li>
<div class="title"><b>听写模式</b></div>
<div class="desc">原有逻辑保持不变</div>
</li>
<li>
<div class="title"><b>默写模式新增</b></div>
<div class="desc">
<ul>
<li>仅显示释义不自动发音不显示单词长度</li>
<li>适合强化拼写记忆的场景</li>
</ul>
</div>
</li>
</ol>
<b>说明</b>
<div>本次更新重点解决了复习单词数量过多效率偏低的问题</div>
<div>通过引入复习默写两种模式使复习流程更加灵活高效</div>
</div>
</div>
</div>
<div class="log-item">
<div class="mb-2">
<div>
<div>日期2025/10/8</div>
<div>内容文章支持自动播放下一篇</div>
</div>
</div>
</div>
<div class="log-item">
<div class="mb-2">
<div>
<div>日期2025/9/14</div>
<div>内容完善文章编辑导入导出等功能</div>
</div>
<div class="text-base mt-1">
<div>1文章的音频管理功能目前已可添加音频设置句子与音频的对应位置</div>
<div>2文章可导入导出</div>
<div>3单词可导入导出</div>
</div>
</div>
</div>
<div class="log-item">
<div class="mb-2">
<div>
<div>日期2025/8/10</div>
<div>内容2.0版本发布全新UI全新逻辑新增短语例句近义词等功能</div>
</div>
</div>
</div>
<div class="log-item">
<div class="mb-2">
<div>
<div>日期2025/7/19</div>
<div>内容1.0版本发布</div>
</div>
</div>
</div>
</div>
<Log v-if="tabIndex === 5"/>
<div v-if="tabIndex === 6" class="center flex-col">
<h1>Type Words</h1>
@@ -640,11 +428,6 @@ function transferOk() {
<style scoped lang="scss">
.log-item {
border-bottom: 1px solid var(--color-input-border);
margin-bottom: 1rem;
}
.col-line {
border-right: 2px solid gainsboro;
}

View File

@@ -145,7 +145,7 @@ watch(dict_list, (val) => {
<div class="w-full" v-else>
<DictGroup
v-for="item in groupedByCategoryAndTag"
:select-id="store.currentStudyWordDict.id"
:select-id="store.sdict.id"
@selectDict="selectDict"
quantifier="个词"
:groupByTag="item[1]"

View File

@@ -1,5 +1,5 @@
<script setup lang="ts">
import { onMounted, provide, ref, watch } from "vue";
import {onMounted, onUnmounted, provide, ref, watch} from "vue";
import Statistics from "@/pages/word/Statistics.vue";
import { emitter, EventKey, useEvents } from "@/utils/eventBus.ts";
@@ -47,6 +47,8 @@ let showConflictNotice = $ref(false)
let allWrongWords = new Set()
let showStatDialog = $ref(false)
let loading = $ref(false)
let timer = $ref(0)
let isFocus = true
let taskWords = $ref<TaskWords>({
new: [],
review: [],
@@ -110,6 +112,13 @@ onMounted(() => {
} else {
showConflictNotice = true
}
document.addEventListener('visibilitychange', () => {
isFocus = !document.hidden
})
})
onUnmounted(() => {
timer && clearInterval(timer)
})
watchOnce(() => data.words.length, (newVal, oldVal) => {
@@ -220,8 +229,17 @@ function initData(initVal: TaskWords, init: boolean = false) {
statStore.startDate = Date.now()
statStore.inputWordNumber = 0
statStore.wrong = 0
statStore.spend = 0
isTypingWrongWord.value = false
}
clearInterval(timer)
timer = setInterval(() => {
if (isFocus) {
statStore.spend += 1000
savePracticeData()
}
}, 1000)
}
const word = $computed<Word>(() => {

View File

@@ -109,15 +109,16 @@ const progress = $computed(() => {
<div class="name">{{ status }}</div>
</div>
<div class="row">
<!-- <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>
<div class="row">
<div class="num">{{ statStore.total }}</div>
<div class="line"></div>
<div class="name">单词总数</div>
</div>
<!-- <div class="row">-->
<!-- <div class="num">{{ format(statStore.inputWordNumber, '', 0) }}</div>-->
<!-- <div class="line"></div>-->
<!-- <div class="name">总输入数</div>-->
<!-- </div>-->
<div class="row">
<div class="num">{{ format(statStore.wrong, '', 0) }}</div>
<div class="line"></div>

View File

@@ -188,7 +188,7 @@ async function onTyping(e: KeyboardEvent) {
}
inputLock = true
let letter = e.key
console.log('letter',letter)
// console.log('letter',letter)
//默写特殊逻辑
if (settingStore.wordPracticeType === WordPracticeType.Dictation) {
if (e.code === 'Space') {
@@ -659,35 +659,35 @@ useEvents([
.typing-word {
padding: 0 0.5rem 12rem;
.word {
font-size: 2rem !important;
letter-spacing: 0.1rem;
margin: 0.5rem 0;
}
.phonetic, .translate {
font-size: 1rem;
}
.label {
width: 4rem;
font-size: 0.9rem;
}
.cn {
font-size: 0.9rem;
}
.en {
font-size: 1rem;
}
.pos {
font-size: 0.9rem;
width: 3rem;
}
// 移动端按钮组调整
.flex.gap-4 {
flex-direction: column;
@@ -695,7 +695,7 @@ useEvents([
gap: 0.5rem;
position: relative;
z-index: 10; // 确保按钮不被其他元素遮挡
.base-button {
width: 100%;
min-height: 48px;
@@ -705,14 +705,14 @@ useEvents([
cursor: pointer;
}
}
// 确保短语和例句区域保持默认层级
.phrase-section,
.sentence {
position: relative;
z-index: auto;
}
// 移动端例句和短语调整
.sentence,
.phrase {
@@ -721,7 +721,7 @@ useEvents([
margin-bottom: 0.5rem;
pointer-events: auto; // 允许点击但不调起输入法
}
// 移动端短语调整
.flex.items-center.gap-4 {
flex-direction: column;
@@ -735,35 +735,35 @@ useEvents([
@media (max-width: 480px) {
.typing-word {
padding: 0 0.3rem 12rem;
.word {
font-size: 1.5rem !important;
letter-spacing: 0.05rem;
margin: 0.3rem 0;
}
.phonetic, .translate {
font-size: 0.9rem;
}
.label {
width: 3rem;
font-size: 0.8rem;
}
.cn {
font-size: 0.8rem;
}
.en {
font-size: 0.9rem;
}
.pos {
font-size: 0.8rem;
width: 2.5rem;
}
.sentence {
font-size: 0.8rem;
line-height: 1.3;

View File

@@ -72,12 +72,6 @@ export const useBaseStore = defineStore('base', {
allIgnoreWords() {
return this.known.words.map((v: Word) => v.word.toLowerCase()).concat(this.simpleWords.map((v: string) => v.toLowerCase()))
},
currentStudyWordDict(): Dict {
if (this.word.studyIndex >= 0) {
return this.word.bookList[this.word.studyIndex] ?? getDefaultDict()
}
return getDefaultDict()
},
sdict(): Dict {
if (this.word.studyIndex >= 0) {
return this.word.bookList[this.word.studyIndex] ?? getDefaultDict()
@@ -93,9 +87,6 @@ export const useBaseStore = defineStore('base', {
if (!this.sdict.perDayStudyNumber) return 0
return Math.ceil((this.sdict.length - this.sdict.lastLearnIndex) / this.sdict.perDayStudyNumber)
},
currentBook(): Dict {
return this.article.bookList[this.article.studyIndex] ?? {}
},
sbook(): Dict {
return this.article.bookList[this.article.studyIndex] ?? {}
},