Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions ui/src/api/API_README.md
Original file line number Diff line number Diff line change
Expand Up @@ -383,6 +383,15 @@ Workspace 与 System 资源管理的 `application/application.ts` 提供 `getAcc
概览使用 `access_token` 拼接 Web 链接,不使用智能体 ID 或 API Key 替代;API 文档地址使用 Chat 部署前缀。
两范围的 `putAccessToken` 向同一路径提交 `{ access_token_reset: true }` 重置链接,或 `{ is_active: boolean }` 修改 Web 访问状态;
载荷复用 `ApplicationAccessTokenPayload`,使用返回的访问凭证与启用状态回显,不二次查询。
访问限制复用上述 GET/PUT,读取与保存 `access_num`、`white_active`、`white_list`、`authentication` 和
`authentication_value`。提问次数为 0~10000000 的整数;社区版仅编辑认证开关,保留已有 `authentication_value`,
不生成登录配置字段,身份认证读写待后台联调。Xpack 版认证配置使用 `type: 'login'`、`login_value`、
`max_attempts`,保留原配置中的其他字段;已有认证 `type` 不自动转换,缺省为 `login`。
保存访问限制携带原 `language`,避免后台省略字段时清空语言配置。
默认登录方式与账号锁定暂按 `authentication_value.default_value / failed_attempts / lock_time` 提交,
字段及认证配置生效能力待后台联调;前端不因认证字段缺失禁用编辑。System 资源管理的访问限制仍需部署环境联调。
Xpack 版可用登录方式统一调用 `system/chat-management/chat-user-auth.ts` 的 `getChatUserAuthType`,
GET `/chat_user/auth/types` 返回 `{ label, value }[]`,两种智能体入口共用。

展示设置共用 `ApplicationDisplaySetting`;`ApplicationAccessToken` 兼容可选展示字段,缺失字段由弹窗补齐默认值。
两范围的 `putDisplaySetting` 沿用 V2 的 `/<applicationId>/setting` PUT 接口,提交 FormData:
Expand Down
7 changes: 5 additions & 2 deletions ui/src/api/admin/system/chat-management/chat-user-auth.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import { get, post, put } from '../../core/request'
import type { AuthProviderSettingPayload, AuthProviderType } from '@/api/types'
import type { AuthProviderSettingPayload, AuthProviderType, OptionItem } from '@/api/types'

const prefix = '/chat_user/auth'

/** 获取对话用户可用的登录方式。 */
const getChatUserAuthType = () => get<OptionItem<string>[]>(`${prefix}/types`)

/** 获取对话用户指定认证源配置。 */
const getAuthSetting = (authType: AuthProviderType) => {
return get<Partial<AuthProviderSettingPayload>>(`${prefix}/${authType}/detail`)
Expand All @@ -17,4 +20,4 @@ const postAuthSettingConnection = (payload: AuthProviderSettingPayload) => {
const putAuthSetting = (authType: AuthProviderType, payload: AuthProviderSettingPayload) => {
return put<AuthProviderSettingPayload, boolean>(`${prefix}/${authType}/info`, payload)
}
export default { getAuthSetting, postAuthSettingConnection, putAuthSetting }
export default { getChatUserAuthType, getAuthSetting, postAuthSettingConnection, putAuthSetting }
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,13 @@ const putApplicationPortal = (applicationId: string, isPortal: boolean) => Promi
/** 获取 System 资源管理智能体详情。 */
const getApplicationDetail = (applicationId: string) => get<ApplicationDetail>(`${prefix}/${applicationId}`)

/** 获取 System 资源管理智能体公开访问凭证。 */
/** 获取 System 资源管理智能体公开访问凭证与访问限制。 */
// TODO:访问限制接口待联调。
// TODO:社区版身份认证读写待后台联调。
const getAccessToken = (applicationId: string) => get<ApplicationAccessToken>(`${prefix}/${applicationId}/access_token`)

/** 修改 System 资源管理智能体公开访问状态或重置凭证,返回更新后的配置。 */
/** 修改 System 资源管理智能体访问配置或重置凭证,返回更新后的配置。 */
// TODO:身份认证、默认登录方式及账号锁定配置待后台联调。
const putAccessToken = (applicationId: string, payload: ApplicationAccessTokenPayload) =>
put<ApplicationAccessTokenPayload, ApplicationAccessToken>(`${prefix}/${applicationId}/access_token`, payload)

Expand Down
6 changes: 4 additions & 2 deletions ui/src/api/admin/workspace/application/application.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,12 @@ const getApplicationDetail = (applicationId: string) => {
return get<ApplicationDetail>(`${getPrefix()}/${applicationId}`)
}

/** 获取智能体公开访问凭证。 */
/** 获取智能体公开访问凭证与访问限制。 */
// TODO:社区版身份认证读写待后台联调。
const getAccessToken = (applicationId: string) => get<ApplicationAccessToken>(`${getPrefix()}/${applicationId}/access_token`)

/** 修改智能体公开访问状态或重置凭证,返回更新后的配置。 */
/** 修改智能体访问配置或重置凭证,返回更新后的配置。 */
// TODO:身份认证、默认登录方式及账号锁定配置待后台联调。
const putAccessToken = (applicationId: string, payload: ApplicationAccessTokenPayload) =>
put<ApplicationAccessTokenPayload, ApplicationAccessToken>(`${getPrefix()}/${applicationId}/access_token`, payload)

Expand Down
26 changes: 24 additions & 2 deletions ui/src/api/types/application.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,17 +49,39 @@ export interface ApplicationDisplaySetting {
show_user_avatar: boolean
}

/** 智能体公开访问链接使用的凭证。 */
/** 智能体登录认证配置;保留后端返回的其他认证字段。 */
export interface ApplicationAuthenticationConfig extends Dict<unknown> {
type?: 'login' | 'password'
login_value?: string[]
max_attempts?: number
// TODO:默认登录方式、账号锁定字段待后台联调。
default_value?: string
failed_attempts?: number
lock_time?: number
}

/** 智能体公开访问凭证与访问限制配置。 */
export interface ApplicationAccessToken extends Partial<ApplicationDisplaySetting> {
application_id: string
access_token: string
is_active: boolean
access_num: number
white_active: boolean
white_list: string[]
authentication?: boolean
authentication_value?: ApplicationAuthenticationConfig | null
}

/** 智能体公开访问状态修改或令牌重置参数。 */
/** 智能体访问配置修改或令牌重置参数。 */
export interface ApplicationAccessTokenPayload {
is_active?: boolean
access_token_reset?: boolean
access_num?: number
white_active?: boolean
white_list?: string[]
language?: string | null
authentication?: boolean
authentication_value?: ApplicationAuthenticationConfig
}

export interface ApplicationDetail extends Omit<ApplicationFormPayload, 'desc'> {
Expand Down
8 changes: 3 additions & 5 deletions ui/src/components/business/api-key-list/EditApiKeyDrawer.vue
Original file line number Diff line number Diff line change
Expand Up @@ -134,11 +134,9 @@ defineExpose({ open })
<el-input :model-value="form.secret_key" disabled>
<template #suffix>
<!-- 复制 API Key -->
<MkTooltip content="复制">
<el-button link @click="copyText(form.secret_key)">
<MkIcon name="icon_copy_outlined" />
</el-button>
</MkTooltip>
<el-button text @click="copyText(form.secret_key)" class="-mr-1">
<MkIcon name="icon_copy_outlined" />
</el-button>
</template>
</el-input>
</el-form-item>
Expand Down
49 changes: 26 additions & 23 deletions ui/src/components/business/api-key-list/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,13 @@ const props = defineProps<{
}>()
const loading = ref(false)
const apiKeys = ref<ApiKeyRecord[]>([])
const revealedIds = ref(new Set<string>())
const createdApiKey = ref('')
const createdDialogVisible = ref(false)
const pagination = ref({ currentPage: 1, pageSize: 20, total: 0 })
const editDrawerRef = useTemplateRef<InstanceType<typeof EditApiKeyDrawer>>('editDrawerRef')
const apiKeyRows = computed(() => apiKeys.value.map((record) => ({ ...record, expiration: getApiKeyExpiration(record) })))

function fetchApiKeys() {
revealedIds.value.clear()
const request =
props.applicationId !== undefined
? (props.api as typeof ApplicationApiKeyApi | typeof SystemResourceApiKeyApi).getApiKeyPage(props.applicationId, pagination.value)
Expand All @@ -51,8 +51,9 @@ function handleCreate() {
? (props.api as typeof ApplicationApiKeyApi | typeof SystemResourceApiKeyApi).postApiKey(props.applicationId)
: (props.api as typeof SystemApiKeyApi).postApiKey()
return request
.then(() => {
MsgSuccess('创建成功')
.then((record) => {
createdApiKey.value = record.secret_key
createdDialogVisible.value = true
pagination.value.currentPage = 1
return fetchApiKeys()
})
Expand Down Expand Up @@ -108,11 +109,6 @@ function handleOpenEdit(record: ApiKeyRecord) {
editDrawerRef.value?.open(record)
}

function handleToggleVisible(id: string) {
if (revealedIds.value.has(id)) revealedIds.value.delete(id)
else revealedIds.value.add(id)
}

onMounted(loadApiKeys)
</script>

Expand All @@ -130,24 +126,16 @@ onMounted(loadApiKeys)
@current-change="loadApiKeys"
@size-change="loadApiKeys"
>
<el-table-column label="API Key" min-width="230">
<el-table-column label="API Key" min-width="160">
<template #default="{ row }">
<div class="flex-align-center gap-2">
<span class="min-w-0 truncate" :title="revealedIds.has(row.id) ? row.secret_key : '********'">
{{ revealedIds.has(row.id) ? row.secret_key : '********' }}
<span>
{{ `******${row.secret_key.slice(-4)}` }}
</span>
<!-- 复制完整 API Key -->
<MkTooltip content="复制">
<el-button link @click="copyText(row.secret_key)">
<MkIcon name="icon_copy_outlined" />
</el-button>
</MkTooltip>
<!-- 切换 API Key 显隐 -->
<MkTooltip :content="revealedIds.has(row.id) ? '点击隐藏' : '点击显示'">
<el-button link @click="handleToggleVisible(row.id)">
<MkIcon :name="revealedIds.has(row.id) ? 'icon_visible_outlined' : 'icon_invisible_outlined'" />
</el-button>
</MkTooltip>
<el-button text @click="copyText(row.secret_key)">
<MkIcon name="icon_copy_outlined" />
</el-button>
</div>
</template>
</el-table-column>
Expand Down Expand Up @@ -202,5 +190,20 @@ onMounted(loadApiKeys)
</el-table-column>
</MkTable>
</div>
<MkDialog v-model="createdDialogVisible" title="API Key" align-center @closed="createdApiKey = ''">
<template #subtitle>请安全保存此密钥,不要泄露。</template>
<el-input :model-value="createdApiKey" readonly>
<template #suffix>
<!-- 复制新建的完整 API Key -->
<el-button text @click="copyText(createdApiKey)" class="-mr-1">
<MkIcon name="icon_copy_outlined" />
</el-button>
</template>
</el-input>
<template #footer>
<!-- 关闭创建结果弹窗 -->
<el-button plain @click="createdDialogVisible = false">知道了</el-button>
</template>
</MkDialog>
<EditApiKeyDrawer v-bind="props" ref="editDrawerRef" @refresh="loadApiKeys" />
</template>
8 changes: 3 additions & 5 deletions ui/src/layout/avatar-dropdown/ApiKeyDialog.vue
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,9 @@ defineExpose({ open })
<el-input :model-value="apiDocUrl" readonly>
<template #suffix>
<!-- 复制 API 文档地址 -->
<MkTooltip content="复制">
<el-button link @click="copyText(apiDocUrl)">
<MkIcon name="icon_copy_outlined" />
</el-button>
</MkTooltip>
<el-button text @click="copyText(apiDocUrl)" class="-mr-1">
<MkIcon name="icon_copy_outlined" />
</el-button>
</template>
</el-input>
</div>
Expand Down
13 changes: 11 additions & 2 deletions ui/src/views/VIEW_README.md
Original file line number Diff line number Diff line change
Expand Up @@ -344,11 +344,20 @@ View 负责路由、资源与模式、图加载、保存/发布/调试编排
Workspace 与 System 资源管理共用智能体弹窗,分别使用各自接口,不回退或使用头像菜单的全局系统 API Key。
嵌入第三方弹窗接收概览已有的 Web 链接与访问凭证,不额外请求接口;按全屏、浮窗、移动端单选切换并复制代码,
关闭后恢复全屏模式。iframe 沿用 Web 链接,移动端增加 `mode=mobile`;浮窗使用 Chat API 前缀下的
`/embed`,携带协议、主机和访问凭证,生成 HTML 时转义属性值。无访问凭证时禁用入口。
`/embed`,携带协议、主机和访问凭证;若传入链接含查询参数则一并保留,生成 HTML 时转义属性值。无访问凭证时禁用入口。
显示设置每次打开通过当前范围的 Application API 查询访问配置,支持主题色、语言、五类图片、
头像与对话展示开关、浮窗位置及免责声明,本地草稿实时预览。恢复默认仅改草稿,保存成功关闭,
失败保留输入;图片限 JPG/PNG/GIF、10 MB,替换、恢复默认、关闭及卸载时释放临时 URL。
展示配置保存协议及后端支持情况见 API 文档。访问限制弹窗业务尚待接入,不模拟保存。
展示配置保存协议及后端支持情况见 API 文档。
访问限制位于本地 `access-restriction/`,入口按 `auth.isCE` 选择社区版 `AccessRestrictionDrawer.vue`,
其他版本使用 `XpackAccessRestrictionDrawer.vue`;按需挂载,关闭动画后卸载。
每次打开通过当前范围 Application API 查询配置;支持提问次数、登录认证及嵌入白名单,开关只修改草稿,保存时统一提交。
社区版身份认证只有开关,不查询登录方式、不生成登录配置字段,保存时保留已有认证配置。
Xpack 版可用登录方式查询 `/chat_user/auth/types`,开启认证时至少选一种;账号登录的验证码阈值沿用 -1~10。
默认登录方式从已勾选的登录方式中选择,取消对应登录方式时同步调整默认值;账号锁定次数与分钟数正常编辑。
前端开放认证配置,不因字段缺失或旧版密码模式禁用;保留已有认证类型,字段生效能力由后台联调确认。
未取得完整配置时不提交保存,不提供失败空态或重试按钮;提交失败保留草稿。
白名单逐行去空白,保存时保留原语言和其他认证字段。
三类场景统一调用 `getMonitoring(workspaceId, range, applicationId)`;全部智能体使用空 ID,
两类首页不提交智能体筛选,概览传当前智能体 ID。页面直接传入完整 API,不包装接口。
排行由概览本地 `components/ApplicationRanking.vue` 调用 Overview API,展示用户 Tokens 消耗与提问次数两类 TOP5。
Expand Down

This file was deleted.

Loading
Loading