mirror of
				https://github.com/yangjian102621/geekai.git
				synced 2025-11-04 16:23:42 +08:00 
			
		
		
		
	feat: implements image function replace Mj with DALL-E-3
This commit is contained in:
		@@ -148,6 +148,7 @@ func authorizeMiddleware(s *AppServer, client *redis.Client) gin.HandlerFunc {
 | 
				
			|||||||
			c.Request.URL.Path == "/api/chat/detail" ||
 | 
								c.Request.URL.Path == "/api/chat/detail" ||
 | 
				
			||||||
			c.Request.URL.Path == "/api/role/list" ||
 | 
								c.Request.URL.Path == "/api/role/list" ||
 | 
				
			||||||
			c.Request.URL.Path == "/api/mj/jobs" ||
 | 
								c.Request.URL.Path == "/api/mj/jobs" ||
 | 
				
			||||||
 | 
								c.Request.URL.Path == "/api/invite/hits" ||
 | 
				
			||||||
			c.Request.URL.Path == "/api/sd/jobs" ||
 | 
								c.Request.URL.Path == "/api/sd/jobs" ||
 | 
				
			||||||
			strings.HasPrefix(c.Request.URL.Path, "/api/sms/") ||
 | 
								strings.HasPrefix(c.Request.URL.Path, "/api/sms/") ||
 | 
				
			||||||
			strings.HasPrefix(c.Request.URL.Path, "/api/captcha/") ||
 | 
								strings.HasPrefix(c.Request.URL.Path, "/api/captcha/") ||
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -145,7 +145,6 @@ type SystemConfig struct {
 | 
				
			|||||||
	VipMonthCalls    int      `json:"vip_month_calls"`     // 会员每个赠送的调用次数
 | 
						VipMonthCalls    int      `json:"vip_month_calls"`     // 会员每个赠送的调用次数
 | 
				
			||||||
	EnabledRegister  bool     `json:"enabled_register"`    // 是否启用注册功能,关闭注册功能之后将无法注册
 | 
						EnabledRegister  bool     `json:"enabled_register"`    // 是否启用注册功能,关闭注册功能之后将无法注册
 | 
				
			||||||
	EnabledMsg       bool     `json:"enabled_msg"`         // 是否启用短信验证码服务
 | 
						EnabledMsg       bool     `json:"enabled_msg"`         // 是否启用短信验证码服务
 | 
				
			||||||
	EnabledDraw      bool     `json:"enabled_draw"`        // 是否启用 AI 绘画功能
 | 
					 | 
				
			||||||
	RewardImg        string   `json:"reward_img"`          // 众筹收款二维码地址
 | 
						RewardImg        string   `json:"reward_img"`          // 众筹收款二维码地址
 | 
				
			||||||
	EnabledFunction  bool     `json:"enabled_function"`    // 启用 API 函数功能
 | 
						EnabledFunction  bool     `json:"enabled_function"`    // 启用 API 函数功能
 | 
				
			||||||
	EnabledReward    bool     `json:"enabled_reward"`      // 启用众筹功能
 | 
						EnabledReward    bool     `json:"enabled_reward"`      // 启用众筹功能
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -23,10 +23,10 @@ type Property struct {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const (
 | 
					const (
 | 
				
			||||||
	FuncZaoBao     = "zao_bao"     // 每日早报
 | 
						FuncZaoBao   = "zao_bao"    // 每日早报
 | 
				
			||||||
	FuncHeadLine   = "headline"    // 今日头条
 | 
						FuncHeadLine = "headline"   // 今日头条
 | 
				
			||||||
	FuncWeibo      = "weibo_hot"   // 微博热搜
 | 
						FuncWeibo    = "weibo_hot"  // 微博热搜
 | 
				
			||||||
	FuncMidJourney = "mid_journey" // MJ 绘画
 | 
						FuncImage    = "draw_image" // AI 绘画
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var InnerFunctions = []Function{
 | 
					var InnerFunctions = []Function{
 | 
				
			||||||
@@ -76,14 +76,14 @@ var InnerFunctions = []Function{
 | 
				
			|||||||
	},
 | 
						},
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		Name:        FuncMidJourney,
 | 
							Name:        FuncImage,
 | 
				
			||||||
		Description: "AI 绘画工具,使用 MJ MidJourney API 进行 AI 绘画",
 | 
							Description: "AI 绘画工具,根据输入的绘图描述用 AI 工具进行绘画",
 | 
				
			||||||
		Parameters: Parameters{
 | 
							Parameters: Parameters{
 | 
				
			||||||
			Type: "object",
 | 
								Type: "object",
 | 
				
			||||||
			Properties: map[string]Property{
 | 
								Properties: map[string]Property{
 | 
				
			||||||
				"prompt": {
 | 
									"prompt": {
 | 
				
			||||||
					Type:        "string",
 | 
										Type:        "string",
 | 
				
			||||||
					Description: "提示词,如果该参数中有中文的话,则需要翻译成英文。提示词中的参数作为提示的一部分,不要删除",
 | 
										Description: "提示词,如果该参数中有中文的话,则需要翻译成英文。",
 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			Required: []string{},
 | 
								Required: []string{},
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -27,6 +27,7 @@ func (h *ApiKeyHandler) Save(c *gin.Context) {
 | 
				
			|||||||
	var data struct {
 | 
						var data struct {
 | 
				
			||||||
		Id       uint   `json:"id"`
 | 
							Id       uint   `json:"id"`
 | 
				
			||||||
		Platform string `json:"platform"`
 | 
							Platform string `json:"platform"`
 | 
				
			||||||
 | 
							Type     string `json:"type"`
 | 
				
			||||||
		Value    string `json:"value"`
 | 
							Value    string `json:"value"`
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if err := c.ShouldBindJSON(&data); err != nil {
 | 
						if err := c.ShouldBindJSON(&data); err != nil {
 | 
				
			||||||
@@ -40,7 +41,8 @@ func (h *ApiKeyHandler) Save(c *gin.Context) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
	apiKey.Platform = data.Platform
 | 
						apiKey.Platform = data.Platform
 | 
				
			||||||
	apiKey.Value = data.Value
 | 
						apiKey.Value = data.Value
 | 
				
			||||||
	res := h.db.Debug().Save(&apiKey)
 | 
						apiKey.Type = data.Type
 | 
				
			||||||
 | 
						res := h.db.Save(&apiKey)
 | 
				
			||||||
	if res.Error != nil {
 | 
						if res.Error != nil {
 | 
				
			||||||
		resp.ERROR(c, "更新数据库失败!")
 | 
							resp.ERROR(c, "更新数据库失败!")
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -127,12 +127,12 @@ func (h *ChatHandler) sendAzureMessage(
 | 
				
			|||||||
			logger.Debugf("函数名称: %s, 函数参数:%s", functionName, params)
 | 
								logger.Debugf("函数名称: %s, 函数参数:%s", functionName, params)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			// for creating image, check if the user's img_calls > 0
 | 
								// for creating image, check if the user's img_calls > 0
 | 
				
			||||||
			if functionName == types.FuncMidJourney && userVo.ImgCalls <= 0 {
 | 
								if functionName == types.FuncImage && userVo.ImgCalls <= 0 {
 | 
				
			||||||
				utils.ReplyMessage(ws, "**当前用户剩余绘图次数已用尽,请扫描下面二维码联系管理员!**")
 | 
									utils.ReplyMessage(ws, "**当前用户剩余绘图次数已用尽,请扫描下面二维码联系管理员!**")
 | 
				
			||||||
				utils.ReplyMessage(ws, ErrImg)
 | 
									utils.ReplyMessage(ws, ErrImg)
 | 
				
			||||||
			} else {
 | 
								} else {
 | 
				
			||||||
				f := h.App.Functions[functionName]
 | 
									f := h.App.Functions[functionName]
 | 
				
			||||||
				if functionName == types.FuncMidJourney {
 | 
									if functionName == types.FuncImage {
 | 
				
			||||||
					params["user_id"] = userVo.Id
 | 
										params["user_id"] = userVo.Id
 | 
				
			||||||
					params["role_id"] = role.Id
 | 
										params["role_id"] = role.Id
 | 
				
			||||||
					params["chat_id"] = session.ChatId
 | 
										params["chat_id"] = session.ChatId
 | 
				
			||||||
@@ -149,9 +149,8 @@ func (h *ChatHandler) sendAzureMessage(
 | 
				
			|||||||
					contents = append(contents, msg)
 | 
										contents = append(contents, msg)
 | 
				
			||||||
				} else {
 | 
									} else {
 | 
				
			||||||
					content := data
 | 
										content := data
 | 
				
			||||||
					if functionName == types.FuncMidJourney {
 | 
										if functionName == types.FuncImage {
 | 
				
			||||||
						content = fmt.Sprintf("绘画提示词:%s 已推送任务到 MidJourney 机器人,请耐心等待任务执行...", data)
 | 
											content = fmt.Sprintf("下面是根据您的描述创作的图片,他们描绘了 【%s】 的场景", params["prompt"])
 | 
				
			||||||
						h.mjService.ChatClients.Put(session.SessionId, ws)
 | 
					 | 
				
			||||||
						// update user's img_calls
 | 
											// update user's img_calls
 | 
				
			||||||
						h.db.Model(&model.User{}).Where("id = ?", userVo.Id).UpdateColumn("img_calls", gorm.Expr("img_calls - ?", 1))
 | 
											h.db.Model(&model.User{}).Where("id = ?", userVo.Id).UpdateColumn("img_calls", gorm.Expr("img_calls - ?", 1))
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -224,9 +224,6 @@ func (h *ChatHandler) sendMessage(ctx context.Context, session *types.ChatSessio
 | 
				
			|||||||
		if h.App.SysConfig.EnabledFunction {
 | 
							if h.App.SysConfig.EnabledFunction {
 | 
				
			||||||
			var functions = make([]types.Function, 0)
 | 
								var functions = make([]types.Function, 0)
 | 
				
			||||||
			for _, f := range types.InnerFunctions {
 | 
								for _, f := range types.InnerFunctions {
 | 
				
			||||||
				if !h.App.SysConfig.EnabledDraw && f.Name == types.FuncMidJourney {
 | 
					 | 
				
			||||||
					continue
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
				functions = append(functions, f)
 | 
									functions = append(functions, f)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			req.Functions = functions
 | 
								req.Functions = functions
 | 
				
			||||||
@@ -405,7 +402,7 @@ func (h *ChatHandler) doRequest(ctx context.Context, req types.ApiRequest, platf
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
	if *apiKey == "" {
 | 
						if *apiKey == "" {
 | 
				
			||||||
		var key model.ApiKey
 | 
							var key model.ApiKey
 | 
				
			||||||
		res := h.db.Where("platform = ?", platform).Order("last_used_at ASC").First(&key)
 | 
							res := h.db.Where("platform = ? AND type = ?", platform, "chat").Order("last_used_at ASC").First(&key)
 | 
				
			||||||
		if res.Error != nil {
 | 
							if res.Error != nil {
 | 
				
			||||||
			return nil, errors.New("no available key, please import key")
 | 
								return nil, errors.New("no available key, please import key")
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -126,12 +126,12 @@ func (h *ChatHandler) sendOpenAiMessage(
 | 
				
			|||||||
			logger.Debugf("函数名称: %s, 函数参数:%s", functionName, params)
 | 
								logger.Debugf("函数名称: %s, 函数参数:%s", functionName, params)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			// for creating image, check if the user's img_calls > 0
 | 
								// for creating image, check if the user's img_calls > 0
 | 
				
			||||||
			if functionName == types.FuncMidJourney && userVo.ImgCalls <= 0 {
 | 
								if functionName == types.FuncImage && userVo.ImgCalls <= 0 {
 | 
				
			||||||
				utils.ReplyMessage(ws, "**当前用户剩余绘图次数已用尽,请扫描下面二维码联系管理员!**")
 | 
									utils.ReplyMessage(ws, "**当前用户剩余绘图次数已用尽,请扫描下面二维码联系管理员!**")
 | 
				
			||||||
				utils.ReplyMessage(ws, ErrImg)
 | 
									utils.ReplyMessage(ws, ErrImg)
 | 
				
			||||||
			} else {
 | 
								} else {
 | 
				
			||||||
				f := h.App.Functions[functionName]
 | 
									f := h.App.Functions[functionName]
 | 
				
			||||||
				if functionName == types.FuncMidJourney {
 | 
									if functionName == types.FuncImage {
 | 
				
			||||||
					params["user_id"] = userVo.Id
 | 
										params["user_id"] = userVo.Id
 | 
				
			||||||
					params["role_id"] = role.Id
 | 
										params["role_id"] = role.Id
 | 
				
			||||||
					params["chat_id"] = session.ChatId
 | 
										params["chat_id"] = session.ChatId
 | 
				
			||||||
@@ -148,9 +148,8 @@ func (h *ChatHandler) sendOpenAiMessage(
 | 
				
			|||||||
					contents = append(contents, msg)
 | 
										contents = append(contents, msg)
 | 
				
			||||||
				} else {
 | 
									} else {
 | 
				
			||||||
					content := data
 | 
										content := data
 | 
				
			||||||
					if functionName == types.FuncMidJourney {
 | 
										if functionName == types.FuncImage {
 | 
				
			||||||
						content = fmt.Sprintf("绘画提示词:%s 已推送任务到 MidJourney 机器人,请耐心等待任务执行...", data)
 | 
											content = fmt.Sprintf("下面是根据您的描述创作的图片,他们描绘了 【%s】 的场景。%s", params["prompt"], data)
 | 
				
			||||||
						h.mjService.ChatClients.Put(session.SessionId, ws)
 | 
					 | 
				
			||||||
						// update user's img_calls
 | 
											// update user's img_calls
 | 
				
			||||||
						h.db.Model(&model.User{}).Where("id = ?", userVo.Id).UpdateColumn("img_calls", gorm.Expr("img_calls - ?", 1))
 | 
											h.db.Model(&model.User{}).Where("id = ?", userVo.Id).UpdateColumn("img_calls", gorm.Expr("img_calls - ?", 1))
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -69,7 +69,7 @@ func (h *ChatHandler) sendXunFeiMessage(
 | 
				
			|||||||
	var apiKey = userVo.ChatConfig.ApiKeys[session.Model.Platform]
 | 
						var apiKey = userVo.ChatConfig.ApiKeys[session.Model.Platform]
 | 
				
			||||||
	if apiKey == "" {
 | 
						if apiKey == "" {
 | 
				
			||||||
		var key model.ApiKey
 | 
							var key model.ApiKey
 | 
				
			||||||
		res := h.db.Where("platform = ?", session.Model.Platform).Order("last_used_at ASC").First(&key)
 | 
							res := h.db.Where("platform = ? AND type = ?", session.Model.Platform, "chat").Order("last_used_at ASC").First(&key)
 | 
				
			||||||
		if res.Error != nil {
 | 
							if res.Error != nil {
 | 
				
			||||||
			utils.ReplyMessage(ws, "抱歉😔😔😔,系统已经没有可用的 API KEY,请联系管理员!")
 | 
								utils.ReplyMessage(ws, "抱歉😔😔😔,系统已经没有可用的 API KEY,请联系管理员!")
 | 
				
			||||||
			return nil
 | 
								return nil
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										92
									
								
								api/service/fun/func_img.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										92
									
								
								api/service/fun/func_img.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,92 @@
 | 
				
			|||||||
 | 
					package fun
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"chatplus/core/types"
 | 
				
			||||||
 | 
						"chatplus/service/oss"
 | 
				
			||||||
 | 
						"chatplus/store/model"
 | 
				
			||||||
 | 
						"chatplus/utils"
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
 | 
						"github.com/imroc/req/v3"
 | 
				
			||||||
 | 
						"gorm.io/gorm"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// AI 绘画函数
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type FuncImage struct {
 | 
				
			||||||
 | 
						name          string
 | 
				
			||||||
 | 
						apiURL        string
 | 
				
			||||||
 | 
						db            *gorm.DB
 | 
				
			||||||
 | 
						uploadManager *oss.UploaderManager
 | 
				
			||||||
 | 
						proxyURL      string
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func NewImageFunc(db *gorm.DB, manager *oss.UploaderManager, config *types.AppConfig) FuncImage {
 | 
				
			||||||
 | 
						return FuncImage{
 | 
				
			||||||
 | 
							db:            db,
 | 
				
			||||||
 | 
							name:          "DALL-E3 绘画",
 | 
				
			||||||
 | 
							uploadManager: manager,
 | 
				
			||||||
 | 
							proxyURL:      config.ProxyURL,
 | 
				
			||||||
 | 
							apiURL:        "https://api.openai.com/v1/images/generations",
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type imgReq struct {
 | 
				
			||||||
 | 
						Model  string `json:"model"`
 | 
				
			||||||
 | 
						Prompt string `json:"prompt"`
 | 
				
			||||||
 | 
						N      int    `json:"n"`
 | 
				
			||||||
 | 
						Size   string `json:"size"`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type imgRes struct {
 | 
				
			||||||
 | 
						Created int64 `json:"created"`
 | 
				
			||||||
 | 
						Data    []struct {
 | 
				
			||||||
 | 
							RevisedPrompt string `json:"revised_prompt"`
 | 
				
			||||||
 | 
							Url           string `json:"url"`
 | 
				
			||||||
 | 
						} `json:"data"`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type ErrRes struct {
 | 
				
			||||||
 | 
						Error struct {
 | 
				
			||||||
 | 
							Code    interface{} `json:"code"`
 | 
				
			||||||
 | 
							Message string      `json:"message"`
 | 
				
			||||||
 | 
							Param   interface{} `json:"param"`
 | 
				
			||||||
 | 
							Type    string      `json:"type"`
 | 
				
			||||||
 | 
						} `json:"error"`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (f FuncImage) Invoke(params map[string]interface{}) (string, error) {
 | 
				
			||||||
 | 
						logger.Infof("绘画参数:%+v", params)
 | 
				
			||||||
 | 
						prompt := utils.InterfaceToString(params["prompt"])
 | 
				
			||||||
 | 
						// 获取绘图 API KEY
 | 
				
			||||||
 | 
						var apiKey model.ApiKey
 | 
				
			||||||
 | 
						f.db.Where("platform = ? AND type = ?", types.OpenAI, "img").Order("last_used_at ASC").First(&apiKey)
 | 
				
			||||||
 | 
						var res imgRes
 | 
				
			||||||
 | 
						var errRes ErrRes
 | 
				
			||||||
 | 
						r, err := req.C().SetProxyURL(f.proxyURL).R().SetHeader("Content-Type", "application/json").
 | 
				
			||||||
 | 
							SetHeader("Authorization", "Bearer "+apiKey.Value).
 | 
				
			||||||
 | 
							SetBody(imgReq{
 | 
				
			||||||
 | 
								Model:  "dall-e-3",
 | 
				
			||||||
 | 
								Prompt: prompt,
 | 
				
			||||||
 | 
								N:      1,
 | 
				
			||||||
 | 
								Size:   "1024x1024",
 | 
				
			||||||
 | 
							}).
 | 
				
			||||||
 | 
							SetErrorResult(&errRes).
 | 
				
			||||||
 | 
							SetSuccessResult(&res).Post(f.apiURL)
 | 
				
			||||||
 | 
						if err != nil || r.IsErrorState() {
 | 
				
			||||||
 | 
							return "", fmt.Errorf("error with http request: %v%v%s", err, r.Err, errRes.Error.Message)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						// 存储图片
 | 
				
			||||||
 | 
						imgURL, err := f.uploadManager.GetUploadHandler().PutImg(res.Data[0].Url, false)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return "", fmt.Errorf("下载图片失败: %s", err.Error())
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						logger.Info(imgURL)
 | 
				
			||||||
 | 
						return fmt.Sprintf("\n\n\n", imgURL), nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (f FuncImage) Name() string {
 | 
				
			||||||
 | 
						return f.name
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var _ Function = &FuncImage{}
 | 
				
			||||||
@@ -1,49 +0,0 @@
 | 
				
			|||||||
package fun
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import (
 | 
					 | 
				
			||||||
	"chatplus/core/types"
 | 
					 | 
				
			||||||
	"chatplus/service/mj"
 | 
					 | 
				
			||||||
	"chatplus/utils"
 | 
					 | 
				
			||||||
	"errors"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// AI 绘画函数
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type FuncMidJourney struct {
 | 
					 | 
				
			||||||
	name    string
 | 
					 | 
				
			||||||
	service *mj.Service
 | 
					 | 
				
			||||||
	config  types.MidJourneyConfig
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func NewMidJourneyFunc(mjService *mj.Service, config types.MidJourneyConfig) FuncMidJourney {
 | 
					 | 
				
			||||||
	return FuncMidJourney{
 | 
					 | 
				
			||||||
		name:    "MidJourney AI 绘画",
 | 
					 | 
				
			||||||
		config:  config,
 | 
					 | 
				
			||||||
		service: mjService}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (f FuncMidJourney) Invoke(params map[string]interface{}) (string, error) {
 | 
					 | 
				
			||||||
	if !f.config.Enabled {
 | 
					 | 
				
			||||||
		return "", errors.New("MidJourney AI 绘画功能没有启用")
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	logger.Infof("MJ 绘画参数:%+v", params)
 | 
					 | 
				
			||||||
	prompt := utils.InterfaceToString(params["prompt"])
 | 
					 | 
				
			||||||
	f.service.PushTask(types.MjTask{
 | 
					 | 
				
			||||||
		SessionId: utils.InterfaceToString(params["session_id"]),
 | 
					 | 
				
			||||||
		Src:       types.TaskSrcChat,
 | 
					 | 
				
			||||||
		Type:      types.TaskImage,
 | 
					 | 
				
			||||||
		Prompt:    prompt,
 | 
					 | 
				
			||||||
		UserId:    utils.IntValue(utils.InterfaceToString(params["user_id"]), 0),
 | 
					 | 
				
			||||||
		RoleId:    utils.IntValue(utils.InterfaceToString(params["role_id"]), 0),
 | 
					 | 
				
			||||||
		Icon:      utils.InterfaceToString(params["icon"]),
 | 
					 | 
				
			||||||
		ChatId:    utils.InterfaceToString(params["chat_id"]),
 | 
					 | 
				
			||||||
	})
 | 
					 | 
				
			||||||
	return prompt, nil
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (f FuncMidJourney) Name() string {
 | 
					 | 
				
			||||||
	return f.name
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
var _ Function = &FuncMidJourney{}
 | 
					 | 
				
			||||||
@@ -3,7 +3,8 @@ package fun
 | 
				
			|||||||
import (
 | 
					import (
 | 
				
			||||||
	"chatplus/core/types"
 | 
						"chatplus/core/types"
 | 
				
			||||||
	logger2 "chatplus/logger"
 | 
						logger2 "chatplus/logger"
 | 
				
			||||||
	"chatplus/service/mj"
 | 
						"chatplus/service/oss"
 | 
				
			||||||
 | 
						"gorm.io/gorm"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Function interface {
 | 
					type Function interface {
 | 
				
			||||||
@@ -29,11 +30,11 @@ type dataItem struct {
 | 
				
			|||||||
	Remark string `json:"remark"`
 | 
						Remark string `json:"remark"`
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func NewFunctions(config *types.AppConfig, mjService *mj.Service) map[string]Function {
 | 
					func NewFunctions(config *types.AppConfig, db *gorm.DB, manager *oss.UploaderManager) map[string]Function {
 | 
				
			||||||
	return map[string]Function{
 | 
						return map[string]Function{
 | 
				
			||||||
		types.FuncZaoBao:     NewZaoBao(config.ApiConfig),
 | 
							types.FuncZaoBao:   NewZaoBao(config.ApiConfig),
 | 
				
			||||||
		types.FuncWeibo:      NewWeiboHot(config.ApiConfig),
 | 
							types.FuncWeibo:    NewWeiboHot(config.ApiConfig),
 | 
				
			||||||
		types.FuncHeadLine:   NewHeadLines(config.ApiConfig),
 | 
							types.FuncHeadLine: NewHeadLines(config.ApiConfig),
 | 
				
			||||||
		types.FuncMidJourney: NewMidJourneyFunc(mjService, config.MjConfig),
 | 
							types.FuncImage:    NewImageFunc(db, manager, config),
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,13 +1,23 @@
 | 
				
			|||||||
package main
 | 
					package main
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
 | 
						"chatplus/utils"
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"reflect"
 | 
						"os"
 | 
				
			||||||
	"time"
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func main() {
 | 
					func main() {
 | 
				
			||||||
	r := time.Now()
 | 
						imgURL := "https://oaidalleapiprodscus.blob.core.windows.net/private/org-UJimNEKhVm07E58nxnjx5FeG/user-e5UAcPVbkm2nwD8urggRRM8q/img-zFXWyrJ9Z1HppI36dZMXNEaA.png?st=2023-11-26T09%3A57%3A49Z&se=2023-11-26T11%3A57%3A49Z&sp=r&sv=2021-08-06&sr=b&rscd=inline&rsct=image/png&skoid=6aaadede-4fb3-4698-a8f6-684d7786b067&sktid=a48cca56-e6da-484e-a814-9c849652bcb3&skt=2023-11-26T08%3A14%3A59Z&ske=2023-11-27T08%3A14%3A59Z&sks=b&skv=2021-08-06&sig=VmlU9didavbl02XYim2XuMmLMFJsLtCY/ULnzCjeO1g%3D"
 | 
				
			||||||
	f := reflect.ValueOf(r)
 | 
						imageData, err := utils.DownloadImage(imgURL, "")
 | 
				
			||||||
	fmt.Println(f.Type().Kind())
 | 
						if err != nil {
 | 
				
			||||||
 | 
							panic(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						newImagePath := "newimage.png"
 | 
				
			||||||
 | 
						err = os.WriteFile(newImagePath, imageData, 0644)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							fmt.Println("Error writing image file:", err)
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						fmt.Println("图片保存成功!")
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,10 +2,7 @@
 | 
				
			|||||||
  <div class="home">
 | 
					  <div class="home">
 | 
				
			||||||
    <div class="navigator">
 | 
					    <div class="navigator">
 | 
				
			||||||
      <div class="logo">
 | 
					      <div class="logo">
 | 
				
			||||||
        <el-link href="/">
 | 
					        <el-image :src="logo"/>
 | 
				
			||||||
          <el-image :src="logo"/>
 | 
					 | 
				
			||||||
        </el-link>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        <div class="divider"></div>
 | 
					        <div class="divider"></div>
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -37,8 +34,6 @@
 | 
				
			|||||||
<script setup>
 | 
					<script setup>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import {useRouter} from "vue-router";
 | 
					import {useRouter} from "vue-router";
 | 
				
			||||||
import {checkSession} from "@/action/session";
 | 
					 | 
				
			||||||
import {isMobile} from "@/utils/libs";
 | 
					 | 
				
			||||||
import {ref} from "vue";
 | 
					import {ref} from "vue";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const router = useRouter();
 | 
					const router = useRouter();
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,85 +1,88 @@
 | 
				
			|||||||
<template>
 | 
					<template>
 | 
				
			||||||
  <div class="page-invitation">
 | 
					  <div class="custom-scroll">
 | 
				
			||||||
    <div class="inner">
 | 
					    <div class="page-invitation" :style="{height: listBoxHeight + 'px'}">
 | 
				
			||||||
      <h2>会员推广计划</h2>
 | 
					      <div class="inner">
 | 
				
			||||||
      <div class="share-box">
 | 
					        <h2>会员推广计划</h2>
 | 
				
			||||||
        <div class="info">
 | 
					        <div class="share-box">
 | 
				
			||||||
          我们非常欢迎您把此应用分享给您身边的朋友,分享成功注册后您将获得 <strong>{{ inviteChatCalls }}</strong> 次对话额度以及
 | 
					          <div class="info">
 | 
				
			||||||
          <strong>{{ inviteImgCalls }}</strong> 次AI绘画额度作为奖励。
 | 
					            我们非常欢迎您把此应用分享给您身边的朋友,分享成功注册后您将获得 <strong>{{ inviteChatCalls }}</strong>
 | 
				
			||||||
          你可以保存下面的二维码或者直接复制分享您的专属推广链接发送给微信好友。
 | 
					            次对话额度以及
 | 
				
			||||||
 | 
					            <strong>{{ inviteImgCalls }}</strong> 次AI绘画额度作为奖励。
 | 
				
			||||||
 | 
					            你可以保存下面的二维码或者直接复制分享您的专属推广链接发送给微信好友。
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          <div class="invite-qrcode">
 | 
				
			||||||
 | 
					            <el-image :src="qrImg"/>
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          <div class="invite-url">
 | 
				
			||||||
 | 
					            <span>{{ inviteURL }}</span>
 | 
				
			||||||
 | 
					            <el-button type="primary" plain class="copy-link" :data-clipboard-text="inviteURL">复制链接</el-button>
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <div class="invite-qrcode">
 | 
					        <div class="invite-stats">
 | 
				
			||||||
          <el-image :src="qrImg"/>
 | 
					          <el-row :gutter="20">
 | 
				
			||||||
 | 
					            <el-col :span="8">
 | 
				
			||||||
 | 
					              <div class="item-box yellow">
 | 
				
			||||||
 | 
					                <el-row :gutter="10">
 | 
				
			||||||
 | 
					                  <el-col :span="10">
 | 
				
			||||||
 | 
					                    <div class="item-icon">
 | 
				
			||||||
 | 
					                      <i class="iconfont icon-role"></i>
 | 
				
			||||||
 | 
					                    </div>
 | 
				
			||||||
 | 
					                  </el-col>
 | 
				
			||||||
 | 
					                  <el-col :span="14">
 | 
				
			||||||
 | 
					                    <div class="item-info">
 | 
				
			||||||
 | 
					                      <div class="num">{{ hits }}</div>
 | 
				
			||||||
 | 
					                      <div class="text">点击量</div>
 | 
				
			||||||
 | 
					                    </div>
 | 
				
			||||||
 | 
					                  </el-col>
 | 
				
			||||||
 | 
					                </el-row>
 | 
				
			||||||
 | 
					              </div>
 | 
				
			||||||
 | 
					            </el-col>
 | 
				
			||||||
 | 
					            <el-col :span="8">
 | 
				
			||||||
 | 
					              <div class="item-box blue">
 | 
				
			||||||
 | 
					                <el-row :gutter="10">
 | 
				
			||||||
 | 
					                  <el-col :span="10">
 | 
				
			||||||
 | 
					                    <div class="item-icon">
 | 
				
			||||||
 | 
					                      <i class="iconfont icon-order"></i>
 | 
				
			||||||
 | 
					                    </div>
 | 
				
			||||||
 | 
					                  </el-col>
 | 
				
			||||||
 | 
					                  <el-col :span="14">
 | 
				
			||||||
 | 
					                    <div class="item-info">
 | 
				
			||||||
 | 
					                      <div class="num">{{ regNum }}</div>
 | 
				
			||||||
 | 
					                      <div class="text">注册量</div>
 | 
				
			||||||
 | 
					                    </div>
 | 
				
			||||||
 | 
					                  </el-col>
 | 
				
			||||||
 | 
					                </el-row>
 | 
				
			||||||
 | 
					              </div>
 | 
				
			||||||
 | 
					            </el-col>
 | 
				
			||||||
 | 
					            <el-col :span="8">
 | 
				
			||||||
 | 
					              <div class="item-box green">
 | 
				
			||||||
 | 
					                <el-row :gutter="10">
 | 
				
			||||||
 | 
					                  <el-col :span="10">
 | 
				
			||||||
 | 
					                    <div class="item-icon">
 | 
				
			||||||
 | 
					                      <i class="iconfont icon-chart"></i>
 | 
				
			||||||
 | 
					                    </div>
 | 
				
			||||||
 | 
					                  </el-col>
 | 
				
			||||||
 | 
					                  <el-col :span="14">
 | 
				
			||||||
 | 
					                    <div class="item-info">
 | 
				
			||||||
 | 
					                      <div class="num">{{ rate }}%</div>
 | 
				
			||||||
 | 
					                      <div class="text">转化率</div>
 | 
				
			||||||
 | 
					                    </div>
 | 
				
			||||||
 | 
					                  </el-col>
 | 
				
			||||||
 | 
					                </el-row>
 | 
				
			||||||
 | 
					              </div>
 | 
				
			||||||
 | 
					            </el-col>
 | 
				
			||||||
 | 
					          </el-row>
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <div class="invite-url">
 | 
					        <h2>您推荐用户</h2>
 | 
				
			||||||
          <span>{{ inviteURL }}</span>
 | 
					
 | 
				
			||||||
          <el-button type="primary" plain class="copy-link" :data-clipboard-text="inviteURL">复制链接</el-button>
 | 
					        <div class="invite-logs">
 | 
				
			||||||
 | 
					          <invite-list v-if="isLogin"/>
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
 | 
					 | 
				
			||||||
      <div class="invite-stats">
 | 
					 | 
				
			||||||
        <el-row :gutter="20">
 | 
					 | 
				
			||||||
          <el-col :span="8">
 | 
					 | 
				
			||||||
            <div class="item-box yellow">
 | 
					 | 
				
			||||||
              <el-row :gutter="10">
 | 
					 | 
				
			||||||
                <el-col :span="10">
 | 
					 | 
				
			||||||
                  <div class="item-icon">
 | 
					 | 
				
			||||||
                    <i class="iconfont icon-role"></i>
 | 
					 | 
				
			||||||
                  </div>
 | 
					 | 
				
			||||||
                </el-col>
 | 
					 | 
				
			||||||
                <el-col :span="14">
 | 
					 | 
				
			||||||
                  <div class="item-info">
 | 
					 | 
				
			||||||
                    <div class="num">{{ hits }}</div>
 | 
					 | 
				
			||||||
                    <div class="text">点击量</div>
 | 
					 | 
				
			||||||
                  </div>
 | 
					 | 
				
			||||||
                </el-col>
 | 
					 | 
				
			||||||
              </el-row>
 | 
					 | 
				
			||||||
            </div>
 | 
					 | 
				
			||||||
          </el-col>
 | 
					 | 
				
			||||||
          <el-col :span="8">
 | 
					 | 
				
			||||||
            <div class="item-box blue">
 | 
					 | 
				
			||||||
              <el-row :gutter="10">
 | 
					 | 
				
			||||||
                <el-col :span="10">
 | 
					 | 
				
			||||||
                  <div class="item-icon">
 | 
					 | 
				
			||||||
                    <i class="iconfont icon-order"></i>
 | 
					 | 
				
			||||||
                  </div>
 | 
					 | 
				
			||||||
                </el-col>
 | 
					 | 
				
			||||||
                <el-col :span="14">
 | 
					 | 
				
			||||||
                  <div class="item-info">
 | 
					 | 
				
			||||||
                    <div class="num">{{ regNum }}</div>
 | 
					 | 
				
			||||||
                    <div class="text">注册量</div>
 | 
					 | 
				
			||||||
                  </div>
 | 
					 | 
				
			||||||
                </el-col>
 | 
					 | 
				
			||||||
              </el-row>
 | 
					 | 
				
			||||||
            </div>
 | 
					 | 
				
			||||||
          </el-col>
 | 
					 | 
				
			||||||
          <el-col :span="8">
 | 
					 | 
				
			||||||
            <div class="item-box green">
 | 
					 | 
				
			||||||
              <el-row :gutter="10">
 | 
					 | 
				
			||||||
                <el-col :span="10">
 | 
					 | 
				
			||||||
                  <div class="item-icon">
 | 
					 | 
				
			||||||
                    <i class="iconfont icon-chart"></i>
 | 
					 | 
				
			||||||
                  </div>
 | 
					 | 
				
			||||||
                </el-col>
 | 
					 | 
				
			||||||
                <el-col :span="14">
 | 
					 | 
				
			||||||
                  <div class="item-info">
 | 
					 | 
				
			||||||
                    <div class="num">{{ rate }}%</div>
 | 
					 | 
				
			||||||
                    <div class="text">转化率</div>
 | 
					 | 
				
			||||||
                  </div>
 | 
					 | 
				
			||||||
                </el-col>
 | 
					 | 
				
			||||||
              </el-row>
 | 
					 | 
				
			||||||
            </div>
 | 
					 | 
				
			||||||
          </el-col>
 | 
					 | 
				
			||||||
        </el-row>
 | 
					 | 
				
			||||||
      </div>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      <h2>您推荐用户</h2>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      <div class="invite-logs">
 | 
					 | 
				
			||||||
        <invite-list v-if="isLogin"/>
 | 
					 | 
				
			||||||
      </div>
 | 
					 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
  </div>
 | 
					  </div>
 | 
				
			||||||
</template>
 | 
					</template>
 | 
				
			||||||
@@ -94,11 +97,11 @@ import InviteList from "@/components/InviteList.vue";
 | 
				
			|||||||
import {checkSession} from "@/action/session";
 | 
					import {checkSession} from "@/action/session";
 | 
				
			||||||
import {useRouter} from "vue-router";
 | 
					import {useRouter} from "vue-router";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const listBoxHeight = window.innerHeight
 | 
				
			||||||
const inviteURL = ref("")
 | 
					const inviteURL = ref("")
 | 
				
			||||||
const qrImg = ref("")
 | 
					const qrImg = ref("")
 | 
				
			||||||
const inviteChatCalls = ref(0)
 | 
					const inviteChatCalls = ref(0)
 | 
				
			||||||
const inviteImgCalls = ref(0)
 | 
					const inviteImgCalls = ref(0)
 | 
				
			||||||
const users = ref([])
 | 
					 | 
				
			||||||
const hits = ref(0)
 | 
					const hits = ref(0)
 | 
				
			||||||
const regNum = ref(0)
 | 
					const regNum = ref(0)
 | 
				
			||||||
const rate = ref(0)
 | 
					const rate = ref(0)
 | 
				
			||||||
@@ -150,11 +153,14 @@ onMounted(() => {
 | 
				
			|||||||
</script>
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<style lang="stylus" scoped>
 | 
					<style lang="stylus" scoped>
 | 
				
			||||||
 | 
					@import "@/assets/css/custom-scroll.styl"
 | 
				
			||||||
.page-invitation {
 | 
					.page-invitation {
 | 
				
			||||||
  display: flex;
 | 
					  display: flex;
 | 
				
			||||||
  justify-content: center;
 | 
					  justify-content: center;
 | 
				
			||||||
  background-color: #282c34;
 | 
					  background-color: #282c34;
 | 
				
			||||||
  height 100vh
 | 
					  height 100vh
 | 
				
			||||||
 | 
					  overflow-x hidden
 | 
				
			||||||
 | 
					  overflow-y visible
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  .inner {
 | 
					  .inner {
 | 
				
			||||||
    max-width 1000px
 | 
					    max-width 1000px
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -152,7 +152,6 @@ import RewardVerify from "@/components/RewardVerify.vue";
 | 
				
			|||||||
import {useRouter} from "vue-router";
 | 
					import {useRouter} from "vue-router";
 | 
				
			||||||
import {removeUserToken} from "@/store/session";
 | 
					import {removeUserToken} from "@/store/session";
 | 
				
			||||||
import UserOrder from "@/components/UserOrder.vue";
 | 
					import UserOrder from "@/components/UserOrder.vue";
 | 
				
			||||||
import CountDown from "@/components/CountDown.vue";
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
const listBoxHeight = window.innerHeight - 97
 | 
					const listBoxHeight = window.innerHeight - 97
 | 
				
			||||||
const list = ref([])
 | 
					const list = ref([])
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -124,9 +124,17 @@ import FooterBar from "@/components/FooterBar.vue";
 | 
				
			|||||||
import SendMsg from "@/components/SendMsg.vue";
 | 
					import SendMsg from "@/components/SendMsg.vue";
 | 
				
			||||||
import {validateMobile} from "@/utils/validate";
 | 
					import {validateMobile} from "@/utils/validate";
 | 
				
			||||||
import {isMobile} from "@/utils/libs";
 | 
					import {isMobile} from "@/utils/libs";
 | 
				
			||||||
import SendMsgMobile from "@/components/SendMsg.vue";
 | 
					 | 
				
			||||||
import {setUserToken} from "@/store/session";
 | 
					import {setUserToken} from "@/store/session";
 | 
				
			||||||
 | 
					import {checkSession} from "@/action/session";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					checkSession().then(() => {
 | 
				
			||||||
 | 
					  if (isMobile()) {
 | 
				
			||||||
 | 
					    router.push('/mobile')
 | 
				
			||||||
 | 
					  } else {
 | 
				
			||||||
 | 
					    router.push('/chat')
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}).catch(() => {
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
const router = useRouter();
 | 
					const router = useRouter();
 | 
				
			||||||
const title = ref('ChatGPT-PLUS 用户注册');
 | 
					const title = ref('ChatGPT-PLUS 用户注册');
 | 
				
			||||||
const formData = ref({
 | 
					const formData = ref({
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -66,19 +66,6 @@
 | 
				
			|||||||
            </el-icon>
 | 
					            </el-icon>
 | 
				
			||||||
          </el-tooltip>
 | 
					          </el-tooltip>
 | 
				
			||||||
        </el-form-item>
 | 
					        </el-form-item>
 | 
				
			||||||
        <el-form-item label="启用AI绘画" prop="enabled_draw">
 | 
					 | 
				
			||||||
          <el-switch v-model="system['enabled_draw']"/>
 | 
					 | 
				
			||||||
          <el-tooltip
 | 
					 | 
				
			||||||
              effect="dark"
 | 
					 | 
				
			||||||
              content="需要开启函数功能此配置才会生效"
 | 
					 | 
				
			||||||
              raw-content
 | 
					 | 
				
			||||||
              placement="right"
 | 
					 | 
				
			||||||
          >
 | 
					 | 
				
			||||||
            <el-icon>
 | 
					 | 
				
			||||||
              <InfoFilled/>
 | 
					 | 
				
			||||||
            </el-icon>
 | 
					 | 
				
			||||||
          </el-tooltip>
 | 
					 | 
				
			||||||
        </el-form-item>
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <el-form-item label="启用众筹功能" prop="enabled_reward">
 | 
					        <el-form-item label="启用众筹功能" prop="enabled_reward">
 | 
				
			||||||
          <el-switch v-model="system['enabled_reward']"/>
 | 
					          <el-switch v-model="system['enabled_reward']"/>
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user