refactor(i18n): 移除多语言支持及相关组件,切换登录页文本为中文
- 删除英文和中文语言文件,去除国际化配置 - 移除语言切换组件 LangSwitch.vue - 登录页中静态替换多语言文本为中文文本 - 站点头部登录、退出等文案替换为中文 - 更新 Nuxt 配置,移除 i18n 模块和相关配置 - 保持核心功能不变,只保留中文语言显示
This commit is contained in:
@@ -1,53 +0,0 @@
|
||||
<template>
|
||||
<a-dropdown :trigger="['click']" placement="bottomRight">
|
||||
<a-button type="text" class="lang-btn">
|
||||
<template #icon>
|
||||
<GlobalOutlined />
|
||||
</template>
|
||||
<span class="current-lang">{{ currentLocaleName }}</span>
|
||||
<DownOutlined class="ml-1" />
|
||||
</a-button>
|
||||
<template #overlay>
|
||||
<a-menu @click="switchLocale">
|
||||
<a-menu-item v-for="loc in availableLocales" :key="loc.code">
|
||||
<div class="flex items-center justify-between gap-4">
|
||||
<span>{{ loc.name }}</span>
|
||||
<CheckOutlined v-if="loc.code === currentLocale" class="text-green-500" />
|
||||
</div>
|
||||
</a-menu-item>
|
||||
</a-menu>
|
||||
</template>
|
||||
</a-dropdown>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { GlobalOutlined, DownOutlined, CheckOutlined } from '@ant-design/icons-vue'
|
||||
|
||||
const { locale: currentLocale, locales, setLocale } = useI18n()
|
||||
|
||||
const availableLocales = computed(() => {
|
||||
return (locales.value as Array<{ code: string; name: string }>).map((l) => ({
|
||||
code: l.code,
|
||||
name: l.name
|
||||
}))
|
||||
})
|
||||
|
||||
const currentLocaleName = computed(() => {
|
||||
const found = availableLocales.value.find((l) => l.code === currentLocale.value)
|
||||
return found?.name || currentLocale.value
|
||||
})
|
||||
|
||||
async function switchLocale({ key }: { key: string }) {
|
||||
await setLocale(key)
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.lang-btn {
|
||||
@apply text-gray-300 hover:text-white;
|
||||
}
|
||||
|
||||
.current-lang {
|
||||
@apply text-sm;
|
||||
}
|
||||
</style>
|
||||
@@ -44,7 +44,7 @@
|
||||
<!-- PC 端:登录/头像 -->
|
||||
<div class="hidden md:flex items-center gap-3">
|
||||
<template v-if="!isAuthed">
|
||||
<a-button type="primary" @click="navigateTo('/login')">{{ $t('nav.login') }}</a-button>
|
||||
<a-button type="primary" @click="navigateTo('/login')">{{ '登录' }}</a-button>
|
||||
</template>
|
||||
<template v-else>
|
||||
<!-- 用户头像 -->
|
||||
@@ -66,7 +66,7 @@
|
||||
<a-menu-item key="admin">⚙️ 后台管理</a-menu-item>
|
||||
</template>
|
||||
<a-menu-divider />
|
||||
<a-menu-item key="logout">{{ $t('nav.logout') }}</a-menu-item>
|
||||
<a-menu-item key="logout">{{ '退出登录' }}</a-menu-item>
|
||||
</a-menu>
|
||||
</template>
|
||||
</a-dropdown>
|
||||
@@ -84,7 +84,7 @@
|
||||
</a-layout-header>
|
||||
</a-affix>
|
||||
|
||||
<a-drawer v-model:open="open" :title="$t('nav.navigation') || '导航'" placement="right">
|
||||
<a-drawer v-model:open="open" :title="'导航' || '导航'" placement="right">
|
||||
<a-menu mode="inline" :selected-keys="selectedKeys">
|
||||
<template v-for="item in nav" :key="item.key">
|
||||
<a-sub-menu v-if="item.children && item.children.length" :key="item.key">
|
||||
@@ -103,11 +103,11 @@
|
||||
</template>
|
||||
</a-menu>
|
||||
<div class="mt-4">
|
||||
<a-button v-if="!isAuthed" block type="primary" @click="onNav('/login')">{{ $t('nav.login') || '登录' }}</a-button>
|
||||
<a-button v-if="!isAuthed" block type="primary" @click="onNav('/login')">{{ '登录' || '登录' }}</a-button>
|
||||
<template v-else>
|
||||
<a-button block type="primary" class="mb-2" @click="onNav('/profile')">个人中心</a-button>
|
||||
<a-button v-if="isSuperAdmin" block @click="onNav('/admin')">⚙️ 后台管理</a-button>
|
||||
<a-button block danger class="mt-2" @click="logout">{{ $t('nav.logout') || '退出登录' }}</a-button>
|
||||
<a-button block danger class="mt-2" @click="logout">{{ '退出登录' || '退出登录' }}</a-button>
|
||||
</template>
|
||||
</div>
|
||||
</a-drawer>
|
||||
|
||||
@@ -57,8 +57,8 @@
|
||||
|
||||
<!-- 登录卡片头部 -->
|
||||
<div class="form-header">
|
||||
<h2 class="form-title">{{ $t('login.welcomeBack') }}</h2>
|
||||
<p class="form-subtitle">{{ $t('login.loginToContinue') }}</p>
|
||||
<h2 class="form-title">{{ '欢迎回来' }}</h2>
|
||||
<p class="form-subtitle">{{ '请登录您的账号以继续' }}</p>
|
||||
</div>
|
||||
|
||||
<!-- 切换标签 -->
|
||||
@@ -69,7 +69,7 @@
|
||||
@click="setLoginType('scan')"
|
||||
>
|
||||
<QrcodeOutlined />
|
||||
{{ $t('login.scanLogin') }}
|
||||
{{ '扫码登录' }}
|
||||
</button>
|
||||
<button
|
||||
class="login-tab"
|
||||
@@ -77,7 +77,7 @@
|
||||
@click="setLoginType('sms')"
|
||||
>
|
||||
<MobileOutlined />
|
||||
{{ $t('login.phoneLogin') }}
|
||||
{{ '手机号登录' }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -91,7 +91,7 @@
|
||||
size="large"
|
||||
allow-clear
|
||||
:maxlength="11"
|
||||
:placeholder="$t('login.phonePlaceholder')"
|
||||
:placeholder="'请输入手机号码'"
|
||||
class="form-input"
|
||||
>
|
||||
<template #prefix>
|
||||
@@ -108,7 +108,7 @@
|
||||
size="large"
|
||||
allow-clear
|
||||
:maxlength="6"
|
||||
:placeholder="$t('login.smsCodePlaceholder')"
|
||||
:placeholder="'请输入验证码'"
|
||||
class="form-input"
|
||||
@press-enter="submitSms"
|
||||
/>
|
||||
@@ -118,8 +118,8 @@
|
||||
:class="{ disabled: countdown > 0 }"
|
||||
@click.prevent="openImgCodeModal"
|
||||
>
|
||||
<span v-if="countdown <= 0">{{ $t('login.sendCode') }}</span>
|
||||
<span v-else>{{ countdown }}{{ $t('login.resendAfter') }}</span>
|
||||
<span v-if="countdown <= 0">{{ '发送验证码' }}</span>
|
||||
<span v-else>{{ countdown }}{{ 's 后重发' }}</span>
|
||||
</button>
|
||||
</div>
|
||||
</a-form-item>
|
||||
@@ -128,10 +128,10 @@
|
||||
<div class="agreement-row">
|
||||
<a-checkbox v-model:checked="form.agreement">
|
||||
<span class="agreement-text">
|
||||
{{ $t('login.agreeTerms') }}
|
||||
<NuxtLink to="/agreement" target="_blank" class="agreement-link" @click.stop>{{ $t('login.registerAgreement') }}</NuxtLink>
|
||||
{{ $t('common.and') || '和' }}
|
||||
<NuxtLink to="/privacy" target="_blank" class="agreement-link" @click.stop>{{ $t('login.privacyPolicy') }}</NuxtLink>
|
||||
{{ '我已阅读并同意' }}
|
||||
<NuxtLink to="/agreement" target="_blank" class="agreement-link" @click.stop>{{ '《注册协议》' }}</NuxtLink>
|
||||
{{ '和' || '和' }}
|
||||
<NuxtLink to="/privacy" target="_blank" class="agreement-link" @click.stop>{{ '《隐私政策》' }}</NuxtLink>
|
||||
</span>
|
||||
</a-checkbox>
|
||||
</div>
|
||||
@@ -145,7 +145,7 @@
|
||||
class="submit-btn"
|
||||
@click="submitSms"
|
||||
>
|
||||
{{ loading ? $t('login.loggingIn') : $t('login.loginNow') }}
|
||||
{{ loading ? '登录中…' : '立即登录' }}
|
||||
</a-button>
|
||||
</a-form-item>
|
||||
</template>
|
||||
@@ -161,39 +161,39 @@
|
||||
<button class="switch-scan-btn" @click="toggleScan">
|
||||
<QrcodeOutlined v-if="loginType !== 'scan'" />
|
||||
<MobileOutlined v-else />
|
||||
{{ loginType === 'scan' ? $t('login.switchToPhone') : $t('login.switchToScan') }}
|
||||
{{ loginType === 'scan' ? '切换到手机号登录' : '切换到扫码登录' }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 图形验证码弹窗(发送短信用) -->
|
||||
<a-modal v-model:open="imgCodeModalOpen" :width="360" :footer="null" :title="$t('login.securityVerify')">
|
||||
<p class="modal-tip">{{ $t('login.completeVerifyFirst') }}</p>
|
||||
<a-modal v-model:open="imgCodeModalOpen" :width="360" :footer="null" :title="'安全验证'">
|
||||
<p class="modal-tip">{{ '请先完成图形验证码验证' }}</p>
|
||||
<div class="captcha-row modal-captcha">
|
||||
<a-input
|
||||
v-model:value="imgCode"
|
||||
size="large"
|
||||
allow-clear
|
||||
:maxlength="5"
|
||||
:placeholder="$t('login.enterImgCode')"
|
||||
:placeholder="'请输入图形验证码'"
|
||||
@press-enter="sendSmsCode"
|
||||
/>
|
||||
<button class="captcha-img-btn" @click.prevent="changeCaptcha" :title="$t('login.clickRefresh')">
|
||||
<button class="captcha-img-btn" @click.prevent="changeCaptcha" :title="'点击刷新'">
|
||||
<img alt="captcha" :src="captcha" />
|
||||
</button>
|
||||
</div>
|
||||
<a-button block size="large" type="primary" :loading="sendingSms" class="submit-btn" @click="sendSmsCode">
|
||||
{{ $t('login.sendCode') }}
|
||||
{{ '发送验证码' }}
|
||||
</a-button>
|
||||
</a-modal>
|
||||
|
||||
<!-- 选择账号弹窗 -->
|
||||
<a-modal v-model:open="selectUserOpen" :width="520" :footer="null" :title="$t('login.selectAccount')">
|
||||
<a-modal v-model:open="selectUserOpen" :width="520" :footer="null" :title="'选择账号登录'">
|
||||
<a-list item-layout="horizontal" :data-source="admins">
|
||||
<template #renderItem="{ item }">
|
||||
<a-list-item class="list-item" @click="selectUser(item)">
|
||||
<a-list-item-meta :description="`${$t('login.tenantId')}: ${item.tenantId}`">
|
||||
<a-list-item-meta :description="`${'租户ID'}: ${item.tenantId}`">
|
||||
<template #title>{{ item.tenantName || item.username }}</template>
|
||||
<template #avatar>
|
||||
<a-avatar :src="item.avatar" />
|
||||
@@ -225,8 +225,6 @@ import { getUserInfo } from '@/api/layout'
|
||||
import { TEMPLATE_ID } from '@/config/setting'
|
||||
import { setToken } from '@/utils/token-util'
|
||||
import type { QrCodeStatusResponse } from '@/api/passport/qrLogin'
|
||||
const { t } = useI18n()
|
||||
|
||||
definePageMeta({ layout: false })
|
||||
|
||||
const route = useRoute()
|
||||
@@ -260,10 +258,10 @@ const form = reactive<LoginParam & { smsCode?: string; agreement?: boolean }>({
|
||||
const phoneReg = /^1[3-9]\d{9}$/
|
||||
const rules = reactive({
|
||||
phone: [
|
||||
{ required: true, message: t('login.enterPhone'), type: 'string' },
|
||||
{ pattern: phoneReg, message: t('login.phoneFormatError'), trigger: 'blur' }
|
||||
{ required: true, message: '请输入手机号码', type: 'string' },
|
||||
{ pattern: phoneReg, message: '手机号格式不正确', trigger: 'blur' }
|
||||
],
|
||||
smsCode: [{ required: true, message: t('login.enterSmsCode'), type: 'string' }]
|
||||
smsCode: [{ required: true, message: '请输入短信验证码', type: 'string' }]
|
||||
})
|
||||
|
||||
const bgStyle = computed(() => {
|
||||
@@ -292,27 +290,27 @@ async function changeCaptcha() {
|
||||
captcha.value = data.base64
|
||||
captchaText.value = data.text
|
||||
} catch (e: unknown) {
|
||||
message.error(e instanceof Error ? e.message : t('login.loginFailed'))
|
||||
message.error(e instanceof Error ? e.message : '登录失败')
|
||||
}
|
||||
}
|
||||
|
||||
function openImgCodeModal() {
|
||||
if (!form.phone) return message.error(t('login.enterPhone'))
|
||||
if (!form.phone) return message.error('请输入手机号码')
|
||||
imgCode.value = ''
|
||||
changeCaptcha()
|
||||
imgCodeModalOpen.value = true
|
||||
}
|
||||
|
||||
async function sendSmsCode() {
|
||||
if (!imgCode.value) return message.error(t('login.enterImgCode'))
|
||||
if (!imgCode.value) return message.error('请输入图形验证码')
|
||||
if (captchaText.value && imgCode.value.toLowerCase() !== captchaText.value.toLowerCase()) {
|
||||
return message.error(t('login.imgCodeIncorrect'))
|
||||
return message.error('图形验证码不正确')
|
||||
}
|
||||
|
||||
sendingSms.value = true
|
||||
try {
|
||||
await sendSmsCaptcha({ phone: form.phone })
|
||||
message.success(t('login.smsSentSuccess'))
|
||||
message.success('短信验证码发送成功,请注意查收')
|
||||
imgCodeModalOpen.value = false
|
||||
countdown.value = 30
|
||||
stopCountdown()
|
||||
@@ -322,7 +320,7 @@ async function sendSmsCode() {
|
||||
if (countdown.value <= 0) stopCountdown()
|
||||
}, 1000)
|
||||
} catch (e: unknown) {
|
||||
message.error(e instanceof Error ? e.message : t('login.sendFailed'))
|
||||
message.error(e instanceof Error ? e.message : '发送失败')
|
||||
} finally {
|
||||
sendingSms.value = false
|
||||
}
|
||||
@@ -360,7 +358,7 @@ async function submitSms() {
|
||||
if (!formRef.value) return
|
||||
// 校验协议勾选
|
||||
if (!form.agreement) {
|
||||
return message.error(t('login.agreeRequired'))
|
||||
return message.error('请先阅读并同意《注册协议》和《隐私政策》')
|
||||
}
|
||||
loading.value = true
|
||||
try {
|
||||
@@ -381,11 +379,11 @@ async function submitSms() {
|
||||
return
|
||||
}
|
||||
|
||||
message.success(msg || t('login.loginSuccess'))
|
||||
message.success(msg || '登录成功')
|
||||
await ensureUserIdPersisted()
|
||||
await goAfterLogin()
|
||||
} catch (e: unknown) {
|
||||
message.error(e instanceof Error ? e.message : t('login.loginFailed'))
|
||||
message.error(e instanceof Error ? e.message : '登录失败')
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
@@ -406,12 +404,12 @@ async function onQrLoginSuccess(payload: QrCodeStatusResponse) {
|
||||
? (payload.userInfo as { userId?: unknown }).userId
|
||||
: undefined
|
||||
await ensureUserIdPersisted(seedUserId)
|
||||
message.success(t('login.scanLoginSuccess'))
|
||||
message.success('扫码登录成功')
|
||||
await goAfterLogin()
|
||||
}
|
||||
|
||||
function onQrLoginError(error: string) {
|
||||
message.error(error || t('login.scanLoginFailed'))
|
||||
message.error(error || '扫码登录失败')
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
|
||||
Reference in New Issue
Block a user