diff --git a/README.md b/README.md index d421442c..1b6191b9 100644 --- a/README.md +++ b/README.md @@ -13,12 +13,6 @@ ChatGLM,讯飞星火,文心一言等多个平台的大语言模型。集成了 * 集成插件 API 功能,可结合大语言模型的 function 功能开发各种强大的插件,已内置实现了微博热搜,今日头条,今日早报和 AI 绘画函数插件。 -## 最新版本一键部署脚本 -目前仅支持 Ubuntu 和 Centos 系统。 -```shell -bash -c "$(curl -fsSL https://img.r9it.com/tmp/install-v3.2.3-8b588904ef.sh)" -``` - ## 功能截图 ### PC 端聊天界面 @@ -69,11 +63,30 @@ bash -c "$(curl -fsSL https://img.r9it.com/tmp/install-v3.2.3-8b588904ef.sh)" ![Mobile chat setting](/docs/imgs/mobile_user_profile.png) ![Mobile chat setting](/docs/imgs/mobile_pay.png) -### 7. 体验地址 +### 体验地址 > 免费体验地址:[https://ai.r9it.com/chat](https://ai.r9it.com/chat)
> **注意:请合法使用,禁止输出任何敏感、不友好或违规的内容!!!** +## 快速部署 +**演示站不提供任何充值点卡售卖或者VIP充值服务。** 如果您体验过后觉得还不错的话,可以花两分钟用下面的一键部署脚本自己部署一套。 +```shell +bash -c "$(curl -fsSL https://img.r9it.com/tmp/install-v3.2.3-8b588904ef.sh)" +``` +目前仅支持 Ubuntu 和 Centos 系统。 部署成功之后可以访问下面地址 + +* 前端访问地址:http://localhost:8080/chat 使用移动设备访问会自动跳转到移动端页面。 +* 后台管理地址:http://localhost:8080/admin +* 移动端地址:http://localhost:8080/mobile +* 初始后台管理账号:admin/admin123 +* 初始前端体验账号:18575670125/12345678 + +服务启动成功之后不能立刻使用,需要先登录管理后台 -> API-KEY 去添加一个 OpenAI 或者文心一言,科大讯飞等至少一个平台的 API KEY。 + +![](https://ai.r9it.com/docs/images/env/admin_api_keys.png) + +另外,如果您目前还没有 OpenAI 的 API KEY的,推荐您去 https://gpt.bemore.lol 购买,**无需魔法,高速稳定,且价格还远低于 OpenAI 官方**。 + ## 使用须知 1. 本项目基于 MIT 协议,免费开放全部源代码,可以作为个人学习使用或者商用。 diff --git a/api/core/types/config.go b/api/core/types/config.go index 54f3e24d..ca11d3a0 100644 --- a/api/core/types/config.go +++ b/api/core/types/config.go @@ -24,6 +24,15 @@ type AppConfig struct { XXLConfig XXLConfig AlipayConfig AlipayConfig HuPiPayConfig HuPiPayConfig + SmtpConfig SmtpConfig // 邮件发送配置 +} + +type SmtpConfig struct { + Host string + Port int + AppName string // 应用名称 + From string // 发件人邮箱地址 + Password string // 发件人邮箱密码 } type ChatPlusApiConfig struct { diff --git a/api/handler/admin/reward_handler.go b/api/handler/admin/reward_handler.go index 61f65696..def4cf87 100644 --- a/api/handler/admin/reward_handler.go +++ b/api/handler/admin/reward_handler.go @@ -46,7 +46,7 @@ func (h *RewardHandler) List(c *gin.Context) { } r.Id = v.Id - r.Username = userMap[v.UserId].Mobile + r.Username = userMap[v.UserId].Username r.CreatedAt = v.CreatedAt.Unix() r.UpdatedAt = v.UpdatedAt.Unix() rewards = append(rewards, r) diff --git a/api/handler/admin/user_handler.go b/api/handler/admin/user_handler.go index 26f3293d..60f18c99 100644 --- a/api/handler/admin/user_handler.go +++ b/api/handler/admin/user_handler.go @@ -27,7 +27,7 @@ func NewUserHandler(app *core.AppServer, db *gorm.DB) *UserHandler { func (h *UserHandler) List(c *gin.Context) { page := h.GetInt(c, "page", 1) pageSize := h.GetInt(c, "page_size", 20) - mobile := h.GetTrim(c, "mobile") + username := h.GetTrim(c, "username") offset := (page - 1) * pageSize var items []model.User @@ -35,8 +35,8 @@ func (h *UserHandler) List(c *gin.Context) { var total int64 session := h.db.Session(&gorm.Session{}) - if mobile != "" { - session = session.Where("mobile LIKE ?", "%"+mobile+"%") + if username != "" { + session = session.Where("username LIKE ?", "%"+username+"%") } session.Model(&model.User{}).Count(&total) @@ -95,7 +95,7 @@ func (h *UserHandler) Save(c *gin.Context) { } else { salt := utils.RandString(8) u := model.User{ - Mobile: data.Mobile, + Username: data.Mobile, Password: utils.GenPassword(data.Password, salt), Avatar: "/images/avatar/user.png", Salt: salt, diff --git a/api/handler/chatimpl/chat_handler.go b/api/handler/chatimpl/chat_handler.go index 6b1bf80e..03512333 100644 --- a/api/handler/chatimpl/chat_handler.go +++ b/api/handler/chatimpl/chat_handler.go @@ -80,7 +80,7 @@ func (h *ChatHandler) ChatHandle(c *gin.Context) { session = &types.ChatSession{ SessionId: sessionId, ClientIP: c.ClientIP(), - Username: user.Mobile, + Username: user.Username, UserId: user.Id, } h.App.ChatSession.Put(sessionId, session) diff --git a/api/handler/payment_handler.go b/api/handler/payment_handler.go index 4a940cee..422f133e 100644 --- a/api/handler/payment_handler.go +++ b/api/handler/payment_handler.go @@ -204,7 +204,7 @@ func (h *PaymentHandler) PayQrcode(c *gin.Context) { } order := model.Order{ UserId: user.Id, - Mobile: user.Mobile, + Mobile: user.Username, ProductId: product.Id, OrderNo: orderNo, Subject: product.Name, diff --git a/api/handler/sms_handler.go b/api/handler/sms_handler.go index 9ccb4e3d..bd33ae3d 100644 --- a/api/handler/sms_handler.go +++ b/api/handler/sms_handler.go @@ -8,6 +8,7 @@ import ( "chatplus/utils/resp" "github.com/gin-gonic/gin" "github.com/go-redis/redis/v8" + "strings" ) const CodeStorePrefix = "/verify/codes/" @@ -16,21 +17,27 @@ type SmsHandler struct { BaseHandler redis *redis.Client sms *service.AliYunSmsService + smtp *service.SmtpService captcha *service.CaptchaService } -func NewSmsHandler(app *core.AppServer, client *redis.Client, sms *service.AliYunSmsService, captcha *service.CaptchaService) *SmsHandler { - handler := &SmsHandler{redis: client, sms: sms, captcha: captcha} +func NewSmsHandler( + app *core.AppServer, + client *redis.Client, + sms *service.AliYunSmsService, + smtp *service.SmtpService, + captcha *service.CaptchaService) *SmsHandler { + handler := &SmsHandler{redis: client, sms: sms, captcha: captcha, smtp: smtp} handler.App = app return handler } -// SendCode 发送验证码短信 +// SendCode 发送验证码 func (h *SmsHandler) SendCode(c *gin.Context) { var data struct { - Mobile string `json:"mobile"` - Key string `json:"key"` - Dots string `json:"dots"` + Receiver string `json:"receiver"` // 接收者 + Key string `json:"key"` + Dots string `json:"dots"` } if err := c.ShouldBindJSON(&data); err != nil { resp.ERROR(c, types.InvalidArgs) @@ -43,14 +50,19 @@ func (h *SmsHandler) SendCode(c *gin.Context) { } code := utils.RandomNumber(6) - err := h.sms.SendVerifyCode(data.Mobile, code) + var err error + if strings.Contains(data.Receiver, "@") { // email + err = h.smtp.SendVerifyCode(data.Receiver, code) + } else { + err = h.sms.SendVerifyCode(data.Receiver, code) + } if err != nil { resp.ERROR(c, err.Error()) return } // 存储验证码,等待后面注册验证 - _, err = h.redis.Set(c, CodeStorePrefix+data.Mobile, code, 0).Result() + _, err = h.redis.Set(c, CodeStorePrefix+data.Receiver, code, 0).Result() if err != nil { resp.ERROR(c, "验证码保存失败") return diff --git a/api/handler/user_handler.go b/api/handler/user_handler.go index 152924f9..8f90af5b 100644 --- a/api/handler/user_handler.go +++ b/api/handler/user_handler.go @@ -39,7 +39,7 @@ func NewUserHandler( func (h *UserHandler) Register(c *gin.Context) { // parameters process var data struct { - Mobile string `json:"mobile"` + Username string `json:"username"` Password string `json:"password"` Code string `json:"code"` InviteCode string `json:"invite_code"` @@ -49,21 +49,16 @@ func (h *UserHandler) Register(c *gin.Context) { return } data.Password = strings.TrimSpace(data.Password) - - if len(data.Mobile) < 10 { - resp.ERROR(c, "请输入合法的手机号") - return - } if len(data.Password) < 8 { resp.ERROR(c, "密码长度不能少于8个字符") return } // 检查验证码 - key := CodeStorePrefix + data.Mobile + key := CodeStorePrefix + data.Username code, err := h.redis.Get(c, key).Result() if err != nil || code != data.Code { - resp.ERROR(c, "短信验证码错误") + resp.ERROR(c, "验证码错误") return } @@ -79,20 +74,20 @@ func (h *UserHandler) Register(c *gin.Context) { // check if the username is exists var item model.User - res := h.db.Where("mobile = ?", data.Mobile).First(&item) + res := h.db.Where("username = ?", data.Username).First(&item) if res.RowsAffected > 0 { - resp.ERROR(c, "该手机号码已经被注册,请更换其他手机号") + resp.ERROR(c, "该用户名已经被注册") return } salt := utils.RandString(8) user := model.User{ + Username: data.Username, Password: utils.GenPassword(data.Password, salt), Nickname: fmt.Sprintf("极客学长@%d", utils.RandomNumber(6)), Avatar: "/images/avatar/user.png", Salt: salt, Status: true, - Mobile: data.Mobile, ChatRoles: utils.JsonEncode([]string{"gpt"}), // 默认只订阅通用助手角色 ChatModels: utils.JsonEncode(h.App.SysConfig.DefaultModels), // 默认开通的模型 ChatConfig: utils.JsonEncode(types.UserChatConfig{ @@ -105,6 +100,7 @@ func (h *UserHandler) Register(c *gin.Context) { Calls: h.App.SysConfig.InitChatCalls, ImgCalls: h.App.SysConfig.InitImgCalls, } + res = h.db.Create(&user) if res.Error != nil { resp.ERROR(c, "保存数据失败") @@ -127,7 +123,7 @@ func (h *UserHandler) Register(c *gin.Context) { h.db.Create(&model.InviteLog{ InviterId: inviteCode.UserId, UserId: user.Id, - Username: user.Mobile, + Username: user.Username, InviteCode: inviteCode.Code, Reward: utils.JsonEncode(types.InviteReward{ChatCalls: h.App.SysConfig.InviteChatCalls, ImgCalls: h.App.SysConfig.InviteImgCalls}), }) @@ -157,7 +153,7 @@ func (h *UserHandler) Register(c *gin.Context) { // Login 用户登录 func (h *UserHandler) Login(c *gin.Context) { var data struct { - Mobile string `json:"username"` + Username string `json:"username"` Password string `json:"password"` } if err := c.ShouldBindJSON(&data); err != nil { @@ -165,7 +161,7 @@ func (h *UserHandler) Login(c *gin.Context) { return } var user model.User - res := h.db.Where("mobile = ?", data.Mobile).First(&user) + res := h.db.Where("username = ?", data.Username).First(&user) if res.Error != nil { resp.ERROR(c, "用户名不存在") return @@ -189,7 +185,7 @@ func (h *UserHandler) Login(c *gin.Context) { h.db.Create(&model.UserLoginLog{ UserId: user.Id, - Username: user.Mobile, + Username: user.Username, LoginIp: c.ClientIP(), LoginAddress: utils.Ip2Region(h.searcher, c.ClientIP()), }) @@ -250,7 +246,7 @@ func (h *UserHandler) Session(c *gin.Context) { type userProfile struct { Id uint `json:"id"` Nickname string `json:"nickname"` - Mobile string `json:"mobile"` + Username string `json:"username"` Avatar string `json:"avatar"` ChatConfig types.UserChatConfig `json:"chat_config"` Calls int `json:"calls"` @@ -348,9 +344,9 @@ func (h *UserHandler) UpdatePass(c *gin.Context) { // ResetPass 重置密码 func (h *UserHandler) ResetPass(c *gin.Context) { var data struct { - Mobile string - Code string // 验证码 - Password string // 新密码 + Username string `json:"username"` + Code string `json:"code"` // 验证码 + Password string `json:"password"` // 新密码 } if err := c.ShouldBindJSON(&data); err != nil { resp.ERROR(c, types.InvalidArgs) @@ -358,14 +354,14 @@ func (h *UserHandler) ResetPass(c *gin.Context) { } var user model.User - res := h.db.Where("mobile", data.Mobile).First(&user) + res := h.db.Where("username", data.Username).First(&user) if res.Error != nil { resp.ERROR(c, "用户不存在!") return } // 检查验证码 - key := CodeStorePrefix + data.Mobile + key := CodeStorePrefix + data.Username code, err := h.redis.Get(c, key).Result() if err != nil || code != data.Code { resp.ERROR(c, "短信验证码错误") @@ -386,8 +382,8 @@ func (h *UserHandler) ResetPass(c *gin.Context) { // BindMobile 绑定手机号 func (h *UserHandler) BindMobile(c *gin.Context) { var data struct { - Mobile string `json:"mobile"` - Code string `json:"code"` + Username string `json:"username"` + Code string `json:"code"` } if err := c.ShouldBindJSON(&data); err != nil { resp.ERROR(c, types.InvalidArgs) @@ -395,7 +391,7 @@ func (h *UserHandler) BindMobile(c *gin.Context) { } // 检查验证码 - key := CodeStorePrefix + data.Mobile + key := CodeStorePrefix + data.Username code, err := h.redis.Get(c, key).Result() if err != nil || code != data.Code { resp.ERROR(c, "短信验证码错误") @@ -404,7 +400,7 @@ func (h *UserHandler) BindMobile(c *gin.Context) { // 检查手机号是否被其他账号绑定 var item model.User - res := h.db.Where("mobile = ?", data.Mobile).First(&item) + res := h.db.Where("username = ?", data.Username).First(&item) if res.Error == nil { resp.ERROR(c, "该手机号已经被其他账号绑定") return @@ -416,7 +412,7 @@ func (h *UserHandler) BindMobile(c *gin.Context) { return } - res = h.db.Model(&user).UpdateColumn("mobile", data.Mobile) + res = h.db.Model(&user).UpdateColumn("username", data.Username) if res.Error != nil { resp.ERROR(c, "更新数据库失败") return diff --git a/api/main.go b/api/main.go index c02816c4..d0508210 100644 --- a/api/main.go +++ b/api/main.go @@ -142,6 +142,9 @@ func main() { fx.Provide(oss.NewUploaderManager), fx.Provide(mj.NewService), + // 邮件服务 + fx.Provide(service.NewSmtpService), + // 微信机器人服务 fx.Provide(wx.NewWeChatBot), fx.Invoke(func(config *types.AppConfig, bot *wx.Bot) { diff --git a/api/service/aliyun_sms_service.go b/api/service/aliyun_sms_service.go index 582b34c5..d3414ee6 100644 --- a/api/service/aliyun_sms_service.go +++ b/api/service/aliyun_sms_service.go @@ -49,3 +49,5 @@ func (s *AliYunSmsService) SendVerifyCode(mobile string, code int) error { return nil } + +var _ SmsService = &AliYunSmsService{} diff --git a/api/service/smtp_sms_service.go b/api/service/smtp_sms_service.go new file mode 100644 index 00000000..fe094d49 --- /dev/null +++ b/api/service/smtp_sms_service.go @@ -0,0 +1,44 @@ +package service + +import ( + "bytes" + "chatplus/core/types" + "fmt" + "mime" + "net/smtp" +) + +type SmtpService struct { + config *types.SmtpConfig +} + +func NewSmtpService(appConfig *types.AppConfig) *SmtpService { + return &SmtpService{ + config: &appConfig.SmtpConfig, + } +} + +func (s *SmtpService) SendVerifyCode(to string, code int) error { + subject := "ChatPlus注册验证码" + body := fmt.Sprintf("您正在注册 ChatPlus AI 助手账户,注册验证码为 %d,请不要告诉他人。如非本人操作,请忽略此邮件。", code) + + // 设置SMTP客户端配置 + auth := smtp.PlainAuth("", s.config.From, s.config.Password, s.config.Host) + + // 对主题进行MIME编码 + encodedSubject := mime.QEncoding.Encode("UTF-8", subject) + // 组装邮件 + message := bytes.NewBuffer(nil) + message.WriteString(fmt.Sprintf("From: \"%s\" <%s>\r\n", s.config.AppName, s.config.From)) + message.WriteString(fmt.Sprintf("To: %s\r\n", to)) + message.WriteString(fmt.Sprintf("Subject: %s\r\n", encodedSubject)) + message.WriteString("\r\n" + body) + + // 发送邮件 + // 发送邮件 + err := smtp.SendMail(s.config.Host+":"+fmt.Sprint(s.config.Port), auth, s.config.From, []string{to}, message.Bytes()) + if err != nil { + return fmt.Errorf("error sending email: %v", err) + } + return nil +} diff --git a/api/service/xxl_job_service.go b/api/service/xxl_job_service.go index 5ff11462..222cbefa 100644 --- a/api/service/xxl_job_service.go +++ b/api/service/xxl_job_service.go @@ -96,7 +96,7 @@ func (e *XXLJobExecutor) ResetVipCalls(cxt context.Context, param *xxl.RunReq) ( for _, u := range users { // 账号到期,直接清零 if u.ExpiredTime <= currentTime.Unix() { - logger.Info("账号过期:", u.Mobile) + logger.Info("账号过期:", u.Username) u.Calls = 0 u.Vip = false } else { @@ -133,7 +133,7 @@ func (e *XXLJobExecutor) ResetVipCalls(cxt context.Context, param *xxl.RunReq) ( } else { u.ImgCalls = u.ImgCalls + config.VipMonthImgCalls } - logger.Infof("%s 点卡结余:%d", u.Mobile, calls) + logger.Infof("%s 点卡结余:%d", u.Username, calls) } u.Tokens = 0 // update user diff --git a/api/store/model/user.go b/api/store/model/user.go index f907599b..fb2dfcc2 100644 --- a/api/store/model/user.go +++ b/api/store/model/user.go @@ -2,7 +2,7 @@ package model type User struct { BaseModel - Mobile string + Username string Nickname string Password string Avatar string diff --git a/api/store/vo/user.go b/api/store/vo/user.go index a286c328..b8807d25 100644 --- a/api/store/vo/user.go +++ b/api/store/vo/user.go @@ -4,7 +4,7 @@ import "chatplus/core/types" type User struct { BaseVo - Mobile string `json:"mobile"` + Username string `json:"username"` Nickname string `json:"nickname"` Avatar string `json:"avatar"` Salt string `json:"salt"` // 密码盐 diff --git a/api/test/test.go b/api/test/test.go index 2fb3b157..79058077 100644 --- a/api/test/test.go +++ b/api/test/test.go @@ -1,10 +1,5 @@ package main -import ( - "chatplus/utils" - "fmt" -) - func main() { - fmt.Println(utils.RandString(64)) + } diff --git a/database/update-v3.2.4.sql b/database/update-v3.2.4.sql index 7644a093..d0324ddc 100644 --- a/database/update-v3.2.4.sql +++ b/database/update-v3.2.4.sql @@ -5,4 +5,4 @@ ALTER TABLE `chatgpt_api_keys` DROP INDEX `value`; ALTER TABLE `chatgpt_mj_jobs` ADD UNIQUE(`task_id`); ALTER TABLE `chatgpt_api_keys` ADD `use_proxy` TINYINT(1) NULL COMMENT '是否使用代理访问' AFTER `enabled`; ALTER TABLE `chatgpt_api_keys` ADD `name` VARCHAR(30) NULL COMMENT '名称' AFTER `platform`; -ALTER TABLE `chatgpt_users` ADD `email` VARCHAR(100) NULL COMMENT '邮箱地址' AFTER `mobile`; \ No newline at end of file +ALTER TABLE `chatgpt_users` CHANGE `mobile` `username` VARCHAR(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '用户名'; \ No newline at end of file diff --git a/web/src/components/ConfigDialog.vue b/web/src/components/ConfigDialog.vue index 4fed0a0e..5790688b 100644 --- a/web/src/components/ConfigDialog.vue +++ b/web/src/components/ConfigDialog.vue @@ -10,7 +10,7 @@
- {{ user.mobile }} + {{ user.username }} {{ user['calls'] }} @@ -54,17 +54,14 @@ const user = ref({ username: '', nickname: '', avatar: '', - mobile: '', calls: 0, tokens: 0, - chat_config: {api_keys: {OpenAI: "", Azure: "", ChatGLM: ""}} }) onMounted(() => { // 获取最新用户信息 httpGet('/api/user/profile').then(res => { user.value = res.data - user.value.chat_config.api_keys = res.data.chat_config.api_keys ?? {OpenAI: "", Azure: "", ChatGLM: ""} }).catch(e => { ElMessage.error("获取用户信息失败:" + e.message) }); diff --git a/web/src/components/BindMobile.vue b/web/src/components/ResetAccount.vue similarity index 65% rename from web/src/components/BindMobile.vue rename to web/src/components/ResetAccount.vue index 20d3619b..04446884 100644 --- a/web/src/components/BindMobile.vue +++ b/web/src/components/ResetAccount.vue @@ -7,21 +7,21 @@ :title="title" >
- -

当前用户已绑定手机号:{{ mobile }}, 绑定其他手机号之后自动解绑该手机号。

+ +

当前绑定账号:{{ username }},只允许使绑定有效的手机号或者邮箱地址作为登录账号。

- - + + - + - + @@ -43,37 +43,36 @@ 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"; +import {validateEmail, validateMobile} from "@/utils/validate"; const props = defineProps({ show: Boolean, - mobile: String + username: String }); const showDialog = computed(() => { return props.show }) -const title = ref('绑定手机号') +const title = ref('重置登录账号') const form = ref({ - mobile: '', + username: '', code: '' }) const emits = defineEmits(['hide']); const save = () => { - if (!validateMobile(form.value.mobile)) { - return ElMessage.error("请输入正确的手机号码"); + if (!validateMobile(form.value.username) && !validateEmail(form.value.username)) { + return ElMessage.error("请输入合法的手机号/邮箱地址") } if (form.value.code === '') { - return ElMessage.error("请输入短信验证码"); + return ElMessage.error("请输入验证码"); } - httpPost('/api/user/bind/mobile', form.value).then(() => { + httpPost('/api/user/bind/username', form.value).then(() => { ElMessage.success({ message: '绑定成功', - appendTo: '#bind-mobile-form', duration: 1000, onClose: () => emits('hide', false) }) diff --git a/web/src/components/ResetPass.vue b/web/src/components/ResetPass.vue index 7c589a7a..c5e8fcd8 100644 --- a/web/src/components/ResetPass.vue +++ b/web/src/components/ResetPass.vue @@ -10,16 +10,16 @@
- - + + - + - + @@ -48,7 +48,7 @@ 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"; +import {validateEmail, validateMobile} from "@/utils/validate"; const props = defineProps({ show: Boolean, @@ -61,7 +61,7 @@ const showDialog = computed(() => { const title = ref('重置密码') const form = ref({ - mobile: '', + username: '', code: '', password: '', repass: '' @@ -70,11 +70,11 @@ const form = ref({ const emits = defineEmits(['hide']); const save = () => { - if (!validateMobile(form.value.mobile)) { - return ElMessage.error("请输入正确的手机号码"); + if (!validateMobile(form.value.username) && !validateEmail(form.value.username)) { + return ElMessage.error("请输入正确的手机号码/邮箱地址"); } if (form.value.code === '') { - return ElMessage.error("请输入短信验证码"); + return ElMessage.error("请输入验证码"); } if (form.value.repass !== form.value.password) { return ElMessage.error("两次输入密码不一致"); diff --git a/web/src/components/SendMsg.vue b/web/src/components/SendMsg.vue index b7b14a6e..2f0f5122 100644 --- a/web/src/components/SendMsg.vue +++ b/web/src/components/SendMsg.vue @@ -28,13 +28,13 @@ // 发送短信验证码组件 import {ref} from "vue"; import lodash from 'lodash' -import {validateMobile} from "@/utils/validate"; +import {validateEmail, validateMobile} from "@/utils/validate"; import {ElMessage} from "element-plus"; import {httpGet, httpPost} from "@/utils/http"; import CaptchaPlus from "@/components/CaptchaPlus.vue"; const props = defineProps({ - mobile: String, + receiver: String, size: String, }); const btnText = ref('发送验证码') @@ -82,8 +82,8 @@ const handleConfirm = (dots) => { } const loadCaptcha = () => { - if (!validateMobile(props.mobile)) { - return ElMessage.error("请输入合法的手机号") + if (!validateMobile(props.receiver) && !validateEmail(props.receiver)) { + return ElMessage.error("请输入合法的手机号/邮箱地址") } showCaptcha.value = true @@ -96,8 +96,8 @@ const sendMsg = () => { } canSend.value = false - httpPost('/api/sms/code', {mobile: props.mobile, key: captKey.value, dots: dots.value}).then(() => { - ElMessage.success('短信发送成功') + httpPost('/api/sms/code', {receiver: props.receiver, key: captKey.value, dots: dots.value}).then(() => { + ElMessage.success('验证码发送成功') let time = 120 btnText.value = time const handler = setInterval(() => { @@ -112,7 +112,7 @@ const sendMsg = () => { }, 1000) }).catch(e => { canSend.value = true - ElMessage.error('短信发送失败:' + e.message) + ElMessage.error('验证码发送失败:' + e.message) }) } diff --git a/web/src/components/UserProfile.vue b/web/src/components/UserProfile.vue index fa121d1f..8c5c5b62 100644 --- a/web/src/components/UserProfile.vue +++ b/web/src/components/UserProfile.vue @@ -17,8 +17,8 @@ - - {{ user.mobile }} + + {{ user.username }} - - - - - - - - - - - - - \ No newline at end of file diff --git a/web/src/utils/libs.js b/web/src/utils/libs.js index f43f3770..7797fd66 100644 --- a/web/src/utils/libs.js +++ b/web/src/utils/libs.js @@ -84,6 +84,10 @@ export function dateFormat(timestamp, format) { // 判断数组中是否包含某个元素 export function arrayContains(array, value, compare) { + if (!array) { + return false + } + if (typeof compare !== 'function') { compare = function (v1, v2) { return v1 === v2; diff --git a/web/src/views/ChatPlus.vue b/web/src/views/ChatPlus.vue index 32c809e4..3505556b 100644 --- a/web/src/views/ChatPlus.vue +++ b/web/src/views/ChatPlus.vue @@ -231,12 +231,17 @@
注意:当前站点仅为开源项目 - ChatPlus + ChatPlus 的演示项目,本项目单纯就是给大家体验项目功能使用。
体验额度用完之后请不要在当前站点进行任何充值操作!!!
体验额度用完之后请不要在当前站点进行任何充值操作!!!
体验额度用完之后请不要在当前站点进行任何充值操作!!!
+ + 如果觉得好用你就花几分钟自己部署一套,没有API KEY 的同学可以去 + https://gpt.bemore.lol + 购买,现在有超级优惠,价格远低于 OpenAI 官方。

@@ -350,7 +355,7 @@ onMounted(() => { httpGet("/api/admin/config/get?key=system").then(res => { title.value = res.data.title - const show = localStorage.getItem(showNoticeKey.value + loginUser.value.mobile) + const show = localStorage.getItem(showNoticeKey.value + loginUser.value.username) if (!show) { showDemoNotice.value = res.data['show_demo_notice'] } @@ -878,7 +883,7 @@ const getModelValue = (model_id) => { const notShow = () => { - localStorage.setItem(showNoticeKey.value + loginUser.value.mobile, true) + localStorage.setItem(showNoticeKey.value + loginUser.value.username, true) showDemoNotice.value = false } diff --git a/web/src/views/Home.vue b/web/src/views/Home.vue index 971ed1c3..471c9387 100644 --- a/web/src/views/Home.vue +++ b/web/src/views/Home.vue @@ -2,9 +2,7 @@