save
This commit is contained in:
@@ -19,7 +19,7 @@
|
||||
|
||||
--color-header-bg: white;
|
||||
--color-tooltip-bg: white;
|
||||
--color-tooltip-shadow: #bbbbbb;
|
||||
--color-tooltip-shadow: #d9d9d9;
|
||||
--color-font-1: rgb(91, 91, 91);
|
||||
--color-font-2: rgb(46, 46, 46);
|
||||
--color-font-3: rgb(75, 85, 99);
|
||||
|
||||
@@ -7,19 +7,55 @@ import {Icon} from "@iconify/vue";
|
||||
defineProps<{
|
||||
title?: string,
|
||||
icon: string,
|
||||
disabled?: boolean,
|
||||
}>()
|
||||
|
||||
defineEmits(['click'])
|
||||
const emit = defineEmits(['click'])
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Tooltip :title="title">
|
||||
<IconWrapper v-bind="$attrs" @click.stop="$emit('click')">
|
||||
<Icon :icon="icon"/>
|
||||
</IconWrapper>
|
||||
<div
|
||||
v-bind="$attrs"
|
||||
@click="e => (!disabled) && emit('click',e)"
|
||||
class="icon-wrapper"
|
||||
:class="{disabled}"
|
||||
>
|
||||
<Icon :icon="icon"/>
|
||||
</div>
|
||||
</Tooltip>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
||||
$w: 1.4rem;
|
||||
.icon-wrapper {
|
||||
cursor: pointer;
|
||||
//padding: 2rem;
|
||||
width: 2rem;
|
||||
height: 2rem;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: .3rem;
|
||||
background: transparent;
|
||||
transition: all .3s;
|
||||
//color: var(--color-main-active);
|
||||
|
||||
&:hover:not(.disabled) {
|
||||
background: var(--color-primary);
|
||||
color: white;
|
||||
}
|
||||
|
||||
&.disabled {
|
||||
cursor: not-allowed;
|
||||
opacity: .3;
|
||||
}
|
||||
|
||||
:deep(svg) {
|
||||
width: $w;
|
||||
height: $w;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
153
src/pages/pc/components/AItem.vue
Normal file
153
src/pages/pc/components/AItem.vue
Normal file
@@ -0,0 +1,153 @@
|
||||
<script setup lang="ts">
|
||||
|
||||
import {Word} from "@/types.ts";
|
||||
import VolumeIcon from "@/components/icon/VolumeIcon.vue";
|
||||
import {usePlayWordAudio} from "@/hooks/sound.ts";
|
||||
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
item: Word,
|
||||
showTranslate?: boolean
|
||||
showWord?: boolean
|
||||
border?: boolean
|
||||
}>(), {
|
||||
showTranslate: true,
|
||||
showWord: true,
|
||||
border: true
|
||||
})
|
||||
|
||||
const playWordAudio = usePlayWordAudio()
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="word-item"
|
||||
:class="{
|
||||
border,
|
||||
}"
|
||||
>
|
||||
<div class="left">
|
||||
<slot name="prefix" :item="item"></slot>
|
||||
<div class="title-wrapper">
|
||||
<div class="item-title">
|
||||
<span class="word" :class="!showWord && 'word-shadow'">{{ item.word }}</span>
|
||||
<span class="phonetic">{{ item.phonetic0 }}</span>
|
||||
<VolumeIcon class="volume" @click="playWordAudio(item.word)"></VolumeIcon>
|
||||
</div>
|
||||
<div class="item-sub-title" v-if="item.trans.length && showTranslate">
|
||||
<div v-for="v in item.trans">{{ (v.pos ? v.pos + '.' : '') + (v.cn || v.en) }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="right">
|
||||
<slot name="suffix" :item="item"></slot>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
<style scoped lang="scss">
|
||||
.word-item {
|
||||
cursor: pointer;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
background: var(--color-item-bg);
|
||||
color: var(--color-font-1);
|
||||
font-size: 1.1rem;
|
||||
border-radius: .5rem;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
transition: all .3s;
|
||||
padding: .6rem;
|
||||
gap: .6rem;
|
||||
border: 1px solid var(--color-item-border);
|
||||
|
||||
.left {
|
||||
display: flex;
|
||||
gap: .6rem;
|
||||
|
||||
.title-wrapper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: .2rem;
|
||||
word-break: break-word;
|
||||
}
|
||||
}
|
||||
|
||||
.right {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: .3rem;
|
||||
transition: all .3s;
|
||||
}
|
||||
|
||||
.volume, .collect, .easy {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background: var(--color-item-hover);
|
||||
|
||||
.volume, .collect, .easy {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
&.active {
|
||||
background: var(--color-item-active);
|
||||
$c: #E6A23C;
|
||||
|
||||
.phonetic, .item-sub-title {
|
||||
color: var(--color-gray) !important;
|
||||
}
|
||||
|
||||
.volume, .collect, .easy, .fill {
|
||||
color: $c;
|
||||
}
|
||||
}
|
||||
|
||||
&.border {
|
||||
&.active {
|
||||
.item-title {
|
||||
border-bottom: 2px solid gray !important;
|
||||
}
|
||||
}
|
||||
|
||||
.item-title {
|
||||
transition: all .3s;
|
||||
cursor: pointer;
|
||||
border-bottom: 2px solid transparent;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
.item-title {
|
||||
border-bottom: 2px solid gray !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.item-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: .5rem;
|
||||
color: var(--color-font-1);
|
||||
|
||||
.word {
|
||||
font-size: 1.2rem;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.phonetic {
|
||||
font-size: .9rem;
|
||||
color: gray;
|
||||
}
|
||||
}
|
||||
|
||||
.item-sub-title {
|
||||
font-size: 1rem;
|
||||
color: gray;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
</style>
|
||||
@@ -2,29 +2,27 @@
|
||||
|
||||
import {useSettingStore} from "@/stores/setting.ts";
|
||||
import {nextTick, useSlots} from "vue";
|
||||
import VolumeIcon from "@/components/icon/VolumeIcon.vue";
|
||||
import {Sort} from "@/types.ts";
|
||||
import MiniDialog from "@/pages/pc/components/dialog/MiniDialog.vue";
|
||||
import BaseIcon from "@/components/BaseIcon.vue";
|
||||
import BaseButton from "@/components/BaseButton.vue";
|
||||
import {cloneDeep, reverse, shuffle} from "lodash-es";
|
||||
import Input from "@/pages/pc/components/Input.vue";
|
||||
import PopConfirm from "@/pages/pc/components/PopConfirm.vue";
|
||||
import Empty from "@/components/Empty.vue";
|
||||
import {Icon} from "@iconify/vue";
|
||||
|
||||
let list = defineModel('list')
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
activeIndex?: number,
|
||||
activeId?: string,
|
||||
isActive?: boolean
|
||||
showBorder?: boolean
|
||||
loading?: boolean
|
||||
del?: Function
|
||||
batchDel?: Function
|
||||
add?: Function
|
||||
}>(), {
|
||||
activeIndex: -1,
|
||||
activeId: '',
|
||||
isActive: false,
|
||||
showBorder: false,
|
||||
loading: true,
|
||||
del: () => void 0,
|
||||
add: () => void 0,
|
||||
batchDel: () => void 0
|
||||
@@ -52,26 +50,16 @@ function scrollToItem(index: number) {
|
||||
})
|
||||
}
|
||||
|
||||
function itemIsActive(item: any, index: number) {
|
||||
return props.activeId ?
|
||||
props.activeId === item.id
|
||||
: props.activeIndex === index
|
||||
}
|
||||
|
||||
defineExpose({scrollToBottom, scrollToItem})
|
||||
|
||||
let pageNo = $ref(1)
|
||||
let pageSize = $ref(50)
|
||||
let currentList = $computed({
|
||||
get() {
|
||||
if (searchKey) {
|
||||
return list.value.filter(v => v.word.includes(searchKey))
|
||||
}
|
||||
return list.value.slice((pageNo - 1) * pageSize, (pageNo - 1) * pageSize + pageSize)
|
||||
},
|
||||
set(v) {
|
||||
list.value = v
|
||||
let currentList = $computed(() => {
|
||||
if (searchKey) {
|
||||
return list.value.filter(v => v.word.includes(searchKey))
|
||||
}
|
||||
return list.value.slice((pageNo - 1) * pageSize, (pageNo - 1) * pageSize + pageSize)
|
||||
})
|
||||
|
||||
let selectIds = $ref([])
|
||||
@@ -116,6 +104,11 @@ function handleBatchDel() {
|
||||
selectIds = []
|
||||
}
|
||||
|
||||
function handlePageNo(e) {
|
||||
pageNo = e
|
||||
console.log('listRef', listRef)
|
||||
}
|
||||
|
||||
const s = useSlots()
|
||||
|
||||
defineRender(
|
||||
@@ -127,43 +120,55 @@ defineRender(
|
||||
|
||||
return (
|
||||
<div class="flex flex-col gap-3">
|
||||
<div class="">
|
||||
<div>
|
||||
{
|
||||
showSearchInput ? (
|
||||
<div
|
||||
class="flex gap-2"
|
||||
class="flex gap-4"
|
||||
>
|
||||
<Input
|
||||
modelValue={searchKey}
|
||||
onUpdate:model-value={e => searchKey = e}
|
||||
class="flex-1"/>
|
||||
<BaseButton onClick={() => showSearchInput = false}>取消</BaseButton>
|
||||
<BaseButton onClick={() => (showSearchInput = false, searchKey = '')}>取消</BaseButton>
|
||||
</div>
|
||||
) : (
|
||||
<div class="flex justify-between " v-else>
|
||||
<el-checkbox
|
||||
onClick={() => toggleSelectAll()}
|
||||
modelValue={selectAll}
|
||||
size="large"/>
|
||||
<div class="flex gap-2 items-center">
|
||||
<el-checkbox
|
||||
disabled={!currentList.length}
|
||||
onClick={() => toggleSelectAll()}
|
||||
modelValue={selectAll}
|
||||
size="large"/>
|
||||
<span>{selectIds.length} / {list.value.length}</span>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="flex gap-2 relative">
|
||||
{
|
||||
selectIds.length ? <BaseIcon
|
||||
onClick={handleBatchDel}
|
||||
class="del"
|
||||
title="删除"
|
||||
icon="solar:trash-bin-minimalistic-linear"/> : null
|
||||
selectIds.length ?
|
||||
<PopConfirm title="确认删除所有选中数据?"
|
||||
onConfirm={handleBatchDel}
|
||||
>
|
||||
<BaseIcon
|
||||
class="del"
|
||||
title="删除"
|
||||
icon="solar:trash-bin-minimalistic-linear"/>
|
||||
</PopConfirm>
|
||||
: null
|
||||
}
|
||||
<BaseIcon
|
||||
onClick={props.add}
|
||||
icon="fluent:add-20-filled"
|
||||
title="添加单词"/>
|
||||
<BaseIcon
|
||||
disabled={!currentList.length}
|
||||
title="改变顺序"
|
||||
icon="icon-park-outline:sort-two"
|
||||
onClick={() => showSortDialog = !showSortDialog}
|
||||
/>
|
||||
<BaseIcon
|
||||
disabled={!currentList.length}
|
||||
onClick={() => showSearchInput = !showSearchInput}
|
||||
title="搜索"
|
||||
icon="fluent:search-24-regular"/>
|
||||
@@ -186,29 +191,41 @@ defineRender(
|
||||
)
|
||||
}
|
||||
</div>
|
||||
<div class="flex-1 overflow-auto"
|
||||
ref="listRef">
|
||||
{
|
||||
currentList.map((item, index) => {
|
||||
return (
|
||||
<div class="list-item-wrapper"
|
||||
key={item.id}
|
||||
>
|
||||
{s.default({checkbox: d, item})}
|
||||
</div>
|
||||
)
|
||||
})
|
||||
}
|
||||
</div>
|
||||
<div class="flex justify-end">
|
||||
<el-pagination background
|
||||
currentPage={pageNo}
|
||||
onUpdate:current-page={(e) => pageNo = e}
|
||||
pageSize={pageSize}
|
||||
onUpdate:page-size={(e) => pageSize = e}
|
||||
layout="prev, pager, next"
|
||||
total={list.value.length}/>
|
||||
</div>
|
||||
{
|
||||
props.loading ?
|
||||
<div class="h-full w-full center text-4xl">
|
||||
<Icon
|
||||
icon="eos-icons:loading"
|
||||
color="gray"
|
||||
/>
|
||||
</div>
|
||||
: currentList.length ? (
|
||||
<>
|
||||
<div class="flex-1 overflow-auto"
|
||||
ref='listRef'>
|
||||
{currentList.map((item) => {
|
||||
return (
|
||||
<div class="list-item-wrapper"
|
||||
key={item.id}
|
||||
>
|
||||
{s.default({checkbox: d, item})}
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
<div class="flex justify-end">
|
||||
<el-pagination background
|
||||
currentPage={pageNo}
|
||||
onUpdate:current-page={handlePageNo}
|
||||
pageSize={pageSize}
|
||||
onUpdate:page-size={(e) => pageSize = e}
|
||||
pageSizes={[20, 50, 100, 200]}
|
||||
layout="sizes, prev, pager, next"
|
||||
total={list.value.length}/>
|
||||
</div>
|
||||
</>
|
||||
) : <Empty/>
|
||||
}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ export default {
|
||||
this.show = true
|
||||
this.$nextTick(() => {
|
||||
let tip = this.$refs?.tip?.getBoundingClientRect()
|
||||
console.log('rect', rect, tip)
|
||||
// console.log('rect', rect, tip)
|
||||
if (!tip) return
|
||||
if (rect.top < 150) {
|
||||
this.$refs.tip.style.top = rect.top + rect.height + tip.height + 30 + 'px'
|
||||
@@ -65,13 +65,13 @@ export default {
|
||||
<Transition>
|
||||
{
|
||||
this.show && (
|
||||
<div ref="tip" className="pop-confirm-content">
|
||||
<div className="text">
|
||||
<div ref="tip" class="pop-confirm-content">
|
||||
<div class="text">
|
||||
{this.title}
|
||||
</div>
|
||||
<div className="options">
|
||||
<div class="options">
|
||||
<div onClick={() => this.show = false}>取消</div>
|
||||
<div className="main" onClick={() => this.confirm()}>确认</div>
|
||||
<div class="main" onClick={() => this.confirm()}>确认</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
@@ -91,7 +91,7 @@ $bg-color: rgb(226, 226, 226);
|
||||
position: fixed;
|
||||
background: var(--color-tooltip-bg);
|
||||
padding: 1rem;
|
||||
border-radius: .24rem;
|
||||
border-radius: .3rem;
|
||||
transform: translate(-50%, calc(-100% - .6rem));
|
||||
box-shadow: 0 0 6px 1px var(--color-tooltip-shadow);
|
||||
z-index: 999;
|
||||
|
||||
@@ -49,19 +49,20 @@ export default {
|
||||
},
|
||||
},
|
||||
render() {
|
||||
if (!this.title) return this.$slots.default()
|
||||
let Vnode = this.$slots.default()[0]
|
||||
return <>
|
||||
{
|
||||
this.show && this.title && (
|
||||
<Teleport to="body">
|
||||
<Transition name="fade">
|
||||
<div ref="tip" className="tip">
|
||||
<Teleport to="body">
|
||||
<Transition name="fade">
|
||||
{
|
||||
this.show && (
|
||||
<div ref="tip" class="tip">
|
||||
{this.title}
|
||||
</div>
|
||||
</Transition>
|
||||
</Teleport>
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
</Transition>
|
||||
</Teleport>
|
||||
<Vnode
|
||||
onClick={() => this.show = false}
|
||||
onmouseenter={(e) => this.showPop(e)}
|
||||
@@ -72,14 +73,12 @@ export default {
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
@import "@/assets/css/style";
|
||||
|
||||
.tip {
|
||||
position: fixed;
|
||||
font-size: 0.8rem;
|
||||
font-size: 0.9rem;
|
||||
z-index: 9999;
|
||||
border-radius: .2rem;
|
||||
padding: .8rem;
|
||||
border-radius: .3rem;
|
||||
padding: 0.4rem .8rem;
|
||||
color: var(--color-font-1);
|
||||
background: var(--color-tooltip-bg);
|
||||
//box-shadow: 1px 1px 6px #bbbbbb;
|
||||
|
||||
@@ -9,9 +9,11 @@ const props = withDefaults(defineProps<{
|
||||
item: Word,
|
||||
showTranslate?: boolean
|
||||
showWord?: boolean
|
||||
hiddenOptionIcon?: boolean
|
||||
}>(), {
|
||||
showTranslate: true,
|
||||
showWord: true
|
||||
showWord: true,
|
||||
hiddenOptionIcon: false,
|
||||
})
|
||||
|
||||
const playWordAudio = usePlayWordAudio()
|
||||
@@ -20,9 +22,7 @@ const playWordAudio = usePlayWordAudio()
|
||||
|
||||
<template>
|
||||
<div class="word-item"
|
||||
:class="{
|
||||
border:true
|
||||
}"
|
||||
:class="{hiddenOptionIcon}"
|
||||
>
|
||||
<div class="left">
|
||||
<slot name="prefix" :item="item"></slot>
|
||||
@@ -79,51 +79,10 @@ const playWordAudio = usePlayWordAudio()
|
||||
transition: all .3s;
|
||||
}
|
||||
|
||||
.volume, .collect, .easy {
|
||||
.volume {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background: var(--color-item-hover);
|
||||
|
||||
.volume, .collect, .easy {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
&.active {
|
||||
background: var(--color-item-active);
|
||||
$c: #E6A23C;
|
||||
|
||||
.phonetic, .item-sub-title {
|
||||
color: var(--color-gray) !important;
|
||||
}
|
||||
|
||||
.volume, .collect, .easy, .fill {
|
||||
color: $c;
|
||||
}
|
||||
}
|
||||
|
||||
&.border {
|
||||
&.active {
|
||||
.item-title {
|
||||
border-bottom: 2px solid gray !important;
|
||||
}
|
||||
}
|
||||
|
||||
.item-title {
|
||||
transition: all .3s;
|
||||
cursor: pointer;
|
||||
border-bottom: 2px solid transparent;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
.item-title {
|
||||
border-bottom: 2px solid gray !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.item-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -146,6 +105,32 @@ const playWordAudio = usePlayWordAudio()
|
||||
color: gray;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background: var(--color-item-hover);
|
||||
|
||||
.volume, :deep(.option-icon) {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
&.hiddenOptionIcon {
|
||||
:deep(.option-icon) {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
&.active {
|
||||
background: var(--color-item-active);
|
||||
$c: #E6A23C;
|
||||
|
||||
.phonetic, .item-sub-title {
|
||||
color: var(--color-gray) !important;
|
||||
}
|
||||
|
||||
.volume, .collect, .easy, .fill {
|
||||
color: $c;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
@@ -13,10 +13,12 @@ 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";
|
||||
|
||||
const runtimeStore = useRuntimeStore()
|
||||
const store = useBaseStore()
|
||||
const route = useRoute()
|
||||
let loading = $ref(false)
|
||||
|
||||
let list = $computed({
|
||||
get() {
|
||||
@@ -27,12 +29,16 @@ let list = $computed({
|
||||
}
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
onMounted(async () => {
|
||||
switch (Number(route.query.type)) {
|
||||
case -1:
|
||||
if (runtimeStore.routeData) {
|
||||
loading = true
|
||||
runtimeStore.editDict = cloneDeep(runtimeStore.routeData)
|
||||
_checkDictWords(runtimeStore.editDict)
|
||||
await _checkDictWords(runtimeStore.editDict)
|
||||
setTimeout(() => {
|
||||
loading = false
|
||||
}, 300)
|
||||
}
|
||||
break
|
||||
case 0:
|
||||
@@ -148,6 +154,10 @@ function closeWordForm() {
|
||||
wordForm = cloneDeep(DefaultFormWord)
|
||||
}
|
||||
|
||||
function s(ss) {
|
||||
console.log('s', ss)
|
||||
}
|
||||
|
||||
defineRender(() => {
|
||||
return (
|
||||
<BasePage>
|
||||
@@ -165,32 +175,39 @@ defineRender(() => {
|
||||
}
|
||||
</div>
|
||||
</header>
|
||||
<div class="flex h-120">
|
||||
<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}>
|
||||
<WordItem
|
||||
item={val.item}>
|
||||
{{
|
||||
prefix: () => val.checkbox(val.item),
|
||||
suffix: () => (
|
||||
<div class='flex flex-col'>
|
||||
<BaseIcon
|
||||
class="del"
|
||||
class="option-icon"
|
||||
onClick={() => editWord(val.item)}
|
||||
title="编辑"
|
||||
icon="tabler:edit"/>
|
||||
<BaseIcon
|
||||
class="del"
|
||||
onClick={() => delWord(val.item.id)}
|
||||
title="删除"
|
||||
icon="solar:trash-bin-minimalistic-linear"/>
|
||||
<PopConfirm title="确认删除?"
|
||||
onConfirm={() => delWord(val.item.id)}
|
||||
>
|
||||
<BaseIcon
|
||||
class="option-icon"
|
||||
title="删除"
|
||||
icon="solar:trash-bin-minimalistic-linear"/>
|
||||
</PopConfirm>
|
||||
|
||||
</div>
|
||||
)
|
||||
}}
|
||||
@@ -205,7 +222,7 @@ defineRender(() => {
|
||||
{wordFormData.type === FormMode.Add ? '添加' : '修改'}单词
|
||||
</div>
|
||||
<el-form
|
||||
class="form"
|
||||
className="form"
|
||||
ref="wordFormRef"
|
||||
rules={wordRules}
|
||||
model={wordForm}
|
||||
|
||||
Reference in New Issue
Block a user