diff --git a/admin/server/source/system/api.go b/admin/server/source/system/api.go
index d0812e645..63b81be93 100644
--- a/admin/server/source/system/api.go
+++ b/admin/server/source/system/api.go
@@ -244,10 +244,12 @@ func (i *initApi) InitializeData(ctx context.Context) (context.Context, error) {
{ApiGroup: "模型管理", Method: "PATCH", Path: "/gaia/proxy/*", Description: "中转API(第三方)-PATCH"},
{ApiGroup: "模型管理", Method: "DELETE", Path: "/gaia/proxy/*", Description: "中转API(第三方)-DELETE"},
// Extend Stop: model provider
- // 转发 Token 管理
+
+ // Extend Start: 转发集成 (forward tokens)
{ApiGroup: "转发集成", Method: "GET", Path: "/gaia/system/forward-tokens", Description: "获取转发 Token 列表"},
{ApiGroup: "转发集成", Method: "POST", Path: "/gaia/system/forward-tokens", Description: "新增转发 Token"},
{ApiGroup: "转发集成", Method: "DELETE", Path: "/gaia/system/forward-tokens/:id", Description: "删除转发 Token"},
+ // Extend Stop: 转发集成
}
if err := db.Create(&entities).Error; err != nil {
return ctx, errors.Wrap(err, sysModel.SysApi{}.TableName()+"表数据初始化失败!")
diff --git a/admin/server/source/system/casbin.go b/admin/server/source/system/casbin.go
index dacbfc9a7..888c838b8 100644
--- a/admin/server/source/system/casbin.go
+++ b/admin/server/source/system/casbin.go
@@ -403,6 +403,15 @@ func (i *initCasbin) InitializeData(ctx context.Context) (context.Context, error
{Ptype: "p", V0: "8881", V1: "/gaia/proxy/*", V2: "PATCH"},
{Ptype: "p", V0: "8881", V1: "/gaia/proxy/*", V2: "DELETE"},
// Extend Stop: model provider
+
+ // Extend Start: 转发集成 (forward tokens)
+ {Ptype: "p", V0: "888", V1: "/gaia/system/forward-tokens", V2: "GET"},
+ {Ptype: "p", V0: "888", V1: "/gaia/system/forward-tokens", V2: "POST"},
+ {Ptype: "p", V0: "888", V1: "/gaia/system/forward-tokens/:id", V2: "DELETE"},
+ {Ptype: "p", V0: "8881", V1: "/gaia/system/forward-tokens", V2: "GET"},
+ {Ptype: "p", V0: "8881", V1: "/gaia/system/forward-tokens", V2: "POST"},
+ {Ptype: "p", V0: "8881", V1: "/gaia/system/forward-tokens/:id", V2: "DELETE"},
+ // Extend Stop: 转发集成
}
if err := db.Create(&entities).Error; err != nil {
return ctx, errors.Wrap(err, "Casbin 表 ("+i.InitializerName()+") 数据初始化失败!")
diff --git a/admin/web/src/view/systemIntegrated/dingTalk/index.vue b/admin/web/src/view/systemIntegrated/dingTalk/index.vue
index 6632bba20..9c10403f3 100644
--- a/admin/web/src/view/systemIntegrated/dingTalk/index.vue
+++ b/admin/web/src/view/systemIntegrated/dingTalk/index.vue
@@ -438,7 +438,7 @@
第三方钉钉 ID 匹配用户 API
- 当本地表中找不到钉钉 ID 对应用户时,调用此 API 通过 ding_id 获取用户名
+ 当本地表中找不到钉钉 ID 对应用户时,调用此 API 通过 ding_id 获取用户名。开启或修改后请点击下方「保存」按钮。
启用:
@@ -470,19 +470,23 @@
{{ dingIdApiConfig.response_user_name_path || '未配置' }}
+
+
+ 保存「转发集成」与「钉钉 ID 匹配 API」配置
+
+
-
+
-
输入 Token 明文,系统将存储其 SHA256 哈希。Token 仅展示一次,请妥善保管。
-
+
点击「生成并保存」将随机生成 Token,保存后会自动复制到系统剪贴板,请粘贴到安全位置保管。Token 仅展示一次。
-
+
复制
@@ -490,9 +494,9 @@
- 取消
- 确认创建
- 完成
+ 取消
+ 生成并保存
+ 完成
@@ -513,8 +517,11 @@
import { ref, computed, watch } from 'vue'
import { ElMessage } from 'element-plus'
import { QuestionFilled } from '@element-plus/icons-vue'
+import { useClipboard } from '@vueuse/core'
import { getSystemDingTalk, setSystemDingTalk, getForwardTokens, createForwardToken, deleteForwardToken } from "@/api/gaia/system";
+const { copy: copyToClipboard, isSupported: isClipboardSupported } = useClipboard()
+
defineOptions({
name: 'IntegratedDingTalk',
})
@@ -570,9 +577,8 @@ const dingIdApiConfig = ref({
// 转发 Token 列表
const forwardTokenList = ref([])
-// 新增 Token 弹窗
+// 新增 Token 弹窗(前端随机生成 → 保存 → 复制到剪贴板)
const showCreateTokenDialog = ref(false)
-const newTokenInput = ref('')
const newTokenValue = ref('')
const creatingToken = ref(false)
@@ -606,24 +612,35 @@ const generateToken = () => {
return token
}
-// 复制 Token
-const copyToken = (token) => {
- navigator.clipboard.writeText(token).then(() => {
+// 复制 Token(使用 VueUse useClipboard,并提示)
+const copyToken = async (token) => {
+ if (!token) return
+ try {
+ if (isClipboardSupported.value) {
+ await copyToClipboard(token)
+ } else {
+ await navigator.clipboard.writeText(token)
+ }
ElMessage({ type: 'success', message: 'Token 已复制到剪贴板' })
- })
+ } catch (e) {
+ ElMessage({ type: 'warning', message: '复制失败,请手动复制' })
+ }
}
-// 创建 Token
+// 生成并保存 Token:前端随机生成 → 调用接口保存(后端存 SHA256)→ 自动复制到剪贴板并提示
const handleCreateToken = async () => {
+ const token = generateToken()
creatingToken.value = true
- const token = newTokenInput.value.trim() || generateToken()
- const res = await createForwardToken({ token })
- creatingToken.value = false
- if (res.code === 0) {
- newTokenValue.value = res.data?.token || token
- ElMessage({ type: 'success', message: 'Token 创建成功' })
- } else {
- ElMessage({ type: 'error', message: res.msg || '创建失败' })
+ try {
+ const res = await createForwardToken({ token })
+ if (res.code === 0) {
+ newTokenValue.value = res.data?.token ?? token
+ await copyToken(newTokenValue.value)
+ } else {
+ ElMessage({ type: 'error', message: res.msg || '保存失败' })
+ }
+ } finally {
+ creatingToken.value = false
}
}
@@ -648,7 +665,7 @@ const handleDeleteToken = async () => {
showDeleteTokenDialog.value = false
deleteTokenPassword.value = ''
deletingTokenId.value = ''
- await loadForwardTokens()
+ await initForm()
} else {
ElMessage({ type: 'error', message: res.msg || '删除失败' })
}
@@ -799,6 +816,11 @@ const handleStatusChange = (val) => {
update();
}
+// 仅保存「转发集成」与「第三方钉钉 ID 匹配用户 API」配置(与主保存共用 update,保证整份 config 一致)
+const saveForwardAndDingIdConfig = () => {
+ update()
+}
+
// 掩码显示文本
const openConfig = () => {
openEdit.value = true
diff --git a/docker/docker-compose.dify-plus.yaml b/docker/docker-compose.dify-plus.yaml
index b74bbd5d9..f4a3ef3f8 100644
--- a/docker/docker-compose.dify-plus.yaml
+++ b/docker/docker-compose.dify-plus.yaml
@@ -1686,6 +1686,13 @@ services:
JWT_SIGNING_KEY: ${SECRET_KEY:-sk-9f73s3ljTXVcMT3Blb3ljTqtsKiGHXVcMT3BlbkFJLK7U}
SECRET_KEY: ${SECRET_KEY:-sk-9f73s3ljTXVcMT3Blb3ljTqtsKiGHXVcMT3BlbkFJLK7U}
EMAIL_DOMAIN: ${EMAIL_DOMAIN:-}
+ # 与 Dify 使用同一套数据库配置,避免密码不一致导致认证失败
+ DB_TYPE: ${DB_TYPE:-postgresql}
+ DB_HOST: ${DB_HOST:-db_postgres}
+ DB_PORT: ${DB_PORT:-5432}
+ DB_USERNAME: ${DB_USERNAME:-postgres}
+ DB_PASSWORD: ${DB_PASSWORD:-difyai123456}
+ DB_DATABASE: ${DB_DATABASE:-dify}
ports:
- '8888:8888'
depends_on: