diff --git a/api/handler/user_handler.go b/api/handler/user_handler.go
index ac9cc240..de96c80e 100644
--- a/api/handler/user_handler.go
+++ b/api/handler/user_handler.go
@@ -329,8 +329,10 @@ func (h *UserHandler) CLogin(c *gin.Context) {
// CLoginCallback 第三方登录回调
func (h *UserHandler) CLoginCallback(c *gin.Context) {
- loginType := h.GetTrim(c, "login_type")
- code := h.GetTrim(c, "code")
+ loginType := c.Query("login_type")
+ code := c.Query("code")
+ userId := h.GetInt(c, "user_id", 0)
+ action := c.Query("action")
var res types.BizVo
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
data := res.Data.(map[string]interface{})
- session := gin.H{}
var user model.User
- tx := h.DB.Debug().Where("openid", data["openid"]).First(&user)
- if tx.Error != nil { // user not exist, create new user
- // 检测最大注册人数
+ if action == "bind" && userId > 0 {
+ 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
h.DB.Model(&model.User{}).Count(&totalUser)
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)
}
-// ResetPass 重置密码
+// ResetPass 找回密码
func (h *UserHandler) ResetPass(c *gin.Context) {
var data struct {
Username string `json:"username"`
@@ -572,11 +597,11 @@ func (h *UserHandler) ResetPass(c *gin.Context) {
}
}
-// BindUsername 重置账号
-func (h *UserHandler) BindUsername(c *gin.Context) {
+// BindMobile 绑定手机号
+func (h *UserHandler) BindMobile(c *gin.Context) {
var data struct {
- Username string `json:"username"`
- Code string `json:"code"`
+ Mobile string `json:"mobile"`
+ Code string `json:"code"`
}
if err := c.ShouldBindJSON(&data); err != nil {
resp.ERROR(c, types.InvalidArgs)
@@ -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()
if err != nil || code != data.Code {
resp.ERROR(c, "验证码错误")
@@ -593,19 +618,54 @@ func (h *UserHandler) BindUsername(c *gin.Context) {
// 检查手机号是否被其他账号绑定
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 {
- resp.ERROR(c, "该账号已经被其他账号绑定")
+ resp.ERROR(c, "该手机号已经绑定了其他账号,请更换手机号")
return
}
- user, err := h.GetLoginUser(c)
- if err != nil {
- resp.NotAuth(c)
- return
- }
+ userId := h.GetLoginUserId(c)
- 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 {
resp.ERROR(c, err.Error())
return
diff --git a/api/main.go b/api/main.go
index ead2032b..58a428be 100644
--- a/api/main.go
+++ b/api/main.go
@@ -231,7 +231,8 @@ func main() {
group.GET("profile", h.Profile)
group.POST("profile/update", h.ProfileUpdate)
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.GET("clogin", h.CLogin)
group.GET("clogin/callback", h.CLoginCallback)
diff --git a/web/src/assets/iconfont/iconfont.css b/web/src/assets/iconfont/iconfont.css
index 2c72d0fd..586dc701 100644
--- a/web/src/assets/iconfont/iconfont.css
+++ b/web/src/assets/iconfont/iconfont.css
@@ -1,8 +1,8 @@
@font-face {
font-family: "iconfont"; /* Project id 4125778 */
- src: url('iconfont.woff2?t=1723434190230') format('woff2'),
- url('iconfont.woff?t=1723434190230') format('woff'),
- url('iconfont.ttf?t=1723434190230') format('truetype');
+ src: url('iconfont.woff2?t=1723593727785') format('woff2'),
+ url('iconfont.woff?t=1723593727785') format('woff'),
+ url('iconfont.ttf?t=1723593727785') format('truetype');
}
.iconfont {
@@ -13,6 +13,14 @@
-moz-osx-font-smoothing: grayscale;
}
+.icon-email:before {
+ content: "\e670";
+}
+
+.icon-mobile:before {
+ content: "\e79a";
+}
+
.icon-drag:before {
content: "\e8ec";
}
diff --git a/web/src/assets/iconfont/iconfont.js b/web/src/assets/iconfont/iconfont.js
index 8d38c060..886819cf 100644
--- a/web/src/assets/iconfont/iconfont.js
+++ b/web/src/assets/iconfont/iconfont.js
@@ -1 +1 @@
-window._iconfont_svg_string_4125778='',function(a){var l=(l=document.getElementsByTagName("script"))[l.length-1],c=l.getAttribute("data-injectcss"),l=l.getAttribute("data-disable-injectsvg");if(!l){var t,h,i,o,z,m=function(l,c){c.parentNode.insertBefore(l,c)};if(c&&!a.__iconfont__svg__cssinject__){a.__iconfont__svg__cssinject__=!0;try{document.write("")}catch(l){console&&console.log(l)}}t=function(){var l,c=document.createElement("div");c.innerHTML=a._iconfont_svg_string_4125778,(c=c.getElementsByTagName("svg")[0])&&(c.setAttribute("aria-hidden","true"),c.style.position="absolute",c.style.width=0,c.style.height=0,c.style.overflow="hidden",c=c,(l=document.body).firstChild?m(c,l.firstChild):l.appendChild(c))},document.addEventListener?~["complete","loaded","interactive"].indexOf(document.readyState)?setTimeout(t,0):(h=function(){document.removeEventListener("DOMContentLoaded",h,!1),t()},document.addEventListener("DOMContentLoaded",h,!1)):document.attachEvent&&(i=t,o=a.document,z=!1,p(),o.onreadystatechange=function(){"complete"==o.readyState&&(o.onreadystatechange=null,s())})}function s(){z||(z=!0,i())}function p(){try{o.documentElement.doScroll("left")}catch(l){return void setTimeout(p,50)}s()}}(window);
\ No newline at end of file
+window._iconfont_svg_string_4125778='',function(a){var l=(l=document.getElementsByTagName("script"))[l.length-1],c=l.getAttribute("data-injectcss"),l=l.getAttribute("data-disable-injectsvg");if(!l){var t,h,i,o,z,m=function(l,c){c.parentNode.insertBefore(l,c)};if(c&&!a.__iconfont__svg__cssinject__){a.__iconfont__svg__cssinject__=!0;try{document.write("")}catch(l){console&&console.log(l)}}t=function(){var l,c=document.createElement("div");c.innerHTML=a._iconfont_svg_string_4125778,(c=c.getElementsByTagName("svg")[0])&&(c.setAttribute("aria-hidden","true"),c.style.position="absolute",c.style.width=0,c.style.height=0,c.style.overflow="hidden",c=c,(l=document.body).firstChild?m(c,l.firstChild):l.appendChild(c))},document.addEventListener?~["complete","loaded","interactive"].indexOf(document.readyState)?setTimeout(t,0):(h=function(){document.removeEventListener("DOMContentLoaded",h,!1),t()},document.addEventListener("DOMContentLoaded",h,!1)):document.attachEvent&&(i=t,o=a.document,z=!1,p(),o.onreadystatechange=function(){"complete"==o.readyState&&(o.onreadystatechange=null,s())})}function s(){z||(z=!0,i())}function p(){try{o.documentElement.doScroll("left")}catch(l){return void setTimeout(p,50)}s()}}(window);
\ No newline at end of file
diff --git a/web/src/assets/iconfont/iconfont.json b/web/src/assets/iconfont/iconfont.json
index 5fbfb566..0d177ae5 100644
--- a/web/src/assets/iconfont/iconfont.json
+++ b/web/src/assets/iconfont/iconfont.json
@@ -5,6 +5,20 @@
"css_prefix_text": "icon-",
"description": "",
"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",
"name": "drag",
diff --git a/web/src/assets/iconfont/iconfont.ttf b/web/src/assets/iconfont/iconfont.ttf
index 887cbd6a..6e879bd8 100644
Binary files a/web/src/assets/iconfont/iconfont.ttf and b/web/src/assets/iconfont/iconfont.ttf differ
diff --git a/web/src/assets/iconfont/iconfont.woff b/web/src/assets/iconfont/iconfont.woff
index 79f8c16d..ef68b85f 100644
Binary files a/web/src/assets/iconfont/iconfont.woff and b/web/src/assets/iconfont/iconfont.woff differ
diff --git a/web/src/assets/iconfont/iconfont.woff2 b/web/src/assets/iconfont/iconfont.woff2
index ab7aa757..f33f132c 100644
Binary files a/web/src/assets/iconfont/iconfont.woff2 and b/web/src/assets/iconfont/iconfont.woff2 differ
diff --git a/web/src/components/BindEmail.vue b/web/src/components/BindEmail.vue
new file mode 100644
index 00000000..1ae9e773
--- /dev/null
+++ b/web/src/components/BindEmail.vue
@@ -0,0 +1,108 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/web/src/components/BindMobile.vue b/web/src/components/BindMobile.vue
index 9fa4d54e..41eceb3f 100644
--- a/web/src/components/BindMobile.vue
+++ b/web/src/components/BindMobile.vue
@@ -2,24 +2,24 @@