feat: UI: move account releated code to header.vue (#84)

This commit is contained in:
Dream Hunter
2024-03-31 16:16:15 +08:00
committed by GitHub
parent ce7430393e
commit a8e961caf4
5 changed files with 168 additions and 147 deletions
+11 -7
View File
@@ -63,14 +63,18 @@ const getOpenSettings = async (message) => {
} }
const getSettings = async () => { const getSettings = async () => {
if (typeof jwt.value != 'string' || jwt.value.trim() === '' || jwt.value === 'undefined') { try {
return ""; if (typeof jwt.value != 'string' || jwt.value.trim() === '' || jwt.value === 'undefined') {
return "";
}
const res = await apiFetch("/api/settings");;
settings.value = {
address: res["address"],
auto_reply: res["auto_reply"]
};
} finally {
settings.value.fetched = true;
} }
const res = await apiFetch("/api/settings");;
settings.value = {
address: res["address"],
auto_reply: res["auto_reply"]
};
} }
const adminShowPassword = async (id) => { const adminShowPassword = async (id) => {
+3
View File
@@ -13,6 +13,7 @@ export const useGlobalState = createGlobalState(
}] }]
}) })
const settings = ref({ const settings = ref({
fetched: false,
address: '', address: '',
auto_reply: { auto_reply: {
subject: '', subject: '',
@@ -29,6 +30,7 @@ export const useGlobalState = createGlobalState(
const jwt = useStorage('jwt', ''); const jwt = useStorage('jwt', '');
const localeCache = useStorage('locale', 'zhCN'); const localeCache = useStorage('locale', 'zhCN');
const themeSwitch = useStorage('themeSwitch', false); const themeSwitch = useStorage('themeSwitch', false);
const showLogin = ref(false);
return { return {
loading, loading,
settings, settings,
@@ -40,6 +42,7 @@ export const useGlobalState = createGlobalState(
themeSwitch, themeSwitch,
adminAuth, adminAuth,
showAdminAuth, showAdminAuth,
showLogin,
} }
}, },
) )
+3 -118
View File
@@ -12,18 +12,13 @@ import { api } from '../api'
import { CloudDownloadRound } from '@vicons/material' import { CloudDownloadRound } from '@vicons/material'
import { useIsMobile } from '../utils/composables' import { useIsMobile } from '../utils/composables'
const { toClipboard } = useClipboard()
const message = useMessage() const message = useMessage()
const isMobile = useIsMobile() const isMobile = useIsMobile()
const { jwt, settings, openSettings, themeSwitch } = useGlobalState() const { settings, themeSwitch } = useGlobalState()
const autoRefresh = ref(false) const autoRefresh = ref(false)
const data = ref([]) const data = ref([])
const timer = ref(null) const timer = ref(null)
const showPassword = ref(false)
const showNewEmail = ref(false)
const emailName = ref("")
const emailDomain = ref("")
const count = ref(0) const count = ref(0)
const page = ref(1) const page = ref(1)
@@ -31,41 +26,20 @@ const pageSize = ref(20)
const showAttachments = ref(false) const showAttachments = ref(false)
const curAttachments = ref([]) const curAttachments = ref([])
const curMail = ref(null);
const { t } = useI18n({ const { t } = useI18n({
locale: 'zh', locale: 'zh',
messages: { messages: {
en: { en: {
yourAddress: 'Your email address is',
pleaseGetNewEmail: 'Please click "Get New Email" button to get a new email address',
getNewEmail: 'Get New Email',
getNewEmailTip1: 'Please input the email you want to use.',
getNewEmailTip2: 'Levaing it blank will generate a random email address.',
cancel: 'Cancel',
ok: 'OK',
copy: 'Copy',
showPassword: 'Show Password',
autoRefresh: 'Auto Refresh', autoRefresh: 'Auto Refresh',
refresh: 'Refresh', refresh: 'Refresh',
password: 'Password',
passwordTip: 'Please copy the password and you can use it to login to your email account.',
attachments: 'Show Attachments', attachments: 'Show Attachments',
pleaseSelectMail: "Please select a mail to view." pleaseSelectMail: "Please select a mail to view."
}, },
zh: { zh: {
yourAddress: '你的邮箱地址是',
pleaseGetNewEmail: '请点击 "获取新邮箱" 按钮来获取一个新的邮箱地址',
getNewEmail: '获取新邮箱',
getNewEmailTip1: '请输入你想要使用的邮箱地址。',
getNewEmailTip2: '留空将会生成一个随机的邮箱地址。',
cancel: '取消',
ok: '确定',
copy: '复制',
showPassword: '显示密码',
autoRefresh: '自动刷新', autoRefresh: '自动刷新',
refresh: '刷新', refresh: '刷新',
password: '密码',
passwordTip: '请复制密码,你可以使用它登录你的邮箱。',
attachments: '查看附件', attachments: '查看附件',
pleaseSelectMail: "请选择一封邮件查看。" pleaseSelectMail: "请选择一封邮件查看。"
} }
@@ -116,33 +90,6 @@ const refresh = async () => {
} }
}; };
const copy = async () => {
try {
await toClipboard(settings.value.address)
message.success('Copied');
} catch (e) {
message.error(e.message || "error");
}
}
const newEmail = async () => {
try {
const res = await api.fetch(
`/api/new_address`
+ `?name=${emailName.value || ''}`
+ `&domain=${emailDomain.value || ''}`
);
jwt.value = res["jwt"];
await api.getSettings();
await refresh();
showNewEmail.value = false;
showPassword.value = true;
} catch (error) {
message.error(error.message || "error");
}
};
const curMail = ref(null);
const clickRow = async (row) => { const clickRow = async (row) => {
curMail.value = row; curMail.value = row;
}; };
@@ -173,8 +120,6 @@ const getAttachments = async (attachment_id) => {
}; };
onMounted(async () => { onMounted(async () => {
await api.getOpenSettings(message);
emailDomain.value = openSettings.value.domains ? openSettings.value.domains[0].value : "";
await api.getSettings(); await api.getSettings();
await refresh(); await refresh();
}); });
@@ -182,24 +127,7 @@ onMounted(async () => {
<template> <template>
<div> <div>
<n-layout> <n-layout v-if="settings.address">
<n-alert :type='settings.address ? "info" : "warning"' show-icon>
<span v-if="settings.address">
{{ t('yourAddress') }} <b>{{ settings.address }}</b>
<n-button size="small" class="center" @click="showPassword = true" tertiary round type="primary">
{{ t('showPassword') }}
</n-button>
<n-button @click="copy" size="small" tertiary round type="primary">
{{ t('copy') }}
</n-button>
</span>
<span v-else>
{{ t('pleaseGetNewEmail') }}
<n-button class="center" @click="showNewEmail = true" tertiary round type="primary">
{{ t('getNewEmail') }}
</n-button>
</span>
</n-alert>
<n-split class="left" v-if="!isMobile" direction="horizontal" :max="0.75" :min="0.25" default-size="0.25"> <n-split class="left" v-if="!isMobile" direction="horizontal" :max="0.75" :min="0.25" default-size="0.25">
<template #1> <template #1>
<div> <div>
@@ -310,44 +238,6 @@ onMounted(async () => {
</n-drawer> </n-drawer>
</div> </div>
</n-layout> </n-layout>
<n-modal v-model:show="showNewEmail" preset="dialog" title="Dialog">
<template #header>
<div>{{ t('getNewEmail') }}</div>
</template>
<span>
<p>{{ t("getNewEmailTip1") }}</p>
<p>{{ t("getNewEmailTip2") }}</p>
</span>
<n-input-group>
<n-input-group-label v-if="openSettings.prefix">
{{ openSettings.prefix }}
</n-input-group-label>
<n-input v-model:value="emailName" />
<n-input-group-label>@</n-input-group-label>
<n-select v-model:value="emailDomain" :consistent-menu-width="false" :options="openSettings.domains" />
</n-input-group>
<template #action>
<n-button @click="showNewEmail = false">
{{ t('cancel') }}
</n-button>
<n-button @click="newEmail" type="primary">
{{ t('ok') }}
</n-button>
</template>
</n-modal>
<n-modal v-model:show="showPassword" preset="dialog" title="Dialog">
<template #header>
<div>{{ t("password") }}</div>
</template>
<span>
<p>{{ t("passwordTip") }}</p>
</span>
<n-card>
<b>{{ jwt }}</b>
</n-card>
<template #action>
</template>
</n-modal>
<n-modal v-model:show="showAttachments" preset="dialog" title="Dialog"> <n-modal v-model:show="showAttachments" preset="dialog" title="Dialog">
<template #header> <template #header>
<div>{{ t("attachments") }}</div> <div>{{ t("attachments") }}</div>
@@ -378,11 +268,6 @@ onMounted(async () => {
</template> </template>
<style scoped> <style scoped>
.n-alert {
margin-bottom: 10px;
text-align: center;
}
.left { .left {
overflow: scroll; overflow: scroll;
text-align: left; text-align: left;
+148 -19
View File
@@ -1,8 +1,11 @@
<script setup> <script setup>
import { NGrid, NLayoutHeader, NInput } from 'naive-ui' import { NGrid, NLayoutHeader, NInput } from 'naive-ui'
import { NButton, NSelect, NModal, NIcon, NMenu } from 'naive-ui' import { NButton, NSelect, NModal, NIcon, NMenu, NAlert } from 'naive-ui'
import { NSwitch, NPopconfirm } from 'naive-ui' import { NInputGroup, NInputGroupLabel, NCard, NResult } from 'naive-ui'
import { ref, h, computed } from 'vue' import { NSwitch, NPopconfirm, NSkeleton } from 'naive-ui'
import { useMessage } from 'naive-ui'
import useClipboard from 'vue-clipboard3'
import { ref, h, computed, onMounted } from 'vue'
import { useI18n } from 'vue-i18n' import { useI18n } from 'vue-i18n'
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
import { useIsMobile } from '../utils/composables' import { useIsMobile } from '../utils/composables'
@@ -10,14 +13,20 @@ import { DarkModeFilled, DarkModeOutlined, StarOutlineFilled, MenuFilled } from
import { useGlobalState } from '../store' import { useGlobalState } from '../store'
import { api } from '../api' import { api } from '../api'
const { toClipboard } = useClipboard()
const message = useMessage()
const { jwt, localeCache, themeSwitch, showAuth, adminAuth, auth } = useGlobalState() const { jwt, localeCache, themeSwitch, showAuth, adminAuth, auth } = useGlobalState()
const { showLogin, openSettings, settings } = useGlobalState()
const router = useRouter() const router = useRouter()
const isMobile = useIsMobile() const isMobile = useIsMobile()
const showLogin = ref(false) const showNewEmail = ref(false)
const showLogout = ref(false) const showLogout = ref(false)
const password = ref('') const password = ref('')
const showPassword = ref(false)
const emailName = ref("")
const emailDomain = ref("")
const login = async () => { const login = async () => {
try { try {
@@ -61,7 +70,18 @@ const { t } = useI18n({
authTip: 'Please enter the correct auth code', authTip: 'Please enter the correct auth code',
settings: 'Settings', settings: 'Settings',
home: 'Home', home: 'Home',
menu: 'Menu' menu: 'Menu',
pleaseGetNewEmail: 'Please login or click "Get New Email" button to get a new email address',
getNewEmail: 'Get New Email',
getNewEmailTip1: 'Please input the email you want to use.',
getNewEmailTip2: 'Levaing it blank will generate a random email address.',
yourAddress: 'Your email address is',
password: 'Password',
passwordTip: 'Please copy the password and you can use it to login to your email account.', cancel: 'Cancel',
ok: 'OK',
copy: 'Copy',
copied: 'Copied',
showPassword: 'Show Password', fetchAddressError: 'Fetch address error, maybe your jwt is invalid or network error.',
}, },
zh: { zh: {
title: 'Cloudflare 临时邮件', title: 'Cloudflare 临时邮件',
@@ -74,7 +94,20 @@ const { t } = useI18n({
authTip: '请输入正确的授权码', authTip: '请输入正确的授权码',
settings: '设置', settings: '设置',
home: '主页', home: '主页',
menu: '菜单' menu: '菜单',
pleaseGetNewEmail: '请"登录"或点击 "获取新邮箱" 按钮来获取一个新的邮箱地址',
getNewEmail: '获取新邮箱',
getNewEmailTip1: '请输入你想要使用的邮箱地址。',
getNewEmailTip2: '留空将会生成一个随机的邮箱地址。',
yourAddress: '你的邮箱地址是',
password: '密码',
passwordTip: '请复制密码,你可以使用它登录你的邮箱。',
cancel: '取消',
ok: '确定',
copy: '复制',
copied: '已复制',
showPassword: '显示密码',
fetchAddressError: '获取地址失败, 请检查你的 jwt 是否有效 或 网络是否正常。',
} }
} }
}); });
@@ -120,19 +153,6 @@ const menuOptions = computed(() => [
), ),
key: "lang" key: "lang"
}, },
{
label: () => h(
NButton,
{
tertiary: true,
ghost: true,
onClick: () => { showLogin.value = true }
},
{ default: () => t('login') }
),
show: !jwt.value,
key: "login"
},
{ {
label: () => h( label: () => h(
NButton, NButton,
@@ -156,6 +176,7 @@ const menuOptions = computed(() => [
}, },
{ default: () => t('settings') } { default: () => t('settings') }
), ),
show: !!settings.value.address,
key: "settings" key: "settings"
} }
]); ]);
@@ -173,6 +194,37 @@ const menuOptionsMobile = [
children: menuOptions.value children: menuOptions.value
}, },
]; ];
const copy = async () => {
try {
await toClipboard(settings.value.address)
message.success(t('copied'));
} catch (e) {
message.error(e.message || "error");
}
}
const newEmail = async () => {
try {
const res = await api.fetch(
`/api/new_address`
+ `?name=${emailName.value || ''}`
+ `&domain=${emailDomain.value || ''}`
);
jwt.value = res["jwt"];
await api.getSettings();
showNewEmail.value = false;
showPassword.value = true;
} catch (error) {
message.error(error.message || "error");
}
};
onMounted(async () => {
await api.getOpenSettings(message);
emailDomain.value = openSettings.value.domains ? openSettings.value.domains[0].value : "";
});
</script> </script>
<template> <template>
@@ -198,6 +250,73 @@ const menuOptionsMobile = [
</n-button> </n-button>
</div> </div>
</n-layout-header> </n-layout-header>
<n-card v-if="!settings.fetched">
<n-skeleton style="height: 50vh" />
</n-card>
<n-alert v-else-if="settings.address" type="info" show-icon>
<span>
{{ t('yourAddress') }} <b>{{ settings.address }}</b>
<n-button size="small" class="center" @click="showPassword = true" tertiary round type="primary">
{{ t('showPassword') }}
</n-button>
<n-button @click="copy" size="small" tertiary round type="primary">
{{ t('copy') }}
</n-button>
</span>
</n-alert>
<n-card v-else>
<n-result status="info" :description="t('pleaseGetNewEmail')">
<template #footer>
<n-alert v-if="jwt" type="warning" show-icon>
<span>{{ t('fetchAddressError') }}</span>
</n-alert>
<n-button @click="showLogin = true" tertiary round type="primary">
{{ t('login') }}
</n-button>
<n-button @click="showNewEmail = true" tertiary round type="primary">
{{ t('getNewEmail') }}
</n-button>
</template>
</n-result>
</n-card>
<n-modal v-model:show="showNewEmail" preset="dialog" title="Dialog">
<template #header>
<div>{{ t('getNewEmail') }}</div>
</template>
<span>
<p>{{ t("getNewEmailTip1") }}</p>
<p>{{ t("getNewEmailTip2") }}</p>
</span>
<n-input-group>
<n-input-group-label v-if="openSettings.prefix">
{{ openSettings.prefix }}
</n-input-group-label>
<n-input v-model:value="emailName" />
<n-input-group-label>@</n-input-group-label>
<n-select v-model:value="emailDomain" :consistent-menu-width="false" :options="openSettings.domains" />
</n-input-group>
<template #action>
<n-button @click="showNewEmail = false">
{{ t('cancel') }}
</n-button>
<n-button @click="newEmail" type="primary">
{{ t('ok') }}
</n-button>
</template>
</n-modal>
<n-modal v-model:show="showPassword" preset="dialog" title="Dialog">
<template #header>
<div>{{ t("password") }}</div>
</template>
<span>
<p>{{ t("passwordTip") }}</p>
</span>
<n-card>
<b>{{ jwt }}</b>
</n-card>
<template #action>
</template>
</n-modal>
<n-modal v-model:show="showLogin" preset="dialog" title="Dialog"> <n-modal v-model:show="showLogin" preset="dialog" title="Dialog">
<template #header> <template #header>
<div>{{ t('login') }}</div> <div>{{ t('login') }}</div>
@@ -246,4 +365,14 @@ const menuOptionsMobile = [
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
} }
.n-alert {
margin-top: 10px;
margin-bottom: 10px;
text-align: center;
}
.n-card {
margin-top: 10px;
}
</style> </style>
+3 -3
View File
@@ -73,13 +73,13 @@ const saveSettings = async () => {
} }
} }
onMounted(() => { onMounted(async () => {
getSettings() await getSettings()
}) })
</script> </script>
<template> <template>
<n-space vertical> <n-space v-if="settings.address" vertical>
<Header /> <Header />
<h1>{{ t("settings") }}</h1> <h1>{{ t("settings") }}</h1>
<n-button type="primary" @click="saveSettings">{{ t('save') }}</n-button> <n-button type="primary" @click="saveSettings">{{ t('save') }}</n-button>