mirror of
https://github.com/xinnan-tech/xiaozhi-esp32-server.git
synced 2026-07-25 08:33:53 +08:00
Merge branch 'main' into manager-web-i18n
This commit is contained in:
@@ -47,12 +47,13 @@
|
||||
<!-- 右侧内容 -->
|
||||
<div class="content-area">
|
||||
<el-card class="model-card" shadow="never">
|
||||
<el-table ref="modelTable" style="width: 100%" v-loading="loading" :element-loading-text="$t('modelConfig.loading')"
|
||||
element-loading-spinner="el-icon-loading" element-loading-background="rgba(255, 255, 255, 0.7)"
|
||||
:header-cell-style="{ background: 'transparent' }" :data="modelList" class="data-table"
|
||||
header-row-class-name="table-header" :header-cell-class-name="headerCellClassName"
|
||||
@selection-change="handleSelectionChange">
|
||||
<el-table-column type="selection" width="55" align="center" :cell-class-name="selectionCellClassName"></el-table-column>
|
||||
<el-table ref="modelTable" style="width: 100%" v-loading="loading"
|
||||
:element-loading-text="$t('modelConfig.loading')" element-loading-spinner="el-icon-loading"
|
||||
element-loading-background="rgba(255, 255, 255, 0.7)" :header-cell-style="{ background: 'transparent' }"
|
||||
:data="modelList" class="data-table" header-row-class-name="table-header"
|
||||
:header-cell-class-name="headerCellClassName" @selection-change="handleSelectionChange">
|
||||
<el-table-column type="selection" width="55" align="center"
|
||||
:cell-class-name="selectionCellClassName"></el-table-column>
|
||||
<el-table-column :label="$t('modelConfig.modelId')" prop="id" align="center"></el-table-column>
|
||||
<el-table-column :label="$t('modelConfig.modelName')" prop="modelName" align="center"></el-table-column>
|
||||
<el-table-column :label="$t('modelConfig.provider')" align="center">
|
||||
@@ -79,7 +80,7 @@
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column :label="$t('modelConfig.action')" align="center" width="180px">
|
||||
<el-table-column :label="$t('modelConfig.action')" align="center" width="210px">
|
||||
<template slot-scope="scope">
|
||||
<el-button type="text" size="mini" @click="editModel(scope.row)" class="edit-btn">
|
||||
{{ $t('modelConfig.edit') }}
|
||||
@@ -109,19 +110,26 @@
|
||||
<div class="custom-pagination">
|
||||
|
||||
<el-select v-model="pageSize" @change="handlePageSizeChange" class="page-size-select">
|
||||
<el-option v-for="item in pageSizeOptions" :key="item" :label="$t('modelConfig.itemsPerPage', { items: item })" :value="item">
|
||||
<el-option v-for="item in pageSizeOptions" :key="item"
|
||||
:label="$t('modelConfig.itemsPerPage', { items: item })" :value="item">
|
||||
</el-option>
|
||||
</el-select>
|
||||
|
||||
<button class="pagination-btn" :disabled="currentPage === 1" @click="goFirst">{{ $t('modelConfig.firstPage') }}</button>
|
||||
<button class="pagination-btn" :disabled="currentPage === 1" @click="goPrev">{{ $t('modelConfig.prevPage') }}</button>
|
||||
<button class="pagination-btn" :disabled="currentPage === 1" @click="goFirst">{{
|
||||
$t('modelConfig.firstPage')
|
||||
}}</button>
|
||||
<button class="pagination-btn" :disabled="currentPage === 1" @click="goPrev">{{
|
||||
$t('modelConfig.prevPage')
|
||||
}}</button>
|
||||
|
||||
<button v-for="page in visiblePages" :key="page" class="pagination-btn"
|
||||
:class="{ active: page === currentPage }" @click="goToPage(page)">
|
||||
{{ page }}
|
||||
</button>
|
||||
|
||||
<button class="pagination-btn" :disabled="currentPage === pageCount" @click="goNext">{{ $t('modelConfig.nextPage') }}</button>
|
||||
<button class="pagination-btn" :disabled="currentPage === pageCount" @click="goNext">{{
|
||||
$t('modelConfig.nextPage')
|
||||
}}</button>
|
||||
<span class="total-text">{{ $t('modelConfig.totalRecords', { total }) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -173,14 +181,14 @@ export default {
|
||||
created() {
|
||||
this.loadData();
|
||||
},
|
||||
|
||||
|
||||
mounted() {
|
||||
// 在组件挂载后确保表头翻译文本正确显示
|
||||
setTimeout(() => {
|
||||
this.updateSelectionHeaderText();
|
||||
}, 100);
|
||||
},
|
||||
|
||||
|
||||
updated() {
|
||||
// 在组件更新后重新设置表头翻译文本
|
||||
this.updateSelectionHeaderText();
|
||||
@@ -345,17 +353,17 @@ export default {
|
||||
const id = formData.id;
|
||||
|
||||
if (this.editModelData.duplicateMode) {
|
||||
Api.model.addModel({modelType, provideCode, formData},
|
||||
({ data }) => {
|
||||
if (data.code === 0) {
|
||||
this.$message.success(this.$t('modelConfig.duplicateSuccess'));
|
||||
this.loadData();
|
||||
this.editDialogVisible = false;
|
||||
} else {
|
||||
this.$message.error(data.msg || this.$t('modelConfig.duplicateFailed'));
|
||||
}
|
||||
done && done(); // 调用done回调关闭加载状态
|
||||
})
|
||||
Api.model.addModel({ modelType, provideCode, formData },
|
||||
({ data }) => {
|
||||
if (data.code === 0) {
|
||||
this.$message.success(this.$t('modelConfig.duplicateSuccess'));
|
||||
this.loadData();
|
||||
this.editDialogVisible = false;
|
||||
} else {
|
||||
this.$message.error(data.msg || this.$t('modelConfig.duplicateFailed'));
|
||||
}
|
||||
done && done(); // 调用done回调关闭加载状态
|
||||
})
|
||||
}
|
||||
else {
|
||||
Api.model.updateModel(
|
||||
@@ -790,9 +798,11 @@ export default {
|
||||
content: attr(data-content);
|
||||
display: block;
|
||||
text-align: center;
|
||||
line-height: 32px; /* 设置合适的行高,确保文本完整显示 */
|
||||
line-height: 32px;
|
||||
/* 设置合适的行高,确保文本完整显示 */
|
||||
color: black;
|
||||
margin-top: 0; /* 移除可能导致偏移的上边距 */
|
||||
margin-top: 0;
|
||||
/* 移除可能导致偏移的上边距 */
|
||||
height: 32px;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
@@ -804,6 +814,7 @@ export default {
|
||||
.custom-selection-header .cell {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
/* 已移除可能影响文本显示的空伪元素 */
|
||||
|
||||
::v-deep .el-table__body .el-checkbox__inner {
|
||||
|
||||
@@ -33,14 +33,16 @@
|
||||
<el-tag v-else type="danger">{{ $t('user.disabled') }}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column :label="$t('modelConfig.action')" align="center">
|
||||
<el-table-column :label="$t('modelConfig.action')" align="center" width="300px">
|
||||
<template slot-scope="scope">
|
||||
<el-button size="mini" type="text" @click="resetPassword(scope.row)">{{ $t('user.resetPassword') }}</el-button>
|
||||
<el-button size="mini" type="text" @click="resetPassword(scope.row)">{{ $t('user.resetPassword')
|
||||
}}</el-button>
|
||||
<el-button size="mini" type="text" v-if="scope.row.status === 1"
|
||||
@click="handleChangeStatus(scope.row, 0)">{{ $t('user.disableAccount') }}</el-button>
|
||||
@click="handleChangeStatus(scope.row, 0)">{{ $t('user.disableAccount') }}</el-button>
|
||||
<el-button size="mini" type="text" v-if="scope.row.status === 0"
|
||||
@click="handleChangeStatus(scope.row, 1)">{{ $t('user.enableAccount') }}</el-button>
|
||||
<el-button size="mini" type="text" @click="deleteUser(scope.row)">{{ $t('user.deleteUser') }}</el-button>
|
||||
@click="handleChangeStatus(scope.row, 1)">{{ $t('user.enableAccount') }}</el-button>
|
||||
<el-button size="mini" type="text" @click="deleteUser(scope.row)">{{ $t('user.deleteUser')
|
||||
}}</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
@@ -50,14 +52,20 @@
|
||||
<el-button size="mini" type="primary" class="select-all-btn" @click="handleSelectAll">
|
||||
{{ isAllSelected ? $t('user.deselectAll') : $t('user.selectAll') }}
|
||||
</el-button>
|
||||
<el-button size="mini" type="success" icon="el-icon-circle-check" @click="batchEnable">{{ $t('user.enable') }}</el-button>
|
||||
<el-button size="mini" type="success" icon="el-icon-circle-check" @click="batchEnable">{{
|
||||
$t('user.enable')
|
||||
}}</el-button>
|
||||
<el-button size="mini" type="warning" @click="batchDisable"><i
|
||||
class="el-icon-remove-outline rotated-icon"></i>{{ $t('user.disable') }}</el-button>
|
||||
<el-button size="mini" type="danger" icon="el-icon-delete" @click="batchDelete">{{ $t('user.delete') }}</el-button>
|
||||
class="el-icon-remove-outline rotated-icon"></i>{{
|
||||
$t('user.disable') }}</el-button>
|
||||
<el-button size="mini" type="danger" icon="el-icon-delete" @click="batchDelete">{{ $t('user.delete')
|
||||
}}</el-button>
|
||||
</div>
|
||||
<div class="custom-pagination">
|
||||
<el-select v-model="pageSize" @change="handlePageSizeChange" :class="['page-size-select', { 'page-size-select-en': isEnglish }]">
|
||||
<el-option v-for="item in pageSizeOptions" :key="item" :label="$t('modelConfig.itemsPerPage', { count: item })" :value="item">
|
||||
<el-select v-model="pageSize" @change="handlePageSizeChange"
|
||||
:class="['page-size-select', { 'page-size-select-en': isEnglish }]">
|
||||
<el-option v-for="item in pageSizeOptions" :key="item"
|
||||
:label="$t('modelConfig.itemsPerPage', { count: item })" :value="item">
|
||||
</el-option>
|
||||
</el-select>
|
||||
|
||||
@@ -713,10 +721,10 @@ export default {
|
||||
color: #606266;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
|
||||
&.page-size-select-en {
|
||||
width: 130px;
|
||||
|
||||
|
||||
:deep(.el-input__inner) {
|
||||
height: 36px;
|
||||
line-height: 36px;
|
||||
|
||||
@@ -1,45 +1,59 @@
|
||||
<template>
|
||||
<div class="welcome">
|
||||
<el-container style="height: 100%;">
|
||||
<el-container style="height: 100%">
|
||||
<el-header>
|
||||
<div style="display: flex;align-items: center;margin-top: 15px;margin-left: 10px;gap: 10px;">
|
||||
<img loading="lazy" alt="" src="@/assets/xiaozhi-logo.png" style="width: 45px;height: 45px;" />
|
||||
<img loading="lazy" alt="" src="@/assets/xiaozhi-ai.png" style="height: 18px;" />
|
||||
<div style="
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-top: 15px;
|
||||
margin-left: 10px;
|
||||
gap: 10px;
|
||||
">
|
||||
<img loading="lazy" alt="" src="@/assets/xiaozhi-logo.png" style="width: 45px; height: 45px" />
|
||||
<img loading="lazy" alt="" src="@/assets/xiaozhi-ai.png" style="height: 18px" />
|
||||
</div>
|
||||
</el-header>
|
||||
<div class="login-person">
|
||||
<img loading="lazy" alt="" src="@/assets/login/login-person.png" style="width: 100%;" />
|
||||
<img loading="lazy" alt="" src="@/assets/login/login-person.png" style="width: 100%" />
|
||||
</div>
|
||||
<el-main style="position: relative;">
|
||||
<el-main style="position: relative">
|
||||
<div class="login-box" @keyup.enter="login">
|
||||
<div style="display: flex;align-items: center;gap: 20px;margin-bottom: 39px;padding: 0 30px;">
|
||||
<img loading="lazy" alt="" src="@/assets/login/hi.png" style="width: 34px;height: 34px;" />
|
||||
<div class="login-text">{{ $t('login.title') }}</div>
|
||||
|
||||
<div style="
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 20px;
|
||||
margin-bottom: 39px;
|
||||
padding: 0 30px;
|
||||
">
|
||||
<img loading="lazy" alt="" src="@/assets/login/hi.png" style="width: 34px; height: 34px" />
|
||||
<div class="login-text">{{ $t("login.title") }}</div>
|
||||
|
||||
<div class="login-welcome">
|
||||
{{ $t('login.welcome') }}
|
||||
{{ $t("login.welcome") }}
|
||||
</div>
|
||||
|
||||
|
||||
<!-- 语言切换下拉菜单 -->
|
||||
<el-dropdown trigger="click" class="title-language-dropdown" @visible-change="handleLanguageDropdownVisibleChange">
|
||||
<el-dropdown trigger="click" class="title-language-dropdown"
|
||||
@visible-change="handleLanguageDropdownVisibleChange">
|
||||
<span class="el-dropdown-link">
|
||||
<i class="el-icon-document"></i>
|
||||
<span class="current-language-text">{{ currentLanguageText }}</span>
|
||||
<i class="el-icon-arrow-down el-icon--right" :class="{ 'rotate-down': languageDropdownVisible }"></i>
|
||||
</span>
|
||||
<el-dropdown-menu slot="dropdown">
|
||||
<el-dropdown-item @click.native="changeLanguage('zh_CN')">
|
||||
{{ $t('language.zhCN') }}
|
||||
{{ $t("language.zhCN") }}
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item @click.native="changeLanguage('zh_TW')">
|
||||
{{ $t('language.zhTW') }}
|
||||
{{ $t("language.zhTW") }}
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item @click.native="changeLanguage('en')">
|
||||
{{ $t('language.en') }}
|
||||
{{ $t("language.en") }}
|
||||
</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</el-dropdown>
|
||||
</div>
|
||||
<div style="padding: 0 30px;">
|
||||
<div style="padding: 0 30px">
|
||||
<!-- 用户名登录 -->
|
||||
<template v-if="!isMobileLogin">
|
||||
<div class="input-box">
|
||||
@@ -51,9 +65,9 @@
|
||||
<!-- 手机号登录 -->
|
||||
<template v-else>
|
||||
<div class="input-box">
|
||||
<div style="display: flex; align-items: center; width: 100%;">
|
||||
<el-select v-model="form.areaCode" style="width: 220px; margin-right: 10px;">
|
||||
<el-option v-for="item in mobileAreaList" :key="item.key" :label="`${item.name} (${item.key})`"
|
||||
<div style="display: flex; align-items: center; width: 100%">
|
||||
<el-select v-model="form.areaCode" style="width: 220px; margin-right: 10px">
|
||||
<el-option v-for="item in mobileAreaList" :key="item.key" :label="`${item.name} (${item.key})`"
|
||||
:value="item.key" />
|
||||
</el-select>
|
||||
<el-input v-model="form.mobile" :placeholder="$t('login.mobilePlaceholder')" />
|
||||
@@ -63,42 +77,64 @@
|
||||
|
||||
<div class="input-box">
|
||||
<img loading="lazy" alt="" class="input-icon" src="@/assets/login/password.png" />
|
||||
<el-input v-model="form.password" :placeholder="$t('login.passwordPlaceholder')" type="password" show-password />
|
||||
<el-input v-model="form.password" :placeholder="$t('login.passwordPlaceholder')" type="password"
|
||||
show-password />
|
||||
</div>
|
||||
<div style="display: flex; align-items: center; margin-top: 20px; width: 100%; gap: 10px;">
|
||||
<div class="input-box" style="width: calc(100% - 130px); margin-top: 0;">
|
||||
<div style="
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-top: 20px;
|
||||
width: 100%;
|
||||
gap: 10px;
|
||||
">
|
||||
<div class="input-box" style="width: calc(100% - 130px); margin-top: 0">
|
||||
<img loading="lazy" alt="" class="input-icon" src="@/assets/login/shield.png" />
|
||||
<el-input v-model="form.captcha" :placeholder="$t('login.captchaPlaceholder')" style="flex: 1;" />
|
||||
<el-input v-model="form.captcha" :placeholder="$t('login.captchaPlaceholder')" style="flex: 1" />
|
||||
</div>
|
||||
<img loading="lazy" v-if="captchaUrl" :src="captchaUrl" alt="验证码"
|
||||
style="width: 150px; height: 40px; cursor: pointer;" @click="fetchCaptcha" />
|
||||
<img loading="lazy" v-if="captchaUrl" :src="captchaUrl" alt="验证码"
|
||||
style="width: 150px; height: 40px; cursor: pointer" @click="fetchCaptcha" />
|
||||
</div>
|
||||
<div
|
||||
style="font-weight: 400;font-size: 14px;text-align: left;color: #5778ff;display: flex;justify-content: space-between;margin-top: 20px;">
|
||||
<div v-if="allowUserRegister" style="cursor: pointer;" @click="goToRegister">{{ $t('login.register') }}</div>
|
||||
<div style="cursor: pointer;" @click="goToForgetPassword" v-if="enableMobileRegister">{{ $t('login.forgetPassword') }}</div>
|
||||
<div style="
|
||||
font-weight: 400;
|
||||
font-size: 14px;
|
||||
text-align: left;
|
||||
color: #5778ff;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-top: 20px;
|
||||
">
|
||||
<div v-if="allowUserRegister" style="cursor: pointer" @click="goToRegister">
|
||||
{{ $t("login.register") }}
|
||||
</div>
|
||||
<div style="cursor: pointer" @click="goToForgetPassword" v-if="enableMobileRegister">
|
||||
{{ $t("login.forgetPassword") }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="login-btn" @click="login">{{ $t('login.login') }}</div>
|
||||
<div class="login-btn" @click="login">{{ $t("login.login") }}</div>
|
||||
|
||||
<!-- 登录方式切换按钮 -->
|
||||
<div class="login-type-container" v-if="enableMobileRegister">
|
||||
<div style="display: flex; gap: 10px;">
|
||||
<div style="display: flex; gap: 10px">
|
||||
<el-tooltip :content="$t('login.mobileLogin')" placement="bottom">
|
||||
<el-button :type="isMobileLogin ? 'primary' : 'default'" icon="el-icon-mobile" circle
|
||||
<el-button :type="isMobileLogin ? 'primary' : 'default'" icon="el-icon-mobile" circle
|
||||
@click="switchLoginType('mobile')"></el-button>
|
||||
</el-tooltip>
|
||||
<el-tooltip :content="$t('login.usernameLogin')" placement="bottom">
|
||||
<el-button :type="!isMobileLogin ? 'primary' : 'default'" icon="el-icon-user" circle
|
||||
<el-button :type="!isMobileLogin ? 'primary' : 'default'" icon="el-icon-user" circle
|
||||
@click="switchLoginType('username')"></el-button>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
</div>
|
||||
<div style="font-size: 14px;color: #979db1;">
|
||||
{{ $t('login.agreeTo') }}
|
||||
<div style="display: inline-block;color: #5778FF;cursor: pointer;">{{ $t('login.userAgreement') }}</div>
|
||||
{{ $t('login.and') }}
|
||||
<div style="display: inline-block;color: #5778FF;cursor: pointer;">{{ $t('login.privacyPolicy') }}</div>
|
||||
<div style="font-size: 14px; color: #979db1">
|
||||
{{ $t("login.agreeTo") }}
|
||||
<div style="display: inline-block; color: #5778ff; cursor: pointer">
|
||||
{{ $t("login.userAgreement") }}
|
||||
</div>
|
||||
{{ $t("login.and") }}
|
||||
<div style="display: inline-block; color: #5778ff; cursor: pointer">
|
||||
{{ $t("login.privacyPolicy") }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-main>
|
||||
@@ -110,44 +146,62 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Api from '@/apis/api';
|
||||
import VersionFooter from '@/components/VersionFooter.vue';
|
||||
import { getUUID, goToPage, showDanger, showSuccess, validateMobile } from '@/utils';
|
||||
import { mapState } from 'vuex';
|
||||
import { changeLanguage } from '@/i18n';
|
||||
import Api from "@/apis/api";
|
||||
import VersionFooter from "@/components/VersionFooter.vue";
|
||||
import i18n, { changeLanguage } from "@/i18n";
|
||||
import { getUUID, goToPage, showDanger, showSuccess, validateMobile } from "@/utils";
|
||||
import { mapState } from "vuex";
|
||||
|
||||
export default {
|
||||
name: 'login',
|
||||
name: "login",
|
||||
components: {
|
||||
VersionFooter
|
||||
VersionFooter,
|
||||
},
|
||||
computed: {
|
||||
...mapState({
|
||||
allowUserRegister: state => state.pubConfig.allowUserRegister,
|
||||
enableMobileRegister: state => state.pubConfig.enableMobileRegister,
|
||||
mobileAreaList: state => state.pubConfig.mobileAreaList
|
||||
})
|
||||
allowUserRegister: (state) => state.pubConfig.allowUserRegister,
|
||||
enableMobileRegister: (state) => state.pubConfig.enableMobileRegister,
|
||||
mobileAreaList: (state) => state.pubConfig.mobileAreaList,
|
||||
}),
|
||||
// 获取当前语言
|
||||
currentLanguage() {
|
||||
return i18n.locale || "zh_CN";
|
||||
},
|
||||
// 获取当前语言显示文本
|
||||
currentLanguageText() {
|
||||
const currentLang = this.currentLanguage;
|
||||
switch (currentLang) {
|
||||
case "zh_CN":
|
||||
return this.$t("language.zhCN");
|
||||
case "zh_TW":
|
||||
return this.$t("language.zhTW");
|
||||
case "en":
|
||||
return this.$t("language.en");
|
||||
default:
|
||||
return this.$t("language.zhCN");
|
||||
}
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
activeName: "username",
|
||||
form: {
|
||||
username: '',
|
||||
password: '',
|
||||
captcha: '',
|
||||
captchaId: '',
|
||||
areaCode: '+86',
|
||||
mobile: ''
|
||||
username: "",
|
||||
password: "",
|
||||
captcha: "",
|
||||
captchaId: "",
|
||||
areaCode: "+86",
|
||||
mobile: "",
|
||||
},
|
||||
captchaUuid: '',
|
||||
captchaUrl: '',
|
||||
captchaUuid: "",
|
||||
captchaUrl: "",
|
||||
isMobileLogin: false,
|
||||
languageDropdownVisible: false
|
||||
}
|
||||
languageDropdownVisible: false,
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
this.fetchCaptcha();
|
||||
this.$store.dispatch('fetchPubConfig').then(() => {
|
||||
this.$store.dispatch("fetchPubConfig").then(() => {
|
||||
// 根据配置决定默认登录方式
|
||||
this.isMobileLogin = this.enableMobileRegister;
|
||||
});
|
||||
@@ -155,8 +209,8 @@ export default {
|
||||
methods: {
|
||||
fetchCaptcha() {
|
||||
if (this.$store.getters.getToken) {
|
||||
if (this.$route.path !== '/home') {
|
||||
this.$router.push('/home')
|
||||
if (this.$route.path !== "/home") {
|
||||
this.$router.push("/home");
|
||||
}
|
||||
} else {
|
||||
this.captchaUuid = getUUID();
|
||||
@@ -166,7 +220,7 @@ export default {
|
||||
const blob = new Blob([res.data], { type: res.data.type });
|
||||
this.captchaUrl = URL.createObjectURL(blob);
|
||||
} else {
|
||||
showDanger('验证码加载失败,点击刷新');
|
||||
showDanger("验证码加载失败,点击刷新");
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -176,25 +230,25 @@ export default {
|
||||
handleLanguageDropdownVisibleChange(visible) {
|
||||
this.languageDropdownVisible = visible;
|
||||
},
|
||||
|
||||
|
||||
// 切换语言
|
||||
changeLanguage(lang) {
|
||||
changeLanguage(lang);
|
||||
this.languageDropdownVisible = false;
|
||||
this.$message.success({
|
||||
message: this.$t('message.success'),
|
||||
showClose: true
|
||||
message: this.$t("message.success"),
|
||||
showClose: true,
|
||||
});
|
||||
},
|
||||
|
||||
// 切换登录方式
|
||||
switchLoginType(type) {
|
||||
this.isMobileLogin = type === 'mobile';
|
||||
this.isMobileLogin = type === "mobile";
|
||||
// 清空表单
|
||||
this.form.username = '';
|
||||
this.form.mobile = '';
|
||||
this.form.password = '';
|
||||
this.form.captcha = '';
|
||||
this.form.username = "";
|
||||
this.form.mobile = "";
|
||||
this.form.password = "";
|
||||
this.form.captcha = "";
|
||||
this.fetchCaptcha();
|
||||
},
|
||||
|
||||
@@ -211,38 +265,46 @@ export default {
|
||||
if (this.isMobileLogin) {
|
||||
// 手机号登录验证
|
||||
if (!validateMobile(this.form.mobile, this.form.areaCode)) {
|
||||
showDanger('请输入正确的手机号码');
|
||||
showDanger("请输入正确的手机号码");
|
||||
return;
|
||||
}
|
||||
// 拼接手机号作为用户名
|
||||
this.form.username = this.form.areaCode + this.form.mobile;
|
||||
} else {
|
||||
// 用户名登录验证
|
||||
if (!this.validateInput(this.form.username, '用户名不能为空')) {
|
||||
if (!this.validateInput(this.form.username, "用户名不能为空")) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// 验证密码
|
||||
if (!this.validateInput(this.form.password, '密码不能为空')) {
|
||||
if (!this.validateInput(this.form.password, "密码不能为空")) {
|
||||
return;
|
||||
}
|
||||
// 验证验证码
|
||||
if (!this.validateInput(this.form.captcha, '验证码不能为空')) {
|
||||
if (!this.validateInput(this.form.captcha, "验证码不能为空")) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.form.captchaId = this.captchaUuid
|
||||
Api.user.login(this.form, ({ data }) => {
|
||||
showSuccess('登录成功!');
|
||||
this.$store.commit('setToken', JSON.stringify(data.data));
|
||||
goToPage('/home');
|
||||
}, (err) => {
|
||||
showDanger(err.data.msg || '登录失败')
|
||||
if (err.data != null && err.data.msg != null && err.data.msg.indexOf('图形验证码') > -1) {
|
||||
this.fetchCaptcha()
|
||||
this.form.captchaId = this.captchaUuid;
|
||||
Api.user.login(
|
||||
this.form,
|
||||
({ data }) => {
|
||||
showSuccess("登录成功!");
|
||||
this.$store.commit("setToken", JSON.stringify(data.data));
|
||||
goToPage("/home");
|
||||
},
|
||||
(err) => {
|
||||
showDanger(err.data.msg || "登录失败");
|
||||
if (
|
||||
err.data != null &&
|
||||
err.data.msg != null &&
|
||||
err.data.msg.indexOf("图形验证码") > -1
|
||||
) {
|
||||
this.fetchCaptcha();
|
||||
}
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
// 重新获取验证码
|
||||
setTimeout(() => {
|
||||
@@ -251,16 +313,16 @@ export default {
|
||||
},
|
||||
|
||||
goToRegister() {
|
||||
goToPage('/register')
|
||||
goToPage("/register");
|
||||
},
|
||||
goToForgetPassword() {
|
||||
goToPage('/retrieve-password')
|
||||
goToPage("/retrieve-password");
|
||||
},
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
@import './auth.scss';
|
||||
@import "./auth.scss";
|
||||
|
||||
.login-type-container {
|
||||
margin: 10px 20px;
|
||||
@@ -273,6 +335,13 @@ export default {
|
||||
margin-left: 20px;
|
||||
}
|
||||
|
||||
.current-language-text {
|
||||
margin-left: 4px;
|
||||
margin-right: 4px;
|
||||
font-size: 12px;
|
||||
color: #3d4566;
|
||||
}
|
||||
|
||||
.language-dropdown {
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user