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
Original file line number Diff line number Diff line change
@@ -1,25 +1,25 @@
import { get, post, put } from '../core/request'
import type { QrLoginPlatform, QrLoginPlatformRequest } from '@/api/types'

const prefix = '/platform'
const prefix = '/platform/source'

/** 获取扫码登录平台配置。 */
const getQrLoginPlatforms = () => {
return get<QrLoginPlatform[]>(prefix)
}

/** 校验扫码登录平台配置是否可用。 */
const postQrLoginPlatformConnection = (platform: QrLoginPlatformRequest) => {
return post<QrLoginPlatformRequest, boolean>(`${prefix}/connection`, platform)
}

/** 保存扫码登录平台配置。 */
const putQrLoginPlatform = (platform: QrLoginPlatformRequest) => {
return put<QrLoginPlatformRequest, boolean>(prefix, platform)
}

/** 校验扫码登录平台配置是否可用。 */
const postValidateQrLoginPlatform = (platform: QrLoginPlatformRequest) => {
return post<QrLoginPlatformRequest, boolean>(`${prefix}`, platform)
}

export default {
getQrLoginPlatforms,
postQrLoginPlatformConnection,
postValidateQrLoginPlatform,
putQrLoginPlatform,
}
25 changes: 25 additions & 0 deletions ui/src/api/admin/system/chat-user-auth-scan.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { get, post, put } from '../core/request'
import type { QrLoginPlatform, QrLoginPlatformRequest } from '@/api/types'

const prefix = '/chat_user/auth/platform/source'

/** 获取对话用户扫码登录平台配置。 */
const getQrLoginPlatforms = () => {
return get<QrLoginPlatform[]>(prefix)
}

/** 保存对话用户扫码登录平台配置。 */
const postQrLoginPlatform = (platform: QrLoginPlatformRequest) => {
return post<QrLoginPlatformRequest, boolean>(prefix, platform)
}

/** 校验对话用户扫码登录平台配置是否可用。 */
const putValidateQrLoginPlatform = (platform: QrLoginPlatformRequest) => {
return put<QrLoginPlatformRequest, boolean>(prefix, platform)
}

export default {
getQrLoginPlatforms,
postQrLoginPlatform,
putValidateQrLoginPlatform,
}
37 changes: 37 additions & 0 deletions ui/src/api/admin/system/chat-user-auth.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { get, post, put } from '../core/request'
import type { AuthProviderSetting, AuthProviderType, LoginAuthSetting } from '@/api/types'

const prefix = '/chat_user/auth'

/** 获取对话用户指定认证源配置。 */
const getAuthSetting = (authType: AuthProviderType) => {
return get<Partial<AuthProviderSetting>>(`${prefix}/${authType}/detail`)
}

/** 测试对话用户认证源连接。 */
const postAuthSettingConnection = (setting: AuthProviderSetting) => {
return post<AuthProviderSetting, boolean>(`${prefix}/connection`, setting)
}

/** 保存对话用户指定认证源配置。 */
const putAuthSetting = (authType: AuthProviderType, setting: AuthProviderSetting) => {
return put<AuthProviderSetting, boolean>(`${prefix}/${authType}/info`, setting)
}

/** 获取对话用户登录设置。 */
const getLoginSetting = () => {
return get<LoginAuthSetting>(`${prefix}/setting`)
}

/** 保存对话用户登录设置。 */
const putLoginSetting = (setting: LoginAuthSetting) => {
return put<LoginAuthSetting, boolean>(`${prefix}/setting`, setting)
}

export default {
getAuthSetting,
getLoginSetting,
postAuthSettingConnection,
putAuthSetting,
putLoginSetting,
}
18 changes: 7 additions & 11 deletions ui/src/api/types/system-authentication.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import type { OptionItem } from '@/api/types/common'
import type { QrCodeProvider } from '@/api/types/login'

export type AuthProviderType = 'LDAP' | 'CAS' | 'OIDC' | 'OAuth2' | 'SAML2'

export interface AuthProviderSetting {
Expand All @@ -7,13 +10,8 @@ export interface AuthProviderSetting {
is_active: boolean
}

export interface LoginMethodOption {
label: string
value: string
}

export interface LoginAuthSetting {
auth_types?: LoginMethodOption[]
auth_types?: OptionItem[]
default_value: string
failed_attempts: number
group_id?: string
Expand All @@ -22,14 +20,12 @@ export interface LoginAuthSetting {
max_attempts: number
permission?: string
role_id?: string
system_options?: LoginMethodOption[]
system_options?: OptionItem[]
workspace_id?: string
}

export type QrLoginPlatformType = 'wecom' | 'dingtalk' | 'lark'

export interface QrLoginPlatform {
auth_type: QrLoginPlatformType
auth_type: QrCodeProvider
config: Record<string, string>
is_active: boolean
is_valid: boolean
Expand All @@ -38,5 +34,5 @@ export interface QrLoginPlatform {
export interface QrLoginPlatformRequest {
config: Record<string, string>
isActive: boolean
key: QrLoginPlatformType
key: QrCodeProvider
}
7 changes: 7 additions & 0 deletions ui/src/assets/logo/logo_enterprise-wechat.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
8 changes: 8 additions & 0 deletions ui/src/constants/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,11 @@ export const LOGIN_METHOD_LABELS: Record<LoginMethod, string> = {
lark: '飞书',
wecom: '企业微信',
}

export const SCAN_FIELD_LABELS: Record<string, string> = {
agent_id: 'Agent ID',
app_key: 'App Key',
app_secret: 'App Secret',
callback_url: '回调地址',
corp_id: 'Corp ID',
}
5 changes: 3 additions & 2 deletions ui/src/router/admin/system/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,8 @@ export const systemRoutes: RouteRecordRaw = {
{
path: 'authentication',
name: 'system-chat-authentication',
component: () => import('@/views/system/SystemView.vue'),
component: () =>
import('@/views/system/chat/authentication/AuthenticationView.vue'),
meta: { title: '对话用户认证', order: 30 },
},
{
Expand All @@ -163,7 +164,7 @@ export const systemRoutes: RouteRecordRaw = {
path: 'authentication',
name: 'system-login-authentication',
component: () =>
import('@/views/system/settings/authentication/AuthenticationSettingsView.vue'),
import('@/views/system/settings/authentication/AuthenticationView.vue'),
meta: { title: '系统用户认证', order: 10 },
},
{
Expand Down
33 changes: 32 additions & 1 deletion ui/src/styles/element-plus.scss
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,18 @@
--el-color-danger-light-7: color-mix(in srgb, var(--mk-danger) 30%, white);
--el-color-danger-light-8: color-mix(in srgb, var(--mk-danger) 20%, white);
--el-color-danger-light-9: color-mix(in srgb, var(--mk-danger) 10%, white);
--el-color-danger-dark-1: color-mix(in srgb, var(--mk-danger) 85%, black);
--el-color-success: var(--mk-success);
--el-color-success-light-1: color-mix(in srgb, var(--mk-success) 85%, white);
--el-color-success-light-3: color-mix(in srgb, var(--mk-success) 70%, white);
--el-color-success-light-4: color-mix(in srgb, var(--mk-success) 60%, white);
--el-color-success-light-5: color-mix(in srgb, var(--mk-success) 50%, white);
--el-color-success-light-6: color-mix(in srgb, var(--mk-success) 40%, white);
--el-color-success-light-7: color-mix(in srgb, var(--mk-success) 30%, white);
--el-color-success-light-8: color-mix(in srgb, var(--mk-success) 20%, white);
--el-color-success-light-9: color-mix(in srgb, var(--mk-success) 10%, white);
--el-color-success-dark-1: color-mix(in srgb, var(--mk-success) 85%, black);

--el-color-warning: var(--mk-warning);
--el-border-color: var(--mk-N350);
--el-border-radius-base: 6px;
Expand Down Expand Up @@ -134,12 +145,21 @@
/* card */
.el-card {
--el-card-border-radius: 12px;
overflow: visible;
&__body {
overflow: inherit;
}
&.is-always-shadow {
border: none;
}
&.is-never-shadow {
border: none;
}
&.is-never-shadow {
&:hover {
border-color: var(--el-color-primary);
}
}
}

.el-card.is-always-shadow,
Expand Down Expand Up @@ -565,6 +585,7 @@
/* switch */
.el-switch {
--el-switch-off-color: var(--mk-N400);
height: 22px;
}
.el-switch--small {
.el-switch__core {
Expand Down Expand Up @@ -644,10 +665,12 @@

/* tag */
.el-tag {
--el-tag-font-size: 14px;
max-width: 115px;
border: none;
padding: 0 6px;
&:not(&--small) {
--el-tag-font-size: 14px;
}

&__content {
overflow: hidden;
Expand All @@ -658,6 +681,14 @@
--el-tag-text-color: var(--el-text-color-primary) !important;
--el-tag-bg-color: var(--mk-N900-transparent-10) !important;
}
&--success {
--el-tag-text-color: var(--el-color-success-dark-1) !important;
--el-tag-bg-color: rgb(var(--mk-success-rgb) / 20%) !important;
}
&--danger {
--el-tag-text-color: var(--el-color-danger-dark-1) !important;
--el-tag-bg-color: rgb(var(--mk-danger-rgb) / 20%) !important;
}
&__close {
.el-icon {
color: var(--el-text-color-regular);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { ref, type Component } from 'vue'
import LDAP from './components/LDAP.vue'
import CAS from './components/CAS.vue'
import OIDC from './components/OIDC.vue'
import SCAN from './components/SCAN.vue'
import SCAN from './components/SCANLogin.vue'
import OAuth2 from './components/OAuth2.vue'
import Saml2 from './components/Saml2.vue'
import LoginSetting from './components/LoginSetting.vue'
Expand All @@ -14,7 +14,7 @@ interface AuthenticationTab {
name: string
}

const activeName = ref('LoginSetting')
const activeName = ref('SCAN')
const authenticationTabs: AuthenticationTab[] = [
{ label: '登录设置', name: 'LoginSetting', component: LoginSetting },
{ label: 'LDAP', name: 'LDAP', component: LDAP },
Expand Down
105 changes: 105 additions & 0 deletions ui/src/views/system/chat/authentication/EditSCANDrawer.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
<script setup lang="ts">
import { computed, reactive, ref, useTemplateRef } from 'vue'
import type { FormInstance, FormRules } from 'element-plus'
import ChatUserAuthScanApi from '@/api/admin/system/chat-user-auth-scan'
import type { QrLoginPlatformRequest } from '@/api/types'
import { LOGIN_METHOD_LABELS, SCAN_FIELD_LABELS } from '@/constants/auth'
import { MsgSuccess, MsgError } from '@/utils/message'

const emit = defineEmits<{ refresh: [] }>()
const visible = ref(false)
const loading = ref(false)
const formRef = useTemplateRef<FormInstance>('formRef')
const form = reactive<QrLoginPlatformRequest>({
key: 'wecom',
isActive: false,
config: {},
})

const rules = computed<FormRules>(() =>
Object.fromEntries(
Object.keys(form.config).map((key) => [
`config.${key}`,
[{ required: true, message: `请输入${SCAN_FIELD_LABELS[key] ?? key}`, trigger: 'blur' }],
]),
),
)
function submit() {
formRef.value?.validate((valid) => {
if (!valid) return

loading.value = true
ChatUserAuthScanApi.postQrLoginPlatform(form)
.then(() => {
MsgSuccess('保存成功')
emit('refresh')
close()
})
.finally(() => {
loading.value = false
})
})
}

/* 校验 */
function handleValidatePlatform() {
loading.value = true
return ChatUserAuthScanApi.putValidateQrLoginPlatform(form)
.then((res) => {
// TODO: 校验判断有误
res ? MsgSuccess('校验成功') : MsgError('校验失败')
})
.finally(() => {
loading.value = false
})
}

function open(platform: QrLoginPlatformRequest) {
Object.assign(form, platform, { config: { ...platform.config } })
visible.value = true
}

function close() {
visible.value = false
resetData()
}

function resetData() {
Object.assign(form, { key: 'wecom', isActive: false, config: {} })
formRef.value?.resetFields()
}
defineExpose({ open })
</script>

<template>
<MkDrawer v-model="visible" :title="`${LOGIN_METHOD_LABELS[form.key]}设置`" @closed="resetData">
<el-form
ref="formRef"
v-loading="loading"
:model="form"
:rules="rules"
label-position="top"
require-asterisk-position="right"
>
<el-form-item
v-for="(_, key) in form.config"
:key="key"
:label="SCAN_FIELD_LABELS[key] ?? key"
:prop="`config.${key}`"
>
<el-input
v-model="form.config[key]"
:show-password="key === 'app_secret'"
:type="key === 'app_secret' ? 'password' : 'text'"
placeholder="请输入"
/>
</el-form-item>
</el-form>

<template #footer>
<el-button @click="close">取消</el-button>
<el-button @click="handleValidatePlatform">校验</el-button>
<el-button type="primary" @click="submit">保存</el-button>
</template>
</MkDrawer>
</template>
Loading
Loading