mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2026-09-22 16:00:51 +00:00
feat: change hermes channel logic (#12551)
This commit is contained in:
@@ -864,6 +864,27 @@ func (b *BaseApi) UpdateAgentDingTalkConfig(c *gin.Context) {
|
||||
helper.Success(c)
|
||||
}
|
||||
|
||||
// @Tags AI
|
||||
// @Summary Get Agent Weixin channel config
|
||||
// @Accept json
|
||||
// @Param request body dto.AgentIDReq true "request"
|
||||
// @Success 200 {object} dto.AgentWeixinConfig
|
||||
// @Security ApiKeyAuth
|
||||
// @Security Timestamp
|
||||
// @Router /ai/agents/channel/weixin/get [post]
|
||||
func (b *BaseApi) GetAgentWeixinConfig(c *gin.Context) {
|
||||
var req dto.AgentIDReq
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
data, err := agentService.GetWeixinConfig(req)
|
||||
if err != nil {
|
||||
helper.BadRequest(c, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, data)
|
||||
}
|
||||
|
||||
// @Tags AI
|
||||
// @Summary Get Agent QQ Bot channel config
|
||||
// @Accept json
|
||||
@@ -905,6 +926,26 @@ func (b *BaseApi) UpdateAgentQQBotConfig(c *gin.Context) {
|
||||
helper.Success(c)
|
||||
}
|
||||
|
||||
// @Tags AI
|
||||
// @Summary Delete Agent channel config
|
||||
// @Accept json
|
||||
// @Param request body dto.AgentChannelDeleteReq true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Security Timestamp
|
||||
// @Router /ai/agents/channel/delete [post]
|
||||
func (b *BaseApi) DeleteAgentChannelConfig(c *gin.Context) {
|
||||
var req dto.AgentChannelDeleteReq
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
if err := agentService.DeleteChannelConfig(req); err != nil {
|
||||
helper.BadRequest(c, err)
|
||||
return
|
||||
}
|
||||
helper.Success(c)
|
||||
}
|
||||
|
||||
// @Tags AI
|
||||
// @Summary Install Agent plugin
|
||||
// @Accept json
|
||||
|
||||
+11
-2
@@ -376,11 +376,16 @@ type AgentTelegramConfig struct {
|
||||
|
||||
type AgentChannelPairingApproveReq struct {
|
||||
AgentID uint `json:"agentId" validate:"required"`
|
||||
Type string `json:"type" validate:"required,oneof=feishu telegram discord wecom qqbot"`
|
||||
Type string `json:"type" validate:"required,oneof=feishu telegram discord wecom qqbot dingtalk"`
|
||||
PairingCode string `json:"pairingCode" validate:"required"`
|
||||
AccountID string `json:"accountId"`
|
||||
}
|
||||
|
||||
type AgentChannelDeleteReq struct {
|
||||
AgentID uint `json:"agentId" validate:"required"`
|
||||
Type string `json:"type" validate:"required,oneof=feishu telegram discord wecom qqbot dingtalk weixin"`
|
||||
}
|
||||
|
||||
type AgentWecomConfigUpdateReq struct {
|
||||
AgentID uint `json:"agentId" validate:"required"`
|
||||
Enabled bool `json:"enabled"`
|
||||
@@ -406,7 +411,7 @@ type AgentWecomConfig struct {
|
||||
type AgentDingTalkConfigUpdateReq struct {
|
||||
AgentID uint `json:"agentId" validate:"required"`
|
||||
Enabled bool `json:"enabled"`
|
||||
DmPolicy string `json:"dmPolicy" validate:"required,oneof=allowlist open disabled"`
|
||||
DmPolicy string `json:"dmPolicy" validate:"required,oneof=pairing allowlist open disabled"`
|
||||
AllowFrom []string `json:"allowFrom"`
|
||||
GroupPolicy string `json:"groupPolicy" validate:"required,oneof=open allowlist disabled"`
|
||||
GroupAllowFrom []string `json:"groupAllowFrom"`
|
||||
@@ -438,6 +443,10 @@ type AgentWeixinLoginReq struct {
|
||||
TaskID string `json:"taskID" validate:"required"`
|
||||
}
|
||||
|
||||
type AgentWeixinConfig struct {
|
||||
Enabled bool `json:"enabled"`
|
||||
}
|
||||
|
||||
type AgentQQBotConfigUpdateReq struct {
|
||||
AgentID uint `json:"agentId" validate:"required"`
|
||||
Enabled bool `json:"enabled"`
|
||||
|
||||
@@ -86,9 +86,11 @@ type IAgentService interface {
|
||||
UpdateWecomConfig(req dto.AgentWecomConfigUpdateReq) error
|
||||
GetDingTalkConfig(req dto.AgentIDReq) (*dto.AgentDingTalkConfig, error)
|
||||
UpdateDingTalkConfig(req dto.AgentDingTalkConfigUpdateReq) error
|
||||
GetWeixinConfig(req dto.AgentIDReq) (*dto.AgentWeixinConfig, error)
|
||||
LoginWeixinChannel(req dto.AgentWeixinLoginReq) error
|
||||
GetQQBotConfig(req dto.AgentIDReq) (*dto.AgentQQBotConfig, error)
|
||||
UpdateQQBotConfig(req dto.AgentQQBotConfigUpdateReq) error
|
||||
DeleteChannelConfig(req dto.AgentChannelDeleteReq) error
|
||||
InstallPlugin(req dto.AgentPluginInstallReq) error
|
||||
UpgradePlugin(req dto.AgentPluginUpgradeReq) error
|
||||
UninstallPlugin(req dto.AgentPluginUninstallReq) error
|
||||
|
||||
@@ -306,6 +306,17 @@ func (a AgentService) GetDingTalkConfig(req dto.AgentIDReq) (*dto.AgentDingTalkC
|
||||
return &result, nil
|
||||
}
|
||||
|
||||
func (a AgentService) GetWeixinConfig(req dto.AgentIDReq) (*dto.AgentWeixinConfig, error) {
|
||||
agent, _, err := a.loadAgentAndInstall(req.AgentID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if agent.AgentType == constant.AppHermesAgent {
|
||||
return readHermesWeixinChannelConfig(path.Dir(agent.ConfigPath))
|
||||
}
|
||||
return nil, fmt.Errorf("%s does not support", agent.AgentType)
|
||||
}
|
||||
|
||||
func (a AgentService) UpdateDingTalkConfig(req dto.AgentDingTalkConfigUpdateReq) error {
|
||||
agent, install, err := a.loadAgentAndInstall(req.AgentID)
|
||||
if err != nil {
|
||||
@@ -495,6 +506,36 @@ func (a AgentService) LoginWeixinChannel(req dto.AgentWeixinLoginReq) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a AgentService) DeleteChannelConfig(req dto.AgentChannelDeleteReq) error {
|
||||
agent, install, err := a.loadAgentAndInstall(req.AgentID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if agent.AgentType != constant.AppHermesAgent {
|
||||
return fmt.Errorf("%s does not support", agent.AgentType)
|
||||
}
|
||||
return updateHermesChannelConfig(agent, install, func(confDir string) error {
|
||||
switch req.Type {
|
||||
case "telegram":
|
||||
return deleteHermesTelegramChannelConfig(confDir)
|
||||
case "discord":
|
||||
return deleteHermesDiscordChannelConfig(confDir)
|
||||
case "qqbot":
|
||||
return deleteHermesQQBotChannelConfig(confDir)
|
||||
case "wecom":
|
||||
return deleteHermesWecomChannelConfig(confDir)
|
||||
case "dingtalk":
|
||||
return deleteHermesDingTalkChannelConfig(confDir)
|
||||
case "feishu":
|
||||
return deleteHermesFeishuChannelConfig(confDir)
|
||||
case "weixin":
|
||||
return deleteHermesWeixinChannelConfig(confDir)
|
||||
default:
|
||||
return fmt.Errorf("unsupported channel type: %s", req.Type)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func (a AgentService) CheckPlugin(req dto.AgentPluginCheckReq) (*dto.AgentPluginStatus, error) {
|
||||
_, install, err := a.loadAgentAndInstall(req.AgentID)
|
||||
if err != nil {
|
||||
@@ -535,14 +576,12 @@ func (a AgentService) ApproveChannelPairing(req dto.AgentChannelPairingApproveRe
|
||||
return err
|
||||
}
|
||||
if agent.AgentType == constant.AppHermesAgent {
|
||||
output, err := cmd.NewCommandMgr(cmd.WithTimeout(20*time.Second)).RunWithStdout(
|
||||
mgr := cmd.NewCommandMgr(cmd.WithTimeout(20 * time.Second))
|
||||
output, err := mgr.RunWithStdout(
|
||||
"docker",
|
||||
buildHermesDockerExecArgs(install.ContainerName, "pairing", "approve", req.Type, req.PairingCode)...,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return validateHermesPairingApproveOutput(output)
|
||||
return validateHermesPairingApproveResult(output, err)
|
||||
}
|
||||
if req.AccountID != "" {
|
||||
return cmd.RunDefaultBashCf(
|
||||
|
||||
@@ -326,6 +326,64 @@ func writeHermesDiscordChannelConfig(confDir string, config dto.AgentDiscordConf
|
||||
return writeHermesConfigMap(configPath, cfg)
|
||||
}
|
||||
|
||||
func deleteHermesEnvKeys(confDir string, keys ...string) error {
|
||||
envPath := path.Join(confDir, ".env")
|
||||
envMap, err := readHermesEnvMap(envPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, key := range keys {
|
||||
delete(envMap, key)
|
||||
}
|
||||
return writeHermesEnvMap(envPath, envMap, keys)
|
||||
}
|
||||
|
||||
func deleteHermesConfigSections(confDir string, topLevelKeys []string, platformKeys []string) error {
|
||||
configPath := path.Join(confDir, "config.yaml")
|
||||
cfg, err := readHermesConfigMap(configPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, key := range topLevelKeys {
|
||||
delete(cfg, key)
|
||||
}
|
||||
if len(platformKeys) > 0 {
|
||||
if platforms, ok := cfg["platforms"].(map[string]interface{}); ok {
|
||||
for _, key := range platformKeys {
|
||||
delete(platforms, key)
|
||||
}
|
||||
if len(platforms) == 0 {
|
||||
delete(cfg, "platforms")
|
||||
}
|
||||
}
|
||||
}
|
||||
return writeHermesConfigMap(configPath, cfg)
|
||||
}
|
||||
|
||||
func deleteHermesTelegramChannelConfig(confDir string) error {
|
||||
if err := deleteHermesEnvKeys(confDir,
|
||||
"TELEGRAM_BOT_TOKEN",
|
||||
"TELEGRAM_ALLOWED_USERS",
|
||||
"TELEGRAM_ALLOW_ALL_USERS",
|
||||
"TELEGRAM_HOME_CHANNEL",
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
return deleteHermesConfigSections(confDir, []string{"telegram"}, []string{"telegram"})
|
||||
}
|
||||
|
||||
func deleteHermesDiscordChannelConfig(confDir string) error {
|
||||
if err := deleteHermesEnvKeys(confDir,
|
||||
"DISCORD_BOT_TOKEN",
|
||||
"DISCORD_ALLOWED_USERS",
|
||||
"DISCORD_ALLOW_ALL_USERS",
|
||||
"DISCORD_HOME_CHANNEL",
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
return deleteHermesConfigSections(confDir, []string{"discord"}, []string{"discord"})
|
||||
}
|
||||
|
||||
func normalizeHermesTimezone(timezone string) string {
|
||||
timezone = strings.TrimSpace(timezone)
|
||||
if timezone == "" {
|
||||
@@ -566,13 +624,21 @@ func extractHermesEnvBool(envMap map[string]string, key string, defaultValue boo
|
||||
return strings.EqualFold(value, "true")
|
||||
}
|
||||
|
||||
func validateHermesPairingApproveOutput(output string) error {
|
||||
text := strings.TrimSpace(output)
|
||||
if text == "" {
|
||||
func validateHermesPairingApproveResult(output string, err error) error {
|
||||
if strings.Contains(output, "Approved!") {
|
||||
return nil
|
||||
}
|
||||
if strings.Contains(text, "not found or expired for platform") {
|
||||
return errors.New(text)
|
||||
if strings.Contains(output, "not found or expired for platform") {
|
||||
return buserr.New("ErrHermesPairingCodeUnavailable")
|
||||
}
|
||||
return nil
|
||||
if err == nil {
|
||||
if strings.TrimSpace(output) == "" {
|
||||
return fmt.Errorf("unexpected hermes pairing approve result")
|
||||
}
|
||||
return errors.New(strings.TrimSpace(output))
|
||||
}
|
||||
if strings.Contains(err.Error(), "not found or expired for platform") {
|
||||
return buserr.New("ErrHermesPairingCodeUnavailable")
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -137,6 +137,23 @@ func writeHermesQQBotChannelConfig(confDir string, config dto.AgentQQBotConfig)
|
||||
return writeHermesConfigMap(configPath, cfg)
|
||||
}
|
||||
|
||||
func deleteHermesQQBotChannelConfig(confDir string) error {
|
||||
if err := deleteHermesEnvKeys(confDir,
|
||||
"QQ_APP_ID",
|
||||
"QQ_CLIENT_SECRET",
|
||||
"QQ_ALLOW_ALL_USERS",
|
||||
"QQ_ALLOWED_USERS",
|
||||
"QQ_HOME_CHANNEL",
|
||||
"QQ_HOME_CHANNEL_NAME",
|
||||
"QQ_STT_API_KEY",
|
||||
"QQ_STT_BASE_URL",
|
||||
"QQ_STT_MODEL",
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
return deleteHermesConfigSections(confDir, nil, []string{"qq"})
|
||||
}
|
||||
|
||||
func readHermesWecomChannelConfig(confDir string) (*dto.AgentWecomConfig, error) {
|
||||
envMap, err := readHermesEnvMap(path.Join(confDir, ".env"))
|
||||
if err != nil {
|
||||
@@ -243,6 +260,19 @@ func writeHermesWecomChannelConfig(confDir string, config dto.AgentWecomConfig)
|
||||
return writeHermesConfigMap(configPath, cfg)
|
||||
}
|
||||
|
||||
func deleteHermesWecomChannelConfig(confDir string) error {
|
||||
if err := deleteHermesEnvKeys(confDir,
|
||||
"WECOM_BOT_ID",
|
||||
"WECOM_SECRET",
|
||||
"WECOM_ALLOW_ALL_USERS",
|
||||
"WECOM_ALLOWED_USERS",
|
||||
"WECOM_HOME_CHANNEL",
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
return deleteHermesConfigSections(confDir, nil, []string{"wecom"})
|
||||
}
|
||||
|
||||
func readHermesDingTalkChannelConfig(confDir string) (*dto.AgentDingTalkConfig, error) {
|
||||
envMap, err := readHermesEnvMap(path.Join(confDir, ".env"))
|
||||
if err != nil {
|
||||
@@ -254,10 +284,15 @@ func readHermesDingTalkChannelConfig(confDir string) (*dto.AgentDingTalkConfig,
|
||||
}
|
||||
|
||||
platform := childMap(childMap(cfg, "platforms"), "dingtalk")
|
||||
extra := childMap(platform, "extra")
|
||||
allowFrom := splitHermesEnvList(envMap["DINGTALK_ALLOWED_USERS"])
|
||||
dmPolicy := "open"
|
||||
if len(allowFrom) > 0 {
|
||||
dmPolicy := "pairing"
|
||||
if extractHermesEnvBool(envMap, "DINGTALK_ALLOW_ALL_USERS", false) {
|
||||
dmPolicy = "open"
|
||||
} else if len(allowFrom) > 0 {
|
||||
dmPolicy = "allowlist"
|
||||
} else if extractStringValue(extra["unauthorized_dm_behavior"]) == "ignore" {
|
||||
dmPolicy = "disabled"
|
||||
}
|
||||
clientID := envMap["DINGTALK_CLIENT_ID"]
|
||||
clientSecret := envMap["DINGTALK_CLIENT_SECRET"]
|
||||
@@ -292,25 +327,29 @@ func writeHermesDingTalkChannelConfig(confDir string, config dto.AgentDingTalkCo
|
||||
return err
|
||||
}
|
||||
clientID, clientSecret := firstHermesDingTalkBotCredentials(config.Bots)
|
||||
if clientID != "" {
|
||||
if config.Enabled && clientID != "" {
|
||||
envMap["DINGTALK_CLIENT_ID"] = clientID
|
||||
} else {
|
||||
delete(envMap, "DINGTALK_CLIENT_ID")
|
||||
}
|
||||
if clientSecret != "" {
|
||||
if config.Enabled && clientSecret != "" {
|
||||
envMap["DINGTALK_CLIENT_SECRET"] = clientSecret
|
||||
} else {
|
||||
delete(envMap, "DINGTALK_CLIENT_SECRET")
|
||||
}
|
||||
delete(envMap, "DINGTALK_ALLOWED_USERS")
|
||||
delete(envMap, "DINGTALK_ALLOW_ALL_USERS")
|
||||
if config.DmPolicy == "allowlist" {
|
||||
if allow := joinHermesEnvList(config.AllowFrom); allow != "" {
|
||||
envMap["DINGTALK_ALLOWED_USERS"] = allow
|
||||
}
|
||||
} else if config.DmPolicy == "open" {
|
||||
envMap["DINGTALK_ALLOW_ALL_USERS"] = "true"
|
||||
}
|
||||
if err := writeHermesEnvMap(envPath, envMap, []string{
|
||||
"DINGTALK_CLIENT_ID",
|
||||
"DINGTALK_CLIENT_SECRET",
|
||||
"DINGTALK_ALLOW_ALL_USERS",
|
||||
"DINGTALK_ALLOWED_USERS",
|
||||
}); err != nil {
|
||||
return err
|
||||
@@ -323,9 +362,31 @@ func writeHermesDingTalkChannelConfig(confDir string, config dto.AgentDingTalkCo
|
||||
}
|
||||
platform := ensureChildMap(ensureChildMap(cfg, "platforms"), "dingtalk")
|
||||
platform["enabled"] = config.Enabled && clientID != "" && clientSecret != ""
|
||||
extra := ensureChildMap(platform, "extra")
|
||||
switch config.DmPolicy {
|
||||
case "pairing":
|
||||
extra["unauthorized_dm_behavior"] = "pair"
|
||||
case "disabled":
|
||||
extra["unauthorized_dm_behavior"] = "ignore"
|
||||
default:
|
||||
delete(extra, "unauthorized_dm_behavior")
|
||||
}
|
||||
return writeHermesConfigMap(configPath, cfg)
|
||||
}
|
||||
|
||||
func deleteHermesDingTalkChannelConfig(confDir string) error {
|
||||
if err := deleteHermesEnvKeys(confDir,
|
||||
"DINGTALK_CLIENT_ID",
|
||||
"DINGTALK_CLIENT_SECRET",
|
||||
"DINGTALK_ALLOW_ALL_USERS",
|
||||
"DINGTALK_ALLOWED_USERS",
|
||||
"DINGTALK_HOME_CHANNEL",
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
return deleteHermesConfigSections(confDir, nil, []string{"dingtalk"})
|
||||
}
|
||||
|
||||
func readHermesFeishuChannelConfig(confDir string) (*dto.AgentFeishuConfig, error) {
|
||||
envMap, err := readHermesEnvMap(path.Join(confDir, ".env"))
|
||||
if err != nil {
|
||||
@@ -432,6 +493,52 @@ func writeHermesFeishuChannelConfig(confDir string, config dto.AgentFeishuConfig
|
||||
return writeHermesConfigMap(configPath, cfg)
|
||||
}
|
||||
|
||||
func deleteHermesFeishuChannelConfig(confDir string) error {
|
||||
if err := deleteHermesEnvKeys(confDir,
|
||||
"FEISHU_APP_ID",
|
||||
"FEISHU_APP_SECRET",
|
||||
"FEISHU_DOMAIN",
|
||||
"FEISHU_CONNECTION_MODE",
|
||||
"FEISHU_ALLOW_ALL_USERS",
|
||||
"FEISHU_ALLOWED_USERS",
|
||||
"FEISHU_GROUP_POLICY",
|
||||
"FEISHU_HOME_CHANNEL",
|
||||
"FEISHU_VERIFICATION_TOKEN",
|
||||
"FEISHU_ENCRYPT_KEY",
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
return deleteHermesConfigSections(confDir, nil, []string{"feishu"})
|
||||
}
|
||||
|
||||
func readHermesWeixinChannelConfig(confDir string) (*dto.AgentWeixinConfig, error) {
|
||||
envMap, err := readHermesEnvMap(path.Join(confDir, ".env"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &dto.AgentWeixinConfig{
|
||||
Enabled: envMap["WEIXIN_ACCOUNT_ID"] != "" || envMap["WEIXIN_TOKEN"] != "",
|
||||
}, nil
|
||||
}
|
||||
|
||||
func deleteHermesWeixinChannelConfig(confDir string) error {
|
||||
if err := deleteHermesEnvKeys(confDir,
|
||||
"WEIXIN_ACCOUNT_ID",
|
||||
"WEIXIN_TOKEN",
|
||||
"WEIXIN_BASE_URL",
|
||||
"WEIXIN_CDN_BASE_URL",
|
||||
"WEIXIN_DM_POLICY",
|
||||
"WEIXIN_ALLOW_ALL_USERS",
|
||||
"WEIXIN_ALLOWED_USERS",
|
||||
"WEIXIN_GROUP_POLICY",
|
||||
"WEIXIN_GROUP_ALLOWED_USERS",
|
||||
"WEIXIN_HOME_CHANNEL",
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
return deleteHermesConfigSections(confDir, nil, []string{"weixin"})
|
||||
}
|
||||
|
||||
func firstHermesDingTalkBotCredentials(bots []dto.AgentDingTalkBot) (string, string) {
|
||||
for _, bot := range bots {
|
||||
if bot.IsDefault || bot.AccountID == "default" {
|
||||
|
||||
@@ -65,6 +65,7 @@ ErrAgentWebsiteBound: 'This agent is already bound to a website'
|
||||
ErrAgentWebsiteTypeUnsupported: 'Only proxy or static websites can be bound'
|
||||
ErrAgentWebsiteInUse: 'This website is already bound to another agent'
|
||||
ErrAgentWebsiteUnbindUnsupported: 'Deployment websites cannot be unbound manually'
|
||||
ErrHermesPairingCodeUnavailable: 'The pairing code is temporarily unavailable in Hermes, possibly due to network issues. Please try again later.'
|
||||
|
||||
#backup
|
||||
Localhost: 'Local'
|
||||
|
||||
@@ -60,6 +60,7 @@ ErrAgentWebsiteBound: 'Este agente ya está vinculado a un sitio web'
|
||||
ErrAgentWebsiteTypeUnsupported: 'Solo se pueden vincular sitios proxy o estáticos'
|
||||
ErrAgentWebsiteInUse: 'Este sitio web ya está vinculado a otro agente'
|
||||
ErrAgentWebsiteUnbindUnsupported: 'Los sitios web de despliegue no se pueden desvincular manualmente'
|
||||
ErrHermesPairingCodeUnavailable: 'El código de emparejamiento no está disponible temporalmente en Hermes, posiblemente por un problema de red. Inténtalo de nuevo más tarde.'
|
||||
Localhost: 'Máquina local'
|
||||
ErrBackupInUsed: 'Cuenta de respaldo en uso por tarea programada'
|
||||
ErrBackupCheck: 'Conexión de respaldo falló: {{ .err }}'
|
||||
|
||||
@@ -60,6 +60,7 @@ ErrAgentWebsiteBound: 'このエージェントはすでにサイトに関連付
|
||||
ErrAgentWebsiteTypeUnsupported: '関連付けできるのはプロキシサイトまたは静的サイトのみです'
|
||||
ErrAgentWebsiteInUse: 'このサイトはすでに別のエージェントに関連付けられています'
|
||||
ErrAgentWebsiteUnbindUnsupported: 'ワンクリックデプロイのサイトは手動で関連解除できません'
|
||||
ErrHermesPairingCodeUnavailable: 'Hermes でペアリングコードが一時的に見つかりません。ネットワーク要因の可能性があるため、しばらくしてから再試行してください。'
|
||||
Localhost: 'ローカルマシン'
|
||||
ErrBackupInUsed: 'バックアップアカウントがスケジュールで使用中'
|
||||
ErrBackupCheck: '接続テストに失敗しました: {{ .err }}'
|
||||
|
||||
@@ -60,6 +60,7 @@ ErrAgentWebsiteBound: '이 에이전트는 이미 웹사이트에 연결되어
|
||||
ErrAgentWebsiteTypeUnsupported: '프록시 또는 정적 웹사이트만 연결할 수 있습니다'
|
||||
ErrAgentWebsiteInUse: '이 웹사이트는 이미 다른 에이전트에 연결되어 있습니다'
|
||||
ErrAgentWebsiteUnbindUnsupported: '원클릭 배포 웹사이트는 수동으로 연결 해제할 수 없습니다'
|
||||
ErrHermesPairingCodeUnavailable: 'Hermes에서 페어링 코드가 일시적으로 존재하지 않습니다. 네트워크 문제일 수 있으니 잠시 후 다시 시도해 주세요.'
|
||||
Localhost: '로컬 머신'
|
||||
ErrBackupInUsed: '백업 계정이 예약에 사용 중'
|
||||
ErrBackupCheck: '연결 테스트 실패: {{ .err }}'
|
||||
|
||||
@@ -60,6 +60,7 @@ ErrAgentWebsiteBound: 'Ejen ini sudah dipautkan ke laman web'
|
||||
ErrAgentWebsiteTypeUnsupported: 'Hanya laman web proxy atau statik boleh dipautkan'
|
||||
ErrAgentWebsiteInUse: 'Laman web ini sudah dipautkan ke ejen lain'
|
||||
ErrAgentWebsiteUnbindUnsupported: 'Laman web one-click deployment tidak menyokong nyahikat manual'
|
||||
ErrHermesPairingCodeUnavailable: 'Kod pasangan buat sementara waktu tidak wujud dalam Hermes, mungkin disebabkan masalah rangkaian. Sila cuba lagi sebentar nanti.'
|
||||
Localhost: 'Mesin Tempatan'
|
||||
ErrBackupInUsed: 'Akaun sandaran sedang digunakan oleh tugas'
|
||||
ErrBackupCheck: 'Ujian sambungan gagal: {{ .err }}'
|
||||
|
||||
@@ -60,6 +60,7 @@ ErrAgentWebsiteBound: 'Este agente já está vinculado a um site'
|
||||
ErrAgentWebsiteTypeUnsupported: 'Somente sites proxy ou estáticos podem ser vinculados'
|
||||
ErrAgentWebsiteInUse: 'Este site já está vinculado a outro agente'
|
||||
ErrAgentWebsiteUnbindUnsupported: 'Sites implantados em um clique não podem ser desvinculados manualmente'
|
||||
ErrHermesPairingCodeUnavailable: 'O código de pareamento está temporariamente indisponível no Hermes, possivelmente por causa de rede. Tente novamente mais tarde.'
|
||||
Localhost: 'Máquina Local'
|
||||
ErrBackupInUsed: 'Conta de backup em uso por tarefa'
|
||||
ErrBackupCheck: 'Teste de conexão falhou: {{ .err }}'
|
||||
|
||||
@@ -60,6 +60,7 @@ ErrAgentWebsiteBound: 'Этот агент уже связан с сайтом'
|
||||
ErrAgentWebsiteTypeUnsupported: 'Можно связывать только proxy- или static-сайты'
|
||||
ErrAgentWebsiteInUse: 'Этот сайт уже связан с другим агентом'
|
||||
ErrAgentWebsiteUnbindUnsupported: 'Сайты one-click deployment нельзя отвязать вручную'
|
||||
ErrHermesPairingCodeUnavailable: 'Код сопряжения временно недоступен в Hermes, возможно из-за проблем с сетью. Повторите попытку позже.'
|
||||
Localhost: 'Локальная машина'
|
||||
ErrBackupInUsed: 'Аккаунт бэкапа занят задачей'
|
||||
ErrBackupCheck: 'Проверка подключения не удалась: {{ .err }}'
|
||||
|
||||
@@ -60,6 +60,7 @@ ErrAgentWebsiteBound: 'Bu ajan zaten bir web sitesine bağlı'
|
||||
ErrAgentWebsiteTypeUnsupported: 'Yalnızca proxy veya statik web siteleri bağlanabilir'
|
||||
ErrAgentWebsiteInUse: 'Bu web sitesi zaten başka bir ajana bağlı'
|
||||
ErrAgentWebsiteUnbindUnsupported: 'Tek tıkla dağıtılan web sitelerinin bağlantısı manuel olarak kaldırılamaz'
|
||||
ErrHermesPairingCodeUnavailable: 'Eşleştirme kodu Hermes içinde geçici olarak bulunamıyor; bu durum ağ kaynaklı olabilir. Lütfen daha sonra tekrar deneyin.'
|
||||
Localhost: 'Yerel Makine'
|
||||
ErrBackupInUsed: 'Yedek hesabı görevde kullanılıyor'
|
||||
ErrBackupCheck: 'Bağlantı testi başarısız: {{ .err }}'
|
||||
|
||||
@@ -60,6 +60,7 @@ ErrAgentWebsiteBound: '該智能體已關聯網站'
|
||||
ErrAgentWebsiteTypeUnsupported: '只能關聯反向代理或靜態網站'
|
||||
ErrAgentWebsiteInUse: '該網站已被其他智能體關聯'
|
||||
ErrAgentWebsiteUnbindUnsupported: '一鍵部署網站不支援手動解綁'
|
||||
ErrHermesPairingCodeUnavailable: '配對碼在 Hermes 中暫時不存在,可能是由於網路原因,請稍後再試'
|
||||
Localhost: '本機'
|
||||
ErrBackupInUsed: '此備份帳號已在排程任務中使用,無法刪除'
|
||||
ErrBackupCheck: '備份帳號測試連線失敗{{ .err }}'
|
||||
|
||||
@@ -65,6 +65,7 @@ ErrAgentWebsiteBound: "该智能体已关联网站"
|
||||
ErrAgentWebsiteTypeUnsupported: "只能关联反向代理或静态网站"
|
||||
ErrAgentWebsiteInUse: "该网站已被其他智能体关联"
|
||||
ErrAgentWebsiteUnbindUnsupported: "一键部署网站不支持手动解绑"
|
||||
ErrHermesPairingCodeUnavailable: "配对码在 hermes 中暂时不存在,可能是由于网络原因,请稍后尝试"
|
||||
|
||||
#backup
|
||||
Localhost: '本机'
|
||||
|
||||
@@ -82,9 +82,11 @@ func (a *AIToolsRouter) InitRouter(Router *gin.RouterGroup) {
|
||||
aiToolsRouter.POST("/agents/channel/wecom/update", baseApi.UpdateAgentWecomConfig)
|
||||
aiToolsRouter.POST("/agents/channel/dingtalk/get", baseApi.GetAgentDingTalkConfig)
|
||||
aiToolsRouter.POST("/agents/channel/dingtalk/update", baseApi.UpdateAgentDingTalkConfig)
|
||||
aiToolsRouter.POST("/agents/channel/weixin/get", baseApi.GetAgentWeixinConfig)
|
||||
aiToolsRouter.POST("/agents/channel/weixin/login", baseApi.LoginAgentWeixinChannel)
|
||||
aiToolsRouter.POST("/agents/channel/qqbot/get", baseApi.GetAgentQQBotConfig)
|
||||
aiToolsRouter.POST("/agents/channel/qqbot/update", baseApi.UpdateAgentQQBotConfig)
|
||||
aiToolsRouter.POST("/agents/channel/delete", baseApi.DeleteAgentChannelConfig)
|
||||
aiToolsRouter.POST("/agents/plugin/install", baseApi.InstallAgentPlugin)
|
||||
aiToolsRouter.POST("/agents/plugin/upgrade", baseApi.UpgradeAgentPlugin)
|
||||
aiToolsRouter.POST("/agents/plugin/uninstall", baseApi.UninstallAgentPlugin)
|
||||
|
||||
@@ -626,7 +626,7 @@ export namespace AI {
|
||||
|
||||
export interface AgentChannelPairingApproveReq {
|
||||
agentId: number;
|
||||
type: 'feishu' | 'telegram' | 'discord' | 'wecom' | 'qqbot';
|
||||
type: 'feishu' | 'telegram' | 'discord' | 'wecom' | 'qqbot' | 'dingtalk';
|
||||
pairingCode: string;
|
||||
accountId?: string;
|
||||
}
|
||||
@@ -670,7 +670,7 @@ export namespace AI {
|
||||
|
||||
export interface AgentDingTalkConfig {
|
||||
enabled: boolean;
|
||||
dmPolicy: 'allowlist' | 'open' | 'disabled';
|
||||
dmPolicy: 'pairing' | 'allowlist' | 'open' | 'disabled';
|
||||
allowFrom: string[];
|
||||
groupPolicy: 'open' | 'allowlist' | 'disabled';
|
||||
groupAllowFrom: string[];
|
||||
@@ -686,7 +686,7 @@ export namespace AI {
|
||||
export interface AgentDingTalkConfigUpdateReq {
|
||||
agentId: number;
|
||||
enabled: boolean;
|
||||
dmPolicy: 'allowlist' | 'open' | 'disabled';
|
||||
dmPolicy: 'pairing' | 'allowlist' | 'open' | 'disabled';
|
||||
allowFrom: string[];
|
||||
groupPolicy: 'open' | 'allowlist' | 'disabled';
|
||||
groupAllowFrom: string[];
|
||||
@@ -703,6 +703,15 @@ export namespace AI {
|
||||
taskID: string;
|
||||
}
|
||||
|
||||
export interface AgentWeixinConfig {
|
||||
enabled: boolean;
|
||||
}
|
||||
|
||||
export interface AgentChannelDeleteReq {
|
||||
agentId: number;
|
||||
type: 'feishu' | 'telegram' | 'discord' | 'wecom' | 'qqbot' | 'dingtalk' | 'weixin';
|
||||
}
|
||||
|
||||
export interface AgentQQBotConfigReq {
|
||||
agentId: number;
|
||||
}
|
||||
|
||||
@@ -262,6 +262,10 @@ export const updateAgentDingTalkConfig = (req: AI.AgentDingTalkConfigUpdateReq)
|
||||
return http.post(`/ai/agents/channel/dingtalk/update`, req);
|
||||
};
|
||||
|
||||
export const getAgentWeixinConfig = (req: AI.AgentIDReq) => {
|
||||
return http.post<AI.AgentWeixinConfig>(`/ai/agents/channel/weixin/get`, req);
|
||||
};
|
||||
|
||||
export const loginAgentWeixinChannel = (req: AI.AgentWeixinLoginReq) => {
|
||||
return http.post(`/ai/agents/channel/weixin/login`, req);
|
||||
};
|
||||
@@ -274,6 +278,10 @@ export const updateAgentQQBotConfig = (req: AI.AgentQQBotConfigUpdateReq) => {
|
||||
return http.post(`/ai/agents/channel/qqbot/update`, req);
|
||||
};
|
||||
|
||||
export const deleteAgentChannelConfig = (req: AI.AgentChannelDeleteReq) => {
|
||||
return http.post(`/ai/agents/channel/delete`, req);
|
||||
};
|
||||
|
||||
export const installAgentPlugin = (req: AI.AgentPluginInstallReq) => {
|
||||
return http.post(`/ai/agents/plugin/install`, req);
|
||||
};
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<el-dialog v-model="open" :show-close="showClose" @close="handleClose" :width="width">
|
||||
<el-dialog v-model="open" :show-close="showClose" @closed="handleClose" :width="width">
|
||||
<div v-if="open">
|
||||
<LogFile :config="config" :showTail="showTail"></LogFile>
|
||||
</div>
|
||||
@@ -67,7 +67,6 @@ const openWithResourceID = (taskType: string, taskOperate: string, resourceID: n
|
||||
const em = defineEmits(['close']);
|
||||
const handleClose = () => {
|
||||
em('close', true);
|
||||
open.value = false;
|
||||
bus.emit('refreshTask', true);
|
||||
bus.emit('refreshApp', true);
|
||||
};
|
||||
|
||||
@@ -786,6 +786,7 @@ const message = {
|
||||
hermesChatDeleteConfirm: 'Delete session {0}?',
|
||||
hermesChatDeleteSuccess: 'Session deleted',
|
||||
weixin: 'Weixin',
|
||||
qq: 'QQ',
|
||||
wecom: 'WeCom',
|
||||
dingtalk: 'DingTalk',
|
||||
feishu: 'Feishu',
|
||||
@@ -842,6 +843,8 @@ const message = {
|
||||
scanConnectHelper:
|
||||
'Click to start the QR login task. The QR code will appear in the task log, and the container will restart automatically after the scan succeeds.',
|
||||
channelAutoRestartHelper: 'Saving will automatically restart the container so the changes take effect.',
|
||||
channelDeleteConfirm: 'Delete the {0} channel configuration?',
|
||||
deleteAndRestartSuccess: 'Deleted successfully. The container is restarting automatically.',
|
||||
customProviderHelper: 'Custom model providers do not validate whether the account is available.',
|
||||
},
|
||||
model: {
|
||||
|
||||
@@ -796,6 +796,7 @@ const message = {
|
||||
hermesChatDeleteConfirm: '¿Eliminar la sesión {0}?',
|
||||
hermesChatDeleteSuccess: 'Sesión eliminada',
|
||||
weixin: 'Weixin',
|
||||
qq: 'QQ',
|
||||
wecom: 'WeCom',
|
||||
dingtalk: 'DingTalk',
|
||||
feishu: 'Feishu',
|
||||
@@ -855,6 +856,8 @@ const message = {
|
||||
'Haga clic para iniciar la tarea de inicio de sesión por QR. El código QR aparecerá en el registro de tareas y el contenedor se reiniciará automáticamente después de completar el escaneo.',
|
||||
channelAutoRestartHelper:
|
||||
'Al guardar, el contenedor se reiniciará automáticamente para que la configuración surta efecto.',
|
||||
channelDeleteConfirm: '¿Eliminar la configuración del canal {0}?',
|
||||
deleteAndRestartSuccess: 'Se eliminó correctamente. El contenedor se está reiniciando automáticamente.',
|
||||
customProviderHelper: 'En el proveedor de modelo personalizado no se valida si la cuenta está disponible',
|
||||
},
|
||||
model: {
|
||||
|
||||
@@ -789,6 +789,7 @@ const message = {
|
||||
hermesChatDeleteConfirm: 'セッション {0} を削除しますか?',
|
||||
hermesChatDeleteSuccess: 'セッションを削除しました',
|
||||
weixin: 'Weixin',
|
||||
qq: 'QQ',
|
||||
wecom: 'WeCom',
|
||||
dingtalk: 'DingTalk',
|
||||
feishu: 'Feishu',
|
||||
@@ -846,6 +847,8 @@ const message = {
|
||||
scanConnectHelper:
|
||||
'クリックして QR ログインタスクを開始します。QR コードはタスクログに表示され、スキャン成功後にコンテナが自動で再起動されます。',
|
||||
channelAutoRestartHelper: '保存後、設定を反映するためにコンテナが自動で再起動されます。',
|
||||
channelDeleteConfirm: '{0} チャンネルの設定を削除しますか?',
|
||||
deleteAndRestartSuccess: '削除に成功しました。コンテナは自動的に再起動しています。',
|
||||
customProviderHelper: 'カスタムモデルプロバイダーでは、アカウントの有効性を検証しません',
|
||||
},
|
||||
model: {
|
||||
|
||||
@@ -775,6 +775,7 @@ const message = {
|
||||
hermesChatDeleteConfirm: '세션 {0}을(를) 삭제하시겠습니까?',
|
||||
hermesChatDeleteSuccess: '세션이 삭제되었습니다',
|
||||
weixin: 'Weixin',
|
||||
qq: 'QQ',
|
||||
wecom: 'WeCom',
|
||||
dingtalk: 'DingTalk',
|
||||
feishu: 'Feishu',
|
||||
@@ -831,6 +832,8 @@ const message = {
|
||||
scanConnectHelper:
|
||||
'클릭하여 QR 로그인 작업을 시작하세요. QR 코드는 작업 로그에 표시되며 스캔이 완료되면 컨테이너가 자동으로 재시작됩니다.',
|
||||
channelAutoRestartHelper: '저장하면 설정 적용을 위해 컨테이너가 자동으로 재시작됩니다.',
|
||||
channelDeleteConfirm: '{0} 채널 구성을 삭제하시겠습니까?',
|
||||
deleteAndRestartSuccess: '삭제되었습니다. 컨테이너가 자동으로 다시 시작되고 있습니다.',
|
||||
customProviderHelper: '사용자 정의 모델 공급자는 계정 사용 가능 여부를 검증하지 않습니다',
|
||||
},
|
||||
model: {
|
||||
|
||||
@@ -794,6 +794,7 @@ const message = {
|
||||
hermesChatDeleteConfirm: 'Padam sesi {0}?',
|
||||
hermesChatDeleteSuccess: 'Sesi berjaya dipadam',
|
||||
weixin: 'Weixin',
|
||||
qq: 'QQ',
|
||||
wecom: 'WeCom',
|
||||
dingtalk: 'DingTalk',
|
||||
feishu: 'Feishu',
|
||||
@@ -854,6 +855,8 @@ const message = {
|
||||
'Klik untuk memulakan tugas log masuk QR. Kod QR akan dipaparkan dalam log tugas dan bekas akan dimulakan semula secara automatik selepas imbasan berjaya.',
|
||||
channelAutoRestartHelper:
|
||||
'Menyimpan akan memulakan semula bekas secara automatik supaya konfigurasi berkuat kuasa.',
|
||||
channelDeleteConfirm: 'Padam konfigurasi saluran {0}?',
|
||||
deleteAndRestartSuccess: 'Berjaya dipadam. Bekas sedang dimulakan semula secara automatik.',
|
||||
customProviderHelper: 'Penyedia model tersuai tidak mengesahkan sama ada akaun boleh digunakan',
|
||||
},
|
||||
model: {
|
||||
|
||||
@@ -791,6 +791,7 @@ const message = {
|
||||
hermesChatDeleteConfirm: 'Excluir a sessão {0}?',
|
||||
hermesChatDeleteSuccess: 'Sessão excluída',
|
||||
weixin: 'Weixin',
|
||||
qq: 'QQ',
|
||||
wecom: 'WeCom',
|
||||
dingtalk: 'DingTalk',
|
||||
feishu: 'Feishu',
|
||||
@@ -850,6 +851,8 @@ const message = {
|
||||
'Clique para iniciar a tarefa de login por QR. O código QR aparecerá no log da tarefa e o contêiner será reiniciado automaticamente após a leitura ser concluída.',
|
||||
channelAutoRestartHelper:
|
||||
'Ao salvar, o contêiner será reiniciado automaticamente para que a configuração entre em vigor.',
|
||||
channelDeleteConfirm: 'Excluir a configuração do canal {0}?',
|
||||
deleteAndRestartSuccess: 'Excluído com sucesso. O contêiner está sendo reiniciado automaticamente.',
|
||||
customProviderHelper: 'Provedores de modelo personalizados não validam se a conta está disponível',
|
||||
},
|
||||
model: {
|
||||
|
||||
@@ -786,6 +786,7 @@ const message = {
|
||||
hermesChatDeleteConfirm: 'Удалить сессию {0}?',
|
||||
hermesChatDeleteSuccess: 'Сессия удалена',
|
||||
weixin: 'Weixin',
|
||||
qq: 'QQ',
|
||||
wecom: 'WeCom',
|
||||
dingtalk: 'DingTalk',
|
||||
feishu: 'Feishu',
|
||||
@@ -845,6 +846,8 @@ const message = {
|
||||
'Нажмите, чтобы запустить задачу входа по QR-коду. QR-код появится в журнале задач, а после успешного сканирования контейнер будет автоматически перезапущен.',
|
||||
channelAutoRestartHelper:
|
||||
'После сохранения контейнер будет автоматически перезапущен, чтобы настройки вступили в силу.',
|
||||
channelDeleteConfirm: 'Удалить конфигурацию канала {0}?',
|
||||
deleteAndRestartSuccess: 'Удаление выполнено. Контейнер автоматически перезапускается.',
|
||||
customProviderHelper: 'Для пользовательского провайдера модели доступность учетной записи не проверяется',
|
||||
},
|
||||
model: {
|
||||
|
||||
@@ -793,6 +793,7 @@ const message = {
|
||||
hermesChatDeleteConfirm: '{0} oturumu silinsin mi?',
|
||||
hermesChatDeleteSuccess: 'Oturum silindi',
|
||||
weixin: 'Weixin',
|
||||
qq: 'QQ',
|
||||
wecom: 'WeCom',
|
||||
dingtalk: 'DingTalk',
|
||||
feishu: 'Feishu',
|
||||
@@ -852,6 +853,8 @@ const message = {
|
||||
'QR giriş görevini başlatmak için tıklayın. QR kodu görev günlüğünde görünecek ve tarama başarılı olduktan sonra konteyner otomatik olarak yeniden başlatılacaktır.',
|
||||
channelAutoRestartHelper:
|
||||
'Kaydettiğinizde ayarların etkili olması için konteyner otomatik olarak yeniden başlatılır.',
|
||||
channelDeleteConfirm: '{0} kanal yapılandırması silinsin mi?',
|
||||
deleteAndRestartSuccess: 'Başarıyla silindi. Konteyner otomatik olarak yeniden başlatılıyor.',
|
||||
customProviderHelper: 'Özel model sağlayıcısında hesabın kullanılabilirliği doğrulanmaz',
|
||||
},
|
||||
model: {
|
||||
|
||||
@@ -740,6 +740,7 @@ const message = {
|
||||
hermesChatDeleteConfirm: '確認刪除會話 {0}?',
|
||||
hermesChatDeleteSuccess: '會話已刪除',
|
||||
weixin: '微信',
|
||||
qq: 'QQ',
|
||||
wecom: '企業微信',
|
||||
dingtalk: '釘釘',
|
||||
feishu: '飛書',
|
||||
@@ -795,6 +796,8 @@ const message = {
|
||||
scanConnect: '掃碼對接',
|
||||
scanConnectHelper: '點擊後將在任務日誌中顯示 QR Code,掃碼確認成功後將自動重新啟動容器。',
|
||||
channelAutoRestartHelper: '保存後將自動重新啟動容器以使設定生效。',
|
||||
channelDeleteConfirm: '確認刪除 {0} 頻道設定?',
|
||||
deleteAndRestartSuccess: '刪除成功,容器正在自動重新啟動。',
|
||||
customProviderHelper: '自訂模型供應商不驗證帳號是否可用',
|
||||
},
|
||||
model: {
|
||||
|
||||
@@ -735,6 +735,7 @@ const message = {
|
||||
hermesChatDeleteConfirm: '确认删除会话 {0}?',
|
||||
hermesChatDeleteSuccess: '会话已删除',
|
||||
weixin: '微信',
|
||||
qq: 'QQ',
|
||||
wecom: '企业微信',
|
||||
dingtalk: '钉钉',
|
||||
feishu: '飞书',
|
||||
@@ -789,6 +790,8 @@ const message = {
|
||||
scanConnect: '扫码对接',
|
||||
scanConnectHelper: '点击后将在任务日志中显示二维码,扫码确认成功后将自动重启容器。',
|
||||
channelAutoRestartHelper: '保存后将自动重启容器以使配置生效。',
|
||||
channelDeleteConfirm: '确认删除 {0} 频道配置?',
|
||||
deleteAndRestartSuccess: '删除成功,容器正在自动重启。',
|
||||
customProviderHelper: '自定义模型供应商不验证账号是否可用',
|
||||
},
|
||||
model: {
|
||||
|
||||
@@ -2,12 +2,6 @@
|
||||
<DrawerPro v-model="open" :header="$t('commons.button.create')" size="large" @close="handleClose">
|
||||
<el-form ref="formRef" :model="form" :rules="rules" label-position="top">
|
||||
<el-card class="form-card">
|
||||
<el-form-item :label="$t('commons.table.name')" prop="name">
|
||||
<el-input v-model="form.name" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('website.remark')" prop="remark">
|
||||
<el-input v-model="form.remark" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="`${$t('aiTools.agents.agent')}${$t('commons.table.type')}`" prop="agentType">
|
||||
<el-select v-model="form.agentType" @change="handleAgentTypeChange">
|
||||
<el-option :label="$t('aiTools.agents.openclawType')" value="openclaw" />
|
||||
@@ -15,6 +9,12 @@
|
||||
<el-option :label="$t('aiTools.agents.copawType')" value="copaw" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('commons.table.name')" prop="name">
|
||||
<el-input v-model="form.name" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('website.remark')" prop="remark">
|
||||
<el-input v-model="form.remark" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('aiTools.agents.appVersion')" prop="appVersion">
|
||||
<el-select v-model="form.appVersion" filterable>
|
||||
<el-option v-for="item in versions" :key="item" :label="item" :value="item" />
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
<template>
|
||||
<el-form ref="formRef" :model="form" :rules="rules" label-position="top">
|
||||
<el-form-item :label="t('commons.table.status')">
|
||||
<el-switch v-model="form.enabled" />
|
||||
<el-form ref="formRef" v-loading="deleting" :model="form" :rules="rules" label-position="top">
|
||||
<el-form-item v-if="configured">
|
||||
<el-button type="danger" plain :loading="deleting" @click="deleteChannel">
|
||||
{{ t('commons.button.delete') }}
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
<el-form-item label="Client ID" prop="clientId">
|
||||
<el-input v-model="form.clientId" />
|
||||
@@ -9,7 +11,15 @@
|
||||
<el-form-item label="Client Secret" prop="clientSecret">
|
||||
<el-input v-model="form.clientSecret" type="password" show-password />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('aiTools.agents.allowFrom')">
|
||||
<el-form-item :label="t('aiTools.agents.dmPolicy')" prop="dmPolicy">
|
||||
<el-select v-model="form.dmPolicy">
|
||||
<el-option :label="t('aiTools.agents.pairingCode')" value="pairing" />
|
||||
<el-option :label="t('aiTools.agents.policyOpen')" value="open" />
|
||||
<el-option :label="t('aiTools.agents.policyAllowlist')" value="allowlist" />
|
||||
<el-option :label="t('aiTools.agents.policyDisabled')" value="disabled" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="form.dmPolicy === 'allowlist'" :label="t('aiTools.agents.allowFrom')" prop="allowFromText">
|
||||
<el-input
|
||||
v-model="form.allowFromText"
|
||||
type="textarea"
|
||||
@@ -24,32 +34,51 @@
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
<el-alert type="info" :closable="false" :title="t('aiTools.agents.channelAutoRestartHelper')" />
|
||||
<template v-if="form.dmPolicy === 'pairing'">
|
||||
<el-form-item :label="t('aiTools.agents.pairingCode')">
|
||||
<el-input v-model="pairingCode" :placeholder="t('aiTools.agents.pairingCodePlaceholder')" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" plain :loading="approving" @click="approvePairing">
|
||||
{{ t('aiTools.agents.approvePairing') }}
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
</template>
|
||||
</el-form>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { reactive, ref } from 'vue';
|
||||
import type { FormInstance } from 'element-plus';
|
||||
import { ElMessageBox, type FormInstance } from 'element-plus';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { getAgentDingTalkConfig, updateAgentDingTalkConfig } from '@/api/modules/ai';
|
||||
import {
|
||||
approveAgentChannelPairing,
|
||||
deleteAgentChannelConfig,
|
||||
getAgentDingTalkConfig,
|
||||
updateAgentDingTalkConfig,
|
||||
} from '@/api/modules/ai';
|
||||
import { Rules } from '@/global/form-rules';
|
||||
import { MsgSuccess } from '@/utils/message';
|
||||
import { MsgSuccess, MsgWarning } from '@/utils/message';
|
||||
|
||||
interface DingTalkForm {
|
||||
enabled: boolean;
|
||||
clientId: string;
|
||||
clientSecret: string;
|
||||
dmPolicy: 'pairing' | 'open' | 'allowlist' | 'disabled';
|
||||
allowFromText: string;
|
||||
}
|
||||
|
||||
const { t } = useI18n();
|
||||
const formRef = ref<FormInstance>();
|
||||
const saving = ref(false);
|
||||
const approving = ref(false);
|
||||
const deleting = ref(false);
|
||||
const agentId = ref(0);
|
||||
const pairingCode = ref('');
|
||||
const configured = ref(false);
|
||||
const form = reactive<DingTalkForm>({
|
||||
enabled: true,
|
||||
clientId: '',
|
||||
clientSecret: '',
|
||||
dmPolicy: 'pairing',
|
||||
allowFromText: '',
|
||||
});
|
||||
|
||||
@@ -67,14 +96,29 @@ const parseTextList = (value: string): string[] => {
|
||||
const rules = reactive({
|
||||
clientId: [Rules.requiredInput],
|
||||
clientSecret: [Rules.requiredInput],
|
||||
dmPolicy: [Rules.requiredSelect],
|
||||
allowFromText: [
|
||||
{
|
||||
validator: (_rule, value, callback) => {
|
||||
if (form.dmPolicy === 'allowlist' && parseTextList(String(value || '')).length === 0) {
|
||||
callback(new Error(t('aiTools.agents.allowFromRequired')));
|
||||
return;
|
||||
}
|
||||
callback();
|
||||
},
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const load = async (id: number) => {
|
||||
agentId.value = id;
|
||||
pairingCode.value = '';
|
||||
const res = await getAgentDingTalkConfig({ agentId: id });
|
||||
form.enabled = res.data?.enabled ?? true;
|
||||
configured.value = !!res.data?.enabled;
|
||||
form.clientId = res.data?.bots?.[0]?.clientId || '';
|
||||
form.clientSecret = res.data?.bots?.[0]?.clientSecret || '';
|
||||
form.dmPolicy = (res.data?.dmPolicy as DingTalkForm['dmPolicy']) || 'pairing';
|
||||
form.allowFromText = (res.data?.allowFrom || []).join('\n');
|
||||
};
|
||||
|
||||
@@ -85,12 +129,11 @@ const save = async () => {
|
||||
await formRef.value.validate();
|
||||
saving.value = true;
|
||||
try {
|
||||
const allowFrom = parseTextList(form.allowFromText);
|
||||
await updateAgentDingTalkConfig({
|
||||
agentId: agentId.value,
|
||||
enabled: form.enabled,
|
||||
dmPolicy: allowFrom.length > 0 ? 'allowlist' : 'open',
|
||||
allowFrom,
|
||||
enabled: true,
|
||||
dmPolicy: form.dmPolicy,
|
||||
allowFrom: form.dmPolicy === 'allowlist' ? parseTextList(form.allowFromText) : [],
|
||||
groupPolicy: 'open',
|
||||
groupAllowFrom: [],
|
||||
separateSessionByConversation: true,
|
||||
@@ -110,11 +153,60 @@ const save = async () => {
|
||||
],
|
||||
});
|
||||
MsgSuccess(t('aiTools.agents.saveAndRestartSuccess'));
|
||||
configured.value = true;
|
||||
} finally {
|
||||
saving.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const deleteChannel = async () => {
|
||||
if (!agentId.value) {
|
||||
return;
|
||||
}
|
||||
await ElMessageBox.confirm(
|
||||
t('aiTools.agents.channelDeleteConfirm', [t('aiTools.agents.dingtalk')]),
|
||||
t('commons.msg.infoTitle'),
|
||||
{
|
||||
confirmButtonText: t('commons.button.confirm'),
|
||||
cancelButtonText: t('commons.button.cancel'),
|
||||
type: 'warning',
|
||||
},
|
||||
);
|
||||
deleting.value = true;
|
||||
try {
|
||||
await deleteAgentChannelConfig({
|
||||
agentId: agentId.value,
|
||||
type: 'dingtalk',
|
||||
});
|
||||
await load(agentId.value);
|
||||
MsgSuccess(t('aiTools.agents.deleteAndRestartSuccess'));
|
||||
} finally {
|
||||
deleting.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const approvePairing = async () => {
|
||||
if (!agentId.value) {
|
||||
return;
|
||||
}
|
||||
if (!pairingCode.value) {
|
||||
MsgWarning(t('aiTools.agents.pairingCodePlaceholder'));
|
||||
return;
|
||||
}
|
||||
approving.value = true;
|
||||
try {
|
||||
await approveAgentChannelPairing({
|
||||
agentId: agentId.value,
|
||||
type: 'dingtalk',
|
||||
pairingCode: pairingCode.value,
|
||||
});
|
||||
pairingCode.value = '';
|
||||
MsgSuccess(t('aiTools.agents.pairingApproveSuccess'));
|
||||
} finally {
|
||||
approving.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
defineExpose({
|
||||
load,
|
||||
});
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
<template>
|
||||
<el-form ref="formRef" :model="form" :rules="rules" label-position="top">
|
||||
<el-form ref="formRef" v-loading="deleting" :model="form" :rules="rules" label-position="top">
|
||||
<el-form-item v-if="configured">
|
||||
<el-button type="danger" plain :loading="deleting" @click="deleteChannel">
|
||||
{{ t('commons.button.delete') }}
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
<el-form-item label="Token" prop="token">
|
||||
<el-input v-model="form.token" show-password />
|
||||
</el-form-item>
|
||||
@@ -43,9 +48,14 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { reactive, ref } from 'vue';
|
||||
import type { FormInstance } from 'element-plus';
|
||||
import { ElMessageBox, type FormInstance } from 'element-plus';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { approveAgentChannelPairing, getAgentDiscordConfig, updateAgentDiscordConfig } from '@/api/modules/ai';
|
||||
import {
|
||||
approveAgentChannelPairing,
|
||||
deleteAgentChannelConfig,
|
||||
getAgentDiscordConfig,
|
||||
updateAgentDiscordConfig,
|
||||
} from '@/api/modules/ai';
|
||||
import { Rules } from '@/global/form-rules';
|
||||
import { MsgSuccess, MsgWarning } from '@/utils/message';
|
||||
|
||||
@@ -60,8 +70,10 @@ const { t } = useI18n();
|
||||
const formRef = ref<FormInstance>();
|
||||
const saving = ref(false);
|
||||
const approving = ref(false);
|
||||
const deleting = ref(false);
|
||||
const agentId = ref(0);
|
||||
const pairingCode = ref('');
|
||||
const configured = ref(false);
|
||||
const form = reactive<DiscordForm>({
|
||||
token: '',
|
||||
dmPolicy: 'pairing',
|
||||
@@ -96,7 +108,9 @@ const rules = reactive({
|
||||
|
||||
const load = async (id: number) => {
|
||||
agentId.value = id;
|
||||
pairingCode.value = '';
|
||||
const res = await getAgentDiscordConfig({ agentId: id });
|
||||
configured.value = !!res.data?.enabled;
|
||||
form.token = res.data?.bots?.[0]?.token || '';
|
||||
form.dmPolicy = (res.data?.dmPolicy as DiscordForm['dmPolicy']) || 'pairing';
|
||||
form.allowFromText = (res.data?.allowFrom || []).join('\n');
|
||||
@@ -132,11 +146,34 @@ const save = async () => {
|
||||
],
|
||||
});
|
||||
MsgSuccess(t('aiTools.agents.saveAndRestartSuccess'));
|
||||
configured.value = true;
|
||||
} finally {
|
||||
saving.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const deleteChannel = async () => {
|
||||
if (!agentId.value) {
|
||||
return;
|
||||
}
|
||||
await ElMessageBox.confirm(t('aiTools.agents.channelDeleteConfirm', ['Discord']), t('commons.msg.infoTitle'), {
|
||||
confirmButtonText: t('commons.button.confirm'),
|
||||
cancelButtonText: t('commons.button.cancel'),
|
||||
type: 'warning',
|
||||
});
|
||||
deleting.value = true;
|
||||
try {
|
||||
await deleteAgentChannelConfig({
|
||||
agentId: agentId.value,
|
||||
type: 'discord',
|
||||
});
|
||||
await load(agentId.value);
|
||||
MsgSuccess(t('aiTools.agents.deleteAndRestartSuccess'));
|
||||
} finally {
|
||||
deleting.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const approvePairing = async () => {
|
||||
if (!agentId.value) {
|
||||
return;
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
<template>
|
||||
<el-form ref="formRef" :model="form" :rules="rules" label-position="top">
|
||||
<el-form-item :label="t('commons.table.status')">
|
||||
<el-switch v-model="form.enabled" />
|
||||
<el-form ref="formRef" v-loading="deleting" :model="form" :rules="rules" label-position="top">
|
||||
<el-form-item v-if="configured">
|
||||
<el-button type="danger" plain :loading="deleting" @click="deleteChannel">
|
||||
{{ t('commons.button.delete') }}
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
<el-form-item label="App ID" prop="appId">
|
||||
<el-input v-model="form.appId" />
|
||||
@@ -53,14 +55,18 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { reactive, ref } from 'vue';
|
||||
import type { FormInstance } from 'element-plus';
|
||||
import { ElMessageBox, type FormInstance } from 'element-plus';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { approveAgentChannelPairing, getAgentFeishuConfig, updateAgentFeishuConfig } from '@/api/modules/ai';
|
||||
import {
|
||||
approveAgentChannelPairing,
|
||||
deleteAgentChannelConfig,
|
||||
getAgentFeishuConfig,
|
||||
updateAgentFeishuConfig,
|
||||
} from '@/api/modules/ai';
|
||||
import { Rules } from '@/global/form-rules';
|
||||
import { MsgSuccess, MsgWarning } from '@/utils/message';
|
||||
|
||||
interface FeishuForm {
|
||||
enabled: boolean;
|
||||
appId: string;
|
||||
appSecret: string;
|
||||
dmPolicy: 'pairing' | 'open' | 'allowlist';
|
||||
@@ -72,10 +78,11 @@ const { t } = useI18n();
|
||||
const formRef = ref<FormInstance>();
|
||||
const saving = ref(false);
|
||||
const approving = ref(false);
|
||||
const deleting = ref(false);
|
||||
const agentId = ref(0);
|
||||
const pairingCode = ref('');
|
||||
const configured = ref(false);
|
||||
const form = reactive<FeishuForm>({
|
||||
enabled: true,
|
||||
appId: '',
|
||||
appSecret: '',
|
||||
dmPolicy: 'pairing',
|
||||
@@ -117,7 +124,7 @@ const load = async (id: number) => {
|
||||
agentId.value = id;
|
||||
pairingCode.value = '';
|
||||
const res = await getAgentFeishuConfig({ agentId: id });
|
||||
form.enabled = res.data?.enabled ?? true;
|
||||
configured.value = !!res.data?.enabled;
|
||||
form.appId = res.data?.bots?.[0]?.appId || '';
|
||||
form.appSecret = res.data?.bots?.[0]?.appSecret || '';
|
||||
form.dmPolicy = (res.data?.bots?.[0]?.dmPolicy as FeishuForm['dmPolicy']) || 'pairing';
|
||||
@@ -135,7 +142,7 @@ const save = async () => {
|
||||
const allowFrom = parseTextList(form.allowFromText);
|
||||
await updateAgentFeishuConfig({
|
||||
agentId: agentId.value,
|
||||
enabled: form.enabled,
|
||||
enabled: true,
|
||||
threadSession: true,
|
||||
replyMode: 'auto',
|
||||
streaming: false,
|
||||
@@ -156,11 +163,38 @@ const save = async () => {
|
||||
],
|
||||
});
|
||||
MsgSuccess(t('aiTools.agents.saveAndRestartSuccess'));
|
||||
configured.value = true;
|
||||
} finally {
|
||||
saving.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const deleteChannel = async () => {
|
||||
if (!agentId.value) {
|
||||
return;
|
||||
}
|
||||
await ElMessageBox.confirm(
|
||||
t('aiTools.agents.channelDeleteConfirm', [t('aiTools.agents.feishu')]),
|
||||
t('commons.msg.infoTitle'),
|
||||
{
|
||||
confirmButtonText: t('commons.button.confirm'),
|
||||
cancelButtonText: t('commons.button.cancel'),
|
||||
type: 'warning',
|
||||
},
|
||||
);
|
||||
deleting.value = true;
|
||||
try {
|
||||
await deleteAgentChannelConfig({
|
||||
agentId: agentId.value,
|
||||
type: 'feishu',
|
||||
});
|
||||
await load(agentId.value);
|
||||
MsgSuccess(t('aiTools.agents.deleteAndRestartSuccess'));
|
||||
} finally {
|
||||
deleting.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const approvePairing = async () => {
|
||||
if (!agentId.value) {
|
||||
return;
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
<template>
|
||||
<el-form ref="formRef" :model="form" :rules="rules" label-position="top">
|
||||
<el-form-item :label="t('commons.table.status')">
|
||||
<el-switch v-model="form.enabled" />
|
||||
<el-form ref="formRef" v-loading="deleting" :model="form" :rules="rules" label-position="top">
|
||||
<el-form-item v-if="configured">
|
||||
<el-button type="danger" plain :loading="deleting" @click="deleteChannel">
|
||||
{{ t('commons.button.delete') }}
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
<el-form-item label="App ID" prop="appId">
|
||||
<el-input v-model="form.appId" />
|
||||
@@ -67,14 +69,18 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { reactive, ref } from 'vue';
|
||||
import type { FormInstance } from 'element-plus';
|
||||
import { ElMessageBox, type FormInstance } from 'element-plus';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { approveAgentChannelPairing, getAgentQQBotConfig, updateAgentQQBotConfig } from '@/api/modules/ai';
|
||||
import {
|
||||
approveAgentChannelPairing,
|
||||
deleteAgentChannelConfig,
|
||||
getAgentQQBotConfig,
|
||||
updateAgentQQBotConfig,
|
||||
} from '@/api/modules/ai';
|
||||
import { Rules } from '@/global/form-rules';
|
||||
import { MsgSuccess, MsgWarning } from '@/utils/message';
|
||||
|
||||
interface QQBotForm {
|
||||
enabled: boolean;
|
||||
appId: string;
|
||||
clientSecret: string;
|
||||
dmPolicy: 'pairing' | 'open' | 'allowlist' | 'disabled';
|
||||
@@ -87,10 +93,11 @@ const { t } = useI18n();
|
||||
const formRef = ref<FormInstance>();
|
||||
const saving = ref(false);
|
||||
const approving = ref(false);
|
||||
const deleting = ref(false);
|
||||
const agentId = ref(0);
|
||||
const pairingCode = ref('');
|
||||
const configured = ref(false);
|
||||
const form = reactive<QQBotForm>({
|
||||
enabled: true,
|
||||
appId: '',
|
||||
clientSecret: '',
|
||||
dmPolicy: 'open',
|
||||
@@ -145,7 +152,7 @@ const load = async (id: number) => {
|
||||
agentId.value = id;
|
||||
pairingCode.value = '';
|
||||
const res = await getAgentQQBotConfig({ agentId: id });
|
||||
form.enabled = res.data?.enabled ?? true;
|
||||
configured.value = !!res.data?.enabled;
|
||||
form.appId = res.data?.bots?.[0]?.appId || '';
|
||||
form.clientSecret = res.data?.bots?.[0]?.clientSecret || '';
|
||||
form.dmPolicy = (res.data?.dmPolicy as QQBotForm['dmPolicy']) || 'open';
|
||||
@@ -163,7 +170,7 @@ const save = async () => {
|
||||
try {
|
||||
await updateAgentQQBotConfig({
|
||||
agentId: agentId.value,
|
||||
enabled: form.enabled,
|
||||
enabled: true,
|
||||
dmPolicy: form.dmPolicy,
|
||||
allowFrom: parseTextList(form.allowFromText),
|
||||
groupPolicy: form.groupPolicy,
|
||||
@@ -182,11 +189,38 @@ const save = async () => {
|
||||
],
|
||||
});
|
||||
MsgSuccess(t('aiTools.agents.saveAndRestartSuccess'));
|
||||
configured.value = true;
|
||||
} finally {
|
||||
saving.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const deleteChannel = async () => {
|
||||
if (!agentId.value) {
|
||||
return;
|
||||
}
|
||||
await ElMessageBox.confirm(
|
||||
t('aiTools.agents.channelDeleteConfirm', [t('aiTools.agents.qq')]),
|
||||
t('commons.msg.infoTitle'),
|
||||
{
|
||||
confirmButtonText: t('commons.button.confirm'),
|
||||
cancelButtonText: t('commons.button.cancel'),
|
||||
type: 'warning',
|
||||
},
|
||||
);
|
||||
deleting.value = true;
|
||||
try {
|
||||
await deleteAgentChannelConfig({
|
||||
agentId: agentId.value,
|
||||
type: 'qqbot',
|
||||
});
|
||||
await load(agentId.value);
|
||||
MsgSuccess(t('aiTools.agents.deleteAndRestartSuccess'));
|
||||
} finally {
|
||||
deleting.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const approvePairing = async () => {
|
||||
if (!agentId.value) {
|
||||
return;
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
<template>
|
||||
<el-form ref="formRef" :model="form" :rules="rules" label-position="top">
|
||||
<el-form ref="formRef" v-loading="deleting" :model="form" :rules="rules" label-position="top">
|
||||
<el-form-item v-if="configured">
|
||||
<el-button type="danger" plain :loading="deleting" @click="deleteChannel">
|
||||
{{ t('commons.button.delete') }}
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
<el-form-item label="Bot Token" prop="botToken">
|
||||
<el-input v-model="form.botToken" show-password />
|
||||
</el-form-item>
|
||||
@@ -43,9 +48,14 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { reactive, ref } from 'vue';
|
||||
import type { FormInstance } from 'element-plus';
|
||||
import { ElMessageBox, type FormInstance } from 'element-plus';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { approveAgentChannelPairing, getAgentTelegramConfig, updateAgentTelegramConfig } from '@/api/modules/ai';
|
||||
import {
|
||||
approveAgentChannelPairing,
|
||||
deleteAgentChannelConfig,
|
||||
getAgentTelegramConfig,
|
||||
updateAgentTelegramConfig,
|
||||
} from '@/api/modules/ai';
|
||||
import { Rules } from '@/global/form-rules';
|
||||
import { MsgSuccess, MsgWarning } from '@/utils/message';
|
||||
|
||||
@@ -60,8 +70,10 @@ const { t } = useI18n();
|
||||
const formRef = ref<FormInstance>();
|
||||
const saving = ref(false);
|
||||
const approving = ref(false);
|
||||
const deleting = ref(false);
|
||||
const agentId = ref(0);
|
||||
const pairingCode = ref('');
|
||||
const configured = ref(false);
|
||||
const form = reactive<TelegramForm>({
|
||||
botToken: '',
|
||||
dmPolicy: 'pairing',
|
||||
@@ -96,7 +108,9 @@ const rules = reactive({
|
||||
|
||||
const load = async (id: number) => {
|
||||
agentId.value = id;
|
||||
pairingCode.value = '';
|
||||
const res = await getAgentTelegramConfig({ agentId: id });
|
||||
configured.value = !!res.data?.enabled;
|
||||
form.botToken = res.data?.bots?.[0]?.botToken || '';
|
||||
form.dmPolicy = (res.data?.dmPolicy as TelegramForm['dmPolicy']) || 'pairing';
|
||||
form.allowFromText = (res.data?.allowFrom || []).join('\n');
|
||||
@@ -137,11 +151,34 @@ const save = async () => {
|
||||
],
|
||||
});
|
||||
MsgSuccess(t('aiTools.agents.saveAndRestartSuccess'));
|
||||
configured.value = true;
|
||||
} finally {
|
||||
saving.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const deleteChannel = async () => {
|
||||
if (!agentId.value) {
|
||||
return;
|
||||
}
|
||||
await ElMessageBox.confirm(t('aiTools.agents.channelDeleteConfirm', ['Telegram']), t('commons.msg.infoTitle'), {
|
||||
confirmButtonText: t('commons.button.confirm'),
|
||||
cancelButtonText: t('commons.button.cancel'),
|
||||
type: 'warning',
|
||||
});
|
||||
deleting.value = true;
|
||||
try {
|
||||
await deleteAgentChannelConfig({
|
||||
agentId: agentId.value,
|
||||
type: 'telegram',
|
||||
});
|
||||
await load(agentId.value);
|
||||
MsgSuccess(t('aiTools.agents.deleteAndRestartSuccess'));
|
||||
} finally {
|
||||
deleting.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const approvePairing = async () => {
|
||||
if (!agentId.value) {
|
||||
return;
|
||||
|
||||
@@ -1,7 +1,15 @@
|
||||
<template>
|
||||
<el-form ref="formRef" :model="form" :rules="rules" label-position="top">
|
||||
<el-form-item :label="t('commons.table.status')">
|
||||
<el-switch v-model="form.enabled" />
|
||||
<el-form ref="formRef" v-loading="deleting" :model="form" :rules="rules" label-position="top">
|
||||
<el-form-item v-if="configured">
|
||||
<el-button type="danger" plain :loading="deleting" @click="deleteChannel">
|
||||
{{ t('commons.button.delete') }}
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('aiTools.agents.botId')" prop="botId">
|
||||
<el-input v-model="form.botId" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('setting.secret')" prop="secret">
|
||||
<el-input v-model="form.secret" type="password" show-password />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('aiTools.agents.dmPolicy')" prop="dmPolicy">
|
||||
<el-select v-model="form.dmPolicy">
|
||||
@@ -40,12 +48,6 @@
|
||||
/>
|
||||
<span class="input-help">{{ t('aiTools.agents.groupAllowFromHelper') }}</span>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('aiTools.agents.botId')" prop="botId">
|
||||
<el-input v-model="form.botId" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('setting.secret')" prop="secret">
|
||||
<el-input v-model="form.secret" type="password" show-password />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" :loading="saving" @click="save">
|
||||
{{ t('commons.button.save') }}
|
||||
@@ -67,14 +69,18 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { reactive, ref } from 'vue';
|
||||
import type { FormInstance } from 'element-plus';
|
||||
import { ElMessageBox, type FormInstance } from 'element-plus';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { approveAgentChannelPairing, getAgentWecomConfig, updateAgentWecomConfig } from '@/api/modules/ai';
|
||||
import {
|
||||
approveAgentChannelPairing,
|
||||
deleteAgentChannelConfig,
|
||||
getAgentWecomConfig,
|
||||
updateAgentWecomConfig,
|
||||
} from '@/api/modules/ai';
|
||||
import { Rules } from '@/global/form-rules';
|
||||
import { MsgSuccess, MsgWarning } from '@/utils/message';
|
||||
|
||||
interface WecomForm {
|
||||
enabled: boolean;
|
||||
dmPolicy: 'pairing' | 'open' | 'allowlist' | 'disabled';
|
||||
allowFromText: string;
|
||||
groupPolicy: 'open' | 'allowlist' | 'disabled';
|
||||
@@ -87,10 +93,11 @@ const { t } = useI18n();
|
||||
const formRef = ref<FormInstance>();
|
||||
const saving = ref(false);
|
||||
const approving = ref(false);
|
||||
const deleting = ref(false);
|
||||
const agentId = ref(0);
|
||||
const pairingCode = ref('');
|
||||
const configured = ref(false);
|
||||
const form = reactive<WecomForm>({
|
||||
enabled: true,
|
||||
dmPolicy: 'pairing',
|
||||
allowFromText: '',
|
||||
groupPolicy: 'open',
|
||||
@@ -139,7 +146,7 @@ const load = async (id: number) => {
|
||||
agentId.value = id;
|
||||
pairingCode.value = '';
|
||||
const res = await getAgentWecomConfig({ agentId: id });
|
||||
form.enabled = res.data?.enabled ?? true;
|
||||
configured.value = !!res.data?.enabled;
|
||||
form.dmPolicy = (res.data?.dmPolicy as WecomForm['dmPolicy']) || 'pairing';
|
||||
form.allowFromText = (res.data?.allowFrom || []).join('\n');
|
||||
form.groupPolicy = (res.data?.groupPolicy as WecomForm['groupPolicy']) || 'open';
|
||||
@@ -157,7 +164,7 @@ const save = async () => {
|
||||
try {
|
||||
await updateAgentWecomConfig({
|
||||
agentId: agentId.value,
|
||||
enabled: form.enabled,
|
||||
enabled: true,
|
||||
dmPolicy: form.dmPolicy,
|
||||
allowFrom: parseTextList(form.allowFromText),
|
||||
groupPolicy: form.groupPolicy,
|
||||
@@ -166,11 +173,38 @@ const save = async () => {
|
||||
secret: form.secret,
|
||||
});
|
||||
MsgSuccess(t('aiTools.agents.saveAndRestartSuccess'));
|
||||
configured.value = true;
|
||||
} finally {
|
||||
saving.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const deleteChannel = async () => {
|
||||
if (!agentId.value) {
|
||||
return;
|
||||
}
|
||||
await ElMessageBox.confirm(
|
||||
t('aiTools.agents.channelDeleteConfirm', [t('aiTools.agents.wecom')]),
|
||||
t('commons.msg.infoTitle'),
|
||||
{
|
||||
confirmButtonText: t('commons.button.confirm'),
|
||||
cancelButtonText: t('commons.button.cancel'),
|
||||
type: 'warning',
|
||||
},
|
||||
);
|
||||
deleting.value = true;
|
||||
try {
|
||||
await deleteAgentChannelConfig({
|
||||
agentId: agentId.value,
|
||||
type: 'wecom',
|
||||
});
|
||||
await load(agentId.value);
|
||||
MsgSuccess(t('aiTools.agents.deleteAndRestartSuccess'));
|
||||
} finally {
|
||||
deleting.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const approvePairing = async () => {
|
||||
if (!agentId.value) {
|
||||
return;
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
<template>
|
||||
<el-form label-position="top">
|
||||
<el-form v-loading="deleting" label-position="top">
|
||||
<el-form-item v-if="configured">
|
||||
<el-button type="danger" plain :loading="deleting" @click="deleteChannel">
|
||||
{{ t('commons.button.delete') }}
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" :loading="loggingIn" @click="loginChannel">
|
||||
{{ t('aiTools.agents.scanConnect') }}
|
||||
@@ -12,19 +17,26 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue';
|
||||
import { ElMessageBox } from 'element-plus';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { loginAgentWeixinChannel } from '@/api/modules/ai';
|
||||
import { deleteAgentChannelConfig, getAgentWeixinConfig, loginAgentWeixinChannel } from '@/api/modules/ai';
|
||||
import TaskLog from '@/components/log/task/index.vue';
|
||||
import { newUUID } from '@/utils/id';
|
||||
import { MsgSuccess } from '@/utils/message';
|
||||
|
||||
const props = defineProps<{
|
||||
agentId: number;
|
||||
}>();
|
||||
const { t } = useI18n();
|
||||
const loggingIn = ref(false);
|
||||
const deleting = ref(false);
|
||||
const loginTaskLogRef = ref();
|
||||
const configured = ref(false);
|
||||
|
||||
const load = async () => {};
|
||||
const load = async () => {
|
||||
const res = await getAgentWeixinConfig({ agentId: props.agentId });
|
||||
configured.value = !!res.data?.enabled;
|
||||
};
|
||||
|
||||
const loginChannel = async () => {
|
||||
const taskID = newUUID();
|
||||
@@ -34,12 +46,36 @@ const loginChannel = async () => {
|
||||
agentId: props.agentId,
|
||||
taskID,
|
||||
});
|
||||
configured.value = true;
|
||||
loginTaskLogRef.value?.openWithTaskID(taskID);
|
||||
} finally {
|
||||
loggingIn.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const deleteChannel = async () => {
|
||||
await ElMessageBox.confirm(
|
||||
t('aiTools.agents.channelDeleteConfirm', [t('aiTools.agents.weixin')]),
|
||||
t('commons.msg.infoTitle'),
|
||||
{
|
||||
confirmButtonText: t('commons.button.confirm'),
|
||||
cancelButtonText: t('commons.button.cancel'),
|
||||
type: 'warning',
|
||||
},
|
||||
);
|
||||
deleting.value = true;
|
||||
try {
|
||||
await deleteAgentChannelConfig({
|
||||
agentId: props.agentId,
|
||||
type: 'weixin',
|
||||
});
|
||||
await load();
|
||||
MsgSuccess(t('aiTools.agents.deleteAndRestartSuccess'));
|
||||
} finally {
|
||||
deleting.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
defineExpose({
|
||||
load,
|
||||
});
|
||||
|
||||
@@ -95,12 +95,9 @@
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column :label="$t('menu.website')" min-width="180" show-overflow-tooltip>
|
||||
<el-table-column :label="$t('menu.website')" min-width="180">
|
||||
<template #default="{ row }">
|
||||
<div v-if="row.websiteId > 0" class="website-link-cell">
|
||||
<el-text type="primary" class="cursor-pointer" @click="openWebsite(row)">
|
||||
{{ getWebsiteDisplayName(row) }}
|
||||
</el-text>
|
||||
<el-popover
|
||||
placement="right"
|
||||
trigger="hover"
|
||||
@@ -108,7 +105,13 @@
|
||||
@before-enter="loadWebsiteDomains(row.websiteId)"
|
||||
>
|
||||
<template #reference>
|
||||
<el-button link icon="Promotion" class="ml-2.5"></el-button>
|
||||
<el-text
|
||||
type="primary"
|
||||
class="cursor-pointer website-link-cell__name"
|
||||
@click="openWebsite(row)"
|
||||
>
|
||||
{{ getWebsiteDisplayName(row) }}
|
||||
</el-text>
|
||||
</template>
|
||||
<table v-if="getWebsiteBaseUrls(row).length > 0">
|
||||
<tbody>
|
||||
@@ -130,6 +133,7 @@
|
||||
v-if="canUnbindWebsite(row)"
|
||||
link
|
||||
type="primary"
|
||||
class="website-link-cell__unbind"
|
||||
@click="onUnbindWebsite(row)"
|
||||
>
|
||||
{{ $t('commons.button.unbind') }}
|
||||
@@ -714,7 +718,16 @@ onMounted(async () => {
|
||||
|
||||
.website-link-cell {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.website-link-cell__name {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.website-link-cell__unbind {
|
||||
margin-left: 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user