feat:fix dict list

This commit is contained in:
zyronon
2025-07-20 22:13:12 +08:00
parent f14b5fe455
commit 8e9821a58a
16 changed files with 261 additions and 304 deletions

View File

@@ -95,8 +95,10 @@ function startStudy() {
<div class="book"
v-for="dict in store.article.bookList"
@click="getBookDetail2(dict)">
<div class="name">{{ dict.name }}</div>
<div class="desc">{{ dict.description }}</div>
<div>
<div class="name">{{ dict.name }}</div>
<div class="desc">{{ dict.description }}</div>
</div>
<div class="absolute bottom-4 right-4">{{ dict.length }}</div>
</div>
<div class="book" @click="showAddChooseDialog = true">
@@ -118,8 +120,10 @@ function startStudy() {
<div class="book"
v-for="dict in enArticle"
@click="getBookDetail(dict)">
<div class="name">{{ dict.name }}</div>
<div class="desc">{{ dict.description }}</div>
<div class="top">
<div class="name">{{ dict.name }}</div>
<div class="desc">{{ dict.description }}</div>
</div>
<div class="absolute bottom-4 right-4">{{ dict.length }}</div>
</div>
</div>

View File

@@ -11,6 +11,7 @@ import BaseButton from "@/components/BaseButton.vue";
import {useRoute, useRouter} from "vue-router";
import EditBook from "@/pages/pc/article/components/EditBook.vue";
import {computed, onMounted} from "vue";
import {cloneDeep} from "lodash-es";
const runtimeStore = useRuntimeStore()
const base = useBaseStore()
@@ -53,7 +54,12 @@ const showBookDetail = computed(() => {
onMounted(() => {
if (route.query?.isAdd) {
isAdd = true
}else {
if (!runtimeStore.editDict.id) {
router.push("/")
}
}
})
function formClose() {
@@ -69,7 +75,7 @@ function formClose() {
<BackIcon class="z-2" @click="$router.back"/>
<div class="absolute text-2xl text-align-center w-full">{{ runtimeStore.editDict.name }}</div>
<div class="flex gap-2">
<BaseButton type="info" @click="isEdit = true">编辑信息</BaseButton>
<BaseButton type="info" @click="isEdit = true">编辑</BaseButton>
<BaseButton type="info" @click="router.push('batch-edit-article')">文章管理</BaseButton>
<BaseButton @click="addMyBookList">学习</BaseButton>
</div>
@@ -109,11 +115,20 @@ function formClose() {
</div>
</div>
<div class="center" v-else>
<div class="w-1/2">
<EditBook :is-add="isAdd"
@close="formClose"
@submit="isEdit = isAdd = false"
<div class="card mb-0 h-[95vh]" v-else>
<div class="flex justify-between items-center relative">
<BackIcon class="z-2" @click="isAdd ? $router.back():(isEdit = false)"/>
<div class="absolute text-2xl text-align-center w-full">{{
runtimeStore.editDict.id ? '修改' : '添加'
}}书籍
</div>
</div>
<div class="center">
<EditBook
:is-add="isAdd"
:is-book="true"
@close="formClose"
@submit="isEdit = isAdd = false"
/>
</div>
</div>

View File

@@ -10,7 +10,8 @@ import {useBaseStore} from "@/stores/base.ts";
import {syncMyDictList} from "@/hooks/dict.ts";
const props = defineProps<{
isAdd: boolean
isAdd: boolean,
isBook: boolean
}>()
const emit = defineEmits<{
submit: []
@@ -44,28 +45,29 @@ async function onSubmit() {
...getDefaultDict(),
...dictForm,
})
let source = [store.article, store.word][props.isBook ? 0 : 1]
//任意修改,都将其变为自定义词典
data.isCustom = true
if (props.isAdd) {
data.id = 'custom-dict-' + Date.now()
//TODO 允许同名?
if (store.article.bookList.find(v => v.name === data.name)) {
if (source.bookList.find(v => v.name === data.name)) {
return ElMessage.warning('已有相同名称书籍!')
} else {
store.article.bookList.push(data)
source.bookList.push(data)
runtimeStore.editDict = data
emit('submit')
ElMessage.success('添加成功')
}
} else {
let rIndex = store.article.bookList.findIndex(v => v.id === data.id)
let rIndex = source.bookList.findIndex(v => v.id === data.id)
if (rIndex > -1) {
store.article.bookList[rIndex] = cloneDeep(data)
source.bookList[rIndex] = cloneDeep(data)
runtimeStore.editDict = cloneDeep(data)
emit('submit')
ElMessage.success('修改成功')
}else {
} else {
ElMessage.warning('修改失败')
}
}
@@ -85,61 +87,43 @@ onMounted(() => {
</script>
<template>
<div class="edit-dict">
<div class="wrapper">
<div class="common-title">{{ dictForm.id ? '修改' : '添加' }}书籍</div>
<el-form
ref="dictFormRef"
:rules="dictRules"
:model="dictForm"
label-width="8rem">
<el-form-item label="名称" prop="name">
<el-input v-model="dictForm.name"/>
</el-form-item>
<el-form-item label="描述">
<el-input v-model="dictForm.description" type="textarea"/>
</el-form-item>
<el-form-item label="原文语言">
<el-select v-model="dictForm.language" placeholder="请选择选项">
<el-option label="语" value="en"/>
<el-option label="德语" value="de"/>
<el-option label="日语" value="ja"/>
<el-option label="代码" value="code"/>
</el-select>
</el-form-item>
<el-form-item label="译文语言">
<el-select v-model="dictForm.translateLanguage" placeholder="请选择选项">
<!-- <el-option label="通用" value="common"/>-->
<el-option label="中文" value="zh-CN"/>
<el-option label="英语" value="en"/>
<el-option label="德语" value="de"/>
<el-option label="日语" value="ja"/>
</el-select>
</el-form-item>
<div class="center">
<el-button @click="emit('close')">关闭</el-button>
<el-button type="primary" @click="onSubmit">确定</el-button>
</div>
</el-form>
</div>
<div class="w-120 mt-4">
<el-form
ref="dictFormRef"
:rules="dictRules"
:model="dictForm"
label-width="8rem">
<el-form-item label="名称" prop="name">
<el-input v-model="dictForm.name"/>
</el-form-item>
<el-form-item label="描述">
<el-input v-model="dictForm.description" type="textarea"/>
</el-form-item>
<el-form-item label="原文语言">
<el-select v-model="dictForm.language" placeholder="请选择选项">
<el-option label="英语" value="en"/>
<el-option label="德语" value="de"/>
<el-option label="语" value="ja"/>
<el-option label="代码" value="code"/>
</el-select>
</el-form-item>
<el-form-item label="译文语言">
<el-select v-model="dictForm.translateLanguage" placeholder="请选择选项">
<el-option label="中文" value="zh-CN"/>
<el-option label="英语" value="en"/>
<el-option label="德语" value="de"/>
<el-option label="日语" value="ja"/>
</el-select>
</el-form-item>
<div class="center">
<el-button @click="emit('close')">关闭</el-button>
<el-button type="primary" @click="onSubmit">确定</el-button>
</div>
</el-form>
</div>
</template>
<style scoped lang="scss">
.edit-dict {
flex: 1;
width: 100%;
overflow: auto;
display: flex;
justify-content: center;
.wrapper {
width: 80rem;
}
.el-select {
width: 100%;
}
}
</style>

View File

@@ -1,6 +1,5 @@
<script setup lang="tsx">
import {useSettingStore} from "@/stores/setting.ts";
import {nextTick, useSlots} from "vue";
import {Sort} from "@/types.ts";
import MiniDialog from "@/pages/pc/components/dialog/MiniDialog.vue";
@@ -101,6 +100,7 @@ function sort(type: Sort) {
ElMessage.success('已随机排序')
list.value = shuffle(cloneDeep(list.value))
}
showSortDialog = false
}
function handleBatchDel() {
@@ -178,7 +178,7 @@ defineRender(
icon="fluent:search-24-regular"/>
<MiniDialog
modelValue={showSortDialog}
onUpdate:model-value={e => showSortDialog = e}
onUpdate:modelValue={e => showSortDialog = e}
style="width: 8rem;"
>
<div class="mini-row-title">

View File

@@ -6,7 +6,7 @@ import {useDisableEventListener, useWindowClick} from "@/hooks/event.ts";
defineProps<{
modelValue: string
placeholder: string
placeholder?: string
autofocus?: boolean
}>()

View File

@@ -99,7 +99,7 @@ $bg-color: rgb(226, 226, 226);
.text {
color: var(--color-font-1);
text-align: start;
font-size: .9rem;
font-size: 1rem;
width: 9rem;
min-width: 9rem;
}
@@ -110,7 +110,7 @@ $bg-color: rgb(226, 226, 226);
justify-content: flex-end;
align-items: center;
gap: .7rem;
font-size: .7rem;
font-size: .9rem;
div {
cursor: pointer;

View File

@@ -1,78 +0,0 @@
<template>
<div class="round">
<svg height="100%" width="100%">
<circle class="circle-full"
cx="3rem"
cy="3rem"
r="2.6rem"
fill="none"
stroke-width=".4rem"
stroke-linecap="round"></circle>
<circle v-if="props.percentage" ref="circleEl"
class="circle-detail"
cx="3rem"
cy="3rem"
r="2.6rem"
fill="none"
stroke-width=".4rem"
stroke-linecap="round"
stroke-dasharray="0,10000"></circle>
</svg>
<span class="text-2xl">{{ props.value }}</span>
<span class="desc">{{ props.desc }}</span>
</div>
</template>
<script setup lang="ts">
import {onMounted} from "vue"
const props = withDefaults(defineProps<{
percentage?: number,
value: string | number,
desc: string,
}>(), {
percentage: 90,
})
const circleEl = $ref(null)
onMounted(() => {
if (props.percentage) {
let circleLength = Math.floor(2 * Math.PI * 35);
let val = Number(props.percentage.toFixed(0));
circleEl.setAttribute("stroke-dasharray", "" + circleLength * val / 100 + "px,10000");
}
})
</script>
<style scoped lang="scss">
$w: 6rem;
$w2: calc($w / 2);
.round {
font-size: 1rem;
width: $w;
height: $w;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
position: relative;
svg {
position: absolute;
.circle-full {
$item-hover: rgb(75, 75, 75);
stroke: $item-hover;
}
.circle-detail {
transform-origin: $w2 $w2;
transform: rotate(-90deg);
stroke: var(--color-main-active);
}
}
}
</style>

View File

@@ -8,10 +8,12 @@ const props = withDefaults(defineProps<{
item: Word,
showTranslate?: boolean
showWord?: boolean
showTransPop?: boolean
hiddenOptionIcon?: boolean
}>(), {
showTranslate: true,
showWord: true,
showTransPop: true,
hiddenOptionIcon: false,
})
@@ -34,7 +36,7 @@ const playWordAudio = usePlayWordAudio()
<div class="item-sub-title flex flex-col gap-2" v-if="item.trans.length && showTranslate">
<div v-for="v in item.trans">
<el-popover
v-if="v.cn.length > 30"
v-if="v.cn.length > 30 && showTransPop"
width="300"
:content="v.pos + ' ' + v.cn"
placement="top"

View File

@@ -73,7 +73,7 @@ const {toggleTheme} = useTheme()
</Tooltip>
</div>
</div>
<div class="flex-1 z-1">
<div class="flex-1 z-1 relative">
<router-view></router-view>
</div>
</div>

View File

@@ -1,19 +1,27 @@
<script setup lang="tsx">
import BasePage from "@/pages/pc/components/BasePage.vue";
import {onMounted, reactive} from "vue";
import {computed, onMounted, reactive} from "vue";
import {useRuntimeStore} from "@/stores/runtime.ts";
import {assign, cloneDeep} from "lodash-es";
import {nanoid} from "nanoid";
import BaseIcon from "@/components/BaseIcon.vue";
import {useNav} from "@/utils";
import BaseTable from "@/pages/pc/components/BaseTable.vue";
import WordItem from "@/pages/pc/components/WordItem.vue";
import type {Word} from "@/types.ts";
import type {FormInstance, FormRules} from "element-plus";
import PopConfirm from "@/pages/pc/components/PopConfirm.vue";
import BackIcon from "@/components/BackIcon.vue";
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";
const runtimeStore = useRuntimeStore()
const base = useBaseStore()
const router = useRouter()
const route = useRoute()
let loading = $ref(false)
let list = $computed({
@@ -25,17 +33,11 @@ let list = $computed({
}
})
onMounted(async () => {
if (runtimeStore.routeData) {
loading = true
runtimeStore.editDict = cloneDeep(runtimeStore.routeData)
// await _checkDictWords(runtimeStore.editDict)
setTimeout(() => {
loading = false
}, 300)
onMounted(() => {
if (!runtimeStore.editDict.id) {
router.push("/")
}
})
const {back} = useNav()
let wordFormData = $ref({
where: '',
@@ -132,119 +134,153 @@ function closeWordForm() {
wordForm = cloneDeep(DefaultFormWord)
}
function s(ss) {
console.log('s', ss)
let isEdit = $ref(false)
let isAdd = $ref(false)
const showBookDetail = computed(() => {
return !(isAdd || isEdit);
})
onMounted(() => {
if (route.query?.isAdd) {
isAdd = true
}
})
function formClose() {
if (isEdit) isEdit = false
else router.back()
}
function addMyBookList() {
}
defineRender(() => {
return (
<BasePage>
<div className="card">
<header class="flex gap-4 mb-2 items-center">
<BaseIcon onClick={back} icon="octicon:arrow-left-24" width={20}/>
<div class="left">
<div class="top">
<div class="text-xl">
{runtimeStore.editDict.name}
{
showBookDetail.value ? <div className="card mb-0 h-[95vh] flex flex-col">
<div class="flex justify-between items-center relative">
<BackIcon class="z-2" onClick={() => router.back()}/>
<div class="absolute text-2xl text-align-center w-full">{runtimeStore.editDict.name}</div>
<div class="flex gap-2">
<BaseButton type="info" onClick={() => isEdit = true}>编辑</BaseButton>
<BaseButton onClick={addMyBookList}>学习</BaseButton>
</div>
</div>
<div class="text-lg ">介绍{runtimeStore.editDict.description}</div>
<div class="line my-3"></div>
<div class="flex flex-1 overflow-hidden">
<div class="w-4/10">
<BaseTable
class="h-full"
list={list}
loading={loading}
onUpdate:list={e => list = e}
del={delWord}
batchDel={batchDel}
add={addWord}
>
{
(val) =>
<WordItem
showTransPop={false}
item={val.item}>
{{
prefix: () => val.checkbox(val.item),
suffix: () => (
<div class='flex flex-col'>
<BaseIcon
class="option-icon"
onClick={() => editWord(val.item)}
title="编辑"
icon="tabler:edit"/>
<PopConfirm title="确认删除?"
onConfirm={() => delWord(val.item.id)}
>
<BaseIcon
class="option-icon"
title="删除"
icon="solar:trash-bin-minimalistic-linear"/>
</PopConfirm>
</div>
)
}}
</WordItem>
}
</BaseTable>
</div>
{
wordFormData.type ? (
<div class="flex-1 ml-4">
<div class="common-title">
{wordFormData.type === FormMode.Add ? '添加' : '修改'}单词
</div>
<el-form
className="form"
ref="wordFormRef"
rules={wordRules}
model={wordForm}
label-width="7rem">
<el-form-item label="单词" prop="word">
<el-input
modelValue={wordForm.word}
onUpdate:model-value={e => wordForm.word = e}
/>
</el-form-item>
<el-form-item label="翻译">
<el-input
modelValue={wordForm.trans}
onUpdate:model-value={e => wordForm.trans = e}
placeholder="多个翻译请换行"
autosize={{minRows: 6, maxRows: 10}}
type="textarea"/>
</el-form-item>
<el-form-item label="音标/发音①">
<el-input
modelValue={wordForm.phonetic0}
onUpdate:model-value={e => wordForm.phonetic0 = e}
/>
</el-form-item>
<el-form-item label="音标/发音②">
<el-input
modelValue={wordForm.phonetic1}
onUpdate:model-value={e => wordForm.phonetic1 = e}/>
</el-form-item>
<div class="center">
<el-button
onClick={closeWordForm}>关闭
</el-button>
<el-button type="primary"
onClick={onSubmitWord}>保存
</el-button>
</div>
</el-form>
</div>
) : null
}
</div>
</div> :
<div class="card mb-0 h-[95vh]">
<div class="flex justify-between items-center relative">
<BackIcon class="z-2" onClick={() => isAdd ? router.back() : (isEdit = false)}/>
<div class="absolute text-2xl text-align-center w-full">
{runtimeStore.editDict.id ? '修改' : '添加'}词典
</div>
</div>
<div class="center">
<EditBook
isAdd={isAdd}
isBook={false}
onClose={formClose}
onSubmit={() => isEdit = isAdd = false}
/>
</div>
</div>
{
runtimeStore.editDict.description ?
<div class="desc">{runtimeStore.editDict.description}</div> : null
}
</div>
</header>
<div class="flex" style="height:calc(100vh - 8rem)">
<div class="w-1/2">
<BaseTable
class="h-full"
list={list}
loading={loading}
onUpdate:list={e => list = e}
del={delWord}
batchDel={batchDel}
add={addWord}
>
{
(val) =>
<WordItem
item={val.item}>
{{
prefix: () => val.checkbox(val.item),
suffix: () => (
<div class='flex flex-col'>
<BaseIcon
class="option-icon"
onClick={() => editWord(val.item)}
title="编辑"
icon="tabler:edit"/>
<PopConfirm title="确认删除?"
onConfirm={() => delWord(val.item.id)}
>
<BaseIcon
class="option-icon"
title="删除"
icon="solar:trash-bin-minimalistic-linear"/>
</PopConfirm>
</div>
)
}}
</WordItem>
}
</BaseTable>
</div>
{
wordFormData.type ? (
<div class="flex-1 ml-4">
<div class="common-title">
{wordFormData.type === FormMode.Add ? '添加' : '修改'}单词
</div>
<el-form
className="form"
ref="wordFormRef"
rules={wordRules}
model={wordForm}
label-width="7rem">
<el-form-item label="单词" prop="word">
<el-input
modelValue={wordForm.word}
onUpdate:model-value={e => wordForm.word = e}
/>
</el-form-item>
<el-form-item label="翻译">
<el-input
modelValue={wordForm.trans}
onUpdate:model-value={e => wordForm.trans = e}
placeholder="多个翻译请换行"
autosize={{minRows: 6, maxRows: 10}}
type="textarea"/>
</el-form-item>
<el-form-item label="音标/发音①">
<el-input
modelValue={wordForm.phonetic0}
onUpdate:model-value={e => wordForm.phonetic0 = e}
/>
</el-form-item>
<el-form-item label="音标/发音②">
<el-input
modelValue={wordForm.phonetic1}
onUpdate:model-value={e => wordForm.phonetic1 = e}/>
</el-form-item>
<div class="center">
<el-button
onClick={closeWordForm}>关闭
</el-button>
<el-button type="primary"
onClick={onSubmitWord}>保存
</el-button>
</div>
</el-form>
</div>
) : null
}
</div>
</div>
}
</BasePage>
)
})

View File

@@ -62,13 +62,13 @@ function selectDict(e) {
async function goDictDetail2(val: Dict) {
runtimeStore.editDict = cloneDeep(val)
nav('edit-word-dict')
nav('edit-word-dict', {})
}
async function getBookDetail(val: DictResource) {
let r = await getArticleBookDataByUrl(val)
runtimeStore.editDict = cloneDeep(r)
nav('book-detail')
nav('book-detail', {})
}
let dictListRef = $ref<any>()

View File

@@ -163,7 +163,7 @@ const progress = $computed(() => {
<RepeatSetting/>
<BaseIcon
@click="emitter.emit(EventKey.openStatModal, {})"
@click="settingStore.showPanel = !settingStore.showPanel"
:title="`单词本(${settingStore.shortcutKeyMap[ShortcutKey.TogglePanel]})`"
icon="tdesign:menu-unfold"/>
</div>
@@ -176,6 +176,7 @@ const progress = $computed(() => {
</div>
</div>
<!--
@click="emitter.emit(EventKey.openStatModal, {})"
@click="settingStore.showPanel = !settingStore.showPanel"-->
</template>

View File

@@ -265,6 +265,7 @@ let tab = $ref(2)
.typing-word {
width: 100%;
flex: 1;
overflow: auto;
word-break: break-word;
position: relative;
color: var(--color-font-2);

View File

@@ -9,13 +9,13 @@ import {useSettingStore} from "@/stores/setting.ts";
import {useOnKeyboardEventListener} from "@/hooks/event.ts";
import {Icon} from "@iconify/vue";
import Tooltip from "@/pages/pc/components/Tooltip.vue";
import Typing from "@/pages/pc/components/Typing.vue";
import Typing from "@/pages/pc/word/components/Typing.vue";
import Panel from "@/pages/pc/components/Panel.vue";
import {useWordOptions} from "@/hooks/dict.ts";
import BaseIcon from "@/components/BaseIcon.vue";
import WordList from "@/pages/pc/components/list/WordList.vue";
import Empty from "@/components/Empty.vue";
import Footer from "@/pages/pc/word/Footer.vue";
import Footer from "@/pages/pc/word/components/Footer.vue";
interface IProps {
data: {
@@ -238,15 +238,14 @@ useEvents([
@wrong="wordWrong"
@complete="next"
/>
<Footer
:is-simple="isWordSimple(word)"
@toggle-simple="toggleWordSimpleWrapper"
:is-collect="isWordCollect(word)"
@toggle-collect="toggleWordCollect(word)"
@skip="next(false)"
/>
</div>
<Footer
:is-simple="isWordSimple(word)"
@toggle-simple="toggleWordSimpleWrapper"
:is-collect="isWordCollect(word)"
@toggle-collect="toggleWordCollect(word)"
@skip="next(false)"
/>
<div class="word-panel-wrapper">
<Panel>
<template v-slot="{active}">
@@ -302,21 +301,16 @@ useEvents([
width: 100%;
height: 100vh;
display: flex;
justify-content: center;
overflow: hidden;
flex-direction: column;
justify-content: space-between;
align-items: center;
position: relative;
}
.practice-word {
overflow: auto;
flex: 1;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
gap: .4rem;
justify-content: space-between;
align-items: center;
position: relative;
width: var(--toolbar-width);
}
@@ -324,6 +318,7 @@ useEvents([
.word-panel-wrapper {
position: absolute;
left: var(--panel-margin-left);
//left: 0;
top: .8rem;
z-index: 1;
height: calc(100% - 1.5rem);

View File

@@ -55,8 +55,7 @@ export const DefaultBaseState = (): BaseState => ({
word: {
bookList: [
getDefaultDict({
index: 1,
name: '收藏', type: DictType.collectWord, words: [
id: 'word-collect', name: '收藏', words: [
{
"id": "pharmacy",
"word": "pharmacy",
@@ -119,14 +118,10 @@ export const DefaultBaseState = (): BaseState => ({
"phonetic0": "ˈfɜ:nɪʃ",
"phonetic1": "ˈfɜ:rnɪʃ"
},
], statistics: []
}),
getDefaultDict({
index: 2, name: '错词', type: DictType.wrong, words: [], statistics: []
}),
getDefaultDict({
index: 3, name: '已掌握', type: DictType.known, words: [], statistics: []
]
}),
getDefaultDict({id: 'word-wrong', name: '错词'}),
getDefaultDict({id: 'word-known', name: '已掌握'}),
getDefaultDict({
id: 'nce-new-2',
name: '新概念英语(新版)-2',
@@ -144,7 +139,7 @@ export const DefaultBaseState = (): BaseState => ({
},
article: {
bookList: [
getDefaultDict({name: '收藏'})
getDefaultDict({id: 'article-collect', name: '收藏'})
],
studyIndex: -1,
}
@@ -245,8 +240,11 @@ export const useBaseStore = defineStore('base', {
// await _checkDictWords(this.currentStudyWordDict)
let current = this.word.bookList[this.word.studyIndex]
let dictResourceUrl = `./dicts/${current.language}/${current.type}/${current.url}`;
current.words = await getDictFile(dictResourceUrl)
let s = await getDictFile(dictResourceUrl)
current.words = cloneDeep(s.map(v => {
v.id = nanoid(6)
return v
}))
console.log('this.current', current)
}
if (this.article.studyIndex >= 0) {

View File

@@ -269,7 +269,6 @@ export const DefaultShortcutKeyMap = {
[ShortcutKey.TogglePanel]: 'Ctrl+L',
}
export enum TranslateEngine {
Baidu = 0,
}