feat:remove unuse components
This commit is contained in:
@@ -91,7 +91,7 @@ export function useArticleOptions() {
|
||||
export function syncMyDictList(dict: Dict, isCustom = true) {
|
||||
const store = useBaseStore()
|
||||
//任意修改,都将其变为自定义词典
|
||||
dict.isCustom = isCustom
|
||||
dict.custom = isCustom
|
||||
if (isArticle(dict.type)) {
|
||||
dict.length = dict.articles.length
|
||||
} else {
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import {Dict} from "@/types.ts";
|
||||
import DictItem from "./DictItem.vue";
|
||||
|
||||
defineProps<{
|
||||
list?: Dict[],
|
||||
@@ -17,11 +16,7 @@ const emit = defineEmits<{
|
||||
|
||||
<template>
|
||||
<div class="dict-list">
|
||||
<DictItem v-for="(dict,index) in list"
|
||||
:active="selectId === dict.id"
|
||||
@click="emit('selectDict',{dict,index})"
|
||||
@add="emit('add')"
|
||||
:dict="dict"/>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -32,4 +27,4 @@ const emit = defineEmits<{
|
||||
gap: 15rem;
|
||||
}
|
||||
|
||||
</style>
|
||||
</style>
|
||||
|
||||
@@ -47,7 +47,7 @@ async function onSubmit() {
|
||||
})
|
||||
let source = [store.article, store.word][props.isBook ? 0 : 1]
|
||||
//任意修改,都将其变为自定义词典
|
||||
data.isCustom = true
|
||||
data.custom = true
|
||||
|
||||
if (props.isAdd) {
|
||||
data.id = 'custom-dict-' + Date.now()
|
||||
|
||||
33
src/pages/pc/components/Book.vue
Normal file
33
src/pages/pc/components/Book.vue
Normal file
@@ -0,0 +1,33 @@
|
||||
<script setup lang="ts">
|
||||
import {Dict} from "@/types.ts";
|
||||
import {Icon} from "@iconify/vue";
|
||||
|
||||
defineProps<{
|
||||
item?: Dict
|
||||
quantifier?: string
|
||||
isAdd: boolean
|
||||
}>()
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="book">
|
||||
<template v-if="!isAdd">
|
||||
<div>
|
||||
<div>{{ item?.name }}</div>
|
||||
<div class="text-sm line-clamp-3" v-opacity="item.name !== item.description">{{ item?.description }}</div>
|
||||
</div>
|
||||
<div class="absolute bottom-4 right-4">{{ item?.words?.length }}{{ quantifier }}</div>
|
||||
</template>
|
||||
<div v-else class="center h-full">
|
||||
<Icon
|
||||
width="40px"
|
||||
icon="fluent:add-20-filled"/>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
||||
</style>
|
||||
@@ -1,71 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
import {DictResource} from "@/types.ts";
|
||||
import DictItem from "@/pages/pc/components/list/DictItem.vue";
|
||||
|
||||
const props = defineProps<{
|
||||
item: {
|
||||
list: any[],
|
||||
tags: string[],
|
||||
name: string,
|
||||
},
|
||||
selectId: string
|
||||
}>()
|
||||
const emit = defineEmits<{
|
||||
selectDict: [val: { dict: DictResource, index: number }]
|
||||
detail: [],
|
||||
}>()
|
||||
let currentTag = $ref(props.item.tags[0])
|
||||
let localList = $computed(() => {
|
||||
return props.item.list.filter(v => v.tags.includes(currentTag))
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="dict-group">
|
||||
<div class="flex items-start border py-4">
|
||||
<div class="text-xl break-keep mt-1">{{ item.name }}:</div>
|
||||
<div class="tags">
|
||||
<div class="tag" :class="i === currentTag &&'active'"
|
||||
@click="currentTag = i"
|
||||
v-for="i in item.tags">{{ i }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="dict-list1 grid grid-cols-4 gap-4">
|
||||
<DictItem v-for="(dict,index) in localList"
|
||||
:active="selectId === dict.id"
|
||||
@click="emit('selectDict',{dict,index})"
|
||||
:dict="dict"/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.dict-group {
|
||||
color: var(--color-font-1);
|
||||
margin-bottom: 1.5rem;
|
||||
|
||||
.border {
|
||||
border-top: 1px dashed gray;
|
||||
}
|
||||
}
|
||||
|
||||
.tags {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
|
||||
.tag {
|
||||
color: var(--color-font-1);
|
||||
cursor: pointer;
|
||||
padding: 0.4rem 1rem;
|
||||
border-radius: 2rem;
|
||||
|
||||
&.active {
|
||||
color: var(--color-font-active-1);
|
||||
background: gray;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
@@ -1,46 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
|
||||
import {DictResource} from "@/types.ts";
|
||||
import {Icon} from "@iconify/vue";
|
||||
import BaseIcon from "@/components/BaseIcon.vue";
|
||||
|
||||
const props = defineProps<{
|
||||
dict?: DictResource,
|
||||
active?: boolean
|
||||
showDel?: boolean
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
add: []
|
||||
del: []
|
||||
}>()
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
class="book anim"
|
||||
:class="active && 'active'"
|
||||
>
|
||||
<template v-if="dict.id">
|
||||
<div class="top">
|
||||
<div class="name">{{ dict.name }}</div>
|
||||
<div class="desc" :style="{opacity:dict.name !== dict.description?1:0}">{{ dict.description }}</div>
|
||||
</div>
|
||||
<div class="bottom">
|
||||
<div class="num text-align-right">{{ dict.length + '词' }}</div>
|
||||
</div>
|
||||
<div class="del" v-if="dict.showDel && !active">
|
||||
<BaseIcon icon="solar:trash-bin-minimalistic-linear" @click="emit('del')"/>
|
||||
</div>
|
||||
</template>
|
||||
<div v-else class="add" @click.stop="emit('add')">
|
||||
<Icon icon="fluent:add-20-filled" width="38" color="#929596"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
||||
</style>
|
||||
@@ -1,10 +1,9 @@
|
||||
<script setup lang="ts">
|
||||
import {Dict, DictResource} from "@/types.ts";
|
||||
import {Icon} from "@iconify/vue";
|
||||
import DictItem from "@/pages/pc/components/list/DictItem.vue";
|
||||
import {Dict} from "@/types.ts";
|
||||
import Book from "@/pages/pc/components/Book.vue";
|
||||
|
||||
defineProps<{
|
||||
list?: DictResource[],
|
||||
list?: Dict[],
|
||||
selectId?: string
|
||||
}>()
|
||||
|
||||
@@ -19,12 +18,11 @@ const emit = defineEmits<{
|
||||
|
||||
<template>
|
||||
<div class="grid grid-cols-6 gap-4 ">
|
||||
<DictItem v-for="(dict,index) in list"
|
||||
:active="selectId === dict.id"
|
||||
@click="emit('selectDict',{dict,index})"
|
||||
@add="emit('add')"
|
||||
@del="emit('del',{dict,index})"
|
||||
:dict="dict"/>
|
||||
<Book v-for="(dict,index) in list"
|
||||
:is-add="false"
|
||||
@click="emit('selectDict',{dict,index})"
|
||||
quantifier="个词"
|
||||
:item="dict"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ import {getDefaultWord} from "@/types";
|
||||
import type {Word} from "@/types";
|
||||
|
||||
import BasePage from "@/pages/pc/components/BasePage.vue";
|
||||
import {computed, onMounted, reactive} from "vue";
|
||||
import {computed, nextTick, onMounted, reactive} from "vue";
|
||||
import {useRuntimeStore} from "@/stores/runtime.ts";
|
||||
import {assign, cloneDeep} from "lodash-es";
|
||||
import {nanoid} from "nanoid";
|
||||
@@ -19,6 +19,7 @@ import BaseButton from "@/components/BaseButton.vue";
|
||||
import {useRoute, useRouter} from "vue-router";
|
||||
import {useBaseStore} from "@/stores/base.ts";
|
||||
import EditBook from "@/pages/pc/article/components/EditBook.vue";
|
||||
import {_nextTick} from "@/utils";
|
||||
|
||||
const runtimeStore = useRuntimeStore()
|
||||
const base = useBaseStore()
|
||||
@@ -42,31 +43,23 @@ onMounted(() => {
|
||||
}
|
||||
})
|
||||
|
||||
let wordFormData = $ref({
|
||||
where: '',
|
||||
type: '',
|
||||
id: '',
|
||||
index: 0
|
||||
})
|
||||
|
||||
enum FormMode {
|
||||
None = '',
|
||||
Add = 'Add',
|
||||
Edit = 'Edit',
|
||||
const getDefaultFormWord = () => {
|
||||
return {
|
||||
id: '',
|
||||
word: '',
|
||||
phonetic0: '',
|
||||
phonetic1: '',
|
||||
trans: '',
|
||||
sentences: '',
|
||||
phrases: '',
|
||||
synos: '',
|
||||
relWords: '',
|
||||
etymology: '',
|
||||
}
|
||||
}
|
||||
|
||||
const DefaultFormWord = {
|
||||
word: '',
|
||||
phonetic0: '',
|
||||
phonetic1: '',
|
||||
trans: '',
|
||||
sentences: '',
|
||||
phrases: '',
|
||||
synos: '',
|
||||
relWords: '',
|
||||
etymology: '',
|
||||
}
|
||||
let wordForm = $ref(cloneDeep(DefaultFormWord))
|
||||
let isOperate = $ref(false)
|
||||
let wordForm = $ref(getDefaultFormWord())
|
||||
let wordFormRef = $ref<FormInstance>()
|
||||
const wordRules = reactive<FormRules>({
|
||||
word: [
|
||||
@@ -170,6 +163,7 @@ function convertToWord(raw) {
|
||||
});
|
||||
|
||||
return getDefaultWord({
|
||||
id: raw.id,
|
||||
word: safeString(raw.word),
|
||||
phonetic0: safeString(raw.phonetic0),
|
||||
phonetic1: safeString(raw.phonetic1),
|
||||
@@ -183,52 +177,69 @@ function convertToWord(raw) {
|
||||
});
|
||||
}
|
||||
|
||||
function syncDictInMyStudyList(study = false) {
|
||||
_nextTick(() => {
|
||||
let rIndex = base.word.bookList.findIndex(v => v.id === runtimeStore.editDict.id)
|
||||
let temp = cloneDeep(runtimeStore.editDict);
|
||||
temp.custom = true
|
||||
if (rIndex > -1) {
|
||||
base.word.bookList[base.word.studyIndex] = temp
|
||||
if (study) base.word.studyIndex = rIndex
|
||||
} else {
|
||||
base.word.bookList.push(temp)
|
||||
if (study) base.word.studyIndex = base.word.bookList.length - 1
|
||||
}
|
||||
}, 100)
|
||||
}
|
||||
|
||||
//TODO trans结构变了,
|
||||
async function onSubmitWord() {
|
||||
await wordFormRef.validate((valid, fields) => {
|
||||
await wordFormRef.validate((valid) => {
|
||||
if (valid) {
|
||||
let data: any = convertToWord(wordForm)
|
||||
if (wordFormData.type === FormMode.Add) {
|
||||
data.id = nanoid(6)
|
||||
data.checked = false
|
||||
let r = list.find(v => v.word === wordForm.word)
|
||||
if (r) return ElMessage.warning('已有相同名称单词!')
|
||||
else list.push(data)
|
||||
ElMessage.success('添加成功')
|
||||
wordForm = cloneDeep(DefaultFormWord)
|
||||
// setTimeout(wordListRef?.scrollToBottom, 100)
|
||||
} else {
|
||||
let r = list.find(v => v.id === wordFormData.id)
|
||||
if (data.id) {
|
||||
let r = list.find(v => v.id === data.id)
|
||||
if (r) {
|
||||
assign(r, data)
|
||||
ElMessage.success('修改成功')
|
||||
}else {
|
||||
} else {
|
||||
ElMessage.success('修改失败,未找到单词')
|
||||
return
|
||||
}
|
||||
} else {
|
||||
data.id = nanoid(6)
|
||||
data.checked = false
|
||||
let r = list.find(v => v.word === wordForm.word)
|
||||
if (r) {
|
||||
ElMessage.warning('已有相同名称单词!')
|
||||
return
|
||||
} else list.push(data)
|
||||
ElMessage.success('添加成功')
|
||||
wordForm = getDefaultFormWord()
|
||||
}
|
||||
syncDictInMyStudyList()
|
||||
} else {
|
||||
ElMessage.warning('请填写完整')
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function delWord(id: string) {
|
||||
function delWord(id: string, isBatch = false) {
|
||||
let rIndex2 = list.findIndex(v => v.id === id)
|
||||
if (rIndex2 > -1) {
|
||||
list.splice(rIndex2, 1)
|
||||
}
|
||||
// if (wordFormData.type === FormMode.Edit && wordForm.word === val.item.word) {
|
||||
// closeWordForm()
|
||||
// }
|
||||
if (!isBatch) syncDictInMyStudyList()
|
||||
}
|
||||
|
||||
function batchDel(ids: string[]) {
|
||||
ids.map(v => delWord(v))
|
||||
ids.map(v => delWord(v, true))
|
||||
syncDictInMyStudyList()
|
||||
}
|
||||
|
||||
function editWord(word: Word) {
|
||||
wordFormData.type = FormMode.Edit
|
||||
wordFormData.id = word.id
|
||||
isOperate = true
|
||||
wordForm.id = word.id
|
||||
wordForm.word = word.word
|
||||
wordForm.phonetic1 = word.phonetic1
|
||||
wordForm.phonetic0 = word.phonetic0
|
||||
@@ -243,13 +254,13 @@ function editWord(word: Word) {
|
||||
|
||||
function addWord() {
|
||||
// setTimeout(wordListRef?.scrollToBottom, 100)
|
||||
wordFormData.type = FormMode.Add
|
||||
wordForm = cloneDeep(DefaultFormWord)
|
||||
isOperate = true
|
||||
wordForm = getDefaultFormWord()
|
||||
}
|
||||
|
||||
function closeWordForm() {
|
||||
wordFormData.type = FormMode.None
|
||||
wordForm = cloneDeep(DefaultFormWord)
|
||||
isOperate = false
|
||||
wordForm = getDefaultFormWord()
|
||||
}
|
||||
|
||||
let isEdit = $ref(false)
|
||||
@@ -339,10 +350,10 @@ defineRender(() => {
|
||||
</BaseTable>
|
||||
</div>
|
||||
{
|
||||
wordFormData.type ? (
|
||||
isOperate ? (
|
||||
<div class="flex-1 flex flex-col ml-4">
|
||||
<div class="common-title">
|
||||
{wordFormData.type === FormMode.Add ? '添加' : '修改'}单词
|
||||
{wordForm.id ? '修改' : '添加'}单词
|
||||
</div>
|
||||
<el-form
|
||||
class="flex-1 overflow-auto pr-2"
|
||||
|
||||
@@ -8,16 +8,14 @@ import BaseIcon from "@/components/BaseIcon.vue";
|
||||
import Dialog from "@/pages/pc/components/dialog/Dialog.vue";
|
||||
import {_getAccomplishDate, _getAccomplishDays, _getDictDataByUrl, useNav} from "@/utils";
|
||||
import BasePage from "@/pages/pc/components/BasePage.vue";
|
||||
import {Dict, DictResource, getDefaultDict} from "@/types.ts";
|
||||
import {Dict, DictResource} from "@/types.ts";
|
||||
import {onMounted} from "vue";
|
||||
import {getCurrentStudyWord} from "@/hooks/dict.ts";
|
||||
import {usePracticeStore} from "@/stores/practice.ts";
|
||||
import {EventKey, useEvent} from "@/utils/eventBus.ts";
|
||||
import DictListPanel from "@/pages/pc/components/DictListPanel.vue";
|
||||
import DictGroup from "@/pages/pc/components/list/DictGroup.vue";
|
||||
import {cloneDeep} from "lodash-es";
|
||||
import {useRuntimeStore} from "@/stores/runtime.ts";
|
||||
import {getArticleBookDataByUrl} from "@/utils/article.ts";
|
||||
import Book from "@/pages/pc/components/Book.vue";
|
||||
|
||||
const store = useBaseStore()
|
||||
const router = useRouter()
|
||||
@@ -157,20 +155,13 @@ function addDict() {
|
||||
<div class="color-blue cursor-pointer" @click="addDict">创建个人词典</div>
|
||||
</div>
|
||||
<div class="grid grid-cols-6 gap-4 mt-4">
|
||||
<div class="book" v-for="item in store.word.bookList" @click="goDictDetail2(item)">
|
||||
<div>
|
||||
<div>{{ item.name }}</div>
|
||||
<div>{{ item.description }}</div>
|
||||
</div>
|
||||
<div class="absolute bottom-4 right-4">{{ item.words.length }}个词</div>
|
||||
</div>
|
||||
<div class="book" @click="dictListRef.startSearch()">
|
||||
<div class="center h-full">
|
||||
<Icon
|
||||
width="40px"
|
||||
icon="fluent:add-20-filled"/>
|
||||
</div>
|
||||
</div>
|
||||
<Book :is-add="false"
|
||||
quantifier="个词"
|
||||
:item="item"
|
||||
v-for="item in store.word.bookList"
|
||||
@click="goDictDetail2(item)"/>
|
||||
<Book :is-add="true"
|
||||
@click="dictListRef.startSearch()"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -175,8 +175,10 @@ export const useBaseStore = defineStore('base', {
|
||||
|
||||
if (this.word.studyIndex >= 3) {
|
||||
// await _checkDictWords(this.currentStudyWordDict)
|
||||
let current = this.word.bookList[this.word.studyIndex]
|
||||
this.word.bookList[this.word.studyIndex] = await _getDictDataByUrl(current)
|
||||
let current: Dict = this.word.bookList[this.word.studyIndex]
|
||||
if (!current.custom) {
|
||||
this.word.bookList[this.word.studyIndex] = await _getDictDataByUrl(current)
|
||||
}
|
||||
console.log('this.current', current)
|
||||
}
|
||||
if (this.article.studyIndex >= 1) {
|
||||
@@ -236,7 +238,7 @@ export const useBaseStore = defineStore('base', {
|
||||
}
|
||||
} else {
|
||||
//如果不是自定义词典,并且有url地址才去下载
|
||||
if (!dict.isCustom && dict.url) {
|
||||
if (!dict.custom && dict.url) {
|
||||
if (!dict.originWords.length) {
|
||||
let v = await getDictFile(url)
|
||||
v.map(s => {
|
||||
|
||||
63
src/types.ts
63
src/types.ts
@@ -68,18 +68,6 @@ export const PronunciationApi = 'https://dict.youdao.com/dictvoice?audio='
|
||||
export type TranslateLanguageType = 'en' | 'zh-CN' | 'ja' | 'de' | 'common' | ''
|
||||
export type LanguageType = 'en' | 'ja' | 'de' | 'code'
|
||||
|
||||
export type DictResource = {
|
||||
id: string
|
||||
name: string
|
||||
description: string
|
||||
url: string
|
||||
length: number
|
||||
category: string
|
||||
tags: string[]
|
||||
translateLanguage: TranslateLanguageType
|
||||
type: DictType
|
||||
language: LanguageType
|
||||
}
|
||||
|
||||
export enum DictType {
|
||||
collect = 'collect',
|
||||
@@ -237,51 +225,48 @@ export const languageCategoryOptions = [
|
||||
{id: 'my', name: '我的', flag: myFlag},
|
||||
]
|
||||
|
||||
export type DictResource = {
|
||||
id: string
|
||||
name: string
|
||||
description: string
|
||||
url: string
|
||||
length: number
|
||||
category: string
|
||||
tags: string[]
|
||||
translateLanguage: TranslateLanguageType
|
||||
type: DictType
|
||||
language: LanguageType
|
||||
}
|
||||
|
||||
export function getDefaultDict(val: Partial<Dict> = {}): Dict {
|
||||
return {
|
||||
id: '',
|
||||
name: '',
|
||||
description: '',
|
||||
url: '',
|
||||
length: 0,
|
||||
category: '',
|
||||
tags: [],
|
||||
translateLanguage: '',
|
||||
type: DictType.word,
|
||||
language: 'en',
|
||||
lastLearnIndex: 0,
|
||||
perDayStudyNumber: 20,
|
||||
description: '',
|
||||
words: [],
|
||||
articles: [],
|
||||
statistics: [],
|
||||
isCustom: false,
|
||||
length: 0,
|
||||
/*资源属性*/
|
||||
resourceId: '',
|
||||
fileName: '',
|
||||
category: '',
|
||||
tags: [],
|
||||
dictType: DictType.word,
|
||||
langTypeStr: 'en',
|
||||
tranTypeStr: 'zh',
|
||||
version: 0,
|
||||
custom: false,
|
||||
...val
|
||||
}
|
||||
}
|
||||
|
||||
export interface Dict {
|
||||
id: any,
|
||||
name: string,
|
||||
export interface Dict extends DictResource {
|
||||
lastLearnIndex: number,
|
||||
perDayStudyNumber: number,
|
||||
description: string,
|
||||
words: Word[],
|
||||
articles: Article[],
|
||||
statistics: Statistics[],
|
||||
isCustom: boolean,
|
||||
length: number,
|
||||
/*资源属性*/
|
||||
resourceId: string,
|
||||
category: string
|
||||
tags: string[]
|
||||
dictType: DictType
|
||||
fileName: string,
|
||||
langTypeStr: string,
|
||||
tranTypeStr: string,
|
||||
version: number,
|
||||
custom: boolean,
|
||||
}
|
||||
|
||||
export interface ArticleItem {
|
||||
|
||||
@@ -117,8 +117,11 @@ export function checkAndUpgradeSaveSetting(val: any) {
|
||||
//筛选未自定义的词典,未自定义的词典不需要保存单词,用的时候再下载
|
||||
export function shakeCommonDict(n: BaseState): BaseState {
|
||||
let data: BaseState = cloneDeep(n)
|
||||
data.wordDictList.map((v: Dict) => {
|
||||
if (!v.isCustom) v.words = []
|
||||
data.word.bookList.map((v: Dict) => {
|
||||
if (!v.custom) v.words = []
|
||||
})
|
||||
data.article.bookList.map((v: Dict) => {
|
||||
if (!v.custom) v.words = []
|
||||
})
|
||||
return data
|
||||
}
|
||||
@@ -180,7 +183,7 @@ export async function _checkDictWords(dict: Dict) {
|
||||
} else {
|
||||
//TODO 需要和其他需要下载的地方统一
|
||||
//如果不是自定义词典,并且有url地址才去下载
|
||||
if (!dict.isCustom && dict.fileName) {
|
||||
if (!dict.custom && dict.fileName) {
|
||||
// let rrr = await axios('http://localhost/static/dict/en/zh/Top50Prepositions-v1.json')
|
||||
// console.log('r', rrr)
|
||||
// return
|
||||
@@ -285,7 +288,7 @@ export function _parseLRC(lrc: string): { start: number, end: number, text: stri
|
||||
return parsed;
|
||||
}
|
||||
|
||||
export async function _getDictDataByUrl(val: DictResource) {
|
||||
export async function _getDictDataByUrl(val: Dict) {
|
||||
let dictResourceUrl = `./dicts/${val.language}/word/${val.url}`.replace('.json', '_v2.json');
|
||||
let s = await getDictFile(dictResourceUrl)
|
||||
let words = cloneDeep(s.map(v => {
|
||||
|
||||
Reference in New Issue
Block a user