mirror of
https://github.com/yangjian102621/geekai.git
synced 2025-09-17 16:56:38 +08:00
add bind mobile, bind email, bind wechat function is ready
This commit is contained in:
parent
43843b92f2
commit
aa42d38387
@ -329,8 +329,10 @@ func (h *UserHandler) CLogin(c *gin.Context) {
|
|||||||
|
|
||||||
// CLoginCallback 第三方登录回调
|
// CLoginCallback 第三方登录回调
|
||||||
func (h *UserHandler) CLoginCallback(c *gin.Context) {
|
func (h *UserHandler) CLoginCallback(c *gin.Context) {
|
||||||
loginType := h.GetTrim(c, "login_type")
|
loginType := c.Query("login_type")
|
||||||
code := h.GetTrim(c, "code")
|
code := c.Query("code")
|
||||||
|
userId := h.GetInt(c, "user_id", 0)
|
||||||
|
action := c.Query("action")
|
||||||
|
|
||||||
var res types.BizVo
|
var res types.BizVo
|
||||||
apiURL := fmt.Sprintf("%s/api/clogin/info", h.App.Config.ApiConfig.ApiURL)
|
apiURL := fmt.Sprintf("%s/api/clogin/info", h.App.Config.ApiConfig.ApiURL)
|
||||||
@ -355,11 +357,34 @@ func (h *UserHandler) CLoginCallback(c *gin.Context) {
|
|||||||
|
|
||||||
// login successfully
|
// login successfully
|
||||||
data := res.Data.(map[string]interface{})
|
data := res.Data.(map[string]interface{})
|
||||||
session := gin.H{}
|
|
||||||
var user model.User
|
var user model.User
|
||||||
tx := h.DB.Debug().Where("openid", data["openid"]).First(&user)
|
if action == "bind" && userId > 0 {
|
||||||
if tx.Error != nil { // user not exist, create new user
|
err = h.DB.Where("openid", data["openid"]).First(&user).Error
|
||||||
// 检测最大注册人数
|
if err == nil {
|
||||||
|
resp.ERROR(c, "该微信已经绑定其他账号,请先解绑")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = h.DB.Where("id", userId).First(&user).Error
|
||||||
|
if err != nil {
|
||||||
|
resp.ERROR(c, "绑定用户不存在")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = h.DB.Model(&user).UpdateColumn("openid", data["openid"]).Error
|
||||||
|
if err != nil {
|
||||||
|
resp.ERROR(c, "更新用户信息失败,"+err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
resp.SUCCESS(c, gin.H{"token": ""})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
session := gin.H{}
|
||||||
|
tx := h.DB.Where("openid", data["openid"]).First(&user)
|
||||||
|
if tx.Error != nil {
|
||||||
|
// create new user
|
||||||
var totalUser int64
|
var totalUser int64
|
||||||
h.DB.Model(&model.User{}).Count(&totalUser)
|
h.DB.Model(&model.User{}).Count(&totalUser)
|
||||||
if h.licenseService.GetLicense().Configs.UserNum > 0 && int(totalUser) >= h.licenseService.GetLicense().Configs.UserNum {
|
if h.licenseService.GetLicense().Configs.UserNum > 0 && int(totalUser) >= h.licenseService.GetLicense().Configs.UserNum {
|
||||||
@ -534,7 +559,7 @@ func (h *UserHandler) UpdatePass(c *gin.Context) {
|
|||||||
resp.SUCCESS(c)
|
resp.SUCCESS(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ResetPass 重置密码
|
// ResetPass 找回密码
|
||||||
func (h *UserHandler) ResetPass(c *gin.Context) {
|
func (h *UserHandler) ResetPass(c *gin.Context) {
|
||||||
var data struct {
|
var data struct {
|
||||||
Username string `json:"username"`
|
Username string `json:"username"`
|
||||||
@ -572,10 +597,10 @@ func (h *UserHandler) ResetPass(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// BindUsername 重置账号
|
// BindMobile 绑定手机号
|
||||||
func (h *UserHandler) BindUsername(c *gin.Context) {
|
func (h *UserHandler) BindMobile(c *gin.Context) {
|
||||||
var data struct {
|
var data struct {
|
||||||
Username string `json:"username"`
|
Mobile string `json:"mobile"`
|
||||||
Code string `json:"code"`
|
Code string `json:"code"`
|
||||||
}
|
}
|
||||||
if err := c.ShouldBindJSON(&data); err != nil {
|
if err := c.ShouldBindJSON(&data); err != nil {
|
||||||
@ -584,7 +609,7 @@ func (h *UserHandler) BindUsername(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 检查验证码
|
// 检查验证码
|
||||||
key := CodeStorePrefix + data.Username
|
key := CodeStorePrefix + data.Mobile
|
||||||
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 {
|
||||||
resp.ERROR(c, "验证码错误")
|
resp.ERROR(c, "验证码错误")
|
||||||
@ -593,19 +618,54 @@ func (h *UserHandler) BindUsername(c *gin.Context) {
|
|||||||
|
|
||||||
// 检查手机号是否被其他账号绑定
|
// 检查手机号是否被其他账号绑定
|
||||||
var item model.User
|
var item model.User
|
||||||
res := h.DB.Where("username = ?", data.Username).First(&item)
|
res := h.DB.Where("mobile", data.Mobile).First(&item)
|
||||||
if res.Error == nil {
|
if res.Error == nil {
|
||||||
resp.ERROR(c, "该账号已经被其他账号绑定")
|
resp.ERROR(c, "该手机号已经绑定了其他账号,请更换手机号")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
user, err := h.GetLoginUser(c)
|
userId := h.GetLoginUserId(c)
|
||||||
if err != nil {
|
|
||||||
resp.NotAuth(c)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
err = h.DB.Model(&user).UpdateColumn("username", data.Username).Error
|
err = h.DB.Model(&item).Where("id", userId).UpdateColumn("mobile", data.Mobile).Error
|
||||||
|
if err != nil {
|
||||||
|
resp.ERROR(c, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
_ = h.redis.Del(c, key) // 删除短信验证码
|
||||||
|
resp.SUCCESS(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// BindEmail 绑定邮箱
|
||||||
|
func (h *UserHandler) BindEmail(c *gin.Context) {
|
||||||
|
var data struct {
|
||||||
|
Email string `json:"email"`
|
||||||
|
Code string `json:"code"`
|
||||||
|
}
|
||||||
|
if err := c.ShouldBindJSON(&data); err != nil {
|
||||||
|
resp.ERROR(c, types.InvalidArgs)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查验证码
|
||||||
|
key := CodeStorePrefix + data.Email
|
||||||
|
code, err := h.redis.Get(c, key).Result()
|
||||||
|
if err != nil || code != data.Code {
|
||||||
|
resp.ERROR(c, "验证码错误")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查手机号是否被其他账号绑定
|
||||||
|
var item model.User
|
||||||
|
res := h.DB.Where("email", data.Email).First(&item)
|
||||||
|
if res.Error == nil {
|
||||||
|
resp.ERROR(c, "该邮箱地址已经绑定了其他账号,请更邮箱地址")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
userId := h.GetLoginUserId(c)
|
||||||
|
|
||||||
|
err = h.DB.Model(&item).Where("id", userId).UpdateColumn("email", data.Email).Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
resp.ERROR(c, err.Error())
|
resp.ERROR(c, err.Error())
|
||||||
return
|
return
|
||||||
|
@ -231,7 +231,8 @@ func main() {
|
|||||||
group.GET("profile", h.Profile)
|
group.GET("profile", h.Profile)
|
||||||
group.POST("profile/update", h.ProfileUpdate)
|
group.POST("profile/update", h.ProfileUpdate)
|
||||||
group.POST("password", h.UpdatePass)
|
group.POST("password", h.UpdatePass)
|
||||||
group.POST("bind/username", h.BindUsername)
|
group.POST("bind/mobile", h.BindMobile)
|
||||||
|
group.POST("bind/email", h.BindEmail)
|
||||||
group.POST("resetPass", h.ResetPass)
|
group.POST("resetPass", h.ResetPass)
|
||||||
group.GET("clogin", h.CLogin)
|
group.GET("clogin", h.CLogin)
|
||||||
group.GET("clogin/callback", h.CLoginCallback)
|
group.GET("clogin/callback", h.CLoginCallback)
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
@font-face {
|
@font-face {
|
||||||
font-family: "iconfont"; /* Project id 4125778 */
|
font-family: "iconfont"; /* Project id 4125778 */
|
||||||
src: url('iconfont.woff2?t=1723434190230') format('woff2'),
|
src: url('iconfont.woff2?t=1723593727785') format('woff2'),
|
||||||
url('iconfont.woff?t=1723434190230') format('woff'),
|
url('iconfont.woff?t=1723593727785') format('woff'),
|
||||||
url('iconfont.ttf?t=1723434190230') format('truetype');
|
url('iconfont.ttf?t=1723593727785') format('truetype');
|
||||||
}
|
}
|
||||||
|
|
||||||
.iconfont {
|
.iconfont {
|
||||||
@ -13,6 +13,14 @@
|
|||||||
-moz-osx-font-smoothing: grayscale;
|
-moz-osx-font-smoothing: grayscale;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.icon-email:before {
|
||||||
|
content: "\e670";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-mobile:before {
|
||||||
|
content: "\e79a";
|
||||||
|
}
|
||||||
|
|
||||||
.icon-drag:before {
|
.icon-drag:before {
|
||||||
content: "\e8ec";
|
content: "\e8ec";
|
||||||
}
|
}
|
||||||
|
File diff suppressed because one or more lines are too long
@ -5,6 +5,20 @@
|
|||||||
"css_prefix_text": "icon-",
|
"css_prefix_text": "icon-",
|
||||||
"description": "",
|
"description": "",
|
||||||
"glyphs": [
|
"glyphs": [
|
||||||
|
{
|
||||||
|
"icon_id": "15838472",
|
||||||
|
"name": "email",
|
||||||
|
"font_class": "email",
|
||||||
|
"unicode": "e670",
|
||||||
|
"unicode_decimal": 58992
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"icon_id": "6151052",
|
||||||
|
"name": "mobile-alt",
|
||||||
|
"font_class": "mobile",
|
||||||
|
"unicode": "e79a",
|
||||||
|
"unicode_decimal": 59290
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"icon_id": "15617554",
|
"icon_id": "15617554",
|
||||||
"name": "drag",
|
"name": "drag",
|
||||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
108
web/src/components/BindEmail.vue
Normal file
108
web/src/components/BindEmail.vue
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
<template>
|
||||||
|
<el-dialog
|
||||||
|
v-model="showDialog"
|
||||||
|
:close-on-click-modal="true"
|
||||||
|
style="max-width: 400px"
|
||||||
|
@close="close"
|
||||||
|
:title="title"
|
||||||
|
>
|
||||||
|
<div class="form">
|
||||||
|
<div class="text-center" v-if="email !== ''">当前已绑定邮箱:{{ email }}</div>
|
||||||
|
|
||||||
|
<el-form label-position="top">
|
||||||
|
<el-form-item label="邮箱地址">
|
||||||
|
<el-input v-model="form.email"/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="验证码">
|
||||||
|
<el-row :gutter="0">
|
||||||
|
<el-col :span="16">
|
||||||
|
<el-input v-model="form.code" maxlength="6"/>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="8" style="padding-left: 10px">
|
||||||
|
<send-msg :receiver="form.email" type="email"/>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<template #footer>
|
||||||
|
<span class="dialog-footer">
|
||||||
|
<el-button type="primary" @click="save">
|
||||||
|
提交绑定
|
||||||
|
</el-button>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import {computed, ref, watch} from "vue";
|
||||||
|
import SendMsg from "@/components/SendMsg.vue";
|
||||||
|
import {ElMessage} from "element-plus";
|
||||||
|
import {httpPost} from "@/utils/http";
|
||||||
|
import {checkSession, removeUserInfo} from "@/store/cache";
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
show: Boolean,
|
||||||
|
});
|
||||||
|
|
||||||
|
const showDialog = computed(() => {
|
||||||
|
return props.show
|
||||||
|
})
|
||||||
|
|
||||||
|
const title = ref('绑定邮箱')
|
||||||
|
const email = ref('')
|
||||||
|
const form = ref({
|
||||||
|
email: '',
|
||||||
|
code: ''
|
||||||
|
})
|
||||||
|
|
||||||
|
watch(showDialog, (val) => {
|
||||||
|
if (val) {
|
||||||
|
form.value.code = ''
|
||||||
|
form.value.email = ''
|
||||||
|
checkSession().then(user => {
|
||||||
|
email.value = user.email
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const emits = defineEmits(['hide']);
|
||||||
|
|
||||||
|
const save = () => {
|
||||||
|
if (form.value.code === '') {
|
||||||
|
return ElMessage.error("请输入验证码");
|
||||||
|
}
|
||||||
|
|
||||||
|
httpPost('/api/user/bind/email', form.value).then(() => {
|
||||||
|
removeUserInfo()
|
||||||
|
ElMessage.success("绑定成功")
|
||||||
|
emits('hide')
|
||||||
|
}).catch(e => {
|
||||||
|
ElMessage.error("绑定失败:" + e.message);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const close = function () {
|
||||||
|
emits('hide');
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="stylus" scoped>
|
||||||
|
.form {
|
||||||
|
.text-center {
|
||||||
|
text-align center
|
||||||
|
padding-bottom 15px
|
||||||
|
font-size 14px
|
||||||
|
color #a1a1a1
|
||||||
|
font-weight 700
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-form-item__content {
|
||||||
|
.el-row {
|
||||||
|
width 100%
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
@ -2,24 +2,24 @@
|
|||||||
<el-dialog
|
<el-dialog
|
||||||
v-model="showDialog"
|
v-model="showDialog"
|
||||||
:close-on-click-modal="true"
|
:close-on-click-modal="true"
|
||||||
style="max-width: 600px"
|
style="max-width: 400px"
|
||||||
:before-close="close"
|
@close="close"
|
||||||
:title="title"
|
:title="title"
|
||||||
>
|
>
|
||||||
<div class="form">
|
<div class="form">
|
||||||
<div class="text-center">当前已绑手机号:{{ mobile }}</div>
|
<div class="text-center" v-if="mobile !== ''">当前已绑手机号:{{ mobile }}</div>
|
||||||
|
|
||||||
<el-form :model="form" label-width="120px">
|
<el-form label-position="top">
|
||||||
<el-form-item label="手机号">
|
<el-form-item label="手机号">
|
||||||
<el-input v-model="form.mobile"/>
|
<el-input v-model="form.mobile"/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="验证码">
|
<el-form-item label="验证码">
|
||||||
<el-row :gutter="20">
|
<el-row :gutter="0">
|
||||||
<el-col :span="16">
|
<el-col :span="16">
|
||||||
<el-input v-model="form.code" maxlength="6"/>
|
<el-input v-model="form.code" maxlength="6"/>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="8">
|
<el-col :span="8" style="padding-left: 10px">
|
||||||
<send-msg size="" :receiver="form.username" type="mobile"/>
|
<send-msg :receiver="form.mobile" type="mobile"/>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@ -37,12 +37,11 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import {computed, ref} from "vue";
|
import {computed, ref, watch} from "vue";
|
||||||
import SendMsg from "@/components/SendMsg.vue";
|
import SendMsg from "@/components/SendMsg.vue";
|
||||||
import {ElMessage} from "element-plus";
|
import {ElMessage} from "element-plus";
|
||||||
import {httpPost} from "@/utils/http";
|
import {httpPost} from "@/utils/http";
|
||||||
import {validateEmail, validateMobile} from "@/utils/validate";
|
import {checkSession, removeUserInfo} from "@/store/cache";
|
||||||
import {checkSession} from "@/store/cache";
|
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
show: Boolean,
|
show: Boolean,
|
||||||
@ -59,33 +58,37 @@ const form = ref({
|
|||||||
code: ''
|
code: ''
|
||||||
})
|
})
|
||||||
|
|
||||||
checkSession().then(user => {
|
watch(showDialog, (val) => {
|
||||||
|
if (val) {
|
||||||
|
form.value = {
|
||||||
|
mobile: '',
|
||||||
|
code: ''
|
||||||
|
}
|
||||||
|
|
||||||
|
checkSession().then(user => {
|
||||||
mobile.value = user.mobile
|
mobile.value = user.mobile
|
||||||
|
})
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const emits = defineEmits(['hide']);
|
const emits = defineEmits(['hide']);
|
||||||
|
|
||||||
const save = () => {
|
const save = () => {
|
||||||
if (!validateMobile(form.value.mobile) && !validateEmail(form.value.mobile)) {
|
|
||||||
return ElMessage.error("请输入合法的手机号/邮箱地址")
|
|
||||||
}
|
|
||||||
if (form.value.code === '') {
|
if (form.value.code === '') {
|
||||||
return ElMessage.error("请输入验证码");
|
return ElMessage.error("请输入验证码");
|
||||||
}
|
}
|
||||||
|
|
||||||
httpPost('/api/user/bind/username', form.value).then(() => {
|
httpPost('/api/user/bind/mobile', form.value).then(() => {
|
||||||
ElMessage.success({
|
removeUserInfo()
|
||||||
message: '绑定成功',
|
ElMessage.success("绑定成功")
|
||||||
duration: 1000,
|
emits('hide')
|
||||||
onClose: () => emits('hide', false)
|
|
||||||
})
|
|
||||||
}).catch(e => {
|
}).catch(e => {
|
||||||
ElMessage.error("绑定失败:" + e.message);
|
ElMessage.error("绑定失败:" + e.message);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const close = function () {
|
const close = function () {
|
||||||
emits('hide', false);
|
emits('hide');
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -66,7 +66,7 @@
|
|||||||
<div class="c-login" v-if="wechatLoginURL !== ''">
|
<div class="c-login" v-if="wechatLoginURL !== ''">
|
||||||
<div class="text">其他登录方式:</div>
|
<div class="text">其他登录方式:</div>
|
||||||
<div class="login-type">
|
<div class="login-type">
|
||||||
<a class="wechat-login" :href="wechatLoginURL"><i class="iconfont icon-wechat"></i></a>
|
<a class="wechat-login" :href="wechatLoginURL" @click="setRoute(router.currentRoute.value.path)"><i class="iconfont icon-wechat"></i></a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</el-col>
|
</el-col>
|
||||||
@ -249,6 +249,8 @@ import {arrayContains} from "@/utils/libs";
|
|||||||
import {getSystemInfo} from "@/store/cache";
|
import {getSystemInfo} from "@/store/cache";
|
||||||
import Captcha from "@/components/Captcha.vue";
|
import Captcha from "@/components/Captcha.vue";
|
||||||
import ResetPass from "@/components/ResetPass.vue";
|
import ResetPass from "@/components/ResetPass.vue";
|
||||||
|
import {setRoute} from "@/store/system";
|
||||||
|
import {useRouter} from "vue-router";
|
||||||
|
|
||||||
// eslint-disable-next-line no-undef
|
// eslint-disable-next-line no-undef
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
@ -282,9 +284,10 @@ const emits = defineEmits(['hide', 'success']);
|
|||||||
const action = ref("login")
|
const action = ref("login")
|
||||||
const enableVerify = ref(false)
|
const enableVerify = ref(false)
|
||||||
const showResetPass = ref(false)
|
const showResetPass = ref(false)
|
||||||
|
const router = useRouter()
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
const returnURL = `${location.protocol}//${location.host}/login/callback`
|
const returnURL = `${location.protocol}//${location.host}/login/callback?action=login`
|
||||||
httpGet("/api/user/clogin?return_url="+returnURL).then(res => {
|
httpGet("/api/user/clogin?return_url="+returnURL).then(res => {
|
||||||
wechatLoginURL.value = res.data.url
|
wechatLoginURL.value = res.data.url
|
||||||
}).catch(e => {
|
}).catch(e => {
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
<el-dialog
|
<el-dialog
|
||||||
v-model="showDialog"
|
v-model="showDialog"
|
||||||
:close-on-click-modal="true"
|
:close-on-click-modal="true"
|
||||||
:show-close="mobile !== ''"
|
|
||||||
:before-close="close"
|
:before-close="close"
|
||||||
:width="450"
|
:width="450"
|
||||||
:title="title"
|
:title="title"
|
||||||
|
@ -58,7 +58,7 @@ const doSendMsg = (data) => {
|
|||||||
canSend.value = false
|
canSend.value = false
|
||||||
httpPost('/api/sms/code', {receiver: props.receiver, key: data.key, dots: data.dots, x:data.x}).then(() => {
|
httpPost('/api/sms/code', {receiver: props.receiver, key: data.key, dots: data.dots, x:data.x}).then(() => {
|
||||||
showMessageOK('验证码发送成功')
|
showMessageOK('验证码发送成功')
|
||||||
let time = 120
|
let time = 60
|
||||||
btnText.value = time
|
btnText.value = time
|
||||||
const handler = setInterval(() => {
|
const handler = setInterval(() => {
|
||||||
time = time - 1
|
time = time - 1
|
||||||
|
93
web/src/components/ThirdLogin.vue
Normal file
93
web/src/components/ThirdLogin.vue
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
<template>
|
||||||
|
<el-dialog
|
||||||
|
v-model="showDialog"
|
||||||
|
:close-on-click-modal="true"
|
||||||
|
style="max-width: 400px"
|
||||||
|
@close="close"
|
||||||
|
:title="title"
|
||||||
|
>
|
||||||
|
<div class="third-login" v-loading="loading">
|
||||||
|
<div class="item" v-if="wechatBindURL !== ''">
|
||||||
|
<a class="link" :href="wechatBindURL"><i class="iconfont icon-wechat"></i></a>
|
||||||
|
<span class="text ok" v-if="openid !== ''">已绑定</span>
|
||||||
|
<span class="text" v-else>未绑定</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import {computed, ref, watch} from "vue";
|
||||||
|
import {httpGet} from "@/utils/http";
|
||||||
|
import {checkSession} from "@/store/cache";
|
||||||
|
import {showMessageError} from "@/utils/dialog";
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
show: Boolean,
|
||||||
|
});
|
||||||
|
const emits = defineEmits(['hide']);
|
||||||
|
|
||||||
|
const showDialog = computed(() => {
|
||||||
|
return props.show
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
const title = ref('绑定第三方登录')
|
||||||
|
const openid = ref('')
|
||||||
|
const wechatBindURL = ref('')
|
||||||
|
const loading = ref(true)
|
||||||
|
|
||||||
|
watch(showDialog, (val) => {
|
||||||
|
if (val) {
|
||||||
|
checkSession().then(user => {
|
||||||
|
openid.value = user.openid
|
||||||
|
})
|
||||||
|
const returnURL = `${location.protocol}//${location.host}/login/callback?action=bind`
|
||||||
|
httpGet("/api/user/clogin?return_url="+returnURL).then(res => {
|
||||||
|
wechatBindURL.value = res.data.url
|
||||||
|
loading.value = false
|
||||||
|
}).catch(e => {
|
||||||
|
showMessageError(e.message)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const close = function () {
|
||||||
|
emits('hide');
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="stylus" scoped>
|
||||||
|
.third-login {
|
||||||
|
display flex
|
||||||
|
justify-content center
|
||||||
|
min-height 100px
|
||||||
|
|
||||||
|
.item {
|
||||||
|
display flex
|
||||||
|
flex-flow column
|
||||||
|
align-items center
|
||||||
|
|
||||||
|
.link {
|
||||||
|
display flex
|
||||||
|
.iconfont {
|
||||||
|
font-size 30px
|
||||||
|
cursor pointer
|
||||||
|
background #e9f1f6
|
||||||
|
padding 10px
|
||||||
|
border-radius 50%
|
||||||
|
}
|
||||||
|
margin-bottom 10px
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.text {
|
||||||
|
font-size 14px
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-wechat,.ok {
|
||||||
|
color: #0bc15f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
@ -6,6 +6,7 @@
|
|||||||
// * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
// * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||||
|
|
||||||
import Storage from "good-storage";
|
import Storage from "good-storage";
|
||||||
|
import {useRouter} from "vue-router";
|
||||||
|
|
||||||
const MOBILE_THEME = process.env.VUE_APP_KEY_PREFIX + "MOBILE_THEME"
|
const MOBILE_THEME = process.env.VUE_APP_KEY_PREFIX + "MOBILE_THEME"
|
||||||
const ADMIN_THEME = process.env.VUE_APP_KEY_PREFIX + "ADMIN_THEME"
|
const ADMIN_THEME = process.env.VUE_APP_KEY_PREFIX + "ADMIN_THEME"
|
||||||
@ -63,3 +64,11 @@ export function FormatFileSize(bytes) {
|
|||||||
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
||||||
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
|
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function setRoute(path) {
|
||||||
|
Storage.set(process.env.VUE_APP_KEY_PREFIX + 'ROUTE_',path)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getRoute() {
|
||||||
|
return Storage.get(process.env.VUE_APP_KEY_PREFIX + 'ROUTE_')
|
||||||
|
}
|
@ -114,7 +114,7 @@ onMounted(() => {
|
|||||||
}).catch(() => {
|
}).catch(() => {
|
||||||
})
|
})
|
||||||
|
|
||||||
const returnURL = `${location.protocol}//${location.host}/login/callback`
|
const returnURL = `${location.protocol}//${location.host}/login/callback?action=login`
|
||||||
httpGet("/api/user/clogin?return_url="+returnURL).then(res => {
|
httpGet("/api/user/clogin?return_url="+returnURL).then(res => {
|
||||||
wechatLoginURL.value = res.data.url
|
wechatLoginURL.value = res.data.url
|
||||||
}).catch(e => {
|
}).catch(e => {
|
||||||
|
@ -39,9 +39,10 @@ import {useRouter} from "vue-router"
|
|||||||
import {ElMessage, ElMessageBox} from "element-plus";
|
import {ElMessage, ElMessageBox} from "element-plus";
|
||||||
import {httpGet} from "@/utils/http";
|
import {httpGet} from "@/utils/http";
|
||||||
import {setUserToken} from "@/store/session";
|
import {setUserToken} from "@/store/session";
|
||||||
import {isMobile} from "@/utils/libs";
|
|
||||||
import Clipboard from "clipboard";
|
import Clipboard from "clipboard";
|
||||||
import {showMessageError, showMessageOK} from "@/utils/dialog";
|
import {showMessageError, showMessageOK} from "@/utils/dialog";
|
||||||
|
import {getRoute} from "@/store/system";
|
||||||
|
import {checkSession, removeUserInfo} from "@/store/cache";
|
||||||
|
|
||||||
const winHeight = ref(window.innerHeight)
|
const winHeight = ref(window.innerHeight)
|
||||||
const loading = ref(true)
|
const loading = ref(true)
|
||||||
@ -52,12 +53,25 @@ const password = ref('')
|
|||||||
|
|
||||||
|
|
||||||
const code = router.currentRoute.value.query.code
|
const code = router.currentRoute.value.query.code
|
||||||
|
const action = router.currentRoute.value.query.action
|
||||||
if (code === "") {
|
if (code === "") {
|
||||||
ElMessage.error({message: "登录失败:code 参数不能为空",duration: 2000, onClose: () => router.push("/")})
|
ElMessage.error({message: "登录失败:code 参数不能为空",duration: 2000, onClose: () => router.push("/")})
|
||||||
} else {
|
} else {
|
||||||
|
checkSession().then(user => {
|
||||||
|
// bind user
|
||||||
|
doLogin(user.id)
|
||||||
|
}).catch(() => {
|
||||||
|
doLogin(0)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const doLogin = (userId) => {
|
||||||
// 发送请求获取用户信息
|
// 发送请求获取用户信息
|
||||||
httpGet("/api/user/clogin/callback",{login_type: "wx",code: code}).then(res => {
|
httpGet("/api/user/clogin/callback",{login_type: "wx",code: code, action:action, user_id: userId}).then(res => {
|
||||||
|
removeUserInfo()
|
||||||
|
if (res.data.token) {
|
||||||
setUserToken(res.data.token)
|
setUserToken(res.data.token)
|
||||||
|
}
|
||||||
if (res.data.username) {
|
if (res.data.username) {
|
||||||
username.value = res.data.username
|
username.value = res.data.username
|
||||||
password.value = res.data.password
|
password.value = res.data.password
|
||||||
@ -96,11 +110,7 @@ onUnmounted(() => {
|
|||||||
|
|
||||||
const finishLogin = () => {
|
const finishLogin = () => {
|
||||||
show.value = false
|
show.value = false
|
||||||
if (isMobile()) {
|
router.push(getRoute())
|
||||||
router.push('/mobile')
|
|
||||||
} else {
|
|
||||||
router.push('/chat')
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -7,13 +7,19 @@
|
|||||||
|
|
||||||
<el-row class="user-opt" :gutter="20">
|
<el-row class="user-opt" :gutter="20">
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-button type="primary" @click="showPasswordDialog = true">修改密码</el-button>
|
<el-button type="primary" @click="showBindEmailDialog = true">绑定邮箱</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-button type="primary" @click="showBindMobileDialog = true">绑定手机</el-button>
|
<el-button type="primary" @click="showBindMobileDialog = true">绑定手机</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-button type="primary" @click="showThirdLoginDialog = true">第三方登录</el-button>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-button type="primary" @click="showPasswordDialog = true">修改密码</el-button>
|
||||||
|
</el-col>
|
||||||
<el-col :span="24">
|
<el-col :span="24">
|
||||||
<el-button type="success" @click="showRedeemVerifyDialog = true">兑换码核销
|
<el-button type="primary" @click="showRedeemVerifyDialog = true">卡密兑换
|
||||||
</el-button>
|
</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
|
|
||||||
@ -95,6 +101,9 @@
|
|||||||
|
|
||||||
<bind-mobile v-if="isLogin" :show="showBindMobileDialog" @hide="showBindMobileDialog = false"/>
|
<bind-mobile v-if="isLogin" :show="showBindMobileDialog" @hide="showBindMobileDialog = false"/>
|
||||||
|
|
||||||
|
<bind-email v-if="isLogin" :show="showBindEmailDialog" @hide="showBindEmailDialog = false"/>
|
||||||
|
<third-login v-if="isLogin" :show="showThirdLoginDialog" @hide="showThirdLoginDialog = false"/>
|
||||||
|
|
||||||
<redeem-verify v-if="isLogin" :show="showRedeemVerifyDialog" @hide="redeemCallback"/>
|
<redeem-verify v-if="isLogin" :show="showRedeemVerifyDialog" @hide="redeemCallback"/>
|
||||||
|
|
||||||
<el-dialog
|
<el-dialog
|
||||||
@ -149,6 +158,8 @@ import {removeUserToken} from "@/store/session";
|
|||||||
import UserOrder from "@/components/UserOrder.vue";
|
import UserOrder from "@/components/UserOrder.vue";
|
||||||
import CountDown from "@/components/CountDown.vue";
|
import CountDown from "@/components/CountDown.vue";
|
||||||
import {useSharedStore} from "@/store/sharedata";
|
import {useSharedStore} from "@/store/sharedata";
|
||||||
|
import BindEmail from "@/components/BindEmail.vue";
|
||||||
|
import ThirdLogin from "@/components/ThirdLogin.vue";
|
||||||
|
|
||||||
const list = ref([])
|
const list = ref([])
|
||||||
const showPayDialog = ref(false)
|
const showPayDialog = ref(false)
|
||||||
@ -156,9 +167,11 @@ const vipImg = ref("/images/vip.png")
|
|||||||
const enableReward = ref(false) // 是否启用众筹功能
|
const enableReward = ref(false) // 是否启用众筹功能
|
||||||
const rewardImg = ref('/images/reward.png')
|
const rewardImg = ref('/images/reward.png')
|
||||||
const qrcode = ref("")
|
const qrcode = ref("")
|
||||||
const showPasswordDialog = ref(false);
|
const showPasswordDialog = ref(false)
|
||||||
const showBindMobileDialog = ref(false);
|
const showBindMobileDialog = ref(false)
|
||||||
const showRedeemVerifyDialog = ref(false);
|
const showBindEmailDialog = ref(false)
|
||||||
|
const showRedeemVerifyDialog = ref(false)
|
||||||
|
const showThirdLoginDialog = ref(false)
|
||||||
const text = ref("")
|
const text = ref("")
|
||||||
const user = ref(null)
|
const user = ref(null)
|
||||||
const isLogin = ref(false)
|
const isLogin = ref(false)
|
||||||
|
Loading…
Reference in New Issue
Block a user