mirror of
				https://github.com/yangjian102621/geekai.git
				synced 2025-11-04 08:13:43 +08:00 
			
		
		
		
	fixed conflicts
This commit is contained in:
		@@ -1,5 +1,9 @@
 | 
			
		||||
# 更新日志
 | 
			
		||||
 | 
			
		||||
## v4.0.6
 | 
			
		||||
 | 
			
		||||
* Bug修复:修复PC端画廊页面的瀑布流组件样式错乱问题
 | 
			
		||||
 | 
			
		||||
## v4.0.5
 | 
			
		||||
 | 
			
		||||
* 功能优化:已授权系统在后台显示授权信息
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,5 @@
 | 
			
		||||
SHELL=/usr/bin/env bash
 | 
			
		||||
NAME := chatgpt-plus
 | 
			
		||||
NAME := geekai
 | 
			
		||||
all: amd64 arm64
 | 
			
		||||
 | 
			
		||||
amd64:
 | 
			
		||||
 
 | 
			
		||||
@@ -207,10 +207,13 @@ func authorizeMiddleware(s *AppServer, client *redis.Client) gin.HandlerFunc {
 | 
			
		||||
 | 
			
		||||
func needLogin(c *gin.Context) bool {
 | 
			
		||||
	if c.Request.URL.Path == "/api/user/login" ||
 | 
			
		||||
		c.Request.URL.Path == "/api/user/logout" ||
 | 
			
		||||
		c.Request.URL.Path == "/api/user/resetPass" ||
 | 
			
		||||
		c.Request.URL.Path == "/api/admin/login" ||
 | 
			
		||||
		c.Request.URL.Path == "/api/admin/logout" ||
 | 
			
		||||
		c.Request.URL.Path == "/api/admin/login/captcha" ||
 | 
			
		||||
		c.Request.URL.Path == "/api/user/register" ||
 | 
			
		||||
		c.Request.URL.Path == "/api/user/session" ||
 | 
			
		||||
		c.Request.URL.Path == "/api/chat/history" ||
 | 
			
		||||
		c.Request.URL.Path == "/api/chat/detail" ||
 | 
			
		||||
		c.Request.URL.Path == "/api/chat/list" ||
 | 
			
		||||
 
 | 
			
		||||
@@ -144,6 +144,7 @@ func (h *ChatHandler) ChatHandle(c *gin.Context) {
 | 
			
		||||
		for {
 | 
			
		||||
			_, msg, err := client.Receive()
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				logger.Debugf("close connection: %s", client.Conn.RemoteAddr())
 | 
			
		||||
				client.Close()
 | 
			
		||||
				h.App.ChatClients.Delete(sessionId)
 | 
			
		||||
				h.App.ChatSession.Delete(sessionId)
 | 
			
		||||
 
 | 
			
		||||
@@ -188,6 +188,11 @@ func (h *FunctionHandler) Dall3(c *gin.Context) {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if user.Power < h.App.SysConfig.DallPower {
 | 
			
		||||
		resp.ERROR(c, "创建 DALL-E 绘图任务失败,算力不足")
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// create dall task
 | 
			
		||||
	prompt := utils.InterfaceToString(params["prompt"])
 | 
			
		||||
	job := model.DallJob{
 | 
			
		||||
 
 | 
			
		||||
@@ -13,21 +13,22 @@ import (
 | 
			
		||||
	"geekai/core"
 | 
			
		||||
	"geekai/core/types"
 | 
			
		||||
	"geekai/store"
 | 
			
		||||
	"github.com/imroc/req/v3"
 | 
			
		||||
	"github.com/shirou/gopsutil/host"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"github.com/imroc/req/v3"
 | 
			
		||||
	"github.com/shirou/gopsutil/host"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type LicenseService struct {
 | 
			
		||||
	config       types.ApiConfig
 | 
			
		||||
	levelDB      *store.LevelDB
 | 
			
		||||
	license      types.License
 | 
			
		||||
	license *types.License
 | 
			
		||||
	urlWhiteList []string
 | 
			
		||||
	machineId    string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewLicenseService(server *core.AppServer, levelDB *store.LevelDB) * LicenseService {
 | 
			
		||||
func NewLicenseService(server *core.AppServer, levelDB *store.LevelDB) *LicenseService {
 | 
			
		||||
	var license types.License
 | 
			
		||||
	var machineId string
 | 
			
		||||
	_ = levelDB.Get(types.LicenseKey, &license)
 | 
			
		||||
@@ -35,18 +36,20 @@ func NewLicenseService(server *core.AppServer, levelDB *store.LevelDB) * License
 | 
			
		||||
	if err == nil {
 | 
			
		||||
		machineId = info.HostID
 | 
			
		||||
	}
 | 
			
		||||
	logger.Infof("License: %+v", license)
 | 
			
		||||
	return &LicenseService{
 | 
			
		||||
		config:    server.Config.ApiConfig,
 | 
			
		||||
		levelDB:   levelDB,
 | 
			
		||||
		license:   license,
 | 
			
		||||
		license: &license,
 | 
			
		||||
		machineId: machineId,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type License struct {
 | 
			
		||||
	Name      string `json:"name"`
 | 
			
		||||
	Value     string `json:"license"`
 | 
			
		||||
	License  string `json:"license"`
 | 
			
		||||
	Mid       string `json:"mid"`
 | 
			
		||||
	ActiveAt int64  `json:"active_at"`
 | 
			
		||||
	ExpiredAt int64  `json:"expired_at"`
 | 
			
		||||
	UserNum   int    `json:"user_num"`
 | 
			
		||||
}
 | 
			
		||||
@@ -67,14 +70,14 @@ func (s *LicenseService) ActiveLicense(license string, machineId string) error {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if response.IsErrorState() {
 | 
			
		||||
		return fmt.Errorf( "发送激活请求失败:%v", response.Status)
 | 
			
		||||
		return fmt.Errorf("发送激活请求失败:%v", response.Status)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if res.Code != types.Success {
 | 
			
		||||
		return fmt.Errorf("激活失败:%v", res.Message)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	s.license = types.License{
 | 
			
		||||
	s.license = &types.License{
 | 
			
		||||
		Key:       license,
 | 
			
		||||
		MachineId: machineId,
 | 
			
		||||
		UserNum:   res.Data.UserNum,
 | 
			
		||||
@@ -91,50 +94,81 @@ func (s *LicenseService) ActiveLicense(license string, machineId string) error {
 | 
			
		||||
// SyncLicense 定期同步 License
 | 
			
		||||
func (s *LicenseService) SyncLicense() {
 | 
			
		||||
	go func() {
 | 
			
		||||
		retryCounter := 0
 | 
			
		||||
		for {
 | 
			
		||||
			var res struct {
 | 
			
		||||
				Code    types.BizCode `json:"code"`
 | 
			
		||||
				Message string        `json:"message"`
 | 
			
		||||
				Data    struct {
 | 
			
		||||
					License License  `json:"license"`
 | 
			
		||||
					Urls    []string `json:"urls"`
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			apiURL := fmt.Sprintf("%s/%s", s.config.ApiURL, "api/license/check")
 | 
			
		||||
			response, err := req.C().R().
 | 
			
		||||
				SetBody(map[string]string{"license": s.license.Key, "machine_id": s.machineId}).
 | 
			
		||||
				SetSuccessResult(&res).Post(apiURL)
 | 
			
		||||
			license, err := s.fetchLicense()
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				logger.Errorf("发送激活请求失败: %v", err)
 | 
			
		||||
				goto next
 | 
			
		||||
			}
 | 
			
		||||
			if response.IsErrorState() {
 | 
			
		||||
				logger.Errorf("激活失败:%v", response.Status)
 | 
			
		||||
				goto next
 | 
			
		||||
			}
 | 
			
		||||
			if res.Code != types.Success {
 | 
			
		||||
				logger.Errorf("激活失败:%v", res.Message)
 | 
			
		||||
				retryCounter++
 | 
			
		||||
				if retryCounter < 5 {
 | 
			
		||||
					logger.Error(err)
 | 
			
		||||
				}
 | 
			
		||||
				s.license.IsActive = false
 | 
			
		||||
				goto next
 | 
			
		||||
			} else {
 | 
			
		||||
				s.license = license
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			s.license = types.License{
 | 
			
		||||
				Key:       res.Data.License.Value,
 | 
			
		||||
				MachineId: res.Data.License.Mid,
 | 
			
		||||
				UserNum:   res.Data.License.UserNum,
 | 
			
		||||
				ExpiredAt: res.Data.License.ExpiredAt,
 | 
			
		||||
				IsActive:  true,
 | 
			
		||||
			urls, err := s.fetchUrlWhiteList()
 | 
			
		||||
			if err == nil {
 | 
			
		||||
				s.urlWhiteList = urls
 | 
			
		||||
			}
 | 
			
		||||
			s.urlWhiteList = res.Data.Urls
 | 
			
		||||
			logger.Debugf("同步 License 成功:%v\n%v", s.license, s.urlWhiteList)
 | 
			
		||||
		next:
 | 
			
		||||
 | 
			
		||||
			time.Sleep(time.Second * 10)
 | 
			
		||||
		}
 | 
			
		||||
	}()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *LicenseService) fetchLicense() (*types.License, error) {
 | 
			
		||||
	var res struct {
 | 
			
		||||
		Code    types.BizCode `json:"code"`
 | 
			
		||||
		Message string        `json:"message"`
 | 
			
		||||
		Data    License       `json:"data"`
 | 
			
		||||
	}
 | 
			
		||||
	apiURL := fmt.Sprintf("%s/%s", s.config.ApiURL, "api/license/check")
 | 
			
		||||
	response, err := req.C().R().
 | 
			
		||||
		SetBody(map[string]string{"license": s.license.Key, "machine_id": s.machineId}).
 | 
			
		||||
		SetSuccessResult(&res).Post(apiURL)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, fmt.Errorf("发送激活请求失败: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
	if response.IsErrorState() {
 | 
			
		||||
		return nil, fmt.Errorf("激活失败:%v", response.Status)
 | 
			
		||||
	}
 | 
			
		||||
	if res.Code != types.Success {
 | 
			
		||||
		return nil, fmt.Errorf("激活失败:%v", res.Message)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return &types.License{
 | 
			
		||||
		Key:       res.Data.License,
 | 
			
		||||
		MachineId: res.Data.Mid,
 | 
			
		||||
		UserNum:   res.Data.UserNum,
 | 
			
		||||
		ExpiredAt: res.Data.ExpiredAt,
 | 
			
		||||
		IsActive:  true,
 | 
			
		||||
	}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *LicenseService) fetchUrlWhiteList() ([]string, error) {
 | 
			
		||||
	var res struct {
 | 
			
		||||
		Code    types.BizCode `json:"code"`
 | 
			
		||||
		Message string        `json:"message"`
 | 
			
		||||
		Data    []string      `json:"data"`
 | 
			
		||||
	}
 | 
			
		||||
	apiURL := fmt.Sprintf("%s/%s", s.config.ApiURL, "api/license/urls")
 | 
			
		||||
	response, err := req.C().R().SetSuccessResult(&res).Get(apiURL)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, fmt.Errorf("发送请求失败: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
	if response.IsErrorState() {
 | 
			
		||||
		return nil, fmt.Errorf("发送请求失败:%v", response.Status)
 | 
			
		||||
	}
 | 
			
		||||
	if res.Code != types.Success {
 | 
			
		||||
		return nil, fmt.Errorf("获取白名单失败:%v", res.Message)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return res.Data, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetLicense 获取许可信息
 | 
			
		||||
func (s *LicenseService) GetLicense() types.License {
 | 
			
		||||
func (s *LicenseService) GetLicense() *types.License {
 | 
			
		||||
	return s.license
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -158,4 +192,4 @@ func (s *LicenseService) IsValidApiURL(uri string) error {
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return fmt.Errorf("当前 API 地址 %s 不在白名单列表当中。", uri)
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -14,15 +14,15 @@ npm run build
 | 
			
		||||
cd ../build
 | 
			
		||||
 | 
			
		||||
# remove docker image if exists
 | 
			
		||||
docker rmi -f registry.cn-shenzhen.aliyuncs.com/geekmaster/chatgpt-plus-api:$version-$arch
 | 
			
		||||
# build docker image for chatgpt-plus-go
 | 
			
		||||
docker build -t registry.cn-shenzhen.aliyuncs.com/geekmaster/chatgpt-plus-api:$version-$arch -f dockerfile-api-go ../
 | 
			
		||||
docker rmi -f registry.cn-shenzhen.aliyuncs.com/geekmaster/geekai-api:$version-$arch
 | 
			
		||||
# build docker image for Geek-AI API
 | 
			
		||||
docker build -t registry.cn-shenzhen.aliyuncs.com/geekmaster/geekai-api:$version-$arch -f dockerfile-api-go ../
 | 
			
		||||
 | 
			
		||||
# build docker image for chatgpt-plus-vue
 | 
			
		||||
docker rmi -f registry.cn-shenzhen.aliyuncs.com/geekmaster/chatgpt-plus-web:$version-$arch
 | 
			
		||||
docker build --platform linux/amd64 -t registry.cn-shenzhen.aliyuncs.com/geekmaster/chatgpt-plus-web:$version-$arch -f dockerfile-vue ../
 | 
			
		||||
# build docker image for Geek-AI-web
 | 
			
		||||
docker rmi -f registry.cn-shenzhen.aliyuncs.com/geekmaster/geekai-web:$version-$arch
 | 
			
		||||
docker build -t registry.cn-shenzhen.aliyuncs.com/geekmaster/geekai-web:$version-$arch -f dockerfile-vue ../
 | 
			
		||||
 | 
			
		||||
if [ "$3" = "push" ];then
 | 
			
		||||
  docker push registry.cn-shenzhen.aliyuncs.com/geekmaster/chatgpt-plus-api:$version-$arch
 | 
			
		||||
  docker push registry.cn-shenzhen.aliyuncs.com/geekmaster/chatgpt-plus-web:$version-$arch
 | 
			
		||||
  docker push registry.cn-shenzhen.aliyuncs.com/geekmaster/geekai-api:$version-$arch
 | 
			
		||||
  docker push registry.cn-shenzhen.aliyuncs.com/geekmaster/geekai-web:$version-$arch
 | 
			
		||||
fi
 | 
			
		||||
 
 | 
			
		||||
@@ -4,9 +4,9 @@ FROM registry.cn-hangzhou.aliyuncs.com/geekmaster/alpine:3.18.2
 | 
			
		||||
MAINTAINER yangjian<yangjian102621@163.com>
 | 
			
		||||
 | 
			
		||||
WORKDIR /var/www/app
 | 
			
		||||
COPY ./api/bin/chatgpt-plus-linux /var/www/app
 | 
			
		||||
COPY ./api/bin/geekai-linux /var/www/app
 | 
			
		||||
 | 
			
		||||
EXPOSE 5678
 | 
			
		||||
 | 
			
		||||
# 容器启动时执行的命令
 | 
			
		||||
CMD ["./chatgpt-plus-linux"]
 | 
			
		||||
CMD ["./geekai-linux"]
 | 
			
		||||
 
 | 
			
		||||
@@ -66,4 +66,14 @@ html, body {
 | 
			
		||||
  white-space: nowrap;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.van-toast--fail {
 | 
			
		||||
  background #fef0f0
 | 
			
		||||
  color #f56c6c
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.van-toast--success {
 | 
			
		||||
  background #D6FBCC
 | 
			
		||||
  color #07C160
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
</style>
 | 
			
		||||
 
 | 
			
		||||
@@ -9,7 +9,7 @@
 | 
			
		||||
 | 
			
		||||
  .chat-list-wrapper {
 | 
			
		||||
    padding 10px 0 10px 0
 | 
			
		||||
    background #F5F5F5;
 | 
			
		||||
    background var(--van-background);
 | 
			
		||||
    overflow hidden
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -81,7 +81,7 @@
 | 
			
		||||
 | 
			
		||||
.van-theme-dark {
 | 
			
		||||
  .mobile-chat {
 | 
			
		||||
    .message-list-box {
 | 
			
		||||
    .chat-list-wrapper {
 | 
			
		||||
      background #232425;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 
 | 
			
		||||
@@ -74,6 +74,7 @@
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  color var(--van-text-color)
 | 
			
		||||
  .pt-6 {
 | 
			
		||||
    padding 15px 10px
 | 
			
		||||
  }
 | 
			
		||||
 
 | 
			
		||||
@@ -80,6 +80,8 @@
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  color var(--van-text-color)
 | 
			
		||||
  
 | 
			
		||||
  .pt-6 {
 | 
			
		||||
    padding 15px 10px
 | 
			
		||||
  }
 | 
			
		||||
 
 | 
			
		||||
@@ -38,11 +38,11 @@
 | 
			
		||||
import {ref} from "vue";
 | 
			
		||||
import lodash from 'lodash'
 | 
			
		||||
import {validateEmail, validateMobile} from "@/utils/validate";
 | 
			
		||||
import {ElMessage} from "element-plus";
 | 
			
		||||
import {httpGet, httpPost} from "@/utils/http";
 | 
			
		||||
import CaptchaPlus from "@/components/CaptchaPlus.vue";
 | 
			
		||||
import SlideCaptcha from "@/components/SlideCaptcha.vue";
 | 
			
		||||
import {isMobile} from "@/utils/libs";
 | 
			
		||||
import {showMessageError, showMessageOK} from "@/utils/dialog";
 | 
			
		||||
 | 
			
		||||
// eslint-disable-next-line no-undef
 | 
			
		||||
const props = defineProps({
 | 
			
		||||
@@ -66,13 +66,13 @@ const handleRequestCaptCode = () => {
 | 
			
		||||
    thumbBase64.value = data.thumb
 | 
			
		||||
    captKey.value = data.key
 | 
			
		||||
  }).catch(e => {
 | 
			
		||||
    ElMessage.error('获取人机验证数据失败:' + e.message)
 | 
			
		||||
    showMessageError('获取人机验证数据失败:' + e.message)
 | 
			
		||||
  })
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const handleConfirm = (dots) => {
 | 
			
		||||
  if (lodash.size(dots) <= 0) {
 | 
			
		||||
    return ElMessage.error('请进行人机验证再操作')
 | 
			
		||||
    return showMessageError('请进行人机验证再操作')
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  let dotArr = []
 | 
			
		||||
@@ -88,14 +88,14 @@ const handleConfirm = (dots) => {
 | 
			
		||||
    showCaptcha.value = false
 | 
			
		||||
    sendMsg()
 | 
			
		||||
  }).catch(() => {
 | 
			
		||||
    ElMessage.error('人机验证失败')
 | 
			
		||||
    showMessageError('人机验证失败')
 | 
			
		||||
    handleRequestCaptCode()
 | 
			
		||||
  })
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const loadCaptcha = () => {
 | 
			
		||||
  if (!validateMobile(props.receiver) && !validateEmail(props.receiver)) {
 | 
			
		||||
    return ElMessage.error("请输入合法的手机号/邮箱地址")
 | 
			
		||||
    return showMessageError("请输入合法的手机号/邮箱地址")
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  showCaptcha.value = true
 | 
			
		||||
@@ -114,7 +114,7 @@ const sendMsg = () => {
 | 
			
		||||
 | 
			
		||||
  canSend.value = false
 | 
			
		||||
  httpPost('/api/sms/code', {receiver: props.receiver, key: captKey.value, dots: dots.value}).then(() => {
 | 
			
		||||
    ElMessage.success('验证码发送成功')
 | 
			
		||||
    showMessageOK('验证码发送成功')
 | 
			
		||||
    let time = 120
 | 
			
		||||
    btnText.value = time
 | 
			
		||||
    const handler = setInterval(() => {
 | 
			
		||||
@@ -129,7 +129,7 @@ const sendMsg = () => {
 | 
			
		||||
    }, 1000)
 | 
			
		||||
  }).catch(e => {
 | 
			
		||||
    canSend.value = true
 | 
			
		||||
    ElMessage.error('验证码发送失败:' + e.message)
 | 
			
		||||
    showMessageError('验证码发送失败:' + e.message)
 | 
			
		||||
  })
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -145,7 +145,7 @@ const getSlideCaptcha = () => {
 | 
			
		||||
    bgImg.value = res.data.bgImg
 | 
			
		||||
    captKey.value = res.data.key
 | 
			
		||||
  }).catch(e => {
 | 
			
		||||
    ElMessage.error('获取人机验证数据失败:' + e.message)
 | 
			
		||||
    showMessageError('获取人机验证数据失败:' + e.message)
 | 
			
		||||
  })
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										43
									
								
								web/src/utils/dialog.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								web/src/utils/dialog.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,43 @@
 | 
			
		||||
/**
 | 
			
		||||
 * Util lib functions
 | 
			
		||||
 */
 | 
			
		||||
import {showConfirmDialog, showFailToast, showSuccessToast, showToast} from "vant";
 | 
			
		||||
import {isMobile} from "@/utils/libs";
 | 
			
		||||
import {ElMessage} from "element-plus";
 | 
			
		||||
 | 
			
		||||
export function showLoginDialog(router) {
 | 
			
		||||
    showConfirmDialog({
 | 
			
		||||
        title: '登录',
 | 
			
		||||
        message:
 | 
			
		||||
            '此操作需要登录才能进行,前往登录?',
 | 
			
		||||
    }).then(() => {
 | 
			
		||||
        router.push("/login")
 | 
			
		||||
    }).catch(() => {
 | 
			
		||||
        // on cancel
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function showMessageOK(message) {
 | 
			
		||||
    if (isMobile()) {
 | 
			
		||||
        showSuccessToast(message)
 | 
			
		||||
    } else {
 | 
			
		||||
        ElMessage.success(message)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
export function showMessageInfo(message) {
 | 
			
		||||
    if (isMobile()) {
 | 
			
		||||
        showToast(message)
 | 
			
		||||
    } else {
 | 
			
		||||
        ElMessage.info(message)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function showMessageError(message) {
 | 
			
		||||
    if (isMobile()) {
 | 
			
		||||
        showFailToast(message)
 | 
			
		||||
    } else {
 | 
			
		||||
        ElMessage.error(message)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -6,7 +6,7 @@
 | 
			
		||||
// * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 | 
			
		||||
 | 
			
		||||
import axios from 'axios'
 | 
			
		||||
import {getAdminToken, getSessionId, getUserToken} from "@/store/session";
 | 
			
		||||
import {getAdminToken, getSessionId, getUserToken, removeAdminToken, removeUserToken} from "@/store/session";
 | 
			
		||||
 | 
			
		||||
axios.defaults.timeout = 180000
 | 
			
		||||
axios.defaults.baseURL = process.env.VUE_APP_API_HOST
 | 
			
		||||
@@ -29,9 +29,14 @@ axios.interceptors.response.use(
 | 
			
		||||
        let data = response.data;
 | 
			
		||||
        if (data.code === 0) {
 | 
			
		||||
            return response
 | 
			
		||||
        } else {
 | 
			
		||||
            return Promise.reject(response.data)
 | 
			
		||||
        } else if (data.code === 400) {
 | 
			
		||||
            if (response.request.responseURL.indexOf("/api/admin") !== -1) {
 | 
			
		||||
                removeAdminToken()
 | 
			
		||||
            } else {
 | 
			
		||||
                removeUserToken()
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
            return Promise.reject(response.data)
 | 
			
		||||
    }, error => {
 | 
			
		||||
        return Promise.reject(error)
 | 
			
		||||
    })
 | 
			
		||||
 
 | 
			
		||||
@@ -13,7 +13,7 @@
 | 
			
		||||
                <span class="name">{{ scope.item.name }}</span>
 | 
			
		||||
                <div class="opt">
 | 
			
		||||
                  <div v-if="hasRole(scope.item.key)">
 | 
			
		||||
                    <el-button size="small" type="success" @click="useRole(scope.item.id)">使用</el-button>
 | 
			
		||||
                    <el-button size="small" type="success" @click="useRole(scope.item)">使用</el-button>
 | 
			
		||||
                    <el-button size="small" type="danger" @click="updateRole(scope.item,'remove')">移除</el-button>
 | 
			
		||||
                  </div>
 | 
			
		||||
                  <el-button v-else size="small"
 | 
			
		||||
@@ -110,8 +110,8 @@ const hasRole = (roleKey) => {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const router = useRouter()
 | 
			
		||||
const useRole = (roleId) => {
 | 
			
		||||
  router.push({name: "chat", params: {role_id: roleId}})
 | 
			
		||||
const useRole = (role) => {
 | 
			
		||||
  router.push(`/chat?role_id=${role.id}`)
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -330,7 +330,10 @@ onMounted(() => {
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
onUnmounted(() => {
 | 
			
		||||
  socket.value = null
 | 
			
		||||
  if (socket.value !== null) {
 | 
			
		||||
    socket.value.close()
 | 
			
		||||
    socket.value = null
 | 
			
		||||
  }
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
// 初始化数据
 | 
			
		||||
@@ -355,8 +358,8 @@ const initData = () => {
 | 
			
		||||
        // 加载角色列表
 | 
			
		||||
        httpGet(`/api/role/list`).then((res) => {
 | 
			
		||||
          roles.value = res.data;
 | 
			
		||||
          if (router.currentRoute.value.params.role_id) {
 | 
			
		||||
            roleId.value = parseInt(router.currentRoute.value.params["role_id"])
 | 
			
		||||
          if (router.currentRoute.value.query.role_id) {
 | 
			
		||||
            roleId.value = parseInt(router.currentRoute.value.query.role_id)
 | 
			
		||||
          } else {
 | 
			
		||||
            roleId.value = roles.value[0]['id']
 | 
			
		||||
          }
 | 
			
		||||
 
 | 
			
		||||
@@ -105,7 +105,7 @@
 | 
			
		||||
              </div>
 | 
			
		||||
 | 
			
		||||
              <h2>创作记录</h2>
 | 
			
		||||
              <div class="finish-job-list" v-loading="loading" element-loading-background="rgba(0, 0, 0, 0.5)">
 | 
			
		||||
              <div class="finish-job-list">
 | 
			
		||||
                <div v-if="finishedJobs.length > 0">
 | 
			
		||||
                  <ItemList :items="finishedJobs" :width="240" :gap="16">
 | 
			
		||||
                    <template #default="scope">
 | 
			
		||||
@@ -272,7 +272,6 @@ const initData = () => {
 | 
			
		||||
    fetchFinishJobs(1)
 | 
			
		||||
    connect()
 | 
			
		||||
  }).catch(() => {
 | 
			
		||||
    loading.value = false
 | 
			
		||||
  });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -341,6 +340,9 @@ const connect = () => {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const fetchRunningJobs = () => {
 | 
			
		||||
  if (!isLogin.value) {
 | 
			
		||||
    return
 | 
			
		||||
  }
 | 
			
		||||
  // 获取运行中的任务
 | 
			
		||||
  httpGet(`/api/dall/jobs?status=0`).then(res => {
 | 
			
		||||
    const jobs = res.data
 | 
			
		||||
@@ -367,10 +369,11 @@ const fetchRunningJobs = () => {
 | 
			
		||||
const page = ref(1)
 | 
			
		||||
const pageSize = ref(15)
 | 
			
		||||
const isOver = ref(false)
 | 
			
		||||
const loading = ref(false)
 | 
			
		||||
// 获取已完成的任务
 | 
			
		||||
const fetchFinishJobs = (page) => {
 | 
			
		||||
  loading.value = true
 | 
			
		||||
  if (!isLogin.value) {
 | 
			
		||||
    return
 | 
			
		||||
  }
 | 
			
		||||
  httpGet(`/api/dall/jobs?status=1&page=${page}&page_size=${pageSize.value}`).then(res => {
 | 
			
		||||
    if (res.data.length < pageSize.value) {
 | 
			
		||||
      isOver.value = true
 | 
			
		||||
@@ -380,9 +383,7 @@ const fetchFinishJobs = (page) => {
 | 
			
		||||
    } else {
 | 
			
		||||
      finishedJobs.value = finishedJobs.value.concat(res.data)
 | 
			
		||||
    }
 | 
			
		||||
    loading.value = false
 | 
			
		||||
  }).catch(e => {
 | 
			
		||||
    loading.value = false
 | 
			
		||||
    ElMessage.error("获取任务失败:" + e.message)
 | 
			
		||||
  })
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -493,7 +493,7 @@
 | 
			
		||||
            </div>
 | 
			
		||||
 | 
			
		||||
            <h2>创作记录</h2>
 | 
			
		||||
            <div class="finish-job-list" v-loading="loading" element-loading-background="rgba(0, 0, 0, 0.5)">
 | 
			
		||||
            <div class="finish-job-list">
 | 
			
		||||
              <div v-if="finishedJobs.length > 0">
 | 
			
		||||
                <ItemList :items="finishedJobs" :width="240" :gap="16">
 | 
			
		||||
                  <template #default="scope">
 | 
			
		||||
@@ -593,7 +593,7 @@
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script setup>
 | 
			
		||||
import {nextTick, onMounted, onUnmounted, ref} from "vue"
 | 
			
		||||
import {onMounted, onUnmounted, ref} from "vue"
 | 
			
		||||
import {ChromeFilled, Delete, DocumentCopy, InfoFilled, Picture, Plus, UploadFilled} from "@element-plus/icons-vue";
 | 
			
		||||
import Compressor from "compressorjs";
 | 
			
		||||
import {httpGet, httpPost} from "@/utils/http";
 | 
			
		||||
@@ -761,7 +761,10 @@ onMounted(() => {
 | 
			
		||||
 | 
			
		||||
onUnmounted(() => {
 | 
			
		||||
  clipboard.value.destroy()
 | 
			
		||||
  socket.value = null
 | 
			
		||||
  if (socket.value !== null) {
 | 
			
		||||
    socket.value.close()
 | 
			
		||||
    socket.value = null
 | 
			
		||||
  }
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
// 初始化数据
 | 
			
		||||
@@ -779,10 +782,6 @@ const initData = () => {
 | 
			
		||||
  });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
onUnmounted(() => {
 | 
			
		||||
  clipboard.value.destroy()
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
const mjPower = ref(1)
 | 
			
		||||
const mjActionPower = ref(1)
 | 
			
		||||
httpGet("/api/config/get?key=system").then(res => {
 | 
			
		||||
@@ -794,6 +793,10 @@ httpGet("/api/config/get?key=system").then(res => {
 | 
			
		||||
 | 
			
		||||
// 获取运行中的任务
 | 
			
		||||
const fetchRunningJobs = () => {
 | 
			
		||||
  if (!isLogin.value) {
 | 
			
		||||
    return
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  httpGet(`/api/mj/jobs?status=0`).then(res => {
 | 
			
		||||
    const jobs = res.data
 | 
			
		||||
    const _jobs = []
 | 
			
		||||
@@ -833,9 +836,11 @@ const handleScrollEnd = () => {
 | 
			
		||||
const page = ref(1)
 | 
			
		||||
const pageSize = ref(15)
 | 
			
		||||
const isOver = ref(false)
 | 
			
		||||
const loading = ref(false)
 | 
			
		||||
const fetchFinishJobs = (page) => {
 | 
			
		||||
  loading.value = true
 | 
			
		||||
  if (!isLogin.value) {
 | 
			
		||||
    return
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // 获取已完成的任务
 | 
			
		||||
  httpGet(`/api/mj/jobs?status=1&page=${page}&page_size=${pageSize.value}`).then(res => {
 | 
			
		||||
    const jobs = res.data
 | 
			
		||||
@@ -862,9 +867,7 @@ const fetchFinishJobs = (page) => {
 | 
			
		||||
    } else {
 | 
			
		||||
      finishedJobs.value = finishedJobs.value.concat(jobs)
 | 
			
		||||
    }
 | 
			
		||||
    nextTick(() => loading.value = false)
 | 
			
		||||
  }).catch(e => {
 | 
			
		||||
    loading.value = false
 | 
			
		||||
    ElMessage.error("获取任务失败:" + e.message)
 | 
			
		||||
  })
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -315,7 +315,7 @@
 | 
			
		||||
                <el-empty :image-size="100" v-else/>
 | 
			
		||||
              </div>
 | 
			
		||||
              <h2>创作记录</h2>
 | 
			
		||||
              <div class="finish-job-list" v-loading="loading" element-loading-background="rgba(0, 0, 0, 0.5)">
 | 
			
		||||
              <div class="finish-job-list">
 | 
			
		||||
                <div v-if="finishedJobs.length > 0">
 | 
			
		||||
                  <ItemList :items="finishedJobs" :width="240" :gap="16">
 | 
			
		||||
                    <template #default="scope">
 | 
			
		||||
@@ -616,7 +616,10 @@ onMounted(() => {
 | 
			
		||||
 | 
			
		||||
onUnmounted(() => {
 | 
			
		||||
  clipboard.value.destroy()
 | 
			
		||||
  socket.value = null
 | 
			
		||||
  if (socket.value !== null) {
 | 
			
		||||
    socket.value.close()
 | 
			
		||||
    socket.value = null
 | 
			
		||||
  }
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -629,11 +632,14 @@ const initData = () => {
 | 
			
		||||
    fetchFinishJobs()
 | 
			
		||||
    connect()
 | 
			
		||||
  }).catch(() => {
 | 
			
		||||
    loading.value = false
 | 
			
		||||
  });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const fetchRunningJobs = () => {
 | 
			
		||||
  if (!isLogin.value) {
 | 
			
		||||
    return
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  // 获取运行中的任务
 | 
			
		||||
  httpGet(`/api/sd/jobs?status=0`).then(res => {
 | 
			
		||||
    const jobs = res.data
 | 
			
		||||
@@ -668,10 +674,11 @@ const handleScrollEnd = () => {
 | 
			
		||||
const page = ref(1)
 | 
			
		||||
const pageSize = ref(15)
 | 
			
		||||
const isOver = ref(false)
 | 
			
		||||
const loading = ref(false)
 | 
			
		||||
// 获取已完成的任务
 | 
			
		||||
const fetchFinishJobs = (page) => {
 | 
			
		||||
  loading.value = true
 | 
			
		||||
  if (!isLogin.value) {
 | 
			
		||||
    return
 | 
			
		||||
  }
 | 
			
		||||
  httpGet(`/api/sd/jobs?status=1&page=${page}&page_size=${pageSize.value}`).then(res => {
 | 
			
		||||
    if (res.data.length < pageSize.value) {
 | 
			
		||||
      isOver.value = true
 | 
			
		||||
@@ -681,9 +688,7 @@ const fetchFinishJobs = (page) => {
 | 
			
		||||
    } else {
 | 
			
		||||
      finishedJobs.value = finishedJobs.value.concat(res.data)
 | 
			
		||||
    }
 | 
			
		||||
    loading.value = false
 | 
			
		||||
  }).catch(e => {
 | 
			
		||||
    loading.value = false
 | 
			
		||||
    ElMessage.error("获取任务失败:" + e.message)
 | 
			
		||||
  })
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -5,9 +5,9 @@
 | 
			
		||||
        <h2>AI 绘画作品墙</h2>
 | 
			
		||||
        <div class="settings">
 | 
			
		||||
          <el-radio-group v-model="imgType" @change="changeImgType">
 | 
			
		||||
            <el-radio label="mj" size="large">MidJourney</el-radio>
 | 
			
		||||
            <el-radio label="sd" size="large">Stable Diffusion</el-radio>
 | 
			
		||||
            <el-radio label="dall" size="large">DALL-E</el-radio>
 | 
			
		||||
            <el-radio value="mj" size="large">MidJourney</el-radio>
 | 
			
		||||
            <el-radio value="sd" size="large">Stable Diffusion</el-radio>
 | 
			
		||||
            <el-radio value="dall" size="large">DALL-E</el-radio>
 | 
			
		||||
          </el-radio-group>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
@@ -72,7 +72,7 @@
 | 
			
		||||
          </template>
 | 
			
		||||
        </v3-waterfall>
 | 
			
		||||
 | 
			
		||||
        <v3-waterfall v-if="imgType === 'dall'"
 | 
			
		||||
        <v3-waterfall v-else-if="imgType === 'dall'"
 | 
			
		||||
                      id="waterfall"
 | 
			
		||||
                      :list="data['dall']"
 | 
			
		||||
                      srcKey="img_thumb"
 | 
			
		||||
@@ -338,7 +338,6 @@ const getNext = () => {
 | 
			
		||||
  loading.value = true
 | 
			
		||||
  page.value = page.value + 1
 | 
			
		||||
  let url = ""
 | 
			
		||||
  console.log(imgType.value)
 | 
			
		||||
  switch (imgType.value) {
 | 
			
		||||
    case "mj":
 | 
			
		||||
      url = "/api/mj/imgWall"
 | 
			
		||||
 
 | 
			
		||||
@@ -56,13 +56,13 @@
 | 
			
		||||
import {ref} from "vue";
 | 
			
		||||
import {Lock, UserFilled} from "@element-plus/icons-vue";
 | 
			
		||||
import {httpGet, httpPost} from "@/utils/http";
 | 
			
		||||
import {ElMessage} from "element-plus";
 | 
			
		||||
import {useRouter} from "vue-router";
 | 
			
		||||
import FooterBar from "@/components/FooterBar.vue";
 | 
			
		||||
import {isMobile} from "@/utils/libs";
 | 
			
		||||
import {checkSession} from "@/action/session";
 | 
			
		||||
import {setUserToken} from "@/store/session";
 | 
			
		||||
import ResetPass from "@/components/ResetPass.vue";
 | 
			
		||||
import {showMessageError} from "@/utils/dialog";
 | 
			
		||||
 | 
			
		||||
const router = useRouter();
 | 
			
		||||
const title = ref('Geek-AI');
 | 
			
		||||
@@ -76,7 +76,7 @@ httpGet("/api/config/get?key=system").then(res => {
 | 
			
		||||
  logo.value = res.data.logo
 | 
			
		||||
  title.value = res.data.title
 | 
			
		||||
}).catch(e => {
 | 
			
		||||
  ElMessage.error("获取系统配置失败:" + e.message)
 | 
			
		||||
  showMessageError("获取系统配置失败:" + e.message)
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -97,10 +97,10 @@ const handleKeyup = (e) => {
 | 
			
		||||
 | 
			
		||||
const login = function () {
 | 
			
		||||
  if (username.value.trim() === '') {
 | 
			
		||||
    return ElMessage.error("请输入用户民")
 | 
			
		||||
    return showMessageError("请输入用户民")
 | 
			
		||||
  }
 | 
			
		||||
  if (password.value.trim() === '') {
 | 
			
		||||
    return ElMessage.error('请输入密码');
 | 
			
		||||
    return showMessageError('请输入密码');
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  httpPost('/api/user/login', {username: username.value.trim(), password: password.value.trim()}).then((res) => {
 | 
			
		||||
@@ -112,11 +112,10 @@ const login = function () {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  }).catch((e) => {
 | 
			
		||||
    ElMessage.error('登录失败,' + e.message)
 | 
			
		||||
    showMessageError('登录失败,' + e.message)
 | 
			
		||||
  })
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="stylus" scoped>
 | 
			
		||||
 
 | 
			
		||||
@@ -264,9 +264,10 @@ const connect = (userId) => {
 | 
			
		||||
 | 
			
		||||
  _socket.addEventListener('close', () => {
 | 
			
		||||
    loading.value = false
 | 
			
		||||
    if (socket.value !== null) {
 | 
			
		||||
    checkSession().then(() => {
 | 
			
		||||
      connect(userId)
 | 
			
		||||
    }
 | 
			
		||||
    }).catch(() => {
 | 
			
		||||
    })
 | 
			
		||||
  });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -180,6 +180,7 @@ import SendMsg from "@/components/SendMsg.vue";
 | 
			
		||||
import {arrayContains} from "@/utils/libs";
 | 
			
		||||
import {setUserToken} from "@/store/session";
 | 
			
		||||
import {validateEmail, validateMobile} from "@/utils/validate";
 | 
			
		||||
import {showMessageError, showMessageOK} from "@/utils/dialog";
 | 
			
		||||
 | 
			
		||||
const router = useRouter();
 | 
			
		||||
const title = ref('Geek-AI 用户注册');
 | 
			
		||||
@@ -227,37 +228,37 @@ httpGet("/api/config/get?key=system").then(res => {
 | 
			
		||||
// 注册操作
 | 
			
		||||
const submitRegister = () => {
 | 
			
		||||
  if (data.value.username === '') {
 | 
			
		||||
    return ElMessage.error('请输入用户名');
 | 
			
		||||
    return showMessageError('请输入用户名');
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (activeName.value === 'mobile' && !validateMobile(data.value.username)) {
 | 
			
		||||
    return ElMessage.error('请输入合法的手机号');
 | 
			
		||||
    return showMessageError('请输入合法的手机号');
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (activeName.value === 'email' && !validateEmail(data.value.username)) {
 | 
			
		||||
    return ElMessage.error('请输入合法的邮箱地址');
 | 
			
		||||
    return showMessageError('请输入合法的邮箱地址');
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (data.value.password.length < 8) {
 | 
			
		||||
    return ElMessage.error('密码的长度为8-16个字符');
 | 
			
		||||
    return showMessageError('密码的长度为8-16个字符');
 | 
			
		||||
  }
 | 
			
		||||
  if (data.value.repass !== data.value.password) {
 | 
			
		||||
    return ElMessage.error('两次输入密码不一致');
 | 
			
		||||
    return showMessageError('两次输入密码不一致');
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if ((activeName.value === 'mobile' || activeName.value === 'email') && data.value.code === '') {
 | 
			
		||||
    return ElMessage.error('请输入验证码');
 | 
			
		||||
    return showMessageError('请输入验证码');
 | 
			
		||||
  }
 | 
			
		||||
  data.value.reg_way = activeName.value
 | 
			
		||||
  httpPost('/api/user/register', data.value).then((res) => {
 | 
			
		||||
    setUserToken(res.data)
 | 
			
		||||
    ElMessage.success({
 | 
			
		||||
    showMessageOK({
 | 
			
		||||
      "message": "注册成功,即将跳转到对话主界面...",
 | 
			
		||||
      onClose: () => router.push("/chat"),
 | 
			
		||||
      duration: 1000
 | 
			
		||||
    })
 | 
			
		||||
  }).catch((e) => {
 | 
			
		||||
    ElMessage.error('注册失败,' + e.message)
 | 
			
		||||
    showMessageError('注册失败,' + e.message)
 | 
			
		||||
  })
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -134,6 +134,7 @@ import ChatReply from "@/components/mobile/ChatReply.vue";
 | 
			
		||||
import {getSessionId, getUserToken} from "@/store/session";
 | 
			
		||||
import {checkSession} from "@/action/session";
 | 
			
		||||
import Clipboard from "clipboard";
 | 
			
		||||
import {showLoginDialog} from "@/utils/dialog";
 | 
			
		||||
 | 
			
		||||
const winHeight = ref(0)
 | 
			
		||||
const navBarRef = ref(null)
 | 
			
		||||
@@ -178,6 +179,7 @@ httpGet('/api/model/list').then(res => {
 | 
			
		||||
  }
 | 
			
		||||
  for (let i = 0; i < models.value.length; i++) {
 | 
			
		||||
    models.value[i].text = models.value[i].name
 | 
			
		||||
    models.value[i].mValue = models.value[i].value
 | 
			
		||||
    models.value[i].value = models.value[i].id
 | 
			
		||||
  }
 | 
			
		||||
  modelValue.value = getModelValue(modelId.value)
 | 
			
		||||
@@ -223,7 +225,10 @@ onMounted(() => {
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
onUnmounted(() => {
 | 
			
		||||
  socket.value = null
 | 
			
		||||
  if (socket.value !== null) {
 | 
			
		||||
    socket.value.close()
 | 
			
		||||
    socket.value = null
 | 
			
		||||
  }
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
const newChat = (item) => {
 | 
			
		||||
@@ -275,35 +280,38 @@ md.use(mathjaxPlugin)
 | 
			
		||||
 | 
			
		||||
const onLoad = () => {
 | 
			
		||||
  if (chatId.value) {
 | 
			
		||||
    httpGet('/api/chat/history?chat_id=' + chatId.value).then(res => {
 | 
			
		||||
      // 加载状态结束
 | 
			
		||||
      finished.value = true;
 | 
			
		||||
      const data = res.data
 | 
			
		||||
      if (data && data.length > 0) {
 | 
			
		||||
        for (let i = 0; i < data.length; i++) {
 | 
			
		||||
          if (data[i].type === "prompt") {
 | 
			
		||||
    checkSession().then(() => {
 | 
			
		||||
      httpGet('/api/chat/history?chat_id=' + chatId.value).then(res => {
 | 
			
		||||
        // 加载状态结束
 | 
			
		||||
        finished.value = true;
 | 
			
		||||
        const data = res.data
 | 
			
		||||
        if (data && data.length > 0) {
 | 
			
		||||
          for (let i = 0; i < data.length; i++) {
 | 
			
		||||
            if (data[i].type === "prompt") {
 | 
			
		||||
              chatData.value.push(data[i]);
 | 
			
		||||
              continue;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            data[i].orgContent = data[i].content;
 | 
			
		||||
            data[i].content = md.render(processContent(data[i].content))
 | 
			
		||||
            chatData.value.push(data[i]);
 | 
			
		||||
            continue;
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          data[i].orgContent = data[i].content;
 | 
			
		||||
          data[i].content = md.render(processContent(data[i].content))
 | 
			
		||||
          chatData.value.push(data[i]);
 | 
			
		||||
        }
 | 
			
		||||
          nextTick(() => {
 | 
			
		||||
            hl.configure({ignoreUnescapedHTML: true})
 | 
			
		||||
            const blocks = document.querySelector("#message-list-box").querySelectorAll('pre code');
 | 
			
		||||
            blocks.forEach((block) => {
 | 
			
		||||
              hl.highlightElement(block)
 | 
			
		||||
            })
 | 
			
		||||
 | 
			
		||||
        nextTick(() => {
 | 
			
		||||
          hl.configure({ignoreUnescapedHTML: true})
 | 
			
		||||
          const blocks = document.querySelector("#message-list-box").querySelectorAll('pre code');
 | 
			
		||||
          blocks.forEach((block) => {
 | 
			
		||||
            hl.highlightElement(block)
 | 
			
		||||
            scrollListBox()
 | 
			
		||||
          })
 | 
			
		||||
 | 
			
		||||
          scrollListBox()
 | 
			
		||||
        })
 | 
			
		||||
      }
 | 
			
		||||
      connect(chatId.value, roleId.value, modelId.value);
 | 
			
		||||
        }
 | 
			
		||||
        connect(chatId.value, roleId.value, modelId.value);
 | 
			
		||||
      }).catch(() => {
 | 
			
		||||
        error.value = true
 | 
			
		||||
      })
 | 
			
		||||
    }).catch(() => {
 | 
			
		||||
      error.value = true
 | 
			
		||||
    })
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
@@ -443,8 +451,7 @@ const connect = function (chat_id, role_id, model_id) {
 | 
			
		||||
    checkSession().then(() => {
 | 
			
		||||
      connect(chat_id, role_id, model_id)
 | 
			
		||||
    }).catch(() => {
 | 
			
		||||
      loading.value = true
 | 
			
		||||
      setTimeout(() => connect(chat_id, role_id, model_id), 3000)
 | 
			
		||||
      showLoginDialog(router)
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
@@ -549,7 +556,7 @@ const getRoleById = function (rid) {
 | 
			
		||||
const getModelValue = (model_id) => {
 | 
			
		||||
  for (let i = 0; i < models.value.length; i++) {
 | 
			
		||||
    if (models.value[i].id === model_id) {
 | 
			
		||||
      return models.value[i].value
 | 
			
		||||
      return models.value[i].mValue
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  return ""
 | 
			
		||||
 
 | 
			
		||||
@@ -57,16 +57,6 @@ bus.on('changeTheme', (value) => {
 | 
			
		||||
  background #1c1c1e
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.van-toast--fail {
 | 
			
		||||
  background #fef0f0
 | 
			
		||||
  color #f56c6c
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.van-toast--success {
 | 
			
		||||
  background #D6FBCC
 | 
			
		||||
  color #07C160
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.van-nav-bar {
 | 
			
		||||
  position fixed
 | 
			
		||||
  width 100%
 | 
			
		||||
 
 | 
			
		||||
@@ -1,13 +1,13 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="mobile-image container">
 | 
			
		||||
    <van-tabs v-model:active="activeName" class="my-tab" animated sticky>
 | 
			
		||||
      <van-tab title="MidJourney" name="mj">
 | 
			
		||||
      <van-tab title="MJ" name="mj">
 | 
			
		||||
        <image-mj/>
 | 
			
		||||
      </van-tab>
 | 
			
		||||
      <van-tab title="Stable-Diffusion" name="sd">
 | 
			
		||||
      <van-tab title="SD" name="sd">
 | 
			
		||||
        <image-sd/>
 | 
			
		||||
      </van-tab>
 | 
			
		||||
      <van-tab title="DALL-E" name="dall">
 | 
			
		||||
      <van-tab title="DALL" name="dall">
 | 
			
		||||
        <van-empty description="功能正在开发中"/>
 | 
			
		||||
      </van-tab>
 | 
			
		||||
    </van-tabs>
 | 
			
		||||
 
 | 
			
		||||
@@ -95,6 +95,7 @@ onMounted(() => {
 | 
			
		||||
  checkSession().then((user) => {
 | 
			
		||||
    isLogin.value = true
 | 
			
		||||
    roles.value = user.chat_roles
 | 
			
		||||
  }).catch(() => {
 | 
			
		||||
  })
 | 
			
		||||
  fetchApps()
 | 
			
		||||
})
 | 
			
		||||
 
 | 
			
		||||
@@ -276,14 +276,7 @@
 | 
			
		||||
 | 
			
		||||
<script setup>
 | 
			
		||||
import {nextTick, onMounted, onUnmounted, ref} from "vue";
 | 
			
		||||
import {
 | 
			
		||||
  showConfirmDialog,
 | 
			
		||||
  showFailToast,
 | 
			
		||||
  showNotify,
 | 
			
		||||
  showToast,
 | 
			
		||||
  showImagePreview,
 | 
			
		||||
  showSuccessToast
 | 
			
		||||
} from "vant";
 | 
			
		||||
import {showConfirmDialog, showFailToast, showImagePreview, showNotify, showSuccessToast, showToast} from "vant";
 | 
			
		||||
import {httpGet, httpPost} from "@/utils/http";
 | 
			
		||||
import Compressor from "compressorjs";
 | 
			
		||||
import {getSessionId} from "@/store/session";
 | 
			
		||||
@@ -364,8 +357,11 @@ onMounted(() => {
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
onUnmounted(() => {
 | 
			
		||||
  socket.value = null
 | 
			
		||||
  clipboard.value.destroy()
 | 
			
		||||
  if (socket.value !== null) {
 | 
			
		||||
    socket.value.close()
 | 
			
		||||
    socket.value = null
 | 
			
		||||
  }
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
const mjPower = ref(1)
 | 
			
		||||
 
 | 
			
		||||
@@ -221,7 +221,8 @@ import {checkSession} from "@/action/session";
 | 
			
		||||
import {useRouter} from "vue-router";
 | 
			
		||||
import {getSessionId} from "@/store/session";
 | 
			
		||||
import {
 | 
			
		||||
  showConfirmDialog, showDialog,
 | 
			
		||||
  showConfirmDialog,
 | 
			
		||||
  showDialog,
 | 
			
		||||
  showFailToast,
 | 
			
		||||
  showImagePreview,
 | 
			
		||||
  showNotify,
 | 
			
		||||
@@ -357,7 +358,10 @@ onMounted(() => {
 | 
			
		||||
 | 
			
		||||
onUnmounted(() => {
 | 
			
		||||
  clipboard.value.destroy()
 | 
			
		||||
  socket.value = null
 | 
			
		||||
  if (socket.value !== null) {
 | 
			
		||||
    socket.value.close()
 | 
			
		||||
    socket.value = null
 | 
			
		||||
  }
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -2,7 +2,7 @@
 | 
			
		||||
  <div class="img-wall container">
 | 
			
		||||
    <div class="content">
 | 
			
		||||
      <van-tabs v-model:active="activeName" animated sticky>
 | 
			
		||||
        <van-tab title="MidJourney" name="mj">
 | 
			
		||||
        <van-tab title="MJ" name="mj">
 | 
			
		||||
          <van-list
 | 
			
		||||
              v-model:error="data['mj'].error"
 | 
			
		||||
              v-model:loading="data['mj'].loading"
 | 
			
		||||
@@ -23,7 +23,7 @@
 | 
			
		||||
            </van-cell>
 | 
			
		||||
          </van-list>
 | 
			
		||||
        </van-tab>
 | 
			
		||||
        <van-tab title="StableDiffusion" name="sd">
 | 
			
		||||
        <van-tab title="SD" name="sd">
 | 
			
		||||
          <van-list
 | 
			
		||||
              v-model:error="data['sd'].error"
 | 
			
		||||
              v-model:loading="data['sd'].loading"
 | 
			
		||||
@@ -43,7 +43,7 @@
 | 
			
		||||
            </van-cell>
 | 
			
		||||
          </van-list>
 | 
			
		||||
        </van-tab>
 | 
			
		||||
        <van-tab title="DALLE3" name="dalle3">
 | 
			
		||||
        <van-tab title="DALL" name="dalle3">
 | 
			
		||||
          <van-empty description="功能正在开发中"/>
 | 
			
		||||
        </van-tab>
 | 
			
		||||
      </van-tabs>
 | 
			
		||||
@@ -57,8 +57,7 @@
 | 
			
		||||
<script setup>
 | 
			
		||||
import {onMounted, onUnmounted, ref} from "vue";
 | 
			
		||||
import {httpGet} from "@/utils/http";
 | 
			
		||||
import {showConfirmDialog, showDialog, showFailToast, showImagePreview, showNotify} from "vant";
 | 
			
		||||
import {Delete} from "@element-plus/icons-vue";
 | 
			
		||||
import {showConfirmDialog, showFailToast, showImagePreview, showNotify} from "vant";
 | 
			
		||||
import Clipboard from "clipboard";
 | 
			
		||||
import {ElMessage} from "element-plus";
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user