mirror of
https://github.com/dreamhunter2333/cloudflare_temp_email.git
synced 2026-09-13 19:36:30 +08:00
* feat(i18n): enhance locale handling and routing - Implemented dynamic locale aliases in router configuration. - Added support for preferred locale storage in global state. - Improved locale resolution logic in router beforeEach guard. - Created utility functions for locale management and path manipulation. - Added tests for locale matching and message extraction. - Updated Header component to allow language selection. - Refactored getRouterPathWithLang to utilize new locale utilities. - Updated Vite configuration to support aliasing for vue-i18n. - Bumped version numbers across various packages to 1.9.0. * feat(i18n): update version to 1.8.0 and enhance locale handling - Updated version numbers across all package.json files to 1.8.0. - Enhanced locale handling in App.vue by centralizing locale configurations. - Improved Turnstile component to support dynamic language rendering. - Refactored i18n utilities to include initial locale setup and empty locale messages. - Updated i18n.ts to utilize the new locale management structure. - Added naive-locale.ts for better integration with Naive UI's locale handling. - Adjusted Header.vue to streamline language selection and locale changes. - Fixed translations in multiple locale files for consistency and accuracy. * fix(i18n): address review feedback * feat(i18n): update default locale to English and enhance language handling in components * fix(i18n): switch locale selector to dropdown * docs: add topbar language and github order design spec * fix(i18n): 修复 Header 语言切换器相关问题,恢复为独立控件并调整样式 * Refactor locale handling in router and add locale-guard utility functions - Improved locale resolution logic in router by introducing utility functions for better readability and maintainability. - Added `locale-guard.js` to encapsulate locale-related functions such as getting route locale, resolving locale for navigation, and applying locale navigation state. - Updated JWT synchronization logic to streamline the handling of JWT from query parameters. - Modified i18n messages test to check for coverage of registered locale message keys instead of extracting English source messages. * 删除顶部栏语言和GitHub顺序设计文档 * fix: 修复前端设置初始化时未返回 domains 数组导致的 undefined 错误 * refactor(i18n): consolidate locale infrastructure * fix(i18n): stabilize locale route switching * fix(i18n): persist default locale selection * fix(i18n): 修复前端设置初始化时未返回 domains 数组导致的 undefined 错误,统一按空数组兜底处理 feat(i18n): 添加 locale 别名处理,支持默认语言的重定向 test(i18n): 增加对默认语言别名重定向的测试用例 * refactor: replace useAppI18n with useScopedI18n in multiple components for improved localization management * fix(tests): 移除不必要的 URL 断言以简化 Passkey 测试 * fix(i18n): 更新语言切换逻辑,确保使用当前语言设置进行路由导航 * fix(i18n): 强制路由切换以确保语言切换后正确导航 * refactor(i18n): 优化消息注册和路由本地化逻辑,移除冗余代码 * refactor(i18n): 拆分 API 文件以优化路由管理,更新语言处理逻辑 * fix: align i18n release notes and frontend test script
161 lines
5.4 KiB
Vue
161 lines
5.4 KiB
Vue
<script setup>
|
|
import { defineAsyncComponent, onMounted, watch } from 'vue'
|
|
import { useScopedI18n } from '@/i18n/app'
|
|
import { useRoute } from 'vue-router'
|
|
|
|
import { useGlobalState } from '../store'
|
|
import { api } from '../api'
|
|
import { useIsMobile } from '../utils/composables'
|
|
import { FullscreenExitOutlined } from '@vicons/material'
|
|
|
|
import AddressBar from './index/AddressBar.vue';
|
|
import MailBox from '../components/MailBox.vue';
|
|
import SendBox from '../components/SendBox.vue';
|
|
import AutoReply from './index/AutoReply.vue';
|
|
import AccountSettings from './index/AccountSettings.vue';
|
|
import Appearance from './common/Appearance.vue';
|
|
import Webhook from './index/Webhook.vue';
|
|
import Attachment from './index/Attachment.vue';
|
|
import About from './common/About.vue';
|
|
import SimpleIndex from './index/SimpleIndex.vue';
|
|
|
|
const { loading, settings, openSettings, indexTab, globalTabplacement, useSimpleIndex } = useGlobalState()
|
|
const message = useMessage()
|
|
const route = useRoute()
|
|
const isMobile = useIsMobile()
|
|
|
|
const SendMail = defineAsyncComponent(() => {
|
|
loading.value = true;
|
|
return import('./index/SendMail.vue')
|
|
.finally(() => loading.value = false);
|
|
});
|
|
|
|
const { t } = useScopedI18n('views.Index')
|
|
|
|
const fetchMailData = async (limit, offset) => {
|
|
if (mailIdQuery.value > 0) {
|
|
const singleMail = await api.fetch(`/api/mail/${mailIdQuery.value}`);
|
|
if (singleMail) return { results: [singleMail], count: 1 };
|
|
return { results: [], count: 0 };
|
|
}
|
|
return await api.fetch(`/api/mails?limit=${limit}&offset=${offset}`);
|
|
};
|
|
|
|
const deleteMail = async (curMailId) => {
|
|
await api.fetch(`/api/mails/${curMailId}`, { method: 'DELETE' });
|
|
};
|
|
|
|
const deleteSenboxMail = async (curMailId) => {
|
|
await api.fetch(`/api/sendbox/${curMailId}`, { method: 'DELETE' });
|
|
};
|
|
|
|
const fetchSenboxData = async (limit, offset) => {
|
|
return await api.fetch(`/api/sendbox?limit=${limit}&offset=${offset}`);
|
|
};
|
|
|
|
const saveToS3 = async (mail_id, filename, blob) => {
|
|
try {
|
|
const { url } = await api.fetch(`/api/attachment/put_url`, {
|
|
method: 'POST',
|
|
body: JSON.stringify({ key: `${mail_id}/${filename}` })
|
|
});
|
|
// upload to s3 by formdata
|
|
const formData = new FormData();
|
|
formData.append(filename, blob);
|
|
await fetch(url, {
|
|
method: 'PUT',
|
|
body: formData
|
|
});
|
|
message.success(t('saveToS3Success'));
|
|
} catch (error) {
|
|
console.error(error);
|
|
message.error(error.message || "save to s3 error");
|
|
}
|
|
}
|
|
|
|
const mailBoxKey = ref("")
|
|
const mailIdQuery = ref("")
|
|
const showMailIdQuery = ref(false)
|
|
|
|
const queryMail = () => {
|
|
mailBoxKey.value = Date.now();
|
|
}
|
|
|
|
watch(route, () => {
|
|
if (!route.query.mail_id) {
|
|
showMailIdQuery.value = false;
|
|
mailIdQuery.value = "";
|
|
queryMail();
|
|
}
|
|
})
|
|
|
|
onMounted(() => {
|
|
if (route.query.mail_id) {
|
|
showMailIdQuery.value = true;
|
|
mailIdQuery.value = route.query.mail_id;
|
|
queryMail();
|
|
}
|
|
})
|
|
</script>
|
|
|
|
<template>
|
|
<div>
|
|
<div v-if="useSimpleIndex">
|
|
<SimpleIndex />
|
|
</div>
|
|
<div v-else>
|
|
<AddressBar />
|
|
<n-tabs v-if="settings.address" type="card" v-model:value="indexTab" :placement="globalTabplacement">
|
|
<template #prefix v-if="!isMobile">
|
|
<n-button @click="useSimpleIndex = true" tertiary size="small">
|
|
<template #icon>
|
|
<n-icon>
|
|
<FullscreenExitOutlined />
|
|
</n-icon>
|
|
</template>
|
|
{{ t('enterSimpleMode') }}
|
|
</n-button>
|
|
</template>
|
|
<n-tab-pane name="mailbox" :tab="t('mailbox')">
|
|
<div v-if="showMailIdQuery" style="margin-bottom: 10px;">
|
|
<n-input-group>
|
|
<n-input v-model:value="mailIdQuery" />
|
|
<n-button @click="queryMail" type="primary" tertiary>
|
|
{{ t('query') }}
|
|
</n-button>
|
|
</n-input-group>
|
|
</div>
|
|
<MailBox :key="mailBoxKey" :showEMailTo="false" :showReply="openSettings.enableSendMail" :showSaveS3="openSettings.isS3Enabled"
|
|
:saveToS3="saveToS3" :enableUserDeleteEmail="openSettings.enableUserDeleteEmail"
|
|
:fetchMailData="fetchMailData" :deleteMail="deleteMail" :showFilterInput="true" />
|
|
</n-tab-pane>
|
|
<n-tab-pane v-if="openSettings.enableSendMail" name="sendbox" :tab="t('sendbox')">
|
|
<SendBox :fetchMailData="fetchSenboxData" :enableUserDeleteEmail="openSettings.enableUserDeleteEmail"
|
|
:deleteMail="deleteSenboxMail" />
|
|
</n-tab-pane>
|
|
<n-tab-pane v-if="openSettings.enableSendMail" name="sendmail" :tab="t('sendmail')">
|
|
<SendMail />
|
|
</n-tab-pane>
|
|
<n-tab-pane name="accountSettings" :tab="t('accountSettings')">
|
|
<AccountSettings />
|
|
</n-tab-pane>
|
|
<n-tab-pane name="appearance" :tab="t('appearance')">
|
|
<Appearance :showUseSimpleIndex="true" />
|
|
</n-tab-pane>
|
|
<n-tab-pane v-if="openSettings.enableAutoReply" name="auto_reply" :tab="t('auto_reply')">
|
|
<AutoReply />
|
|
</n-tab-pane>
|
|
<n-tab-pane v-if="openSettings.enableWebhook" name="webhook" :tab="t('webhookSettings')">
|
|
<Webhook />
|
|
</n-tab-pane>
|
|
<n-tab-pane v-if="openSettings.isS3Enabled" name="s3_attachment" :tab="t('s3Attachment')">
|
|
<Attachment />
|
|
</n-tab-pane>
|
|
<n-tab-pane v-if="openSettings.enableIndexAbout" name="about" :tab="t('about')">
|
|
<About />
|
|
</n-tab-pane>
|
|
</n-tabs>
|
|
</div>
|
|
</div>
|
|
</template>
|