opt: optimize index and login page UI

This commit is contained in:
RockYang 2024-04-26 16:07:02 +08:00
parent 1966e69460
commit 34648c704f
8 changed files with 158 additions and 80 deletions

View File

@ -1,5 +1,13 @@
# 更新日志 # 更新日志
## v4.0.5
* 功能优化:已授权系统在后台显示授权信息
* 功能优化:使用思维链提示词生成思维导图,确保生成的思维导图不会出现格式错误
* 功能优化:优化首页登录注册页面的 UI
* BUG修复修复License验证的逻辑漏洞
* 功能优化:支持点卡充值设置有效期
## v4.0.4 ## v4.0.4
* Bug修复修复统一千问第二句不回复的问题 * Bug修复修复统一千问第二句不回复的问题

View File

@ -108,7 +108,8 @@ WeChatBot = false
ApiURL = "https://api.xunhupay.com" ApiURL = "https://api.xunhupay.com"
NotifyURL = "https://ai.r9it.com/api/payment/hupipay/notify" NotifyURL = "https://ai.r9it.com/api/payment/hupipay/notify"
[SmtpConfig] # 注意阿里云服务器禁用了25号端口所以如果需要使用邮件功能请别用阿里云服务器 [SmtpConfig] # 注意阿里云服务器禁用了25号端口请使用 465 端口,并开启 TLS 连接
UseTls = false
Host = "smtp.163.com" Host = "smtp.163.com"
Port = 25 Port = 25
AppName = "极客学长" AppName = "极客学长"

View File

@ -71,7 +71,7 @@ func (h *UserHandler) Register(c *gin.Context) {
// 检查验证码 // 检查验证码
var key string var key string
if data.RegWay == "email" || data.RegWay == "mobile" || data.Code != "" { if data.RegWay == "email" || data.RegWay == "mobile" {
key = CodeStorePrefix + data.Username key = CodeStorePrefix + data.Username
code, err := h.redis.Get(c, key).Result() code, err := h.redis.Get(c, key).Result()
if err != nil || code != data.Code { if err != nil || code != data.Code {

View File

@ -110,7 +110,8 @@ WeChatBot = false
ApiURL = "https://api.xunhupay.com" ApiURL = "https://api.xunhupay.com"
NotifyURL = "https://ai.r9it.com/api/payment/hupipay/notify" NotifyURL = "https://ai.r9it.com/api/payment/hupipay/notify"
[SmtpConfig] # 注意阿里云服务器禁用了25号端口所以如果需要使用邮件功能请别用阿里云服务器 [SmtpConfig] # 注意阿里云服务器禁用了25号端口请使用 465 端口,并开启 TLS 连接
UseTls = false
Host = "smtp.163.com" Host = "smtp.163.com"
Port = 25 Port = 25
AppName = "极客学长" AppName = "极客学长"

View File

@ -106,7 +106,7 @@
autocomplete="off"> autocomplete="off">
<template #prefix> <template #prefix>
<el-icon> <el-icon>
<Iphone/> <Message/>
</el-icon> </el-icon>
</template> </template>
</el-input> </el-input>

View File

@ -24,6 +24,8 @@
<span>项目源码</span> <span>项目源码</span>
</el-button> </el-button>
</a> </a>
<el-button @click="router.push('/login')" round>登录</el-button>
<el-button @click="router.push('/register')" round>注册</el-button>
</div> </div>
</el-menu> </el-menu>
</div> </div>

View File

@ -4,7 +4,7 @@
<div class="main"> <div class="main">
<div class="contain"> <div class="contain">
<div class="logo"> <div class="logo">
<el-image :src="logo" fit="cover"/> <el-image :src="logo" fit="cover" @click="router.push('/')"/>
</div> </div>
<div class="header">{{ title }}</div> <div class="header">{{ title }}</div>
<div class="content"> <div class="content">
@ -34,7 +34,7 @@
<el-button class="login-btn" size="large" type="primary" @click="login">登录</el-button> <el-button class="login-btn" size="large" type="primary" @click="login">登录</el-button>
</el-row> </el-row>
<el-row class="text-line" gutter="20"> <el-row class="text-line" :gutter="20">
<el-button type="primary" @click="router.push('/register')" size="small" plain>注册新账号</el-button> <el-button type="primary" @click="router.push('/register')" size="small" plain>注册新账号</el-button>
<el-button type="success" @click="showResetPass = true" size="small" plain>重置密码</el-button> <el-button type="success" @click="showResetPass = true" size="small" plain>重置密码</el-button>
</el-row> </el-row>
@ -61,11 +61,10 @@ import FooterBar from "@/components/FooterBar.vue";
import {isMobile} from "@/utils/libs"; import {isMobile} from "@/utils/libs";
import {checkSession} from "@/action/session"; import {checkSession} from "@/action/session";
import {setUserToken} from "@/store/session"; import {setUserToken} from "@/store/session";
import {prevRoute} from "@/router";
import ResetPass from "@/components/ResetPass.vue"; import ResetPass from "@/components/ResetPass.vue";
const router = useRouter(); const router = useRouter();
const title = ref('ChatPlus 用户登录'); const title = ref('Geek-AI');
const username = ref(process.env.VUE_APP_USER); const username = ref(process.env.VUE_APP_USER);
const password = ref(process.env.VUE_APP_PASS); const password = ref(process.env.VUE_APP_PASS);
const showResetPass = ref(false) const showResetPass = ref(false)
@ -74,6 +73,7 @@ const logo = ref("/images/logo.png")
// //
httpGet("/api/config/get?key=system").then(res => { httpGet("/api/config/get?key=system").then(res => {
logo.value = res.data.logo logo.value = res.data.logo
title.value = res.data.title
}).catch(e => { }).catch(e => {
ElMessage.error("获取系统配置失败:" + e.message) ElMessage.error("获取系统配置失败:" + e.message)
}) })
@ -104,15 +104,11 @@ const login = function () {
httpPost('/api/user/login', {username: username.value.trim(), password: password.value.trim()}).then((res) => { httpPost('/api/user/login', {username: username.value.trim(), password: password.value.trim()}).then((res) => {
setUserToken(res.data) setUserToken(res.data)
if (prevRoute.path === '' || prevRoute.path === '/register') {
if (isMobile()) { if (isMobile()) {
router.push('/mobile') router.push('/mobile')
} else { } else {
router.push('/chat') router.push('/chat')
} }
} else {
router.push(prevRoute.path)
}
}).catch((e) => { }).catch((e) => {
ElMessage.error('登录失败,' + e.message) ElMessage.error('登录失败,' + e.message)
@ -154,6 +150,7 @@ const login = function () {
.el-image { .el-image {
width 120px; width 120px;
cursor pointer
} }
} }
@ -164,6 +161,7 @@ const login = function () {
color $white_v1 color $white_v1
letter-space 2px letter-space 2px
text-align center text-align center
padding-top 10px
} }
.content { .content {

View File

@ -5,16 +5,19 @@
<div class="page-inner"> <div class="page-inner">
<div class="contain" v-if="enableRegister"> <div class="contain" v-if="enableRegister">
<div class="logo"> <div class="logo">
<el-image :src="logo" fit="cover"/> <el-image :src="logo" fit="cover" @click="router.push('/')"/>
</div> </div>
<div class="header">{{ title }}</div> <div class="header">{{ title }}</div>
<div class="content"> <div class="content">
<el-form :model="formData" label-width="120px" ref="formRef"> <el-form :model="data" class="form" v-if="enableRegister">
<el-tabs v-model="activeName" class="demo-tabs">
<el-tab-pane label="手机注册" name="mobile" v-if="enableMobile">
<div class="block"> <div class="block">
<el-input :placeholder="placeholder" <el-input placeholder="手机号码"
size="large" size="large"
v-model="formData.username" v-model="data.username"
maxlength="11"
autocomplete="off"> autocomplete="off">
<template #prefix> <template #prefix>
<el-icon> <el-icon>
@ -23,11 +26,79 @@
</template> </template>
</el-input> </el-input>
</div> </div>
<div class="block">
<el-row :gutter="10">
<el-col :span="12">
<el-input placeholder="验证码"
size="large" maxlength="30"
v-model="data.code"
autocomplete="off">
<template #prefix>
<el-icon>
<Checked/>
</el-icon>
</template>
</el-input>
</el-col>
<el-col :span="12">
<send-msg size="large" :receiver="data.username"/>
</el-col>
</el-row>
</div>
</el-tab-pane>
<el-tab-pane label="邮箱注册" name="email" v-if="enableEmail">
<div class="block">
<el-input placeholder="邮箱地址"
size="large"
v-model="data.username"
autocomplete="off">
<template #prefix>
<el-icon>
<Message/>
</el-icon>
</template>
</el-input>
</div>
<div class="block">
<el-row :gutter="10">
<el-col :span="12">
<el-input placeholder="验证码"
size="large" maxlength="30"
v-model="data.code"
autocomplete="off">
<template #prefix>
<el-icon>
<Checked/>
</el-icon>
</template>
</el-input>
</el-col>
<el-col :span="12">
<send-msg size="large" :receiver="data.username"/>
</el-col>
</el-row>
</div>
</el-tab-pane>
<el-tab-pane label="用户名注册" name="username" v-if="enableUser">
<div class="block">
<el-input placeholder="用户名"
size="large"
v-model="data.username"
autocomplete="off">
<template #prefix>
<el-icon>
<Iphone/>
</el-icon>
</template>
</el-input>
</div>
</el-tab-pane>
</el-tabs>
<div class="block"> <div class="block">
<el-input placeholder="请输入密码(8-16位)" <el-input placeholder="请输入密码(8-16位)"
maxlength="16" size="large" maxlength="16" size="large"
v-model="formData.password" show-password v-model="data.password" show-password
autocomplete="off"> autocomplete="off">
<template #prefix> <template #prefix>
<el-icon> <el-icon>
@ -39,7 +110,7 @@
<div class="block"> <div class="block">
<el-input placeholder="重复密码(8-16位)" <el-input placeholder="重复密码(8-16位)"
size="large" maxlength="16" v-model="formData.repass" show-password size="large" maxlength="16" v-model="data.repass" show-password
autocomplete="off"> autocomplete="off">
<template #prefix> <template #prefix>
<el-icon> <el-icon>
@ -49,30 +120,10 @@
</el-input> </el-input>
</div> </div>
<div class="block" v-if="enableMobile || enableEmail">
<el-row :gutter="10">
<el-col :span="12">
<el-input placeholder="验证码"
size="large" maxlength="30"
v-model="formData.code"
autocomplete="off">
<template #prefix>
<el-icon>
<Checked/>
</el-icon>
</template>
</el-input>
</el-col>
<el-col :span="12">
<send-msg size="large" :receiver="formData.username"/>
</el-col>
</el-row>
</div>
<div class="block"> <div class="block">
<el-input placeholder="邀请码" <el-input placeholder="邀请码(可选)"
size="large" size="large"
v-model="formData.invite_code" v-model="data.invite_code"
autocomplete="off"> autocomplete="off">
<template #prefix> <template #prefix>
<el-icon> <el-icon>
@ -82,8 +133,10 @@
</el-input> </el-input>
</div> </div>
<el-row class="btn-row"> <el-row class="btn-row" :gutter="20">
<el-button class="login-btn" size="large" type="primary" @click="register">注册</el-button> <el-col :span="24">
<el-button class="login-btn" type="primary" size="large" @click="submitRegister">注册</el-button>
</el-col>
</el-row> </el-row>
<el-row class="text-line"> <el-row class="text-line">
@ -91,6 +144,8 @@
<el-link type="primary" @click="router.push('/login')">登录</el-link> <el-link type="primary" @click="router.push('/login')">登录</el-link>
</el-row> </el-row>
</el-form> </el-form>
</div> </div>
</div> </div>
@ -124,70 +179,77 @@ import FooterBar from "@/components/FooterBar.vue";
import SendMsg from "@/components/SendMsg.vue"; import SendMsg from "@/components/SendMsg.vue";
import {arrayContains} from "@/utils/libs"; import {arrayContains} from "@/utils/libs";
import {setUserToken} from "@/store/session"; import {setUserToken} from "@/store/session";
import {validateEmail, validateMobile} from "@/utils/validate";
const router = useRouter(); const router = useRouter();
const title = ref('ChatPlus 用户注册'); const title = ref('Geek-AI 用户注册');
const formData = ref({ const logo = ref("/images/logo")
const data = ref({
username: '', username: '',
password: '', password: '',
code: '', code: '',
repass: '', repass: '',
invite_code: router.currentRoute.value.query['invite_code'], invite_code: router.currentRoute.value.query['invite_code'],
}) })
const formRef = ref(null)
const enableMobile = ref(false) const enableMobile = ref(false)
const enableEmail = ref(false) const enableEmail = ref(false)
const enableRegister = ref(true) const enableUser = ref(false)
const enableRegister = ref(false)
const activeName = ref("mobile")
const wxImg = ref("/images/wx.png") const wxImg = ref("/images/wx.png")
const ways = []
const placeholder = ref("用户名:")
const logo = ref("/images/logo.png")
httpGet("/api/config/get?key=system").then(res => { httpGet("/api/config/get?key=system").then(res => {
if (res.data) { if (res.data) {
title.value = res.data.title
logo.value = res.data.logo
const registerWays = res.data['register_ways'] const registerWays = res.data['register_ways']
if (arrayContains(registerWays, "mobile")) { if (arrayContains(registerWays, "mobile")) {
enableMobile.value = true enableMobile.value = true
ways.push("手机号")
} }
if (arrayContains(registerWays, "email")) { if (arrayContains(registerWays, "email")) {
enableEmail.value = true enableEmail.value = true
ways.push("邮箱地址")
} }
placeholder.value += ways.join("/") if (arrayContains(registerWays, "username")) {
enableUser.value = true
}
// //
enableRegister.value = res.data['enabled_register'] enableRegister.value = res.data['enabled_register']
// // 使
if (res.data['wechat_card_url'] !== '') { if (res.data['wechat_card_url'] !== '') {
wxImg.value = res.data['wechat_card_url'] wxImg.value = res.data['wechat_card_url']
} }
logo.value = res.data.logo
} }
}).catch(e => { }).catch(e => {
ElMessage.error("获取系统配置失败:" + e.message) ElMessage.error("获取系统配置失败:" + e.message)
}) })
httpGet("/api/invite/hits", {code: formData.value.invite_code}).then(() => { //
}).catch(() => { const submitRegister = () => {
}) if (data.value.username === '') {
const register = function () {
if (formData.value.username === '') {
return ElMessage.error('请输入用户名'); return ElMessage.error('请输入用户名');
} }
if (formData.value.password.length < 8) { if (activeName.value === 'mobile' && !validateMobile(data.value.username)) {
return ElMessage.error('请输入合法的手机号');
}
if (activeName.value === 'email' && !validateEmail(data.value.username)) {
return ElMessage.error('请输入合法的邮箱地址');
}
if (data.value.password.length < 8) {
return ElMessage.error('密码的长度为8-16个字符'); return ElMessage.error('密码的长度为8-16个字符');
} }
if (formData.value.repass !== formData.value.password) { if (data.value.repass !== data.value.password) {
return ElMessage.error('两次输入密码不一致'); return ElMessage.error('两次输入密码不一致');
} }
if ((enableEmail.value || enableMobile.value) && formData.value.code === '') { if ((activeName.value === 'mobile' || activeName.value === 'email') && data.value.code === '') {
return ElMessage.error('请输入验证码'); return ElMessage.error('请输入验证码');
} }
httpPost('/api/user/register', formData.value).then((res) => { data.value.reg_way = activeName.value
httpPost('/api/user/register', data.value).then((res) => {
setUserToken(res.data) setUserToken(res.data)
ElMessage.success({ ElMessage.success({
"message": "注册成功,即将跳转到对话主界面...", "message": "注册成功,即将跳转到对话主界面...",
@ -222,7 +284,7 @@ const register = function () {
.page-inner { .page-inner {
max-width 450px max-width 450px
min-width 360px width 100%
height 100vh height 100vh
display flex display flex
justify-content center justify-content center
@ -234,13 +296,14 @@ const register = function () {
color #ffffff color #ffffff
border-radius 10px; border-radius 10px;
z-index 10 z-index 10
background-color rgba(255, 255, 255, 0.3) background-color rgba(255, 255, 255, 0.2)
.logo { .logo {
text-align center text-align center
.el-image { .el-image {
width 120px; width 120px;
cursor pointer
} }
} }
@ -251,6 +314,7 @@ const register = function () {
color $white_v1 color $white_v1
letter-space 2px letter-space 2px
text-align center text-align center
padding-top 10px
} }
.content { .content {
@ -326,5 +390,9 @@ const register = function () {
color #c1c1c1 color #c1c1c1
} }
} }
.el-tabs__item {
color #ffffff
}
} }
</style> </style>