mirror of
				https://github.com/yangjian102621/geekai.git
				synced 2025-11-04 16:23:42 +08:00 
			
		
		
		
	feat: reset password function is ready
This commit is contained in:
		@@ -139,6 +139,7 @@ func corsMiddleware() gin.HandlerFunc {
 | 
			
		||||
func authorizeMiddleware(s *AppServer, client *redis.Client) gin.HandlerFunc {
 | 
			
		||||
	return func(c *gin.Context) {
 | 
			
		||||
		if c.Request.URL.Path == "/api/user/login" ||
 | 
			
		||||
			c.Request.URL.Path == "/api/user/resetPass" ||
 | 
			
		||||
			c.Request.URL.Path == "/api/admin/login" ||
 | 
			
		||||
			c.Request.URL.Path == "/api/user/register" ||
 | 
			
		||||
			c.Request.URL.Path == "/api/chat/history" ||
 | 
			
		||||
 
 | 
			
		||||
@@ -275,8 +275,8 @@ func (h *UserHandler) ProfileUpdate(c *gin.Context) {
 | 
			
		||||
	resp.SUCCESS(c)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Password 更新密码
 | 
			
		||||
func (h *UserHandler) Password(c *gin.Context) {
 | 
			
		||||
// UpdatePass 更新密码
 | 
			
		||||
func (h *UserHandler) UpdatePass(c *gin.Context) {
 | 
			
		||||
	var data struct {
 | 
			
		||||
		OldPass  string `json:"old_pass"`
 | 
			
		||||
		Password string `json:"password"`
 | 
			
		||||
@@ -315,6 +315,46 @@ func (h *UserHandler) Password(c *gin.Context) {
 | 
			
		||||
	resp.SUCCESS(c)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ResetPass 重置密码
 | 
			
		||||
func (h *UserHandler) ResetPass(c *gin.Context) {
 | 
			
		||||
	var data struct {
 | 
			
		||||
		Mobile   string
 | 
			
		||||
		Code     string // 验证码
 | 
			
		||||
		Password string // 新密码
 | 
			
		||||
	}
 | 
			
		||||
	if err := c.ShouldBindJSON(&data); err != nil {
 | 
			
		||||
		resp.ERROR(c, types.InvalidArgs)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var user model.User
 | 
			
		||||
	res := h.db.Where("mobile", data.Mobile).First(&user)
 | 
			
		||||
	if res.Error != nil {
 | 
			
		||||
		resp.ERROR(c, "用户不存在!")
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// 检查验证码
 | 
			
		||||
	key := CodeStorePrefix + data.Mobile
 | 
			
		||||
	if h.App.SysConfig.EnabledMsg {
 | 
			
		||||
		code, err := h.redis.Get(c, key).Result()
 | 
			
		||||
		if err != nil || code != data.Code {
 | 
			
		||||
			resp.ERROR(c, "短信验证码错误")
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	password := utils.GenPassword(data.Password, user.Salt)
 | 
			
		||||
	user.Password = password
 | 
			
		||||
	res = h.db.Updates(&user)
 | 
			
		||||
	if res.Error != nil {
 | 
			
		||||
		resp.ERROR(c)
 | 
			
		||||
	} else {
 | 
			
		||||
		h.redis.Del(c, key)
 | 
			
		||||
		resp.SUCCESS(c)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// BindMobile 绑定手机号
 | 
			
		||||
func (h *UserHandler) BindMobile(c *gin.Context) {
 | 
			
		||||
	var data struct {
 | 
			
		||||
 
 | 
			
		||||
@@ -216,8 +216,9 @@ func main() {
 | 
			
		||||
			group.GET("session", h.Session)
 | 
			
		||||
			group.GET("profile", h.Profile)
 | 
			
		||||
			group.POST("profile/update", h.ProfileUpdate)
 | 
			
		||||
			group.POST("password", h.Password)
 | 
			
		||||
			group.POST("password", h.UpdatePass)
 | 
			
		||||
			group.POST("bind/mobile", h.BindMobile)
 | 
			
		||||
			group.POST("resetPass", h.ResetPass)
 | 
			
		||||
		}),
 | 
			
		||||
		fx.Invoke(func(s *core.AppServer, h *chatimpl.ChatHandler) {
 | 
			
		||||
			group := s.Engine.Group("/api/chat/")
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										108
									
								
								web/src/components/ResetPass.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										108
									
								
								web/src/components/ResetPass.vue
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,108 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="reset-pass">
 | 
			
		||||
    <el-dialog
 | 
			
		||||
        v-model="showDialog"
 | 
			
		||||
        :close-on-click-modal="true"
 | 
			
		||||
        width="540px"
 | 
			
		||||
        :before-close="close"
 | 
			
		||||
        :title="title"
 | 
			
		||||
    >
 | 
			
		||||
      <div class="form">
 | 
			
		||||
 | 
			
		||||
        <el-form :model="form" label-width="120px" label-position="left">
 | 
			
		||||
          <el-form-item label="手机号码">
 | 
			
		||||
            <el-input v-model="form.mobile"/>
 | 
			
		||||
          </el-form-item>
 | 
			
		||||
          <el-form-item label="手机验证码">
 | 
			
		||||
            <el-row :gutter="20">
 | 
			
		||||
              <el-col :span="16">
 | 
			
		||||
                <el-input v-model="form.code" maxlength="6"/>
 | 
			
		||||
              </el-col>
 | 
			
		||||
              <el-col :span="8">
 | 
			
		||||
                <send-msg size="" :mobile="form.mobile"/>
 | 
			
		||||
              </el-col>
 | 
			
		||||
            </el-row>
 | 
			
		||||
          </el-form-item>
 | 
			
		||||
          <el-form-item label="新密码">
 | 
			
		||||
            <el-input v-model="form.password" type="password"/>
 | 
			
		||||
          </el-form-item>
 | 
			
		||||
          <el-form-item label="重复密码">
 | 
			
		||||
            <el-input v-model="form.repass" type="password"/>
 | 
			
		||||
          </el-form-item>
 | 
			
		||||
        </el-form>
 | 
			
		||||
      </div>
 | 
			
		||||
 | 
			
		||||
      <template #footer>
 | 
			
		||||
        <div class="dialog-footer">
 | 
			
		||||
          <el-button type="primary" @click="save" round>
 | 
			
		||||
            重置密码
 | 
			
		||||
          </el-button>
 | 
			
		||||
        </div>
 | 
			
		||||
      </template>
 | 
			
		||||
    </el-dialog>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script setup>
 | 
			
		||||
import {computed, ref} from "vue";
 | 
			
		||||
import SendMsg from "@/components/SendMsg.vue";
 | 
			
		||||
import {ElMessage} from "element-plus";
 | 
			
		||||
import {httpPost} from "@/utils/http";
 | 
			
		||||
import {validateMobile} from "@/utils/validate";
 | 
			
		||||
 | 
			
		||||
const props = defineProps({
 | 
			
		||||
  show: Boolean,
 | 
			
		||||
  mobile: String
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const showDialog = computed(() => {
 | 
			
		||||
  return props.show
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
const title = ref('重置密码')
 | 
			
		||||
const form = ref({
 | 
			
		||||
  mobile: '',
 | 
			
		||||
  code: '',
 | 
			
		||||
  password: '',
 | 
			
		||||
  repass: ''
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
const emits = defineEmits(['hide']);
 | 
			
		||||
 | 
			
		||||
const save = () => {
 | 
			
		||||
  if (!validateMobile(form.value.mobile)) {
 | 
			
		||||
    return ElMessage.error("请输入正确的手机号码");
 | 
			
		||||
  }
 | 
			
		||||
  if (form.value.code === '') {
 | 
			
		||||
    return ElMessage.error("请输入短信验证码");
 | 
			
		||||
  }
 | 
			
		||||
  if (form.value.repass !== form.value.password) {
 | 
			
		||||
    return ElMessage.error("两次输入密码不一致");
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  httpPost('/api/user/resetPass', form.value).then(() => {
 | 
			
		||||
    ElMessage.success({
 | 
			
		||||
      message: '重置密码成功', duration: 1000, onClose: () => emits('hide', false)
 | 
			
		||||
    })
 | 
			
		||||
  }).catch(e => {
 | 
			
		||||
    ElMessage.error("重置密码失败:" + e.message);
 | 
			
		||||
  })
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const close = function () {
 | 
			
		||||
  emits('hide', false);
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="stylus">
 | 
			
		||||
.reset-pass {
 | 
			
		||||
  .form {
 | 
			
		||||
    padding 10px 40px
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .el-dialog__footer {
 | 
			
		||||
    text-align center
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
</style>
 | 
			
		||||
@@ -27,7 +27,7 @@ export function setSessionId(sessionId) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function getUserToken() {
 | 
			
		||||
    return Storage.get(UserTokenKey)
 | 
			
		||||
    return Storage.get(UserTokenKey) ?? ""
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function setUserToken(token) {
 | 
			
		||||
 
 | 
			
		||||
@@ -32,13 +32,15 @@
 | 
			
		||||
            <el-button class="login-btn" size="large" type="primary" @click="login">登录</el-button>
 | 
			
		||||
          </el-row>
 | 
			
		||||
 | 
			
		||||
          <el-row class="text-line">
 | 
			
		||||
            还没有账号?
 | 
			
		||||
            <el-link type="primary" @click="router.push('/register')">注册新账号</el-link>
 | 
			
		||||
          <el-row class="text-line" gutter="20">
 | 
			
		||||
            <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-row>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
 | 
			
		||||
      <reset-pass @hide="showResetPass = false" :show="showResetPass"/>
 | 
			
		||||
 | 
			
		||||
      <footer class="footer">
 | 
			
		||||
        <footer-bar/>
 | 
			
		||||
      </footer>
 | 
			
		||||
@@ -59,11 +61,13 @@ import {checkSession} from "@/action/session";
 | 
			
		||||
import {setUserToken} from "@/store/session";
 | 
			
		||||
import {validateMobile} from "@/utils/validate";
 | 
			
		||||
import {prevRoute} from "@/router";
 | 
			
		||||
import ResetPass from "@/components/ResetPass.vue";
 | 
			
		||||
 | 
			
		||||
const router = useRouter();
 | 
			
		||||
const title = ref('ChatGPT-PLUS 用户登录');
 | 
			
		||||
const username = ref(process.env.VUE_APP_USER);
 | 
			
		||||
const password = ref(process.env.VUE_APP_PASS);
 | 
			
		||||
const showResetPass = ref(false)
 | 
			
		||||
 | 
			
		||||
checkSession().then(() => {
 | 
			
		||||
  if (isMobile()) {
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user