mirror of
				https://github.com/yangjian102621/geekai.git
				synced 2025-11-04 16:23:42 +08:00 
			
		
		
		
	opt: optimize the layout for regiseter page. add function to disable registration
This commit is contained in:
		
							
								
								
									
										11
									
								
								CHANGELOG.md
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								CHANGELOG.md
									
									
									
									
									
								
							@@ -1,5 +1,16 @@
 | 
			
		||||
# 更新日志
 | 
			
		||||
 | 
			
		||||
## v3.0.6
 | 
			
		||||
1. 管理后台:新增用户名和手机号码搜索功能
 | 
			
		||||
2. 管理后台:新增重置用户密码功能
 | 
			
		||||
3. 管理后台:支持关闭注册功能,新增添加用户功能,适用于内部使用场景
 | 
			
		||||
4. 管理后台:新增仪表盘页面,统计当天的新增用户,新增会话数据,以及 Token 消耗
 | 
			
		||||
5. Bug修复:修复注册页面验证码不显示 Bug
 | 
			
		||||
6. Bug修复:优化上下文 Token 计算算法,修复聊天上下文超出限制时循环发送消息的 Bug
 | 
			
		||||
7. 功能修正:允许用户使用手机号码登录
 | 
			
		||||
8. 功能优化:更新系统配置后同步更新服务端内存变量数据
 | 
			
		||||
9. 功能优化:优化打包脚本,减少容器镜像大小
 | 
			
		||||
 | 
			
		||||
## v3.0.5
 | 
			
		||||
 | 
			
		||||
重磅功能更新!!! 新增函数插件支持,可以轻松地接入你的第三方插件服务,ChatGPT 自动帮您调用对应的函数完成任务。
 | 
			
		||||
 
 | 
			
		||||
@@ -85,10 +85,9 @@ type ChatConfig struct {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type SystemConfig struct {
 | 
			
		||||
	Title         string   `json:"title"`
 | 
			
		||||
	AdminTitle    string   `json:"admin_title"`
 | 
			
		||||
	Models        []string `json:"models"`
 | 
			
		||||
	UserInitCalls int      `json:"user_init_calls"` // 新用户注册默认总送多少次调用
 | 
			
		||||
	Title           string   `json:"title"`
 | 
			
		||||
	AdminTitle      string   `json:"admin_title"`
 | 
			
		||||
	Models          []string `json:"models"`
 | 
			
		||||
	UserInitCalls   int      `json:"user_init_calls"` // 新用户注册默认总送多少次调用
 | 
			
		||||
	EnabledRegister bool     `json:"enabled_register"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const UserInitCalls = 20
 | 
			
		||||
 
 | 
			
		||||
@@ -52,12 +52,17 @@ func (h *ConfigHandler) Update(c *gin.Context) {
 | 
			
		||||
		// update config cache for AppServer
 | 
			
		||||
		var cfg model.Config
 | 
			
		||||
		h.db.Where("marker", data.Key).First(&cfg)
 | 
			
		||||
		err := utils.JsonDecode(cfg.Config, &h.App.ChatConfig)
 | 
			
		||||
		var err error
 | 
			
		||||
		if data.Key == "system" {
 | 
			
		||||
			err = utils.JsonDecode(cfg.Config, &h.App.SysConfig)
 | 
			
		||||
		} else if data.Key == "chat" {
 | 
			
		||||
			err = utils.JsonDecode(cfg.Config, &h.App.ChatConfig)
 | 
			
		||||
		}
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			resp.ERROR(c, "Failed to update config cache: "+err.Error())
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		logger.Debugf("Update AppServer's config successfully: %v", config.Config)
 | 
			
		||||
		logger.Infof("Update AppServer's config successfully: %v", config.Config)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	resp.SUCCESS(c, config)
 | 
			
		||||
 
 | 
			
		||||
@@ -59,7 +59,12 @@ func (h *SmsHandler) SendCode(c *gin.Context) {
 | 
			
		||||
	resp.SUCCESS(c)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type statusVo struct {
 | 
			
		||||
	EnabledMsgService bool `json:"enabled_msg_service"`
 | 
			
		||||
	EnabledRegister   bool `json:"enabled_register"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Status check if the message service is enabled
 | 
			
		||||
func (h *SmsHandler) Status(c *gin.Context) {
 | 
			
		||||
	resp.SUCCESS(c, h.App.Config.EnabledMsgService)
 | 
			
		||||
	resp.SUCCESS(c, statusVo{EnabledMsgService: h.App.Config.EnabledMsgService, EnabledRegister: h.App.SysConfig.EnabledRegister})
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,101 +1,111 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div>
 | 
			
		||||
    <div class="bg"></div>
 | 
			
		||||
    <div class="main">
 | 
			
		||||
      <div class="contain">
 | 
			
		||||
        <div class="logo">
 | 
			
		||||
          <el-image src="images/logo.png" fit="cover"/>
 | 
			
		||||
        </div>
 | 
			
		||||
    <div class="register-page">
 | 
			
		||||
      <div class="page-inner">
 | 
			
		||||
        <div class="contain" v-if="enableRegister">
 | 
			
		||||
          <div class="logo">
 | 
			
		||||
            <el-image src="images/logo.png" fit="cover"/>
 | 
			
		||||
          </div>
 | 
			
		||||
 | 
			
		||||
        <div class="header">{{ title }}</div>
 | 
			
		||||
        <div class="content">
 | 
			
		||||
          <el-form :model="formData" label-width="120px" ref="formRef">
 | 
			
		||||
            <div class="block">
 | 
			
		||||
              <el-input placeholder="请输入用户名(4-30位)"
 | 
			
		||||
                        size="large" maxlength="30"
 | 
			
		||||
                        v-model="formData.username"
 | 
			
		||||
                        autocomplete="off">
 | 
			
		||||
                <template #prefix>
 | 
			
		||||
                  <el-icon>
 | 
			
		||||
                    <UserFilled/>
 | 
			
		||||
                  </el-icon>
 | 
			
		||||
                </template>
 | 
			
		||||
              </el-input>
 | 
			
		||||
            </div>
 | 
			
		||||
          <div class="header">{{ title }}</div>
 | 
			
		||||
          <div class="content">
 | 
			
		||||
            <el-form :model="formData" label-width="120px" ref="formRef">
 | 
			
		||||
              <div class="block">
 | 
			
		||||
                <el-input placeholder="请输入用户名(4-30位)"
 | 
			
		||||
                          size="large" maxlength="30"
 | 
			
		||||
                          v-model="formData.username"
 | 
			
		||||
                          autocomplete="off">
 | 
			
		||||
                  <template #prefix>
 | 
			
		||||
                    <el-icon>
 | 
			
		||||
                      <UserFilled/>
 | 
			
		||||
                    </el-icon>
 | 
			
		||||
                  </template>
 | 
			
		||||
                </el-input>
 | 
			
		||||
              </div>
 | 
			
		||||
 | 
			
		||||
            <div class="block">
 | 
			
		||||
              <el-input placeholder="请输入密码(8-16位)"
 | 
			
		||||
                        maxlength="16" size="large"
 | 
			
		||||
                        v-model="formData.password" show-password
 | 
			
		||||
                        autocomplete="off">
 | 
			
		||||
                <template #prefix>
 | 
			
		||||
                  <el-icon>
 | 
			
		||||
                    <Lock/>
 | 
			
		||||
                  </el-icon>
 | 
			
		||||
                </template>
 | 
			
		||||
              </el-input>
 | 
			
		||||
            </div>
 | 
			
		||||
              <div class="block">
 | 
			
		||||
                <el-input placeholder="请输入密码(8-16位)"
 | 
			
		||||
                          maxlength="16" size="large"
 | 
			
		||||
                          v-model="formData.password" show-password
 | 
			
		||||
                          autocomplete="off">
 | 
			
		||||
                  <template #prefix>
 | 
			
		||||
                    <el-icon>
 | 
			
		||||
                      <Lock/>
 | 
			
		||||
                    </el-icon>
 | 
			
		||||
                  </template>
 | 
			
		||||
                </el-input>
 | 
			
		||||
              </div>
 | 
			
		||||
 | 
			
		||||
            <div class="block">
 | 
			
		||||
              <el-input placeholder="重复密码(8-16位)"
 | 
			
		||||
                        size="large" maxlength="16" v-model="formData.repass" show-password
 | 
			
		||||
                        autocomplete="off">
 | 
			
		||||
                <template #prefix>
 | 
			
		||||
                  <el-icon>
 | 
			
		||||
                    <Lock/>
 | 
			
		||||
                  </el-icon>
 | 
			
		||||
                </template>
 | 
			
		||||
              </el-input>
 | 
			
		||||
            </div>
 | 
			
		||||
              <div class="block">
 | 
			
		||||
                <el-input placeholder="重复密码(8-16位)"
 | 
			
		||||
                          size="large" maxlength="16" v-model="formData.repass" show-password
 | 
			
		||||
                          autocomplete="off">
 | 
			
		||||
                  <template #prefix>
 | 
			
		||||
                    <el-icon>
 | 
			
		||||
                      <Lock/>
 | 
			
		||||
                    </el-icon>
 | 
			
		||||
                  </template>
 | 
			
		||||
                </el-input>
 | 
			
		||||
              </div>
 | 
			
		||||
 | 
			
		||||
            <div class="block" v-if="enableMsg">
 | 
			
		||||
              <el-input placeholder="手机号码"
 | 
			
		||||
                        size="large" maxlength="11"
 | 
			
		||||
                        v-model="formData.mobile"
 | 
			
		||||
                        autocomplete="off">
 | 
			
		||||
                <template #prefix>
 | 
			
		||||
                  <el-icon>
 | 
			
		||||
                    <Iphone/>
 | 
			
		||||
                  </el-icon>
 | 
			
		||||
                </template>
 | 
			
		||||
              </el-input>
 | 
			
		||||
            </div>
 | 
			
		||||
              <div class="block" v-if="enableMsg">
 | 
			
		||||
                <el-input placeholder="手机号码"
 | 
			
		||||
                          size="large" maxlength="11"
 | 
			
		||||
                          v-model="formData.mobile"
 | 
			
		||||
                          autocomplete="off">
 | 
			
		||||
                  <template #prefix>
 | 
			
		||||
                    <el-icon>
 | 
			
		||||
                      <Iphone/>
 | 
			
		||||
                    </el-icon>
 | 
			
		||||
                  </template>
 | 
			
		||||
                </el-input>
 | 
			
		||||
              </div>
 | 
			
		||||
 | 
			
		||||
            <div class="block" v-if="enableMsg">
 | 
			
		||||
              <el-row :gutter="10">
 | 
			
		||||
                <el-col :span="12">
 | 
			
		||||
                  <el-input placeholder="手机验证码"
 | 
			
		||||
                            size="large" maxlength="30"
 | 
			
		||||
                            v-model.number="formData.code"
 | 
			
		||||
                            autocomplete="off">
 | 
			
		||||
                    <template #prefix>
 | 
			
		||||
                      <el-icon>
 | 
			
		||||
                        <Checked/>
 | 
			
		||||
                      </el-icon>
 | 
			
		||||
                    </template>
 | 
			
		||||
                  </el-input>
 | 
			
		||||
                </el-col>
 | 
			
		||||
                <el-col :span="12">
 | 
			
		||||
                  <send-msg size="large" :mobile="formData.mobile"/>
 | 
			
		||||
                </el-col>
 | 
			
		||||
              <div class="block" v-if="enableMsg">
 | 
			
		||||
                <el-row :gutter="10">
 | 
			
		||||
                  <el-col :span="12">
 | 
			
		||||
                    <el-input placeholder="手机验证码"
 | 
			
		||||
                              size="large" maxlength="30"
 | 
			
		||||
                              v-model.number="formData.code"
 | 
			
		||||
                              autocomplete="off">
 | 
			
		||||
                      <template #prefix>
 | 
			
		||||
                        <el-icon>
 | 
			
		||||
                          <Checked/>
 | 
			
		||||
                        </el-icon>
 | 
			
		||||
                      </template>
 | 
			
		||||
                    </el-input>
 | 
			
		||||
                  </el-col>
 | 
			
		||||
                  <el-col :span="12">
 | 
			
		||||
                    <send-msg size="large" :mobile="formData.mobile"/>
 | 
			
		||||
                  </el-col>
 | 
			
		||||
                </el-row>
 | 
			
		||||
              </div>
 | 
			
		||||
 | 
			
		||||
              <el-row class="btn-row">
 | 
			
		||||
                <el-button class="login-btn" size="large" type="primary" @click="register">注册</el-button>
 | 
			
		||||
              </el-row>
 | 
			
		||||
            </div>
 | 
			
		||||
 | 
			
		||||
            <el-row class="btn-row">
 | 
			
		||||
              <el-button class="login-btn" size="large" type="primary" @click="register">注册</el-button>
 | 
			
		||||
            </el-row>
 | 
			
		||||
 | 
			
		||||
            <el-row class="text-line">
 | 
			
		||||
              已经有账号?
 | 
			
		||||
              <el-link type="primary" @click="router.push('login')">登录</el-link>
 | 
			
		||||
            </el-row>
 | 
			
		||||
          </el-form>
 | 
			
		||||
              <el-row class="text-line">
 | 
			
		||||
                已经有账号?
 | 
			
		||||
                <el-link type="primary" @click="router.push('login')">登录</el-link>
 | 
			
		||||
              </el-row>
 | 
			
		||||
            </el-form>
 | 
			
		||||
          </div>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
 | 
			
		||||
      <footer class="footer">
 | 
			
		||||
        <footer-bar/>
 | 
			
		||||
      </footer>
 | 
			
		||||
        <div class="tip-result" v-else>
 | 
			
		||||
          <el-result icon="error" title="注册功能已关闭">
 | 
			
		||||
            <template #sub-title>
 | 
			
		||||
              <p>抱歉,系统已关闭注册功能,请联系管理员添加账号!</p>
 | 
			
		||||
            </template>
 | 
			
		||||
          </el-result>
 | 
			
		||||
        </div>
 | 
			
		||||
 | 
			
		||||
        <footer class="footer">
 | 
			
		||||
          <footer-bar/>
 | 
			
		||||
        </footer>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
@@ -121,10 +131,12 @@ const formData = ref({
 | 
			
		||||
})
 | 
			
		||||
const formRef = ref(null)
 | 
			
		||||
const enableMsg = ref(false)
 | 
			
		||||
const enableRegister = ref(true)
 | 
			
		||||
 | 
			
		||||
httpGet('/api/sms/status').then(res => {
 | 
			
		||||
  if (res.data === true) {
 | 
			
		||||
    enableMsg.value = true
 | 
			
		||||
  if (res.data) {
 | 
			
		||||
    enableMsg.value = res.data['enabled_msg_service']
 | 
			
		||||
    enableRegister.value = res.data['enabled_register']
 | 
			
		||||
  }
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
@@ -166,76 +178,108 @@ const register = function () {
 | 
			
		||||
  //filter: blur(10px); /* 调整模糊程度,可以根据需要修改值 */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.main {
 | 
			
		||||
  .contain {
 | 
			
		||||
    position fixed
 | 
			
		||||
    left 50%
 | 
			
		||||
    top 40%
 | 
			
		||||
    width 90%
 | 
			
		||||
    max-width 400px
 | 
			
		||||
    transform translate(-50%, -50%)
 | 
			
		||||
    padding 20px 40px;
 | 
			
		||||
    color #ffffff
 | 
			
		||||
    border-radius 10px;
 | 
			
		||||
    background rgba(255, 255, 255, 0.3)
 | 
			
		||||
.register-page {
 | 
			
		||||
  display flex
 | 
			
		||||
  justify-content center
 | 
			
		||||
 | 
			
		||||
    .logo {
 | 
			
		||||
      text-align center
 | 
			
		||||
  .page-inner {
 | 
			
		||||
    max-width 450px
 | 
			
		||||
    height 100vh
 | 
			
		||||
    display flex
 | 
			
		||||
    justify-content center
 | 
			
		||||
    align-items center
 | 
			
		||||
 | 
			
		||||
      .el-image {
 | 
			
		||||
        width 120px;
 | 
			
		||||
    .contain {
 | 
			
		||||
      padding 0 40px 20px 40px;
 | 
			
		||||
      color #ffffff
 | 
			
		||||
      border-radius 10px;
 | 
			
		||||
      z-index 10
 | 
			
		||||
      background-color rgba(255, 255, 255, 0.3)
 | 
			
		||||
 | 
			
		||||
      .logo {
 | 
			
		||||
        text-align center
 | 
			
		||||
 | 
			
		||||
        .el-image {
 | 
			
		||||
          width 120px;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .header {
 | 
			
		||||
      width 100%
 | 
			
		||||
      margin-bottom 24px
 | 
			
		||||
      font-size 24px
 | 
			
		||||
      color $white_v1
 | 
			
		||||
      letter-space 2px
 | 
			
		||||
      text-align center
 | 
			
		||||
    }
 | 
			
		||||
      .header {
 | 
			
		||||
        width 100%
 | 
			
		||||
        margin-bottom 24px
 | 
			
		||||
        font-size 24px
 | 
			
		||||
        color $white_v1
 | 
			
		||||
        letter-space 2px
 | 
			
		||||
        text-align center
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
    .content {
 | 
			
		||||
      width 100%
 | 
			
		||||
      height: auto
 | 
			
		||||
      border-radius 3px
 | 
			
		||||
      .content {
 | 
			
		||||
        width 100%
 | 
			
		||||
        height: auto
 | 
			
		||||
        border-radius 3px
 | 
			
		||||
 | 
			
		||||
      .block {
 | 
			
		||||
        margin-bottom 16px
 | 
			
		||||
        .block {
 | 
			
		||||
          margin-bottom 16px
 | 
			
		||||
 | 
			
		||||
        .el-input__inner {
 | 
			
		||||
          border 1px solid $gray-v6 !important
 | 
			
		||||
          .el-input__inner {
 | 
			
		||||
            border 1px solid $gray-v6 !important
 | 
			
		||||
 | 
			
		||||
          .el-icon-user, .el-icon-lock {
 | 
			
		||||
            font-size 20px
 | 
			
		||||
            .el-icon-user, .el-icon-lock {
 | 
			
		||||
              font-size 20px
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      .btn-row {
 | 
			
		||||
        padding-top 10px;
 | 
			
		||||
        .btn-row {
 | 
			
		||||
          padding-top 10px;
 | 
			
		||||
 | 
			
		||||
        .login-btn {
 | 
			
		||||
          width 100%
 | 
			
		||||
          font-size 16px
 | 
			
		||||
          letter-spacing 2px
 | 
			
		||||
          .login-btn {
 | 
			
		||||
            width 100%
 | 
			
		||||
            font-size 16px
 | 
			
		||||
            letter-spacing 2px
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        .text-line {
 | 
			
		||||
          justify-content center
 | 
			
		||||
          padding-top 10px;
 | 
			
		||||
          font-size 14px;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
      .text-line {
 | 
			
		||||
        justify-content center
 | 
			
		||||
        padding-top 10px;
 | 
			
		||||
        font-size 14px;
 | 
			
		||||
 | 
			
		||||
    .tip-result {
 | 
			
		||||
      z-index 10
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .footer {
 | 
			
		||||
      color #ffffff;
 | 
			
		||||
 | 
			
		||||
      .container {
 | 
			
		||||
        padding 20px;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .footer {
 | 
			
		||||
    color #ffffff;
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
 | 
			
		||||
    .container {
 | 
			
		||||
      padding 20px;
 | 
			
		||||
<style lang="stylus">
 | 
			
		||||
.register-page {
 | 
			
		||||
  .el-result {
 | 
			
		||||
 | 
			
		||||
    border-radius 10px;
 | 
			
		||||
    background-color rgba(14, 25, 30, 0.6)
 | 
			
		||||
    border 1px solid #666
 | 
			
		||||
 | 
			
		||||
    .el-result__title p {
 | 
			
		||||
      color #ffffff
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .el-result__subtitle p {
 | 
			
		||||
      color #c1c1c1
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -12,6 +12,9 @@
 | 
			
		||||
        <el-form-item label="注册赠送次数" prop="init_calls">
 | 
			
		||||
          <el-input v-model.number="system['user_init_calls']" placeholder="新用户注册赠送对话次数"/>
 | 
			
		||||
        </el-form-item>
 | 
			
		||||
        <el-form-item label="开放用户注册" prop="init_calls">
 | 
			
		||||
          <el-switch v-model="system['enabled_register']"/>
 | 
			
		||||
        </el-form-item>
 | 
			
		||||
        <el-alert type="info" show-icon :closable="false">
 | 
			
		||||
          <p>在这里维护前端聊天页面可用的 GPT 模型列表</p>
 | 
			
		||||
        </el-alert>
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user