Skip to content

Commit c20b009

Browse files
authored
wip
1 parent 05ee2b0 commit c20b009

16 files changed

Lines changed: 282 additions & 762 deletions

File tree

apps/nuxt/app/pages/(articles)/articles.vue

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -363,7 +363,7 @@ onMounted(() => {
363363
>
364364
{{ isMultiple ? $t('cancel') : $t('manage_books') }}
365365
</div>
366-
<div class="color-link cursor-pointer" @click="nav('/book', { isAdd: true })">
366+
<div class="color-link cursor-pointer" @click="nav('/book/new', { isAdd: true })">
367367
{{ $t('create_personal_book') }}
368368
</div>
369369
</div>
@@ -418,4 +418,4 @@ onMounted(() => {
418418
@apply color-gray-500;
419419
}
420420
}
421-
</style>
421+
</style>

apps/nuxt/app/pages/(articles)/batch-edit-article.vue

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,24 @@
11
<script setup lang="ts">
22
import type { Article } from '@typewords/core/types/types.ts'
33
import { BaseButton, Toast, MiniDialog, UploadButton ,BackIcon} from '@typewords/base'
4-
import { cloneDeep, loadJsLib } from '@typewords/core/utils'
4+
import { cloneDeep, ensureCustomDictCopy, loadJsLib } from '@typewords/core/utils'
55
66
import List from '@typewords/core/components/list/List.vue'
77
import { useWindowClick } from '@typewords/core/hooks/event.ts'
88
import { MessageBox } from '@typewords/core/utils/MessageBox.tsx'
99
import { useRuntimeStore } from '@typewords/core/stores/runtime.ts'
1010
import { nanoid } from 'nanoid'
1111
import EditArticle from '@typewords/core/components/article/EditArticle.vue'
12-
import { getDefaultArticle } from '@typewords/core/types/func.ts'
12+
import { getDefaultArticle, getDefaultDict } from '@typewords/core/types/func.ts'
13+
import { useBaseStore } from '@typewords/core/stores/base.ts'
1314
import { onMounted } from 'vue'
1415
import { LIB_JS_URL } from '@typewords/core/config/env.ts'
1516
import { syncBookInMyStudyList } from '@typewords/core/hooks/article.ts'
1617
import { useI18n } from 'vue-i18n'
1718
const { t } = useI18n()
1819
1920
const runtimeStore = useRuntimeStore()
21+
const baseStore = useBaseStore()
2022
2123
let article = $ref<Article>(getDefaultArticle())
2224
let editArticleRef: any = $ref()
@@ -119,6 +121,16 @@ let showExport = $ref(false)
119121
useWindowClick(() => (showExport = false))
120122
121123
onMounted(() => {
124+
// 官方资源不允许直接编辑,自动转为副本
125+
if (!runtimeStore.editDict.custom) {
126+
const copy = ensureCustomDictCopy(runtimeStore.editDict)
127+
copy.name = runtimeStore.editDict.name + ' (副本)'
128+
const existIdx = baseStore.article.bookList.findIndex(v => v.id === copy.id)
129+
if (existIdx === -1) {
130+
baseStore.article.bookList.push(getDefaultDict(copy))
131+
}
132+
runtimeStore.editDict = copy
133+
}
122134
if (runtimeStore.editDict.articles.length) {
123135
article = runtimeStore.editDict.articles[0]
124136
}

apps/nuxt/app/pages/(articles)/book/[id].vue

Lines changed: 54 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ import {
1212
_dateFormat,
1313
_getDictDataByUrl,
1414
_nextTick,
15+
ensureCustomDictCopy,
16+
findOfficialSourceDict,
1517
msToHourMinute,
1618
resourceWrap,
1719
total,
@@ -46,6 +48,7 @@ const practice = usePracticeWordPersistence()
4648
let isEdit = $ref(false)
4749
let isAdd = $ref(false)
4850
let studyLoading = $ref(false)
51+
let _copyData: Dict | null = null // createCopy 生成的副本数据,作为 initialData 传给 EditBook
4952
let articleRef = $ref<HTMLDivElement>()
5053
let audioRef = $ref<HTMLAudioElement>()
5154
@@ -94,8 +97,17 @@ const showBookDetail = computed(() => {
9497
9598
const { loading } = useGetDict()
9699
100+
function createCopy() {
101+
// 生成副本数据,不写入 store。经由 initialData 传给 EditBook,确认后才写入
102+
const copy = ensureCustomDictCopy(runtimeStore.editDict)
103+
copy.name = runtimeStore.editDict.name + ' (副本)'
104+
_copyData = copy
105+
isAdd = true
106+
}
107+
97108
onMounted(() => {
98-
if (route.query?.isAdd) {
109+
// id='new' 或 ?isAdd=true 均为新建场景(兼容从 /book/new 进入)
110+
if (route.query?.isAdd || route.params?.id === 'new') {
99111
isAdd = true
100112
runtimeStore.editDict = getDefaultDict()
101113
}
@@ -113,8 +125,26 @@ function handleResize() {
113125
}
114126
115127
function formClose() {
116-
if (isEdit) isEdit = false
117-
else router.back()
128+
if (isEdit) {
129+
isEdit = false
130+
} else if (isAdd) {
131+
if (_copyData) {
132+
// 创建副本场景:取消回到书籍详情
133+
_copyData = null
134+
isAdd = false
135+
} else {
136+
// 直接新建场景(/book/new):取消返回上一页
137+
router.back()
138+
}
139+
} else {
140+
router.back()
141+
}
142+
}
143+
144+
function handleSubmit() {
145+
_copyData = null
146+
isEdit = false
147+
isAdd = false
118148
}
119149
120150
const { data: book_list } = useFetch(resourceWrap(DICT_LIST.ARTICLE.ALL)).json()
@@ -124,17 +154,24 @@ function reset() {
124154
'继续此操作会重置所有文章,并从官方书籍获取最新文章列表,学习记录不会被重置。确认恢复默认吗?',
125155
'恢复默认',
126156
async () => {
127-
let dict = book_list.value.find(v => v.url === runtimeStore.editDict.url) as Dict
157+
let dict = findOfficialSourceDict(book_list.value ?? [], runtimeStore.editDict) as Dict
128158
if (dict && dict.id) {
129159
dict = await _getDictDataByUrl(dict, DictType.article)
130160
let rIndex = store.article.bookList.findIndex(v => v.id === runtimeStore.editDict.id)
131161
if (rIndex > -1) {
132162
let item = store.article.bookList[rIndex]
133-
item.custom = false
134-
item.id = dict.id
135163
item.articles = dict.articles
164+
item.length = dict.articles.length
165+
item.url = dict.url
166+
item.cover = dict.cover
167+
item.description = dict.description
168+
item.name = dict.name
169+
item.category = dict.category
170+
item.tags = dict.tags
171+
item.enName = dict.enName
172+
item.sourceId = String(dict.id)
136173
if (item.lastLearnIndex >= item.articles.length) {
137-
item.lastLearnIndex = item.articles.length - 1
174+
item.lastLearnIndex = Math.max(item.articles.length - 1, 0)
138175
}
139176
runtimeStore.editDict = item
140177
Toast.success('恢复成功')
@@ -285,10 +322,11 @@ watch(
285322
<BaseButton v-if="runtimeStore.editDict.custom && runtimeStore.editDict.url" type="info" @click="reset">
286323
{{ $t('restore_default') }}
287324
</BaseButton>
288-
<BaseButton :loading="studyLoading || loading" type="info" @click="isEdit = true">{{
289-
$t('edit')
290-
}}</BaseButton>
291-
<BaseButton type="info" @click="router.push('/batch-edit-article')">{{
325+
<BaseButton v-if="!runtimeStore.editDict.custom" type="info" @click="createCopy">{{ $t('create_copy') }}</BaseButton>
326+
<BaseButton v-if="runtimeStore.editDict.custom" :loading="studyLoading || loading" type="info" @click="isEdit = true">{{
327+
$t('edit')
328+
}}</BaseButton>
329+
<BaseButton v-if="runtimeStore.editDict.custom || runtimeStore.editDict.system" type="info" @click="router.push('/batch-edit-article')">{{
292330
$t('article_management')
293331
}}</BaseButton>
294332
<BaseButton :loading="studyLoading || loading" @click="startPractice">{{ $t('learn') }}</BaseButton>
@@ -489,13 +527,13 @@ watch(
489527
</div>
490528
<div class="" v-else>
491529
<div class="dict-header flex justify-between items-center relative">
492-
<BackIcon class="dict-back z-2" @click="isAdd ? $router.back() : (isEdit = false)" />
493-
<div class="dict-title absolute text-2xl text-align-center w-full">
494-
{{ runtimeStore.editDict.id ? $t('edit_book') : $t('create_book') }}
530+
<BackIcon class="dict-back z-2" @click="formClose" />
531+
<div class="dict-title absolute text-2xl text-align-center w-full">
532+
{{ isAdd ? $t('create_book') : $t('edit_book') }}
495533
</div>
496534
</div>
497535
<div class="center">
498-
<EditBook :is-add="isAdd" :is-book="true" @close="formClose" @submit="isEdit = isAdd = false" />
536+
<EditBook :is-add="isAdd" :is-book="true" :initial-data="_copyData" @close="formClose" @submit="handleSubmit" />
499537
</div>
500538
</div>
501539
</div>
@@ -658,4 +696,4 @@ $article-lh: 2.4;
658696
line-height: 1.35;
659697
}
660698
}
661-
</style>
699+
</style>

0 commit comments

Comments
 (0)