This commit is contained in:
zyronon
2023-09-21 23:26:05 +08:00
parent 9ed29f6827
commit 6e0d8a0185
13 changed files with 237 additions and 127 deletions

3
components.d.ts vendored
View File

@@ -9,10 +9,12 @@ declare module 'vue' {
export interface GlobalComponents {
Add: typeof import('./src/components/Toolbar/Add.vue')['default']
AddArticle: typeof import('./src/components/Practice/AddArticle.vue')['default']
Alert: typeof import('./src/components/Modal/Alert.vue')['default']
Backgorund: typeof import('./src/components/Backgorund.vue')['default']
BaseButton: typeof import('./src/components/BaseButton.vue')['default']
ChapterDetail: typeof import('./src/components/ChapterDetail.vue')['default']
ChapterList: typeof import('./src/components/ChapterList.vue')['default']
Confirm: typeof import('./src/components/Modal/Confirm.vue')['default']
DictList: typeof import('./src/components/DictList.vue')['default']
DictModal: typeof import('./src/components/Toolbar/DictModal.vue')['default']
EditAbleText: typeof import('./src/components/EditAbleText.vue')['default']
@@ -32,7 +34,6 @@ declare module 'vue' {
IconWrapper: typeof import('./src/components/IconWrapper.vue')['default']
MiniModal: typeof import('./src/components/MiniModal.vue')['default']
Modal: typeof import('./src/components/Modal/Modal.vue')['default']
NewModal: typeof import('./src/components/Modal/NewModal.vue')['default']
PopConfirm: typeof import('./src/components/PopConfirm.vue')['default']
Practice: typeof import('./src/components/Practice/Practice.vue')['default']
RepeatSetting: typeof import('./src/components/Toolbar/RepeatSetting.vue')['default']

View File

@@ -39,7 +39,6 @@ onMounted(() => {
useEventListener('keyup', (e: KeyboardEvent) => {
if (e.key === 'Escape') {
let lastItem = runtimeStore.modalList.pop()
console.log('la',lastItem)
lastItem && lastItem.close()
}
})

View File

@@ -111,7 +111,11 @@ function click() {
}
&.link {
border-bottom-color: black;
border-radius: 0;
border-bottom: 2px solid transparent;
&:hover{
border-bottom: 2px solid black;
}
}
&.active {

View File

@@ -1,14 +0,0 @@
<script setup lang="ts">
import Modal from "@/components/Modal/Modal.vue";
</script>
<template>
<Modal>
</Modal>
</template>
<style scoped lang="scss">
</style>

View File

@@ -10,20 +10,29 @@ interface IProps {
modelValue?: boolean,
showClose?: boolean,
title?: string,
subTitle?: string,
fullScreen?: boolean;
padding?: boolean
footer?: boolean
header?: boolean
confirmButtonText?: string
cancelButtonText?: string
}
const props = withDefaults(defineProps<IProps>(), {
modelValue: undefined,
showClose: true,
fullScreen: false,
footer: false,
header: true,
confirmButtonText: '确认',
cancelButtonText: '取消',
})
const emit = defineEmits([
'update:modelValue',
'close'
'close',
'ok',
'cancel',
])
let visible = $ref(false)
@@ -47,6 +56,7 @@ function close() {
setTimeout(() => {
emit('update:modelValue', false)
emit('close')
emit('cancel')
visible = false
resolve(true)
}, closeTime)
@@ -54,6 +64,7 @@ function close() {
}
watch(() => props.modelValue, n => {
// console.log('n', n)
if (n) {
visible = true
} else {
@@ -62,6 +73,7 @@ watch(() => props.modelValue, n => {
})
onMounted(() => {
// console.log('props.modelValue', props.modelValue)
if (props.modelValue === undefined) {
visible = true
}
@@ -84,7 +96,7 @@ useEsc(close, () => props.modelValue)
fullScreen?'full':'window'
]"
>
<div class="modal-header">
<div class="modal-header" v-if="header">
<div class="title">{{ props.title }}</div>
<Tooltip title="关闭">
<Icon @click="close"
@@ -93,18 +105,16 @@ useEsc(close, () => props.modelValue)
width="20" color="#929596"
icon="ion:close-outline"/>
</Tooltip>
<!-- <div class="sub-title" v-if="props.subTitle">{{ props.subTitle }}</div>-->
</div>
<div class="modal-body" :class="{padding}">
<slot></slot>
</div>
<div class="modal-footer">
<div class="modal-footer" v-if="footer">
<div class="left">
</div>
<div class="right">
<BaseButton type="link">取消</BaseButton>
<BaseButton>确定</BaseButton>
<BaseButton type="link" @click="close">取消</BaseButton>
<BaseButton @click="emit('ok'),close()">确定</BaseButton>
</div>
</div>
</div>
@@ -223,15 +233,9 @@ $header-height: 60rem;
.title {
color: var(--color-font-1);
font-weight: bold;
font-size: 28rem;
font-size: 24rem;
line-height: 33rem;
}
.sub-title {
color: var(--color-font-1);
font-weight: 500;
font-size: 14rem;
}
}
.modal-body {
@@ -288,11 +292,5 @@ $header-height: 60rem;
}
}
}
.close {
position: absolute;
right: 20rem;
top: 20rem;
}
}
</style>

View File

@@ -16,42 +16,59 @@ import {Icon} from "@iconify/vue";
import {cloneDeep} from "lodash-es";
import {useDisableEventListener, useEsc} from "@/hooks/event.ts";
import {Action} from "element-plus";
import {MessageBox} from "@/utils/MessageBox.tsx";
import Modal from "@/components/Modal/Modal.vue";
interface IProps {
article?: Article
modelValue: boolean
}
const props = withDefaults(defineProps<IProps>(), {
article: () => cloneDeep(DefaultArticle)
article: () => cloneDeep(DefaultArticle),
modelValue: false
})
let article = reactive<Article>(props.article)
let article = $ref<Article>(cloneDeep(props.article))
let networkTranslateEngine = $ref('baidu')
let progress = $ref(0)
const TranslateEngineOptions = [
{value: 'baidu', label: '百度'},
{value: 'youdao', label: '有道'},
]
const emit = defineEmits(['close', 'save'])
const emit = defineEmits([
'update:modelValue',
'close',
'save'
])
useDisableEventListener()
useDisableEventListener(() => props.modelValue)
onMounted(() => {
if (article.text.trim()) {
if (article.useTranslateType === TranslateType.custom) {
if (article.textCustomTranslate.trim()) {
if (!article.textCustomTranslateIsFormat) {
let r = getSplitTranslateText(article.textCustomTranslate)
if (r) article.textCustomTranslate = r
ElMessageBox.alert('检测到本地翻译未格式化,已自动格式', '提示', {
confirmButtonText: '好的',
})
watch(() => props.modelValue, n => {
if (n) {
article = cloneDeep(props.article)
if (article.text.trim()) {
if (article.useTranslateType === TranslateType.custom) {
if (article.textCustomTranslate.trim()) {
if (!article.textCustomTranslateIsFormat) {
let r = getSplitTranslateText(article.textCustomTranslate)
if (r) article.textCustomTranslate = r
ElMessage({
message: '检测到本地翻译未格式化,已自动格式',
type: 'success',
duration: 5000
})
}
}
}
}
updateSentenceTranslate()
}
updateSentenceTranslate()
})
onMounted(() => {
})
async function startNetworkTranslate() {
@@ -100,6 +117,8 @@ function updateSentenceTranslate() {
if (article.useTranslateType === TranslateType.network) {
updateLocalSentenceTranslate(article, article.textNetworkTranslate)
}
} else {
article.sections = []
}
}
@@ -155,6 +174,16 @@ function save() {
if (article.useTranslateType === TranslateType.network) {
if (!article.textNetworkTranslate.trim()) {
// MessageBox.confirm(
// '您选择了“网络翻译”,但译文内容却为空白,是否修改为“不需要翻译”并保存?',
// '提示',
// () => {
// // article.useTranslateType = TranslateType.none
// // saveTemp()
// },
// () => void 0,
// )
// return
return ElMessageBox.confirm('您选择了“网络翻译”,但译文内容却为空白,是否修改为“不需要翻译”并保存?', '提示', {
confirmButtonText: '确认',
cancelButtonText: '取消',
@@ -215,10 +244,11 @@ watch(() => article.useTranslateType, () => {
</script>
<template>
<Modal @close="$emit('close')"
title="设置"
:full-screen="true"
subTitle="修改立即生效,实时保存">
<Modal
:model-value="props.modelValue"
@close="emit('update:modelValue')"
:full-screen="true"
>
<div class="add-article" @click.stop="null">
<div class="content">
<div class="row">
@@ -338,7 +368,7 @@ watch(() => article.useTranslateType, () => {
</div>
</div>
</div>
<Icon @click="$emit('close')"
<Icon @click="emit('update:modelValue')"
class="close hvr-grow pointer"
width="20" color="#929596"
icon="ion:close-outline"/>

View File

@@ -17,6 +17,8 @@ import AddArticle from "@/components/Practice/AddArticle.vue";
import {useStartKeyboardEventListener} from "@/hooks/event.ts";
import {useRuntimeStore} from "@/stores/runtime.ts";
import {updateLocalSentenceTranslate, updateSections} from "@/hooks/translate.ts";
import BaseButton from "@/components/BaseButton.vue";
import {MessageBox} from "@/utils/MessageBox.tsx";
const practiceStore = usePracticeStore()
const store = useBaseStore()
@@ -57,7 +59,7 @@ watch(() => store.load, n => {
function getCurrentPractice() {
if (store.isArticle) {
return
// return
let tempArticle = {...DefaultArticle, ...store.currentDict.articles[store.currentDict.chapterIndex]}
console.log('article', tempArticle)
if (tempArticle.sections.length) {
@@ -149,11 +151,24 @@ function saveArticle(article: Article) {
articleData.article = article
}
function test() {
MessageBox.confirm(
'2您选择了“本地翻译”但译文内容却为空白是否修改为“不需要翻译”并保存?',
'1提示',
() => {
console.log('ok')
},
() => {
console.log('cencal')
})
}
</script>
<template>
<div class="practice">
<Toolbar/>
<!-- <BaseButton @click="test">test</BaseButton>-->
<TypeArticle
v-if="store.isArticle"
:article="articleData.article"
@@ -173,8 +188,7 @@ function saveArticle(article: Article) {
@repeat="repeat"
@next="next"
/>
<AddArticle v-if="showEditArticle"
@close="showEditArticle = false"
<AddArticle v-model="showEditArticle"
:article="editArticle"
@save="saveArticle"
/>

View File

@@ -38,6 +38,7 @@ function options(emitType: string) {
<template>
<Modal
:header="false"
v-model="statModalIsOpen"
@close="options('next')">
<div class="statistics">

View File

@@ -202,7 +202,7 @@ function onKeyDown(e: KeyboardEvent) {
let letter = e.key
let key = currentWord.name[stringIndex]
console.log('key', key,)
// console.log('key', key,)
let isWrong = false
if (settingStore.ignoreCase) {

View File

@@ -28,8 +28,7 @@ function toggle() {
/>
</IconWrapper>
</Tooltip>
<AddArticle v-if="show"
@close="show = false"
<AddArticle v-model="show"
/>
</div>
</template>

View File

@@ -22,8 +22,7 @@ useWatchAllSound()
<template>
<Modal
@close="emit('close')"
title="设置"
subTitle="修改立即生效,实时保存">
title="设置">
<div class="setting-modal">
<div class="tabs">
<div class="tab" :class="tabIndex === 0 && 'active'" @click="tabIndex = 0">

View File

@@ -4,84 +4,95 @@ import {useRuntimeStore} from "@/stores/runtime.ts";
import {$ref} from "vue/macros";
export function useWindowClick(cb: () => void) {
onMounted(() => {
emitter.on(EventKey.closeOther, cb)
window.addEventListener('click', cb)
})
onUnmounted(() => {
window.removeEventListener('click', cb)
})
onMounted(() => {
emitter.on(EventKey.closeOther, cb)
window.addEventListener('click', cb)
})
onUnmounted(() => {
window.removeEventListener('click', cb)
})
}
export function useEventListener(type: string, listener: EventListenerOrEventListenerObject) {
onMounted(() => window.addEventListener(type, listener))
onUnmounted(() => window.removeEventListener(type, listener))
onMounted(() => window.addEventListener(type, listener))
onUnmounted(() => window.removeEventListener(type, listener))
}
export function useStartKeyboardEventListener() {
const runtimeStore = useRuntimeStore()
const runtimeStore = useRuntimeStore()
useEventListener('keydown', (e: KeyboardEvent) => {
if (!runtimeStore.disableEventListener) {
emitter.emit(EventKey.keydown, e)
}
})
useEventListener('keyup', (e: KeyboardEvent) => {
if (!runtimeStore.disableEventListener) {
emitter.emit(EventKey.keyup, e)
}
})
useEventListener('keydown', (e: KeyboardEvent) => {
if (!runtimeStore.disableEventListener) {
emitter.emit(EventKey.keydown, e)
}
})
useEventListener('keyup', (e: KeyboardEvent) => {
if (!runtimeStore.disableEventListener) {
emitter.emit(EventKey.keyup, e)
}
})
}
export function useOnKeyboardEventListener(onKeyDown: (e: KeyboardEvent) => void, onKeyUp: (e: KeyboardEvent) => void) {
onMounted(() => {
emitter.on(EventKey.keydown, onKeyDown)
emitter.on(EventKey.keyup, onKeyUp)
})
onUnmounted(() => {
emitter.off(EventKey.keydown, onKeyDown)
emitter.off(EventKey.keyup, onKeyUp)
})
onMounted(() => {
emitter.on(EventKey.keydown, onKeyDown)
emitter.on(EventKey.keyup, onKeyUp)
})
onUnmounted(() => {
emitter.off(EventKey.keydown, onKeyDown)
emitter.off(EventKey.keyup, onKeyUp)
})
}
export function useDisableEventListener() {
const runtimeStore = useRuntimeStore()
onMounted(() => {
runtimeStore.disableEventListener = true
})
onUnmounted(() => {
runtimeStore.disableEventListener = false
})
export function useDisableEventListener(watchVal?: any) {
const runtimeStore = useRuntimeStore()
watch(watchVal, n => {
if (n) {
runtimeStore.disableEventListener = true
} else {
runtimeStore.disableEventListener = false
}
})
onMounted(() => {
if (!watchVal) {
runtimeStore.disableEventListener = true
}
})
onUnmounted(() => {
if (!watchVal) {
runtimeStore.disableEventListener = false
}
})
}
export function useEsc(close: () => void, watchVal?: any) {
const runtimeStore = useRuntimeStore()
const id = $ref(Date.now())
const runtimeStore = useRuntimeStore()
const id = $ref(Date.now())
watch(watchVal, n => {
if (n) {
runtimeStore.modalList.push({id, close})
} else {
let rIndex = runtimeStore.modalList.findIndex(item => item.id === id)
if (rIndex > 0) {
runtimeStore.modalList.splice(rIndex, 1)
}
}
})
watch(watchVal, n => {
if (n) {
runtimeStore.modalList.push({id, close})
} else {
let rIndex = runtimeStore.modalList.findIndex(item => item.id === id)
if (rIndex > 0) {
runtimeStore.modalList.splice(rIndex, 1)
}
}
})
onMounted(() => {
if (watchVal() === undefined) {
runtimeStore.modalList.push({id, close})
}
})
onMounted(() => {
if (watchVal() === undefined) {
runtimeStore.modalList.push({id, close})
}
})
onUnmounted(() => {
if (watchVal() === undefined) {
let rIndex = runtimeStore.modalList.findIndex(item => item.id === id)
if (rIndex > 0) {
runtimeStore.modalList.splice(rIndex, 1)
}
}
})
onUnmounted(() => {
if (watchVal() === undefined) {
let rIndex = runtimeStore.modalList.findIndex(item => item.id === id)
if (rIndex > 0) {
runtimeStore.modalList.splice(rIndex, 1)
}
}
})
}

68
src/utils/MessageBox.tsx Normal file
View File

@@ -0,0 +1,68 @@
import {createApp} from 'vue'
import Modal from "@/components/Modal/Modal.vue";
export class MessageBox {
static confirm(
content: string,
title: string,
onOk: () => any = () => void 0,
onCancel: () => any = () => void 0,
) {
let remove = () => {
let parent = document.querySelector('.dialog-ctn')
parent.remove()
}
let tempOnCancel = () => {
remove()
onCancel()
}
const app = createApp({
render() {
return <Modal
footer={true}
title={title}
onOk={onOk}
padding={true}
onCancel={tempOnCancel}
>
<div style=' width: 350rem;color: black;'>{content}</div>
</Modal>
},
})
let parent = document.createElement('div')
parent.classList.add(...['dialog-ctn'])
document.body.append(parent)
app.mount(parent)
}
static notice(
content: string,
title: string,
) {
let remove = () => {
let parent = document.querySelector('.dialog-ctn')
parent.remove()
}
let tempOnCancel = () => {
remove()
}
const app = createApp({
render() {
return <Modal
footer={false}
title={title}
padding={true}
onCancel={tempOnCancel}
>
<div style=' width: 350rem;color: black;'>{content}</div>
</Modal>
},
})
let parent = document.createElement('div')
parent.classList.add(...['dialog-ctn'])
document.body.append(parent)
app.mount(parent)
}
}