wip
This commit is contained in:
@@ -1,6 +1,10 @@
|
||||
import http from '@/utils/http.ts'
|
||||
import { Dict } from '@/types/types.ts'
|
||||
|
||||
export function addDict(params?, data?) {
|
||||
return http<Dict>('dict/addDict', data, params, 'post')
|
||||
export function copyOfficialDict(params?, data?) {
|
||||
return http<Dict>('dict/copyOfficialDict', data, params, 'post')
|
||||
}
|
||||
|
||||
export function deleteDict(params?, data?) {
|
||||
return http<Dict>('dict/delete', data, params, 'post')
|
||||
}
|
||||
|
||||
@@ -38,6 +38,7 @@ import { nanoid } from 'nanoid'
|
||||
import { computed, onMounted, reactive, ref, watch } from 'vue'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { wordDelete } from '@/apis/words.ts'
|
||||
import { copyOfficialDict } from '@/apis/dict.ts'
|
||||
|
||||
const runtimeStore = useRuntimeStore()
|
||||
const base = useBaseStore()
|
||||
@@ -147,32 +148,33 @@ async function batchDel(ids: string[]) {
|
||||
syncDictInMyStudyList()
|
||||
}
|
||||
|
||||
let cloudHandle = async dictId => {
|
||||
let res = await wordDelete(null, {
|
||||
wordIds: ids,
|
||||
dictId,
|
||||
})
|
||||
if (res.success) {
|
||||
tableRef.value.getData()
|
||||
} else {
|
||||
return Toast.error(res.msg ?? '删除失败')
|
||||
}
|
||||
}
|
||||
|
||||
if (AppEnv.CAN_REQUEST) {
|
||||
if (dict.custom) {
|
||||
if (dict.sync) {
|
||||
let res = await wordDelete(null, {
|
||||
wordIds: ids,
|
||||
userDictId: dict?.userDictId,
|
||||
dictId: dict.id,
|
||||
})
|
||||
if (res.success) {
|
||||
tableRef.value.getData()
|
||||
} else {
|
||||
return Toast.error(res.msg ?? '删除失败')
|
||||
}
|
||||
await cloudHandle(dict.id)
|
||||
} else {
|
||||
localHandle()
|
||||
}
|
||||
} else {
|
||||
let r = await add2MyDict({
|
||||
id: dict.id,
|
||||
perDayStudyNumber: dict.perDayStudyNumber,
|
||||
lastLearnIndex: dict.lastLearnIndex,
|
||||
complete: dict.complete,
|
||||
})
|
||||
if (!r.success) return Toast.error(r.msg)
|
||||
else {
|
||||
dict.userDictId = r.data
|
||||
let r = await copyOfficialDict(null, { id: dict.id })
|
||||
if (r.success) {
|
||||
await cloudHandle(r.data.id)
|
||||
getDetail(r.data.id)
|
||||
} else {
|
||||
//todo 权限判断,能否复制
|
||||
return Toast.error(r.msg)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -255,11 +257,7 @@ onMounted(async () => {
|
||||
}
|
||||
if (base.word.bookList.find(book => book.id === runtimeStore.editDict.id)) {
|
||||
if (AppEnv.CAN_REQUEST) {
|
||||
//todo 优化:这里只返回详情
|
||||
let res = await detail({ id: runtimeStore.editDict.id })
|
||||
if (res.success) {
|
||||
runtimeStore.editDict.statistics = res.data.statistics
|
||||
}
|
||||
getDetail(runtimeStore.editDict.id)
|
||||
}
|
||||
}
|
||||
loading = false
|
||||
@@ -270,6 +268,14 @@ onMounted(async () => {
|
||||
tableRef.value.getData()
|
||||
})
|
||||
|
||||
async function getDetail(id) {
|
||||
//todo 优化:这里只返回详情
|
||||
let res = await detail({ id })
|
||||
if (res.success) {
|
||||
runtimeStore.editDict = res.data
|
||||
}
|
||||
}
|
||||
|
||||
function formClose() {
|
||||
if (isEdit) isEdit = false
|
||||
else router.back()
|
||||
|
||||
@@ -1,38 +1,45 @@
|
||||
<script setup lang="ts">
|
||||
import { useBaseStore } from "@/stores/base.ts";
|
||||
import { useRouter } from "vue-router";
|
||||
import BaseIcon from "@/components/BaseIcon.vue";
|
||||
import { useBaseStore } from '@/stores/base.ts'
|
||||
import { useRouter } from 'vue-router'
|
||||
import BaseIcon from '@/components/BaseIcon.vue'
|
||||
import {
|
||||
_getAccomplishDate,
|
||||
_getDictDataByUrl, _getStudyProgress,
|
||||
_getDictDataByUrl,
|
||||
_nextTick,
|
||||
isMobile,
|
||||
loadJsLib,
|
||||
resourceWrap,
|
||||
shuffle,
|
||||
useNav
|
||||
} from "@/utils";
|
||||
import BasePage from "@/components/BasePage.vue";
|
||||
import { DictResource, WordPracticeMode } from "@/types/types.ts";
|
||||
import { watch } from "vue";
|
||||
import { getCurrentStudyWord } from "@/hooks/dict.ts";
|
||||
import { useRuntimeStore } from "@/stores/runtime.ts";
|
||||
import Book from "@/components/Book.vue";
|
||||
import PopConfirm from "@/components/PopConfirm.vue";
|
||||
import Progress from '@/components/base/Progress.vue';
|
||||
import Toast from '@/components/base/toast/Toast.ts';
|
||||
import BaseButton from "@/components/BaseButton.vue";
|
||||
import { getDefaultDict } from "@/types/func.ts";
|
||||
import DeleteIcon from "@/components/icon/DeleteIcon.vue";
|
||||
import PracticeSettingDialog from "@/pages/word/components/PracticeSettingDialog.vue";
|
||||
import ChangeLastPracticeIndexDialog from "@/pages/word/components/ChangeLastPracticeIndexDialog.vue";
|
||||
import { useSettingStore } from "@/stores/setting.ts";
|
||||
import { useFetch } from "@vueuse/core";
|
||||
import { AppEnv, DICT_LIST, Host, LIB_JS_URL, PracticeSaveWordKey, TourConfig } from "@/config/env.ts";
|
||||
import { myDictList } from "@/apis";
|
||||
import PracticeWordListDialog from "@/pages/word/components/PracticeWordListDialog.vue";
|
||||
import ShufflePracticeSettingDialog from "@/pages/word/components/ShufflePracticeSettingDialog.vue";
|
||||
|
||||
useNav,
|
||||
} from '@/utils'
|
||||
import BasePage from '@/components/BasePage.vue'
|
||||
import { DictResource, WordPracticeMode } from '@/types/types.ts'
|
||||
import { watch } from 'vue'
|
||||
import { getCurrentStudyWord } from '@/hooks/dict.ts'
|
||||
import { useRuntimeStore } from '@/stores/runtime.ts'
|
||||
import Book from '@/components/Book.vue'
|
||||
import PopConfirm from '@/components/PopConfirm.vue'
|
||||
import Progress from '@/components/base/Progress.vue'
|
||||
import Toast from '@/components/base/toast/Toast.ts'
|
||||
import BaseButton from '@/components/BaseButton.vue'
|
||||
import { getDefaultDict } from '@/types/func.ts'
|
||||
import DeleteIcon from '@/components/icon/DeleteIcon.vue'
|
||||
import PracticeSettingDialog from '@/pages/word/components/PracticeSettingDialog.vue'
|
||||
import ChangeLastPracticeIndexDialog from '@/pages/word/components/ChangeLastPracticeIndexDialog.vue'
|
||||
import { useSettingStore } from '@/stores/setting.ts'
|
||||
import { useFetch } from '@vueuse/core'
|
||||
import {
|
||||
AppEnv,
|
||||
DICT_LIST,
|
||||
Host,
|
||||
LIB_JS_URL,
|
||||
PracticeSaveWordKey,
|
||||
TourConfig,
|
||||
} from '@/config/env.ts'
|
||||
import { myDictList } from '@/apis'
|
||||
import PracticeWordListDialog from '@/pages/word/components/PracticeWordListDialog.vue'
|
||||
import ShufflePracticeSettingDialog from '@/pages/word/components/ShufflePracticeSettingDialog.vue'
|
||||
import { deleteDict } from '@/apis/dict.ts'
|
||||
|
||||
const store = useBaseStore()
|
||||
const settingStore = useSettingStore()
|
||||
@@ -49,41 +56,45 @@ let currentStudy = $ref({
|
||||
shuffle: [],
|
||||
})
|
||||
|
||||
watch(() => store.load, n => {
|
||||
if (n) {
|
||||
init()
|
||||
_nextTick(async () => {
|
||||
const Shepherd = await loadJsLib('Shepherd', LIB_JS_URL.SHEPHERD);
|
||||
const tour = new Shepherd.Tour(TourConfig);
|
||||
tour.on('cancel', () => {
|
||||
localStorage.setItem('tour-guide', '1');
|
||||
});
|
||||
tour.addStep({
|
||||
id: 'step1',
|
||||
text: '点击这里选择一本词典开始学习',
|
||||
attachTo: {
|
||||
element: '#step1',
|
||||
on: 'bottom'
|
||||
},
|
||||
buttons: [
|
||||
{
|
||||
text: `下一步(1/${TourConfig.total})`,
|
||||
action() {
|
||||
tour.next()
|
||||
router.push('/dict-list')
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
const r = localStorage.getItem('tour-guide');
|
||||
if (settingStore.first && !r && !isMobile()) tour.start();
|
||||
}, 500)
|
||||
}
|
||||
}, { immediate: true })
|
||||
watch(
|
||||
() => store.load,
|
||||
n => {
|
||||
if (n) {
|
||||
init()
|
||||
_nextTick(async () => {
|
||||
const Shepherd = await loadJsLib('Shepherd', LIB_JS_URL.SHEPHERD)
|
||||
const tour = new Shepherd.Tour(TourConfig)
|
||||
tour.on('cancel', () => {
|
||||
localStorage.setItem('tour-guide', '1')
|
||||
})
|
||||
tour.addStep({
|
||||
id: 'step1',
|
||||
text: '点击这里选择一本词典开始学习',
|
||||
attachTo: {
|
||||
element: '#step1',
|
||||
on: 'bottom',
|
||||
},
|
||||
buttons: [
|
||||
{
|
||||
text: `下一步(1/${TourConfig.total})`,
|
||||
action() {
|
||||
tour.next()
|
||||
router.push('/dict-list')
|
||||
},
|
||||
},
|
||||
],
|
||||
})
|
||||
const r = localStorage.getItem('tour-guide')
|
||||
if (settingStore.first && !r && !isMobile()) tour.start()
|
||||
}, 500)
|
||||
}
|
||||
},
|
||||
{ immediate: true }
|
||||
)
|
||||
|
||||
async function init() {
|
||||
if (AppEnv.CAN_REQUEST) {
|
||||
let res = await myDictList({ type: "word" })
|
||||
let res = await myDictList({ type: 'word' })
|
||||
if (res.success) {
|
||||
store.setState(Object.assign(store.$state, res.data))
|
||||
}
|
||||
@@ -122,7 +133,7 @@ function startPractice() {
|
||||
perDayStudyNumber: store.sdict.perDayStudyNumber,
|
||||
custom: store.sdict.custom,
|
||||
complete: store.sdict.complete,
|
||||
wordPracticeMode: settingStore.wordPracticeMode
|
||||
wordPracticeMode: settingStore.wordPracticeMode,
|
||||
})
|
||||
//把是否是第一次设置为false
|
||||
settingStore.first = false
|
||||
@@ -147,21 +158,30 @@ async function goDictDetail(val: DictResource) {
|
||||
let isManageDict = $ref(false)
|
||||
let selectIds = $ref([])
|
||||
|
||||
function handleBatchDel() {
|
||||
selectIds.forEach(id => {
|
||||
let r = store.word.bookList.findIndex(v => v.id === id)
|
||||
if (r !== -1) {
|
||||
if (store.word.studyIndex === r) {
|
||||
store.word.studyIndex = -1
|
||||
}
|
||||
if (store.word.studyIndex > r) {
|
||||
store.word.studyIndex--
|
||||
}
|
||||
store.word.bookList.splice(r, 1)
|
||||
async function handleBatchDel() {
|
||||
if (AppEnv.CAN_REQUEST) {
|
||||
let res = await deleteDict(null, selectIds)
|
||||
if (res.success) {
|
||||
init()
|
||||
} else {
|
||||
Toast.error(res.msg)
|
||||
}
|
||||
})
|
||||
selectIds = []
|
||||
Toast.success("删除成功!")
|
||||
} else {
|
||||
selectIds.forEach(id => {
|
||||
let r = store.word.bookList.findIndex(v => v.id === id)
|
||||
if (r !== -1) {
|
||||
if (store.word.studyIndex === r) {
|
||||
store.word.studyIndex = -1
|
||||
}
|
||||
if (store.word.studyIndex > r) {
|
||||
store.word.studyIndex--
|
||||
}
|
||||
store.word.bookList.splice(r, 1)
|
||||
}
|
||||
})
|
||||
selectIds = []
|
||||
Toast.success('删除成功!')
|
||||
}
|
||||
}
|
||||
|
||||
function toggleSelect(item) {
|
||||
@@ -212,11 +232,17 @@ async function onShufflePracticeSettingOk(total) {
|
||||
localStorage.removeItem(PracticeSaveWordKey.key)
|
||||
|
||||
let ignoreList = [store.allIgnoreWords, store.knownWords][settingStore.ignoreSimpleWord ? 0 : 1]
|
||||
currentStudy.shuffle = shuffle(store.sdict.words.slice(0, store.sdict.lastLearnIndex).filter(v => !ignoreList.includes(v.word))).slice(0, total)
|
||||
nav('practice-words/' + store.sdict.id, {}, {
|
||||
taskWords: currentStudy,
|
||||
total //用于再来一组时,随机出正确的长度,因为练习中可能会点击已掌握,导致重学一遍之后长度变少,如果再来一组,此时长度就不正确
|
||||
})
|
||||
currentStudy.shuffle = shuffle(
|
||||
store.sdict.words.slice(0, store.sdict.lastLearnIndex).filter(v => !ignoreList.includes(v.word))
|
||||
).slice(0, total)
|
||||
nav(
|
||||
'practice-words/' + store.sdict.id,
|
||||
{},
|
||||
{
|
||||
taskWords: currentStudy,
|
||||
total, //用于再来一组时,随机出正确的长度,因为练习中可能会点击已掌握,导致重学一遍之后长度变少,如果再来一组,此时长度就不正确
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
async function saveLastPracticeIndex(e) {
|
||||
@@ -229,20 +255,19 @@ 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)
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<BasePage>
|
||||
<div class="mb-4" v-if="!isNewHost">
|
||||
新域名已启用,后续请访问 <a href="https://typewords.cc/words?from_old_site=1">https://typewords.cc</a>。当前
|
||||
2study.top 域名将在不久后停止使用
|
||||
新域名已启用,后续请访问
|
||||
<a href="https://typewords.cc/words?from_old_site=1">https://typewords.cc</a>。当前 2study.top
|
||||
域名将在不久后停止使用
|
||||
</div>
|
||||
|
||||
<div class="card flex flex-col md:flex-row gap-4">
|
||||
@@ -259,11 +284,17 @@ let isNewHost = $ref(window.location.host === Host)
|
||||
<template v-if="store.sdict.id">
|
||||
<div class="mt-4 flex flex-col gap-2">
|
||||
<div class="">当前进度:{{ progressTextLeft }}</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>已完成 {{ progressTextRight }} 词 / 共 {{ store.sdict.words.length }} 词</span>
|
||||
<span v-if="store.sdict.id">
|
||||
预计完成日期:{{ _getAccomplishDate(store.sdict.words.length, store.sdict.perDayStudyNumber) }}
|
||||
预计完成日期:{{
|
||||
_getAccomplishDate(store.sdict.words.length, store.sdict.perDayStudyNumber)
|
||||
}}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -274,8 +305,11 @@ let isNewHost = $ref(window.location.host === Host)
|
||||
<span>选择词典</span>
|
||||
</div>
|
||||
</BaseButton>
|
||||
<PopConfirm :disabled="!isSaveData" title="当前存在未完成的学习任务,修改会重新生成学习任务,是否继续?"
|
||||
@confirm="check(() => showChangeLastPracticeIndexDialog = true)">
|
||||
<PopConfirm
|
||||
:disabled="!isSaveData"
|
||||
title="当前存在未完成的学习任务,修改会重新生成学习任务,是否继续?"
|
||||
@confirm="check(() => (showChangeLastPracticeIndexDialog = true))"
|
||||
>
|
||||
<BaseButton type="info" size="small" v-if="store.sdict.id">
|
||||
<div class="center gap-1">
|
||||
<IconFluentSlideTextTitleEdit20Regular />
|
||||
@@ -297,29 +331,37 @@ let isNewHost = $ref(window.location.host === Host)
|
||||
</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 ">
|
||||
<div class="p-2 center rounded-full bg-white">
|
||||
<IconFluentStar20Filled class="text-lg color-amber" />
|
||||
</div>
|
||||
<div class="text-xl font-bold">
|
||||
{{ isSaveData ? '上次任务' : '今日任务' }}
|
||||
</div>
|
||||
<span class="color-link cursor-pointer" v-if="store.sdict.id"
|
||||
@click="showPracticeWordListDialog = true">词表</span>
|
||||
|
||||
<span
|
||||
class="color-link cursor-pointer"
|
||||
v-if="store.sdict.id"
|
||||
@click="showPracticeWordListDialog = true"
|
||||
>词表</span
|
||||
>
|
||||
</div>
|
||||
<div class="flex gap-1 items-center" v-if="store.sdict.id">
|
||||
每日目标
|
||||
<div style="color:#ac6ed1;" class="bg-third px-2 h-10 flex center text-2xl rounded">
|
||||
<div style="color: #ac6ed1" class="bg-third px-2 h-10 flex center text-2xl rounded">
|
||||
{{ store.sdict.id ? store.sdict.perDayStudyNumber : 0 }}
|
||||
</div>
|
||||
个单词
|
||||
<PopConfirm :disabled="!isSaveData" title="当前存在未完成的学习任务,修改会重新生成学习任务,是否继续?"
|
||||
@confirm="check(() => showPracticeSettingDialog = true)">
|
||||
<BaseButton type="info" size="small">更改
|
||||
</BaseButton>
|
||||
<PopConfirm
|
||||
:disabled="!isSaveData"
|
||||
title="当前存在未完成的学习任务,修改会重新生成学习任务,是否继续?"
|
||||
@confirm="check(() => (showPracticeSettingDialog = true))"
|
||||
>
|
||||
<BaseButton type="info" size="small">更改 </BaseButton>
|
||||
</PopConfirm>
|
||||
</div>
|
||||
</div>
|
||||
@@ -340,32 +382,45 @@ let isNewHost = $ref(window.location.host === Host)
|
||||
</template>
|
||||
</div>
|
||||
<div class="flex items-end mt-4">
|
||||
<BaseButton size="large" class="flex-1" :disabled="!store.sdict.id" :loading="loading" @click="startPractice">
|
||||
<BaseButton
|
||||
size="large"
|
||||
class="flex-1"
|
||||
:disabled="!store.sdict.id"
|
||||
:loading="loading"
|
||||
@click="startPractice"
|
||||
>
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="line-height-[2]">{{ isSaveData ? '继续学习' : '开始学习' }}</span>
|
||||
<IconFluentArrowCircleRight16Regular class="text-xl" />
|
||||
</div>
|
||||
</BaseButton>
|
||||
|
||||
<div v-if="false" class="w-full flex box-border cp color-white">
|
||||
<div @click="startPractice"
|
||||
class="flex-1 rounded-l-lg center gap-2 py-1 bg-[var(--btn-primary)] hover:opacity-50">
|
||||
<div v-if="false" class="w-full flex box-border cp color-white">
|
||||
<div
|
||||
@click="startPractice"
|
||||
class="flex-1 rounded-l-lg center gap-2 py-1 bg-[var(--btn-primary)] hover:opacity-50"
|
||||
>
|
||||
<span class="line-height-[2]">{{ isSaveData ? '继续学习' : '开始学习' }}</span>
|
||||
<IconFluentArrowCircleRight16Regular class="text-xl" />
|
||||
</div>
|
||||
|
||||
<div class="relative group">
|
||||
<div
|
||||
class="w-10 rounded-r-lg h-full center bg-[var(--btn-primary)] hover:bg-gray border-solid border-2 border-l-gray border-transparent box-border">
|
||||
class="w-10 rounded-r-lg h-full center bg-[var(--btn-primary)] hover:bg-gray border-solid border-2 border-l-gray border-transparent box-border"
|
||||
>
|
||||
<IconFluentChevronDown20Regular />
|
||||
</div>
|
||||
|
||||
<div class="space-y-2 pt-2 absolute z-2 right-0 border rounded opacity-0 scale-95
|
||||
group-hover:opacity-100 group-hover:scale-100
|
||||
transition-all duration-150 pointer-events-none group-hover:pointer-events-auto">
|
||||
<div
|
||||
class="space-y-2 pt-2 absolute z-2 right-0 border rounded opacity-0 scale-95 group-hover:opacity-100 group-hover:scale-100 transition-all duration-150 pointer-events-none group-hover:pointer-events-auto"
|
||||
>
|
||||
<div>
|
||||
<BaseButton size="large" type="orange" :loading="loading"
|
||||
@click="check(() => showShufflePracticeSettingDialog = true)">
|
||||
<BaseButton
|
||||
size="large"
|
||||
type="orange"
|
||||
:loading="loading"
|
||||
@click="check(() => (showShufflePracticeSettingDialog = true))"
|
||||
>
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="line-height-[2]">随机复习</span>
|
||||
<IconFluentArrowShuffle20Filled class="text-xl" />
|
||||
@@ -373,8 +428,12 @@ let isNewHost = $ref(window.location.host === Host)
|
||||
</BaseButton>
|
||||
</div>
|
||||
<div>
|
||||
<BaseButton size="large" type="orange" :loading="loading"
|
||||
@click="check(() => showShufflePracticeSettingDialog = true)">
|
||||
<BaseButton
|
||||
size="large"
|
||||
type="orange"
|
||||
:loading="loading"
|
||||
@click="check(() => (showShufflePracticeSettingDialog = true))"
|
||||
>
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="line-height-[2]">重新学习</span>
|
||||
<IconFluentArrowShuffle20Filled class="text-xl" />
|
||||
@@ -385,8 +444,13 @@ let isNewHost = $ref(window.location.host === Host)
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<BaseButton v-if="store.sdict.id && store.sdict.lastLearnIndex" size="large" type="orange" :loading="loading"
|
||||
@click="check(() => showShufflePracticeSettingDialog = true)">
|
||||
<BaseButton
|
||||
v-if="store.sdict.id && store.sdict.lastLearnIndex"
|
||||
size="large"
|
||||
type="orange"
|
||||
:loading="loading"
|
||||
@click="check(() => (showShufflePracticeSettingDialog = true))"
|
||||
>
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="line-height-[2]">随机复习</span>
|
||||
<IconFluentArrowShuffle20Filled class="text-xl" />
|
||||
@@ -400,22 +464,44 @@ let isNewHost = $ref(window.location.host === Host)
|
||||
<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>
|
||||
</PopConfirm>
|
||||
|
||||
<div class="color-link cursor-pointer" v-if="store.word.bookList.length > 3"
|
||||
@click="isManageDict = !isManageDict; selectIds = []">{{ isManageDict ? '取消' : '管理词典' }}
|
||||
<div
|
||||
class="color-link cursor-pointer"
|
||||
v-if="store.word.bookList.length > 3"
|
||||
@click="
|
||||
() => {
|
||||
isManageDict = !isManageDict
|
||||
selectIds = []
|
||||
}
|
||||
"
|
||||
>
|
||||
{{ 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">
|
||||
<Book :is-add="false" quantifier="个词" :item="item" :checked="selectIds.includes(item.id)"
|
||||
@check="() => toggleSelect(item)" :show-checkbox="isManageDict && j >= 3"
|
||||
v-for="(item, j) in store.word.bookList" @click="goDictDetail(item)" />
|
||||
<div class="flex gap-4 flex-wrap mt-4">
|
||||
<Book
|
||||
:is-add="false"
|
||||
quantifier="个词"
|
||||
:item="item"
|
||||
:checked="selectIds.includes(item.id)"
|
||||
@check="() => toggleSelect(item)"
|
||||
:show-checkbox="isManageDict && j >= 3"
|
||||
v-for="(item, j) in store.word.bookList"
|
||||
@click="goDictDetail(item)"
|
||||
/>
|
||||
<Book :is-add="true" @click="router.push('/dict-list')" />
|
||||
</div>
|
||||
</div>
|
||||
@@ -428,21 +514,35 @@ let isNewHost = $ref(window.location.host === Host)
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex gap-4 flex-wrap mt-4 min-h-50">
|
||||
<Book :is-add="false" quantifier="个词" :item="item as any" v-for="(item, j) in recommendDictList"
|
||||
@click="goDictDetail(item as any)" />
|
||||
<div class="flex gap-4 flex-wrap mt-4 min-h-50">
|
||||
<Book
|
||||
:is-add="false"
|
||||
quantifier="个词"
|
||||
:item="item as any"
|
||||
v-for="(item, j) in recommendDictList"
|
||||
@click="goDictDetail(item as any)"
|
||||
/>
|
||||
</div>
|
||||
</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">
|
||||
|
||||
Reference in New Issue
Block a user