feat: add audio-setting icon
This commit is contained in:
@@ -109,7 +109,7 @@ html.dark {
|
||||
|
||||
--color-label-bg: rgb(10, 10, 10);
|
||||
|
||||
--color-card-bg: rgb(30, 31, 34);
|
||||
--color-card-bg: var(--color-second);
|
||||
|
||||
--bg-card-primary: rgb(30, 31, 34);
|
||||
--bg-card-secend: rgb(43, 45, 48);
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<template>
|
||||
<div class="flex gap-5 w-full h-4">
|
||||
<div class="flex gap-5 w-full h-3">
|
||||
<template v-for="i of props.stages">
|
||||
<template v-if="i?.children?.length && i.active">
|
||||
<div class="flex gap-1 h-4" :style="{ width: i.ratio + '%' }">
|
||||
<div class="flex gap-1" :style="{ width: i.ratio + '%' }">
|
||||
<template v-for="j of i.children">
|
||||
<Tooltip :title="j.name">
|
||||
<Progress
|
||||
|
||||
@@ -1,16 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import {
|
||||
computed,
|
||||
nextTick,
|
||||
onBeforeUnmount,
|
||||
onMounted,
|
||||
provide,
|
||||
ref,
|
||||
useAttrs,
|
||||
useSlots,
|
||||
VNode,
|
||||
watch,
|
||||
} from 'vue'
|
||||
import { computed, nextTick, onBeforeUnmount, onMounted, provide, ref, useSlots, VNode, watch } from 'vue'
|
||||
import { useWindowClick } from '@/hooks/event.ts'
|
||||
|
||||
interface Option {
|
||||
@@ -26,8 +15,7 @@ const props = defineProps<{
|
||||
options?: Option[]
|
||||
}>()
|
||||
|
||||
const emit = defineEmits(['update:modelValue'])
|
||||
const attrs = useAttrs()
|
||||
const emit = defineEmits(['update:modelValue', 'toggle'])
|
||||
|
||||
const isOpen = ref(false)
|
||||
const isReverse = ref(false)
|
||||
@@ -69,6 +57,7 @@ const toggleDropdown = async () => {
|
||||
if (props.disabled) return
|
||||
|
||||
isOpen.value = !isOpen.value
|
||||
emit('toggle', isOpen.value)
|
||||
|
||||
if (isOpen.value) {
|
||||
await nextTick()
|
||||
@@ -81,6 +70,7 @@ const selectOption = (value: any, label: string) => {
|
||||
selectedOption.value = { value, label }
|
||||
emit('update:modelValue', value)
|
||||
isOpen.value = false
|
||||
emit('toggle', isOpen.value)
|
||||
}
|
||||
|
||||
let selectValue = ref(props.modelValue)
|
||||
@@ -97,6 +87,7 @@ useWindowClick((e: PointerEvent) => {
|
||||
!dropdownRef.value.contains(e.target as Node)
|
||||
) {
|
||||
isOpen.value = false
|
||||
emit('toggle', isOpen.value)
|
||||
}
|
||||
})
|
||||
|
||||
@@ -158,26 +149,15 @@ onBeforeUnmount(() => {
|
||||
|
||||
<template>
|
||||
<div class="select" ref="selectRef">
|
||||
<div
|
||||
class="select__wrapper"
|
||||
:class="{ disabled: disabled, active: isOpen }"
|
||||
@click="toggleDropdown"
|
||||
>
|
||||
<div class="select__wrapper" :class="{ disabled: disabled, active: isOpen }" @click="toggleDropdown">
|
||||
<div class="select__label" :class="{ 'is-placeholder': !selectedOption }">
|
||||
{{ displayValue }}
|
||||
</div>
|
||||
<IconFluentChevronLeft20Filled
|
||||
class="select__arrow"
|
||||
:class="{ 'is-reverse': isOpen }"
|
||||
width="16"
|
||||
/>
|
||||
<IconFluentChevronLeft20Filled class="select__arrow" :class="{ 'is-reverse': isOpen }" width="16" />
|
||||
</div>
|
||||
|
||||
<teleport to="body">
|
||||
<transition
|
||||
:name="isReverse ? 'zoom-in-bottom' : 'zoom-in-top'"
|
||||
:key="isReverse ? 'bottom' : 'top'"
|
||||
>
|
||||
<transition :name="isReverse ? 'zoom-in-bottom' : 'zoom-in-top'" :key="isReverse ? 'bottom' : 'top'">
|
||||
<div class="select__dropdown" v-if="isOpen" ref="dropdownRef" :style="dropdownStyle">
|
||||
<slot></slot>
|
||||
</div>
|
||||
@@ -237,9 +217,8 @@ onBeforeUnmount(() => {
|
||||
.select__dropdown {
|
||||
max-height: 200px;
|
||||
overflow-y: auto;
|
||||
background-color: var(--color-third);
|
||||
border-radius: 0.25rem;
|
||||
@apply shadow-lg;
|
||||
background-color: var(--color-card-bg);
|
||||
@apply shadow-xl rounded-lg border border-gray-300 border-solid;
|
||||
}
|
||||
|
||||
/* 往下展开的动画 */
|
||||
|
||||
@@ -35,37 +35,19 @@ watch(() => props.modelValue, (n) => {
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
|
||||
|
||||
.mini-row-title {
|
||||
min-height: 2rem;
|
||||
text-align: center;
|
||||
font-size: 1rem;
|
||||
font-weight: bold;
|
||||
@apply text-center text-base font-bold mb-2;
|
||||
color: var(--color-font-1);
|
||||
}
|
||||
|
||||
.mini-row {
|
||||
min-height: 2rem;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
gap: var(--space);
|
||||
@apply min-h-10 flex justify-between items-center gap-space text-base text-font-1 word-break-keep-all;
|
||||
color: var(--color-font-1);
|
||||
word-break: keep-all;
|
||||
}
|
||||
|
||||
.mini-modal {
|
||||
position: absolute;
|
||||
z-index: 9;
|
||||
width: 12rem;
|
||||
background: var(--color-second);
|
||||
border-radius: .5rem;
|
||||
box-shadow: 0 0 8px 2px var(--color-item-border);
|
||||
padding: .6rem var(--space);
|
||||
//top: 2.4rem;
|
||||
left: 50%;
|
||||
transform: translate3d(-50%, 0, 0);
|
||||
//margin-top: 10rem;
|
||||
background: var(--color-card-bg);
|
||||
padding: var(--space) 1rem;
|
||||
@apply z-9 absolute left-1/2 transform -translate-x-1/2 shadow-lg rounded-xl w-50;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -13,6 +13,7 @@ export function useSound(audioSrcList?: string[], audioFileLength?: number) {
|
||||
if (audioSrcList) setAudio(audioSrcList, audioFileLength)
|
||||
})
|
||||
|
||||
//这里同一个音频弄好几份是为了快速打字是,可同时发音
|
||||
function setAudio(audioSrcList2: string[], audioFileLength2?: number) {
|
||||
if (audioFileLength2) audioLength = audioFileLength2
|
||||
audioList = []
|
||||
@@ -23,6 +24,7 @@ export function useSound(audioSrcList?: string[], audioFileLength?: number) {
|
||||
}
|
||||
|
||||
function play(volume: number = 100) {
|
||||
console.log('play',audioList)
|
||||
index++
|
||||
if (audioList.length > 1 && audioList.length !== audioLength) {
|
||||
audioList[index % audioList.length].volume = volume / 100
|
||||
@@ -46,7 +48,7 @@ export function usePlayKeyboardAudio() {
|
||||
settingStore.keyboardSoundFile = '机械键盘2'
|
||||
}
|
||||
let urlList = getAudioFileUrl(settingStore.keyboardSoundFile)
|
||||
setAudio(urlList, urlList.length === 1 ? 3 : 1)
|
||||
setAudio(urlList, urlList.length === 1 ? 4 : 1)
|
||||
})
|
||||
|
||||
function playAudio() {
|
||||
@@ -150,4 +152,4 @@ export function getAudioFileUrl(name: string) {
|
||||
} else {
|
||||
return [`/sound/key-sounds/${name}.mp3`]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,274 +1,136 @@
|
||||
<script setup lang="ts">
|
||||
|
||||
let logList = [
|
||||
{
|
||||
date: '2025/12/30',
|
||||
content: '单词练习界面,底部工具栏新增音频设置按钮',
|
||||
},
|
||||
{
|
||||
date: '2025/12/27',
|
||||
content: '优化进度条展示,现可展示当前阶段、所有阶段',
|
||||
},
|
||||
{
|
||||
date: '2025/12/23',
|
||||
content: '新增复习、自测、默写、听写模式',
|
||||
},
|
||||
{
|
||||
date: '2025/12/20',
|
||||
content: '新增资源分享页面',
|
||||
},
|
||||
{
|
||||
date: '2025/12/17',
|
||||
content: '新增帮助页面',
|
||||
},
|
||||
{
|
||||
date: '2025/12/16',
|
||||
content: '修复弹框内边距太小;单词、文章、通用设置在设置页面、练习界面均可进行设置',
|
||||
},
|
||||
{
|
||||
date: '2025/12/15',
|
||||
content: '修复在黑暗模式下,翻译颜色不正确;支持中文符号输入',
|
||||
},
|
||||
{
|
||||
date: '2025/12/11',
|
||||
content: '修复音标显示错误问题,优化反馈页面',
|
||||
},
|
||||
{
|
||||
date: '2025/12/10',
|
||||
content: '新增选项:复习比(单词练习时,复习词与新词的比例)',
|
||||
},
|
||||
{
|
||||
date: '2025/12/5',
|
||||
content: '解决练习界面无法复制、全选的问题',
|
||||
},
|
||||
{
|
||||
date: '2025/12/3',
|
||||
content: '单词、文章设置修改为弹框,更方便',
|
||||
},
|
||||
{
|
||||
date: '2025/12/3',
|
||||
content: '录入新概念(三、四)部分音频,优化文章相关功能',
|
||||
},
|
||||
{
|
||||
date: '2025/12/2',
|
||||
content: '完成新概念(一)音频,优化文章管理页面',
|
||||
},
|
||||
{
|
||||
date: '2025/11/30',
|
||||
content: '文章里的单词可点击播放',
|
||||
},
|
||||
{
|
||||
date: '2025/11/29',
|
||||
content: '修改 Slider 组件显示bug,新增 IE 浏览器检测提示',
|
||||
},
|
||||
{
|
||||
date: '2025/11/28',
|
||||
content: '新增引导框、 新增词典测试模式(由大佬hebeihang 开发)',
|
||||
},
|
||||
{
|
||||
date: '2025/11/25',
|
||||
content: '文章练习新增人名忽略功能(新概念一已全部适配),上传了新概念(一)1-18 音频',
|
||||
},
|
||||
{
|
||||
date: '2025/11/23',
|
||||
content: '优化练习完成结算界面,新增分享功能',
|
||||
},
|
||||
{
|
||||
date: '2025/11/22',
|
||||
content: '适配移动端',
|
||||
},
|
||||
{
|
||||
date: '2025/11/16',
|
||||
content: '自测单词时,不认识单词可以直接输入,自动标识为错误单词,无需按2',
|
||||
},
|
||||
{
|
||||
date: '2025/11/15',
|
||||
content: '练习单词时,底部工具栏新增“跳到下一阶段”按钮',
|
||||
},
|
||||
{
|
||||
date: '2025/11/14',
|
||||
content:
|
||||
'新增文章练习时可跳过空格:如果在单词的最后一位上,不按空格直接输入下一个字母的话,自动跳下一个单词,按空格也自动跳下一个单词',
|
||||
},
|
||||
{
|
||||
date: '2025/11/13',
|
||||
content: '新增文章练习时“输入时忽略符号/数字”选项',
|
||||
},
|
||||
{
|
||||
date: '2025/11/6',
|
||||
content: '新增随机复习功能',
|
||||
},
|
||||
{
|
||||
date: '2025/10/30',
|
||||
content: '集成PWA基础配置,支持用户以类App形式打开项目',
|
||||
},
|
||||
{
|
||||
date: '2025/10/26',
|
||||
content: '进一步完善单词练习,解决复习数量太多的问题',
|
||||
},
|
||||
{
|
||||
date: '2025/10/8',
|
||||
content: '文章支持自动播放下一篇',
|
||||
},
|
||||
{
|
||||
date: '2025/9/14',
|
||||
content: '完善文章编辑、导入、导出等功能',
|
||||
},
|
||||
{
|
||||
date: '2025/8/10',
|
||||
content: '2.0版本发布,全新UI,全新逻辑,新增短语、例句、近义词等功能',
|
||||
},
|
||||
{
|
||||
date: '2025/7/19',
|
||||
content: '1.0版本发布',
|
||||
},
|
||||
]
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<div class="log-item">
|
||||
<div class="log-item" v-for="item in logList" :key="item.date">
|
||||
<div class="mb-2">
|
||||
<div>
|
||||
<div>日期:2025/12/20</div>
|
||||
<div>内容:新增资源分享页面</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="log-item">
|
||||
<div class="mb-2">
|
||||
<div>
|
||||
<div>日期:2025/12/17</div>
|
||||
<div>内容:新增帮助页面</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="log-item">
|
||||
<div class="mb-2">
|
||||
<div>
|
||||
<div>日期:2025/12/16</div>
|
||||
<div>内容:修复弹框内边距太小;单词、文章、通用设置在设置页面、练习界面均可进行设置</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="log-item">
|
||||
<div class="mb-2">
|
||||
<div>
|
||||
<div>日期:2025/12/15</div>
|
||||
<div>内容:修复在黑暗模式下,翻译颜色不正确;支持中文符号输入</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="log-item">
|
||||
<div class="mb-2">
|
||||
<div>
|
||||
<div>日期:2025/12/11</div>
|
||||
<div>内容:修复音标显示错误问题,优化反馈页面</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="log-item">
|
||||
<div class="mb-2">
|
||||
<div>
|
||||
<div>日期:2025/12/10</div>
|
||||
<div>内容:新增选项:复习比(单词练习时,复习词与新词的比例)</div>
|
||||
</div>
|
||||
</div>
|
||||
</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>日期:{{ item.date }}</div>
|
||||
<div>内容:{{ item.content }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -276,10 +138,8 @@
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
||||
.log-item {
|
||||
border-bottom: 1px solid var(--color-input-border);
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
import { onMounted, onUnmounted, provide, ref, watch } from 'vue'
|
||||
|
||||
import Statistics from '@/pages/word/Statistics.vue'
|
||||
import Statistics from '@/pages/word/components/Statistics.vue'
|
||||
import { emitter, EventKey, useEvents } from '@/utils/eventBus.ts'
|
||||
import { useSettingStore } from '@/stores/setting.ts'
|
||||
import { useRuntimeStore } from '@/stores/runtime.ts'
|
||||
|
||||
@@ -18,6 +18,8 @@ import Progress from '@/components/base/Progress.vue'
|
||||
import SettingDialog from '@/components/setting/SettingDialog.vue'
|
||||
import BaseButton from '@/components/BaseButton.vue'
|
||||
import { useBaseStore } from '@/stores/base.ts'
|
||||
import VolumeSettingMiniDialog from '@/pages/word/components/VolumeSettingMiniDialog.vue'
|
||||
import StageProgress from '@/components/StageProgress.vue'
|
||||
|
||||
const statStore = usePracticeStore()
|
||||
const store = useBaseStore()
|
||||
@@ -238,6 +240,9 @@ const stages = $computed(() => {
|
||||
</div>
|
||||
<div class="flex gap-2 justify-center items-center" id="toolbar-icons">
|
||||
<SettingDialog type="word" />
|
||||
|
||||
<VolumeSettingMiniDialog/>
|
||||
|
||||
<BaseIcon
|
||||
v-if="settingStore.wordPracticeMode !== WordPracticeMode.Free"
|
||||
@click="emit('skipStep')"
|
||||
|
||||
128
src/pages/word/components/VolumeSettingMiniDialog.vue
Normal file
128
src/pages/word/components/VolumeSettingMiniDialog.vue
Normal file
@@ -0,0 +1,128 @@
|
||||
<script setup lang="ts">
|
||||
import BaseIcon from '@/components/BaseIcon.vue'
|
||||
import Switch from '@/components/base/Switch.vue'
|
||||
import { Option, Select } from '@/components/base/select'
|
||||
import MiniDialog from '@/components/dialog/MiniDialog.vue'
|
||||
import VolumeIcon from '@/components/icon/VolumeIcon.vue'
|
||||
import { SoundFileOptions } from '@/config/env.ts'
|
||||
import { useWindowClick } from '@/hooks/event.ts'
|
||||
import { getAudioFileUrl, usePlayAudio } from '@/hooks/sound.ts'
|
||||
import { useSettingStore } from '@/stores/setting.ts'
|
||||
import { emitter, EventKey } from '@/utils/eventBus.ts'
|
||||
|
||||
const settingStore = useSettingStore()
|
||||
let timer = 0
|
||||
//停止切换事件,因为hover到select时会跳出mini-dialog
|
||||
let selectIsOpen = false
|
||||
let show = $ref(false)
|
||||
|
||||
useWindowClick(() => {
|
||||
if (selectIsOpen) {
|
||||
selectIsOpen = false
|
||||
} else {
|
||||
show = false
|
||||
}
|
||||
})
|
||||
|
||||
function toggle(val: boolean) {
|
||||
if (selectIsOpen) return
|
||||
clearTimeout(timer)
|
||||
if (val) {
|
||||
emitter.emit(EventKey.closeOther)
|
||||
show = val
|
||||
} else {
|
||||
timer = setTimeout(() => {
|
||||
show = val
|
||||
}, 100)
|
||||
}
|
||||
}
|
||||
|
||||
function selectToggle(e: boolean) {
|
||||
//这里要延时设置,因为关闭的时候,如果太早设置了false了,useWindowClick的事件就会把弹框关闭
|
||||
setTimeout(() => (selectIsOpen = e))
|
||||
}
|
||||
|
||||
function eventCheck(e) {
|
||||
const isSelfOrChild = e.currentTarget.contains(e.target)
|
||||
if (isSelfOrChild) {
|
||||
//如果下拉框打开的情况就不拦截
|
||||
if (selectIsOpen) return
|
||||
e.stopPropagation()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="setting" @click="eventCheck">
|
||||
<BaseIcon @mouseenter="toggle(true)" @mouseleave="toggle(false)">
|
||||
<IconClarityVolumeUpLine />
|
||||
</BaseIcon>
|
||||
<MiniDialog width="18rem" @mouseenter="toggle(true)" @mouseleave="toggle(false)" v-model="show">
|
||||
<div class="mini-row-title">音效设置</div>
|
||||
<div class="mini-row">
|
||||
<label class="item-title">单词自动发音</label>
|
||||
<div class="wrapper">
|
||||
<Switch v-model="settingStore.wordSound" inline-prompt active-text="开" inactive-text="关" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="mini-row">
|
||||
<label class="item-title">单词发音口音</label>
|
||||
<div class="wrapper">
|
||||
<Select v-model="settingStore.soundType" @toggle="selectToggle" placeholder="请选择" size="small">
|
||||
<Option label="美音" value="us" />
|
||||
<Option label="英音" value="uk" />
|
||||
</Select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mini-row">
|
||||
<label class="item-title">按键音</label>
|
||||
<div class="wrapper">
|
||||
<Switch v-model="settingStore.keyboardSound" inline-prompt active-text="开" inactive-text="关" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="mini-row">
|
||||
<label class="item-title">按键音效</label>
|
||||
<div class="wrapper">
|
||||
<Select v-model="settingStore.keyboardSoundFile" @toggle="selectToggle" placeholder="请选择" size="small">
|
||||
<Option v-for="item in SoundFileOptions" :key="item.value" :label="item.label" :value="item.value">
|
||||
<div class="el-option-row">
|
||||
<span>{{ item.label }}</span>
|
||||
<VolumeIcon :time="100" @click="usePlayAudio(getAudioFileUrl(item.value)[0])" />
|
||||
</div>
|
||||
</Option>
|
||||
</Select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mini-row">
|
||||
<label class="item-title">效果音</label>
|
||||
<div class="wrapper">
|
||||
<Switch v-model="settingStore.effectSound" inline-prompt active-text="开" inactive-text="关" />
|
||||
</div>
|
||||
</div>
|
||||
</MiniDialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
||||
.wrapper {
|
||||
width: 50%;
|
||||
position: relative;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.setting {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.el-option-row {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
|
||||
.icon-wrapper {
|
||||
transform: translateX(10rem);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user