mirror of
https://github.com/dreamhunter2333/cloudflare_temp_email.git
synced 2026-09-06 07:57:04 +08:00
feat: UI use wangeditor for send mail (#157)
This commit is contained in:
@@ -29,3 +29,4 @@ coverage
|
|||||||
|
|
||||||
.env.*
|
.env.*
|
||||||
*-dist/
|
*-dist/
|
||||||
|
components.d.ts
|
||||||
|
|||||||
@@ -14,6 +14,8 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@vicons/material": "^0.12.0",
|
"@vicons/material": "^0.12.0",
|
||||||
"@vueuse/core": "^10.9.0",
|
"@vueuse/core": "^10.9.0",
|
||||||
|
"@wangeditor/editor": "^5.1.23",
|
||||||
|
"@wangeditor/editor-for-vue": "^5.1.12",
|
||||||
"axios": "^1.6.8",
|
"axios": "^1.6.8",
|
||||||
"mail-parser-wasm": "^0.1.6",
|
"mail-parser-wasm": "^0.1.6",
|
||||||
"naive-ui": "^2.38.1",
|
"naive-ui": "^2.38.1",
|
||||||
|
|||||||
Generated
+3744
-2725
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,9 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
|
import '@wangeditor/editor/dist/css/style.css'
|
||||||
|
import { Editor, Toolbar } from '@wangeditor/editor-for-vue'
|
||||||
|
import { DomEditor } from '@wangeditor/editor'
|
||||||
import { useI18n } from 'vue-i18n'
|
import { useI18n } from 'vue-i18n'
|
||||||
import { onMounted, ref } from 'vue'
|
import { onMounted, onBeforeUnmount, ref, shallowRef } from 'vue'
|
||||||
import { useStorage } from '@vueuse/core'
|
import { useStorage } from '@vueuse/core'
|
||||||
|
|
||||||
import { useGlobalState } from '../../store'
|
import { useGlobalState } from '../../store'
|
||||||
@@ -9,13 +12,14 @@ import router from '../../router'
|
|||||||
|
|
||||||
const message = useMessage()
|
const message = useMessage()
|
||||||
const isPreview = ref(false)
|
const isPreview = ref(false)
|
||||||
|
const editorRef = shallowRef()
|
||||||
|
|
||||||
const mailModel = useStorage('mailModelCache', {
|
const mailModel = useStorage('mailModelCache', {
|
||||||
fromName: "",
|
fromName: "",
|
||||||
toName: "",
|
toName: "",
|
||||||
toMail: "",
|
toMail: "",
|
||||||
subject: "",
|
subject: "",
|
||||||
isHtml: false,
|
contentType: 'text',
|
||||||
content: "",
|
content: "",
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -30,7 +34,6 @@ const { t } = useI18n({
|
|||||||
toName: 'Recipient Name and Address, leave Name blank to use email address',
|
toName: 'Recipient Name and Address, leave Name blank to use email address',
|
||||||
subject: 'Subject',
|
subject: 'Subject',
|
||||||
options: 'Options',
|
options: 'Options',
|
||||||
isHtml: 'Enable HTML',
|
|
||||||
edit: 'Edit',
|
edit: 'Edit',
|
||||||
preview: 'Preview',
|
preview: 'Preview',
|
||||||
content: 'Content',
|
content: 'Content',
|
||||||
@@ -38,6 +41,10 @@ const { t } = useI18n({
|
|||||||
requestAccess: 'Request Access',
|
requestAccess: 'Request Access',
|
||||||
requestAccessTip: 'You need to request access to send mail, if have request, please contact admin.',
|
requestAccessTip: 'You need to request access to send mail, if have request, please contact admin.',
|
||||||
send_balance: 'Send Mail Balance Left',
|
send_balance: 'Send Mail Balance Left',
|
||||||
|
text: 'Text',
|
||||||
|
html: 'HTML',
|
||||||
|
'rich text': 'Rich Text',
|
||||||
|
tooLarge: 'Too large file, please upload file less than 1MB.',
|
||||||
},
|
},
|
||||||
zh: {
|
zh: {
|
||||||
successSend: '请查看您的发件箱, 如果失败, 请检查您的余额或稍后重试。',
|
successSend: '请查看您的发件箱, 如果失败, 请检查您的余额或稍后重试。',
|
||||||
@@ -45,7 +52,6 @@ const { t } = useI18n({
|
|||||||
toName: '收件人名称和地址,名称不填写则使用邮箱地址',
|
toName: '收件人名称和地址,名称不填写则使用邮箱地址',
|
||||||
subject: '主题',
|
subject: '主题',
|
||||||
options: '选项',
|
options: '选项',
|
||||||
isHtml: '启用HTML',
|
|
||||||
edit: '编辑',
|
edit: '编辑',
|
||||||
preview: '预览',
|
preview: '预览',
|
||||||
content: '内容',
|
content: '内容',
|
||||||
@@ -53,10 +59,20 @@ const { t } = useI18n({
|
|||||||
requestAccess: '申请权限',
|
requestAccess: '申请权限',
|
||||||
requestAccessTip: '您需要申请权限才能发送邮件, 如果已经申请过, 请联系管理员提升额度。',
|
requestAccessTip: '您需要申请权限才能发送邮件, 如果已经申请过, 请联系管理员提升额度。',
|
||||||
send_balance: '剩余发送邮件额度',
|
send_balance: '剩余发送邮件额度',
|
||||||
|
text: '文本',
|
||||||
|
html: 'HTML',
|
||||||
|
'rich text': '富文本',
|
||||||
|
tooLarge: '文件过大, 请上传小于1MB的文件。',
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const contentTypes = [
|
||||||
|
{ label: t('text'), value: 'text' },
|
||||||
|
{ label: t('html'), value: 'html' },
|
||||||
|
{ label: t('rich text'), value: 'rich' },
|
||||||
|
]
|
||||||
|
|
||||||
const send = async () => {
|
const send = async () => {
|
||||||
try {
|
try {
|
||||||
await api.fetch(`/api/send_mail`,
|
await api.fetch(`/api/send_mail`,
|
||||||
@@ -68,7 +84,7 @@ const send = async () => {
|
|||||||
to_name: mailModel.value.toName,
|
to_name: mailModel.value.toName,
|
||||||
to_mail: mailModel.value.toMail,
|
to_mail: mailModel.value.toMail,
|
||||||
subject: mailModel.value.subject,
|
subject: mailModel.value.subject,
|
||||||
is_html: mailModel.value.isHtml,
|
is_html: mailModel.value.contentType != 'text',
|
||||||
content: mailModel.value.content,
|
content: mailModel.value.content,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@@ -77,7 +93,7 @@ const send = async () => {
|
|||||||
toName: "",
|
toName: "",
|
||||||
toMail: "",
|
toMail: "",
|
||||||
subject: "",
|
subject: "",
|
||||||
isHtml: false,
|
contentType: 'text',
|
||||||
content: "",
|
content: "",
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -103,6 +119,33 @@ const requestAccess = async () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const toolbarConfig = {
|
||||||
|
excludeKeys: ["uploadVideo"]
|
||||||
|
}
|
||||||
|
|
||||||
|
const editorConfig = {
|
||||||
|
MENU_CONF: {
|
||||||
|
'uploadImage': {
|
||||||
|
async customUpload() {
|
||||||
|
message.error(t('tooLarge'))
|
||||||
|
},
|
||||||
|
maxFileSize: 1 * 1024 * 1024,
|
||||||
|
base64LimitSize: 1 * 1024 * 1024,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
const editor = editorRef.value
|
||||||
|
if (editor == null) return
|
||||||
|
editor.destroy()
|
||||||
|
})
|
||||||
|
|
||||||
|
const handleCreated = (editor) => {
|
||||||
|
editorRef.value = editor;
|
||||||
|
console.log(editor.getAllMenuKeys())
|
||||||
|
}
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
await api.getSettings();
|
await api.getSettings();
|
||||||
})
|
})
|
||||||
@@ -143,18 +186,29 @@ onMounted(async () => {
|
|||||||
<n-input v-model:value="mailModel.subject" />
|
<n-input v-model:value="mailModel.subject" />
|
||||||
</n-form-item>
|
</n-form-item>
|
||||||
<n-form-item :label="t('options')" label-placement="top">
|
<n-form-item :label="t('options')" label-placement="top">
|
||||||
<n-checkbox v-model:checked="mailModel.isHtml">
|
<n-radio-group v-model:value="mailModel.contentType">
|
||||||
{{ t('isHtml') }}
|
<n-radio-button v-for="option in contentTypes" :key="option.value" :value="option.value"
|
||||||
</n-checkbox>
|
:label="option.label" />
|
||||||
<n-button v-if="mailModel.isHtml" @click="isPreview = !isPreview">
|
</n-radio-group>
|
||||||
|
<n-button v-if="mailModel.contentType != 'text'" @click="isPreview = !isPreview"
|
||||||
|
style="margin-left: 10px;">
|
||||||
{{ isPreview ? t('edit') : t('preview') }}
|
{{ isPreview ? t('edit') : t('preview') }}
|
||||||
</n-button>
|
</n-button>
|
||||||
</n-form-item>
|
</n-form-item>
|
||||||
<n-form-item :label="t('content')" label-placement="top">
|
<n-form-item :label="t('content')" label-placement="top">
|
||||||
<div v-if="isPreview" v-html="mailModel.content" />
|
<n-card v-if="isPreview">
|
||||||
|
<div v-html="mailModel.content" />
|
||||||
|
</n-card>
|
||||||
|
<div v-else-if="mailModel.contentType == 'rich'" style="border: 1px solid #ccc">
|
||||||
|
<Toolbar style="border-bottom: 1px solid #ccc" :defaultConfig="toolbarConfig"
|
||||||
|
:editor="editorRef" mode="default" />
|
||||||
|
<Editor style="height: 500px; overflow-y: hidden;" v-model="mailModel.content"
|
||||||
|
:defaultConfig="editorConfig" mode="default" @onCreated="handleCreated" />
|
||||||
|
</div>
|
||||||
<n-input v-else type="textarea" v-model:value="mailModel.content" :autosize="{
|
<n-input v-else type="textarea" v-model:value="mailModel.content" :autosize="{
|
||||||
minRows: 3
|
minRows: 3
|
||||||
}" />
|
}" />
|
||||||
|
|
||||||
</n-form-item>
|
</n-form-item>
|
||||||
</n-form>
|
</n-form>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ import { fileURLToPath, URL } from 'node:url'
|
|||||||
import { defineConfig } from 'vite'
|
import { defineConfig } from 'vite'
|
||||||
import vue from '@vitejs/plugin-vue'
|
import vue from '@vitejs/plugin-vue'
|
||||||
import { VitePWA } from 'vite-plugin-pwa'
|
import { VitePWA } from 'vite-plugin-pwa'
|
||||||
import { splitVendorChunkPlugin } from 'vite';
|
|
||||||
import AutoImport from 'unplugin-auto-import/vite'
|
import AutoImport from 'unplugin-auto-import/vite'
|
||||||
import Components from 'unplugin-vue-components/vite'
|
import Components from 'unplugin-vue-components/vite'
|
||||||
import { NaiveUiResolver } from 'unplugin-vue-components/resolvers'
|
import { NaiveUiResolver } from 'unplugin-vue-components/resolvers'
|
||||||
@@ -14,12 +13,20 @@ import topLevelAwait from "vite-plugin-top-level-await";
|
|||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
build: {
|
build: {
|
||||||
outDir: './dist',
|
outDir: './dist',
|
||||||
|
rollupOptions: {
|
||||||
|
output: {
|
||||||
|
manualChunks(id) {
|
||||||
|
if (id.includes('wangeditor')) {
|
||||||
|
return 'vendor-wangeditor';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
vue(),
|
vue(),
|
||||||
wasm(),
|
wasm(),
|
||||||
topLevelAwait(),
|
topLevelAwait(),
|
||||||
splitVendorChunkPlugin(),
|
|
||||||
AutoImport({
|
AutoImport({
|
||||||
imports: [
|
imports: [
|
||||||
'vue',
|
'vue',
|
||||||
|
|||||||
Reference in New Issue
Block a user