This commit is contained in:
zyronon
2023-09-25 23:58:46 +08:00
parent 5c1994f0db
commit c0185f585b
4 changed files with 87 additions and 99 deletions

4
components.d.ts vendored
View File

@@ -21,11 +21,15 @@ declare module 'vue' {
DictModal: typeof import('./src/components/Toolbar/DictModal.vue')['default']
EditAbleText: typeof import('./src/components/EditAbleText.vue')['default']
ElInput: typeof import('element-plus/es')['ElInput']
ElInputNumber: typeof import('element-plus/es')['ElInputNumber']
ElOption: typeof import('element-plus/es')['ElOption']
ElProgress: typeof import('element-plus/es')['ElProgress']
ElRadio: typeof import('element-plus/es')['ElRadio']
ElRadioButton: typeof import('element-plus/es')['ElRadioButton']
ElRadioGroup: typeof import('element-plus/es')['ElRadioGroup']
ElSelect: typeof import('element-plus/es')['ElSelect']
ElSlider: typeof import('element-plus/es')['ElSlider']
ElSwitch: typeof import('element-plus/es')['ElSwitch']
FeedbackModal: typeof import('./src/components/Toolbar/FeedbackModal.vue')['default']
Fireworks: typeof import('./src/components/Fireworks.vue')['default']
Footer: typeof import('./src/components/Practice/Footer.vue')['default']

View File

@@ -21,6 +21,7 @@ import {useBaseStore} from "@/stores/base.ts";
import {$computed, $ref} from "vue/macros";
import Input from "@/components/Input.vue";
import List from "@/components/List.vue";
import {v4 as uuidv4} from 'uuid';
interface IProps {
selectIndex?: number
@@ -32,10 +33,7 @@ const props = withDefaults(defineProps<IProps>(), {
const base = useBaseStore()
let article = $ref<Article>(cloneDeep(DefaultArticle))
let selectIndex = $ref<number>(props.selectIndex)
let selectItem = $ref<number>(props.selectIndex)
let networkTranslateEngine = $ref('baidu')
let searchKey = $ref('')
let progress = $ref(0)
const TranslateEngineOptions = [
{value: 'baidu', label: '百度'},
@@ -71,12 +69,6 @@ watch(() => props.article, n => {
}
})
onMounted(() => {
if (selectIndex > -1) {
article = base.currentEditDict.articles[selectIndex]
}
})
async function startNetworkTranslate() {
if (!article.title.trim()) {
return ElMessage.error('请填写标题!')
@@ -184,7 +176,7 @@ function save(option: 'save' | 'next') {
}
let has = base.currentEditDict.articles.find((item: Article) => item.title === article.title)
if (has && selectIndex === -1) {
if (has && !article.id) {
return ElMessage.error('已存在同名文章!')
}
@@ -192,18 +184,22 @@ function save(option: 'save' | 'next') {
article.textCustomTranslateIsFormat = true
// emit('close')
// emit('save', cloneDeep(article))
if (selectIndex > -1) {
base.currentEditDict.articles[selectIndex] = cloneDeep(article)
if (article.id) {
let rIndex = base.currentEditDict.articles.findIndex(v => v.id === article.id)
if (rIndex > -1) {
base.currentEditDict.articles[rIndex] = cloneDeep(article)
}
} else {
base.currentEditDict.articles.push(cloneDeep(article))
let data = {...article, id: uuidv4()}
base.currentEditDict.articles.push(data)
if (option === 'save') {
selectIndex = base.currentEditDict.articles.length - 1
article = cloneDeep(data)
}
}
if (option === 'next') {
selectIndex = -1
article = cloneDeep(DefaultArticle)
}
//TODO 保存完成后滚动到对应位置
ElMessage.success('保存成功!')
}
@@ -268,41 +264,8 @@ watch(() => article.useTranslateType, () => {
}
})
const list = $computed(() => {
if (searchKey) {
return base.currentEditDict.articles.filter((item: Article) => {
//把搜索内容,分词之后,判断是否有这个词,比单纯遍历包含体验更好
return searchKey.toLowerCase().split(' ').filter(v => v).some(value => {
return item.title.toLowerCase().includes(value) || item.titleTranslate.toLowerCase().includes(value)
})
})
} else {
return base.currentEditDict.articles
}
})
function selectArticle(index: number) {
article = cloneDeep(base.currentEditDict.articles[index])
selectIndex = index
}
function delArticle(item: Article) {
let rIndex = base.currentEditDict.articles.findIndex((v: Article) => v.id === item.id)
if (rIndex > -1) {
if (index < selectIndex) {
selectIndex--
} else if (index === selectIndex) {
if (selectIndex === base.currentEditDict.articles.length - 1) {
selectIndex--
}
}
base.currentEditDict.articles.splice(index, 1)
if (selectIndex < 0) {
article = cloneDeep(DefaultArticle)
} else {
article = cloneDeep(base.currentEditDict.articles[selectIndex])
}
}
function selectArticle(item: Article) {
article = cloneDeep(item)
}
</script>
@@ -315,12 +278,10 @@ function delArticle(item: Article) {
<BaseIcon title="选择其他词典/文章" icon="carbon:change-catalog"/>
</header>
<List
v-model:list="list"
v-model:searchKey="searchKey"
:select-index="selectIndex"
:row-key="(item:Article) => item.title"
@del-article="delArticle"
@select-article="selectArticle"
v-model:list="base.currentEditDict.articles"
:select-item="article"
@del-select-item="article = cloneDeep(DefaultArticle)"
@select-item="selectArticle"
>
<template v-slot="{item,index}">
<div class="name"> {{ `${index + 1}. ${item.title}` }}</div>

View File

@@ -1,49 +1,67 @@
<script setup lang="ts" generic="T">
<script setup lang="ts" generic="T extends {id:string}">
import BaseIcon from "@/components/BaseIcon.vue";
import Input from "@/components/Input.vue";
import {$ref} from "vue/macros";
import {$computed, $ref} from "vue/macros";
import {cloneDeep, throttle} from "lodash-es";
let dragIndex = $ref(-1)
import {Article} from "@/types.ts";
interface IProps {
list: T[]
searchKey: string,
selectIndex: number,
rowKey: (item: T) => string
selectItem: T,
}
const props = defineProps<IProps>()
const emit = defineEmits<{
selectArticle: [index: number],
delArticle: [item: T],
selectItem: [index: T],
delSelectItem: [],
'update:searchKey': [val: string],
'update:list': [list: T[]],
}>()
let dragItem: T = $ref({id: ''} as any)
let searchKey = $ref('')
let draggable = $ref(false)
function dragstart(index: number) {
dragIndex = index;
let localList = $computed({
get() {
if (searchKey) {
return props.list.filter((item: Article) => {
//把搜索内容,分词之后,判断是否有这个词,比单纯遍历包含体验更好
return searchKey.toLowerCase().split(' ').filter(v => v).some(value => {
return item.title.toLowerCase().includes(value) || item.titleTranslate.toLowerCase().includes(value)
})
})
} else {
return props.list
}
},
set(newValue) {
emit('update:list', newValue)
}
})
function dragstart(item: T) {
dragItem = item;
}
const dragenter = throttle((e, index) => {
// console.log('dragenter', 'dragIndex', dragIndex, 'index', index)
const dragenter = throttle((e, item: T) => {
// console.log('dragenter', 'item.id', item.id, 'dragItem.id', dragItem.id)
e.preventDefault();
// 避免源对象触发自身的dragenter事件
if (dragIndex !== index && dragIndex !== -1) {
const source = props.list[dragIndex];
if (dragItem.id && dragItem.id !== item.id) {
let rIndex = props.list.findIndex(v => v.id === dragItem.id)
let rIndex2 = props.list.findIndex(v => v.id === item.id)
// console.log('dragenter', 'item-Index', rIndex2, 'dragItem.index', rIndex)
//这里不能直接用localList splice。不知道为什么会导致有筛选的情况下多动无法变换位置
let temp = cloneDeep(props.list)
temp.splice(dragIndex, 1);
temp.splice(index, 0, source);
emit('update:list', temp)
// props.list = temp
// 排序变化后目标对象的索引变成源对象的索引
dragIndex = index;
temp.splice(rIndex, 1);
temp.splice(rIndex2, 0, cloneDeep(dragItem));
localList = temp;
}
}, 200)
}, 300)
function dragover(e, index) {
function dragover(e) {
// console.log('dragover')
e.preventDefault();
}
@@ -51,7 +69,17 @@ function dragover(e, index) {
function dragend() {
// console.log('dragend')
draggable = false
dragIndex = -1
dragItem = {id: ''} as T
}
function delItem(item: T) {
if (item.id === props.selectItem.id) {
emit('delSelectItem')
}
let rIndex = props.list.findIndex(v => v.id === item.id)
if (rIndex > -1) {
localList.splice(rIndex, 1)
}
}
</script>
@@ -59,28 +87,22 @@ function dragend() {
<template>
<div class="list-wrapper">
<div class="search">
<Input :model-value="searchKey"
@update:model-value="(e:string) => emit('update:searchKey',e)"
/>
<Input v-model="searchKey"/>
</div>
<transition-group
name="drag"
class="list"
tag="div"
>
<transition-group name="drag" class="list" tag="div">
<div class="item"
:class="[
(props.selectIndex === index) && 'active',
(selectItem.id === item.id) && 'active',
draggable && 'draggable',
(dragIndex === index) && 'active'
(dragItem.id === item.id) && 'active'
]"
@click="emit('selectArticle',index)"
v-for="(item,index) in props.list"
:key="rowKey(item)"
@click="emit('selectItem',item)"
v-for="(item,index) in localList"
:key="item.id"
:draggable="draggable"
@dragstart="dragstart(index)"
@dragenter="dragenter($event, index)"
@dragover="dragover($event, index)"
@dragstart="dragstart(item)"
@dragenter="dragenter($event, item)"
@dragover="dragover($event)"
@dragend="dragend()"
>
<div class="left">
@@ -88,7 +110,7 @@ function dragend() {
</div>
<div class="right">
<BaseIcon
@click="emit('delArticle',item)"
@click="delItem(item)"
title="删除" icon="fluent:delete-24-regular"/>
<div
@mousedown="draggable = true"
@@ -113,7 +135,7 @@ function dragend() {
.drag-enter-from,
.drag-leave-to {
opacity: 0;
transform: translateX(30px);
transform: translateX(50rem);
}
/* 确保将离开的元素从布局流中删除

View File

@@ -138,7 +138,8 @@ export interface Article {
}
export const DefaultArticle: Article = {
id: uuidv4(),
// id: uuidv4(),
id: '',
title: '',
titleTranslate: '',
text: '',