mirror of
https://github.com/1Panel-dev/MaxKB.git
synced 2025-12-28 14:52:58 +00:00
feat: user
This commit is contained in:
parent
31f6da272f
commit
bbcc45181c
|
|
@ -0,0 +1,127 @@
|
|||
<template>
|
||||
<div class="authentication-setting__main main-calc-height">
|
||||
<el-scrollbar>
|
||||
<div class="form-container p-24" v-loading="loading">
|
||||
<el-form
|
||||
ref="authFormRef"
|
||||
:rules="rules"
|
||||
:model="form"
|
||||
label-position="top"
|
||||
require-asterisk-position="right"
|
||||
>
|
||||
<el-form-item
|
||||
:label="$t('views.system.authentication.cas.ldpUri')"
|
||||
prop="config.ldpUri"
|
||||
>
|
||||
<el-input
|
||||
v-model="form.config.ldpUri"
|
||||
:placeholder="$t('views.system.authentication.cas.ldpUriPlaceholder')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
:label="$t('views.system.authentication.cas.validateUrl')"
|
||||
prop="config.validateUrl"
|
||||
>
|
||||
<el-input
|
||||
v-model="form.config.validateUrl"
|
||||
:placeholder="$t('views.system.authentication.cas.validateUrlPlaceholder')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
:label="$t('views.system.authentication.cas.redirectUrl')"
|
||||
prop="config.redirectUrl"
|
||||
>
|
||||
<el-input
|
||||
v-model="form.config.redirectUrl"
|
||||
:placeholder="$t('views.system.authentication.cas.redirectUrlPlaceholder')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-checkbox v-model="form.is_active"
|
||||
>{{ $t('views.system.authentication.cas.enableAuthentication') }}
|
||||
</el-checkbox>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<div class="text-right">
|
||||
<el-button @click="submit(authFormRef)" type="primary" :disabled="loading">
|
||||
{{ $t('common.save') }}
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</el-scrollbar>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { reactive, ref, watch, onMounted } from 'vue'
|
||||
import authApi from '@/api/system-settings/auth-setting'
|
||||
import type { FormInstance, FormRules } from 'element-plus'
|
||||
import { t } from '@/locales'
|
||||
import { MsgSuccess } from '@/utils/message'
|
||||
|
||||
const form = ref<any>({
|
||||
id: '',
|
||||
auth_type: 'CAS',
|
||||
config: {
|
||||
ldpUri: '',
|
||||
validateUrl: '',
|
||||
redirectUrl: ''
|
||||
},
|
||||
is_active: true
|
||||
})
|
||||
|
||||
const authFormRef = ref()
|
||||
|
||||
const loading = ref(false)
|
||||
|
||||
const rules = reactive<FormRules<any>>({
|
||||
'config.ldpUri': [
|
||||
{
|
||||
required: true,
|
||||
message: t('views.system.authentication.cas.ldpUriPlaceholder'),
|
||||
trigger: 'blur'
|
||||
}
|
||||
],
|
||||
'config.validateUrl': [
|
||||
{
|
||||
required: true,
|
||||
message: t('views.system.authentication.cas.validateUrlPlaceholder'),
|
||||
trigger: 'blur'
|
||||
}
|
||||
],
|
||||
'config.redirectUrl': [
|
||||
{
|
||||
required: true,
|
||||
message: t('views.system.authentication.cas.redirectUrlPlaceholder'),
|
||||
trigger: 'blur'
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
const submit = async (formEl: FormInstance | undefined) => {
|
||||
if (!formEl) return
|
||||
await formEl.validate((valid, fields) => {
|
||||
if (valid) {
|
||||
authApi.putAuthSetting(form.value.auth_type, form.value, loading).then((res) => {
|
||||
MsgSuccess(t('common.saveSuccess'))
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function getDetail() {
|
||||
authApi.getAuthSetting(form.value.auth_type, loading).then((res: any) => {
|
||||
if (res.data && JSON.stringify(res.data) !== '{}') {
|
||||
if (!res.data.config.validateUrl) {
|
||||
res.data.config.validateUrl = res.data.config.ldpUri
|
||||
}
|
||||
form.value = res.data
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
getDetail()
|
||||
})
|
||||
</script>
|
||||
<style lang="scss" scoped></style>
|
||||
|
|
@ -0,0 +1,230 @@
|
|||
template
|
||||
<template>
|
||||
<el-drawer
|
||||
v-model="visible"
|
||||
size="60%"
|
||||
:append-to-body="true"
|
||||
:destroy-on-close="true"
|
||||
@close="handleClose"
|
||||
>
|
||||
<template #header>
|
||||
<div class="flex align-center" style="margin-left: -8px">
|
||||
<h4>
|
||||
{{ currentPlatform.name + $t('views.system.authentication.scanTheQRCode.setting') }}
|
||||
</h4>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<el-form
|
||||
:model="currentPlatform.config"
|
||||
label-width="120px"
|
||||
label-position="top"
|
||||
require-asterisk-position="right"
|
||||
ref="formRef"
|
||||
>
|
||||
<el-form-item
|
||||
v-for="(value, key) in currentPlatform.config"
|
||||
:key="key"
|
||||
:label="formatFieldName(key)"
|
||||
:prop="key"
|
||||
:rules="getValidationRules(key)"
|
||||
>
|
||||
<el-input
|
||||
v-model="currentPlatform.config[key]"
|
||||
:type="isPasswordField(key) ? 'password' : 'text'"
|
||||
:show-password="isPasswordField(key)"
|
||||
>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="handleClose">{{ $t('common.cancel') }}</el-button>
|
||||
<el-button @click="validateConnection">{{
|
||||
$t('views.system.authentication.scanTheQRCode.validate')
|
||||
}}</el-button>
|
||||
<el-button type="primary" @click="validateForm">{{ $t('common.save') }}</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-drawer>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { reactive, ref } from 'vue'
|
||||
import { ElForm } from 'element-plus'
|
||||
import platformApi from '@/api/system-settings/platform-source'
|
||||
import { MsgError, MsgSuccess } from '@/utils/message'
|
||||
import { t } from '@/locales'
|
||||
|
||||
const visible = ref(false)
|
||||
const loading = ref(false)
|
||||
const formRef = ref<InstanceType<typeof ElForm>>()
|
||||
|
||||
interface PlatformConfig {
|
||||
[key: string]: string
|
||||
}
|
||||
|
||||
interface Platform {
|
||||
key: string
|
||||
logoSrc: string
|
||||
name: string
|
||||
isActive: boolean
|
||||
isValid: boolean
|
||||
config: PlatformConfig
|
||||
}
|
||||
|
||||
const currentPlatform = reactive<Platform>({
|
||||
key: '',
|
||||
logoSrc: '',
|
||||
name: '',
|
||||
isActive: false,
|
||||
isValid: false,
|
||||
config: {}
|
||||
})
|
||||
|
||||
const formatFieldName = (key?: any): string => {
|
||||
const fieldNames: { [key: string]: string } = {
|
||||
corp_id: 'Corp ID',
|
||||
app_key: currentPlatform?.key != 'lark' ? 'APP Key' : 'App ID',
|
||||
app_secret: 'APP Secret',
|
||||
agent_id: 'Agent ID',
|
||||
callback_url: t('views.application.applicationAccess.callback')
|
||||
}
|
||||
return (
|
||||
fieldNames[key as keyof typeof fieldNames] ||
|
||||
(key ? key.charAt(0).toUpperCase() + key.slice(1) : '')
|
||||
)
|
||||
}
|
||||
|
||||
const getValidationRules = (key: any) => {
|
||||
switch (key) {
|
||||
case 'app_key':
|
||||
return [
|
||||
{
|
||||
required: true,
|
||||
message: t('views.system.authentication.scanTheQRCode.appKeyPlaceholder'),
|
||||
trigger: ['blur', 'change']
|
||||
}
|
||||
]
|
||||
case 'app_secret':
|
||||
return [
|
||||
{
|
||||
required: true,
|
||||
message: t('views.system.authentication.scanTheQRCode.appSecretPlaceholder'),
|
||||
trigger: ['blur', 'change']
|
||||
}
|
||||
]
|
||||
case 'corp_id':
|
||||
return [
|
||||
{
|
||||
required: true,
|
||||
message: t('views.system.authentication.scanTheQRCode.corpIdPlaceholder'),
|
||||
trigger: ['blur', 'change']
|
||||
}
|
||||
]
|
||||
case 'agent_id':
|
||||
return [
|
||||
{
|
||||
required: true,
|
||||
message: t('views.system.authentication.scanTheQRCode.agentIdPlaceholder'),
|
||||
trigger: ['blur', 'change']
|
||||
}
|
||||
]
|
||||
case 'callback_url':
|
||||
return [
|
||||
{
|
||||
required: true,
|
||||
message: t('views.application.applicationAccess.callbackTip'),
|
||||
trigger: ['blur', 'change']
|
||||
},
|
||||
{
|
||||
pattern: /^https?:\/\/.+/,
|
||||
message: t('views.system.authentication.scanTheQRCode.callbackWarning'),
|
||||
trigger: ['blur', 'change']
|
||||
}
|
||||
]
|
||||
default:
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
||||
const open = async (platform: Platform) => {
|
||||
visible.value = true
|
||||
loading.value = true
|
||||
Object.assign(currentPlatform, platform)
|
||||
|
||||
// 设置默认的 callback_url
|
||||
const defaultCallbackUrl = window.location.origin
|
||||
switch (platform.key) {
|
||||
case 'wecom':
|
||||
if (currentPlatform.config.app_key) {
|
||||
currentPlatform.config.agent_id = currentPlatform.config.app_key
|
||||
delete currentPlatform.config.app_key
|
||||
}
|
||||
currentPlatform.config.callback_url = `${defaultCallbackUrl}/api/wecom`
|
||||
break
|
||||
case 'dingtalk':
|
||||
if (currentPlatform.config.agent_id) {
|
||||
currentPlatform.config.corp_id = currentPlatform.config.agent_id
|
||||
delete currentPlatform.config.agent_id
|
||||
}
|
||||
currentPlatform.config = {
|
||||
corp_id: currentPlatform.config.corp_id,
|
||||
app_key: currentPlatform.config.app_key,
|
||||
app_secret: currentPlatform.config.app_secret,
|
||||
callback_url: defaultCallbackUrl
|
||||
}
|
||||
currentPlatform.config.callback_url = `${defaultCallbackUrl}/api/dingtalk`
|
||||
break
|
||||
case 'lark':
|
||||
currentPlatform.config.callback_url = `${defaultCallbackUrl}/api/feishu`
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
formRef.value?.clearValidate()
|
||||
}
|
||||
defineExpose({ open })
|
||||
|
||||
const validateForm = () => {
|
||||
formRef.value?.validate((valid) => {
|
||||
if (valid) {
|
||||
saveConfig()
|
||||
} else {
|
||||
MsgError(t('views.system.authentication.scanTheQRCode.validateFailedTip'))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const handleClose = () => {
|
||||
visible.value = false
|
||||
formRef.value?.clearValidate()
|
||||
emit('refresh')
|
||||
}
|
||||
|
||||
function validateConnection() {
|
||||
platformApi.validateConnection(currentPlatform, loading).then((res: any) => {
|
||||
if (res.data) {
|
||||
MsgSuccess(t('views.system.authentication.scanTheQRCode.validateSuccess'))
|
||||
} else {
|
||||
MsgError(t('views.system.authentication.scanTheQRCode.validateFailed'))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const passwordFields = new Set(['app_secret', 'client_secret', 'secret'])
|
||||
|
||||
const isPasswordField = (key: any) => passwordFields.has(key)
|
||||
const emit = defineEmits(['refresh'])
|
||||
|
||||
function saveConfig() {
|
||||
platformApi.updateConfig(currentPlatform, loading).then((res: any) => {
|
||||
MsgSuccess(t('common.saveSuccess'))
|
||||
emit('refresh')
|
||||
visible.value = false
|
||||
formRef.value?.clearValidate()
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
|
|
@ -0,0 +1,184 @@
|
|||
<template>
|
||||
<div class="authentication-setting__main main-calc-height">
|
||||
<el-scrollbar>
|
||||
<div class="form-container p-24" v-loading="loading">
|
||||
<el-form
|
||||
ref="authFormRef"
|
||||
:rules="rules"
|
||||
:model="form"
|
||||
label-position="top"
|
||||
require-asterisk-position="right"
|
||||
>
|
||||
<el-form-item
|
||||
:label="$t('views.system.authentication.ldap.address')"
|
||||
prop="config.ldap_server"
|
||||
>
|
||||
<el-input
|
||||
v-model="form.config.ldap_server"
|
||||
:placeholder="$t('views.system.authentication.ldap.serverPlaceholder')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
:label="$t('views.system.authentication.ldap.bindDN')"
|
||||
prop="config.base_dn"
|
||||
>
|
||||
<el-input
|
||||
v-model="form.config.base_dn"
|
||||
:placeholder="$t('views.system.authentication.ldap.bindDNPlaceholder')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('views.system.password')" prop="config.password">
|
||||
<el-input
|
||||
v-model="form.config.password"
|
||||
:placeholder="$t('views.userManage.form.password.placeholder')"
|
||||
show-password
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('views.system.authentication.ldap.ou')" prop="config.ou">
|
||||
<el-input
|
||||
v-model="form.config.ou"
|
||||
:placeholder="$t('views.system.authentication.ldap.ouPlaceholder')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
:label="$t('views.system.authentication.ldap.ldap_filter')"
|
||||
prop="config.ldap_filter"
|
||||
>
|
||||
<el-input
|
||||
v-model="form.config.ldap_filter"
|
||||
:placeholder="$t('views.system.authentication.ldap.ldap_filterPlaceholder')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
:label="$t('views.system.authentication.ldap.ldap_mapping')"
|
||||
prop="config.ldap_mapping"
|
||||
>
|
||||
<el-input
|
||||
v-model="form.config.ldap_mapping"
|
||||
placeholder='{"name":"name","email":"mail","username":"cn"}'
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-checkbox v-model="form.is_active">{{
|
||||
$t('views.system.authentication.ldap.enableAuthentication')
|
||||
}}</el-checkbox>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<div class="text-right">
|
||||
<el-button @click="submit(authFormRef, 'test')" :disabled="loading">
|
||||
{{ $t('views.system.test') }}</el-button
|
||||
>
|
||||
<el-button @click="submit(authFormRef)" type="primary" :disabled="loading">
|
||||
{{ $t('common.save') }}
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</el-scrollbar>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { reactive, ref, watch, onMounted } from 'vue'
|
||||
import authApi from '@/api/system-settings/auth-setting'
|
||||
import type { FormInstance, FormRules } from 'element-plus'
|
||||
import { t } from '@/locales'
|
||||
import { MsgSuccess } from '@/utils/message'
|
||||
|
||||
const form = ref<any>({
|
||||
id: '',
|
||||
auth_type: 'LDAP',
|
||||
config: {
|
||||
ldap_server: '',
|
||||
base_dn: '',
|
||||
password: '',
|
||||
ou: '',
|
||||
ldap_filter: '',
|
||||
ldap_mapping: ''
|
||||
},
|
||||
is_active: true
|
||||
})
|
||||
|
||||
const authFormRef = ref()
|
||||
|
||||
const loading = ref(false)
|
||||
|
||||
const rules = reactive<FormRules<any>>({
|
||||
'config.ldap_server': [
|
||||
{
|
||||
required: true,
|
||||
message: t('views.system.authentication.ldap.serverPlaceholder'),
|
||||
trigger: 'blur'
|
||||
}
|
||||
],
|
||||
'config.base_dn': [
|
||||
{
|
||||
required: true,
|
||||
message: t('views.system.authentication.ldap.bindDNPlaceholder'),
|
||||
trigger: 'blur'
|
||||
}
|
||||
],
|
||||
'config.password': [
|
||||
{
|
||||
required: true,
|
||||
message: t('views.userManage.form.password.requiredMessage'),
|
||||
trigger: 'blur'
|
||||
}
|
||||
],
|
||||
'config.ou': [
|
||||
{
|
||||
required: true,
|
||||
message: t('views.system.authentication.ldap.ouPlaceholder'),
|
||||
trigger: 'blur'
|
||||
}
|
||||
],
|
||||
'config.ldap_filter': [
|
||||
{
|
||||
required: true,
|
||||
message: t('views.system.authentication.ldap.ldap_filterPlaceholder'),
|
||||
trigger: 'blur'
|
||||
}
|
||||
],
|
||||
'config.ldap_mapping': [
|
||||
{
|
||||
required: true,
|
||||
message: t('views.system.authentication.ldap.ldap_mappingPlaceholder'),
|
||||
trigger: 'blur'
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
const submit = async (formEl: FormInstance | undefined, test?: string) => {
|
||||
if (!formEl) return
|
||||
await formEl.validate((valid, fields) => {
|
||||
if (valid) {
|
||||
if (test) {
|
||||
authApi.postAuthSetting(form.value, loading).then((res) => {
|
||||
MsgSuccess(t('views.system.testSuccess'))
|
||||
})
|
||||
} else {
|
||||
authApi.putAuthSetting(form.value.auth_type, form.value, loading).then((res) => {
|
||||
MsgSuccess(t('common.saveSuccess'))
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function getDetail() {
|
||||
authApi.getAuthSetting(form.value.auth_type, loading).then((res: any) => {
|
||||
if (res.data && JSON.stringify(res.data) !== '{}') {
|
||||
form.value = res.data
|
||||
if (res.data.config.ldap_mapping) {
|
||||
form.value.config.ldap_mapping = JSON.stringify(
|
||||
JSON.parse(res.data.config.ldap_mapping)
|
||||
)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
getDetail()
|
||||
})
|
||||
</script>
|
||||
<style lang="scss" scoped></style>
|
||||
|
|
@ -0,0 +1,210 @@
|
|||
<template>
|
||||
<div class="authentication-setting__main main-calc-height">
|
||||
<el-scrollbar>
|
||||
<div class="form-container p-24" v-loading="loading">
|
||||
<el-form
|
||||
ref="authFormRef"
|
||||
:rules="rules"
|
||||
:model="form"
|
||||
label-position="top"
|
||||
require-asterisk-position="right"
|
||||
>
|
||||
<el-form-item
|
||||
:label="$t('views.system.authentication.oauth2.authEndpoint')"
|
||||
prop="config.authEndpoint"
|
||||
>
|
||||
<el-input
|
||||
v-model="form.config.authEndpoint"
|
||||
:placeholder="$t('views.system.authentication.oauth2.authEndpointPlaceholder')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
:label="$t('views.system.authentication.oauth2.tokenEndpoint')"
|
||||
prop="config.tokenEndpoint"
|
||||
>
|
||||
<el-input
|
||||
v-model="form.config.tokenEndpoint"
|
||||
:placeholder="$t('views.system.authentication.oauth2.tokenEndpointPlaceholder')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
:label="$t('views.system.authentication.oauth2.userInfoEndpoint')"
|
||||
prop="config.userInfoEndpoint"
|
||||
>
|
||||
<el-input
|
||||
v-model="form.config.userInfoEndpoint"
|
||||
:placeholder="$t('views.system.authentication.oauth2.userInfoEndpointPlaceholder')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
:label="$t('views.system.authentication.oauth2.scope')"
|
||||
prop="config.scope"
|
||||
>
|
||||
<el-input
|
||||
v-model="form.config.scope"
|
||||
:placeholder="$t('views.system.authentication.oauth2.scopePlaceholder')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
:label="$t('views.system.authentication.oauth2.clientId')"
|
||||
prop="config.clientId"
|
||||
>
|
||||
<el-input
|
||||
v-model="form.config.clientId"
|
||||
:placeholder="$t('views.system.authentication.oauth2.clientIdPlaceholder')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
:label="$t('views.system.authentication.oauth2.clientSecret')"
|
||||
prop="config.clientSecret"
|
||||
>
|
||||
<el-input
|
||||
v-model="form.config.clientSecret"
|
||||
:placeholder="$t('views.system.authentication.oauth2.clientSecretPlaceholder')"
|
||||
show-password
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
:label="$t('views.system.authentication.oauth2.redirectUrl')"
|
||||
prop="config.redirectUrl"
|
||||
>
|
||||
<el-input
|
||||
v-model="form.config.redirectUrl"
|
||||
:placeholder="$t('views.system.authentication.oauth2.redirectUrlPlaceholder')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
:label="$t('views.system.authentication.oauth2.filedMapping')"
|
||||
prop="config.fieldMapping"
|
||||
>
|
||||
<el-input
|
||||
v-model="form.config.fieldMapping"
|
||||
:placeholder="$t('views.system.authentication.oauth2.filedMappingPlaceholder')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-checkbox v-model="form.is_active"
|
||||
>{{ $t('views.system.authentication.oauth2.enableAuthentication') }}
|
||||
</el-checkbox>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<div class="text-right">
|
||||
<el-button @click="submit(authFormRef)" type="primary" :disabled="loading">
|
||||
{{ $t('common.save') }}
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</el-scrollbar>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { reactive, ref, onMounted } from 'vue'
|
||||
import authApi from '@/api/system-settings/auth-setting'
|
||||
import type { FormInstance, FormRules } from 'element-plus'
|
||||
import { t } from '@/locales'
|
||||
import { MsgSuccess } from '@/utils/message'
|
||||
|
||||
const form = ref<any>({
|
||||
id: '',
|
||||
auth_type: 'OAuth2',
|
||||
config: {
|
||||
authEndpoint: '',
|
||||
tokenEndpoint: '',
|
||||
userInfoEndpoint: '',
|
||||
scope: '',
|
||||
clientId: '',
|
||||
clientSecret: '',
|
||||
redirectUrl: '',
|
||||
fieldMapping: ''
|
||||
},
|
||||
is_active: true
|
||||
})
|
||||
|
||||
const authFormRef = ref()
|
||||
|
||||
const loading = ref(false)
|
||||
|
||||
const rules = reactive<FormRules<any>>({
|
||||
'config.authEndpoint': [
|
||||
{
|
||||
required: true,
|
||||
message: t('views.system.authentication.oauth2.authEndpointPlaceholder'),
|
||||
trigger: 'blur'
|
||||
}
|
||||
],
|
||||
'config.tokenEndpoint': [
|
||||
{
|
||||
required: true,
|
||||
message: t('views.system.authentication.oauth2.tokenEndpointPlaceholder'),
|
||||
trigger: 'blur'
|
||||
}
|
||||
],
|
||||
'config.userInfoEndpoint': [
|
||||
{
|
||||
required: true,
|
||||
message: t('views.system.authentication.oauth2.userInfoEndpointPlaceholder'),
|
||||
trigger: 'blur'
|
||||
}
|
||||
],
|
||||
'config.scope': [
|
||||
{
|
||||
required: true,
|
||||
message: t('views.system.authentication.oauth2.scopePlaceholder'),
|
||||
trigger: 'blur'
|
||||
}
|
||||
],
|
||||
'config.clientId': [
|
||||
{
|
||||
required: true,
|
||||
message: t('views.system.authentication.oauth2.clientIdPlaceholder'),
|
||||
trigger: 'blur'
|
||||
}
|
||||
],
|
||||
'config.clientSecret': [
|
||||
{
|
||||
required: true,
|
||||
message: t('views.system.authentication.oauth2.clientSecretPlaceholder'),
|
||||
trigger: 'blur'
|
||||
}
|
||||
],
|
||||
'config.redirectUrl': [
|
||||
{
|
||||
required: true,
|
||||
message: t('views.system.authentication.oauth2.redirectUrlPlaceholder'),
|
||||
trigger: 'blur'
|
||||
}
|
||||
],
|
||||
'config.fieldMapping': [
|
||||
{
|
||||
required: true,
|
||||
message: t('views.system.authentication.oauth2.filedMappingPlaceholder'),
|
||||
trigger: 'blur'
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
const submit = async (formEl: FormInstance | undefined, test?: string) => {
|
||||
if (!formEl) return
|
||||
await formEl.validate((valid, fields) => {
|
||||
if (valid) {
|
||||
authApi.putAuthSetting(form.value.auth_type, form.value, loading).then((res) => {
|
||||
MsgSuccess(t('common.saveSuccess'))
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function getDetail() {
|
||||
authApi.getAuthSetting(form.value.auth_type, loading).then((res: any) => {
|
||||
if (res.data && JSON.stringify(res.data) !== '{}') {
|
||||
form.value = res.data
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
getDetail()
|
||||
})
|
||||
</script>
|
||||
<style lang="scss" scoped></style>
|
||||
|
|
@ -0,0 +1,221 @@
|
|||
<template>
|
||||
<div class="authentication-setting__main main-calc-height">
|
||||
<el-scrollbar>
|
||||
<div class="form-container p-24" v-loading="loading">
|
||||
<el-form
|
||||
ref="authFormRef"
|
||||
:rules="rules"
|
||||
:model="form"
|
||||
label-position="top"
|
||||
require-asterisk-position="right"
|
||||
>
|
||||
<el-form-item
|
||||
:label="$t('views.system.authentication.oidc.authEndpoint')"
|
||||
prop="config.authEndpoint"
|
||||
>
|
||||
<el-input
|
||||
v-model="form.config.authEndpoint"
|
||||
:placeholder="$t('views.system.authentication.oidc.authEndpointPlaceholder')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
:label="$t('views.system.authentication.oidc.tokenEndpoint')"
|
||||
prop="config.tokenEndpoint"
|
||||
>
|
||||
<el-input
|
||||
v-model="form.config.tokenEndpoint"
|
||||
:placeholder="$t('views.system.authentication.oidc.tokenEndpointPlaceholder')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
:label="$t('views.system.authentication.oidc.userInfoEndpoint')"
|
||||
prop="config.userInfoEndpoint"
|
||||
>
|
||||
<el-input
|
||||
v-model="form.config.userInfoEndpoint"
|
||||
:placeholder="$t('views.system.authentication.oidc.userInfoEndpointPlaceholder')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="Scope" prop="config.scope">
|
||||
<el-input v-model="form.config.scope" placeholder="openid+profile+email " />
|
||||
</el-form-item>
|
||||
<el-form-item label="State" prop="config.state">
|
||||
<el-input v-model="form.config.state" placeholder="" />
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
:label="$t('views.system.authentication.oidc.clientId')"
|
||||
prop="config.clientId"
|
||||
>
|
||||
<el-input
|
||||
v-model="form.config.clientId"
|
||||
:placeholder="$t('views.system.authentication.oidc.clientIdPlaceholder')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
:label="$t('views.system.authentication.oidc.clientSecret')"
|
||||
prop="config.clientSecret"
|
||||
>
|
||||
<el-input
|
||||
v-model="form.config.clientSecret"
|
||||
:placeholder="$t('views.system.authentication.oidc.clientSecretPlaceholder')"
|
||||
show-password
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
:label="$t('views.system.authentication.oauth2.filedMapping')"
|
||||
prop="config.fieldMapping"
|
||||
>
|
||||
<el-input
|
||||
v-model="form.config.fieldMapping"
|
||||
:placeholder="$t('views.system.authentication.oauth2.filedMappingPlaceholder')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
:label="$t('views.system.authentication.oidc.redirectUrl')"
|
||||
prop="config.redirectUrl"
|
||||
>
|
||||
<el-input
|
||||
v-model="form.config.redirectUrl"
|
||||
:placeholder="$t('views.system.authentication.oidc.redirectUrlPlaceholder')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-checkbox v-model="form.is_active"
|
||||
>{{ $t('views.system.authentication.oidc.enableAuthentication') }}
|
||||
</el-checkbox>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<div class="text-right">
|
||||
<el-button @click="submit(authFormRef)" type="primary" :disabled="loading">
|
||||
{{ $t('common.save') }}
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</el-scrollbar>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { reactive, ref, watch, onMounted } from 'vue'
|
||||
import authApi from '@/api/system-settings/auth-setting'
|
||||
import type { FormInstance, FormRules } from 'element-plus'
|
||||
import { t } from '@/locales'
|
||||
import { MsgSuccess } from '@/utils/message'
|
||||
|
||||
const form = ref<any>({
|
||||
id: '',
|
||||
auth_type: 'OIDC',
|
||||
config: {
|
||||
authEndpoint: '',
|
||||
tokenEndpoint: '',
|
||||
userInfoEndpoint: '',
|
||||
scope: '',
|
||||
state: '',
|
||||
clientId: '',
|
||||
clientSecret: '',
|
||||
fieldMapping: '{"username": "preferred_username", "email": "email"}',
|
||||
redirectUrl: ''
|
||||
},
|
||||
is_active: true
|
||||
})
|
||||
|
||||
const authFormRef = ref()
|
||||
|
||||
const loading = ref(false)
|
||||
|
||||
const rules = reactive<FormRules<any>>({
|
||||
'config.authEndpoint': [
|
||||
{
|
||||
required: true,
|
||||
message: t('views.system.authentication.oidc.authEndpointPlaceholder'),
|
||||
trigger: 'blur'
|
||||
}
|
||||
],
|
||||
'config.tokenEndpoint': [
|
||||
{
|
||||
required: true,
|
||||
message: t('views.system.authentication.oidc.tokenEndpointPlaceholder'),
|
||||
trigger: 'blur'
|
||||
}
|
||||
],
|
||||
'config.userInfoEndpoint': [
|
||||
{
|
||||
required: true,
|
||||
message: t('views.system.authentication.oidc.userInfoEndpointPlaceholder'),
|
||||
trigger: 'blur'
|
||||
}
|
||||
],
|
||||
'config.scope': [
|
||||
{
|
||||
required: true,
|
||||
message: t('views.system.authentication.oidc.scopePlaceholder'),
|
||||
trigger: 'blur'
|
||||
}
|
||||
],
|
||||
'config.clientId': [
|
||||
{
|
||||
required: true,
|
||||
message: t('views.system.authentication.oidc.clientIdPlaceholder'),
|
||||
trigger: 'blur'
|
||||
}
|
||||
],
|
||||
'config.clientSecret': [
|
||||
{
|
||||
required: true,
|
||||
message: t('views.system.authentication.oidc.clientSecretPlaceholder'),
|
||||
trigger: 'blur'
|
||||
}
|
||||
],
|
||||
'config.fieldMapping': [
|
||||
{
|
||||
required: true,
|
||||
message: t('views.system.authentication.oauth2.filedMappingPlaceholder'),
|
||||
trigger: 'blur'
|
||||
}
|
||||
],
|
||||
'config.redirectUrl': [
|
||||
{
|
||||
required: true,
|
||||
message: t('views.system.authentication.oidc.redirectUrlPlaceholder'),
|
||||
trigger: 'blur'
|
||||
}
|
||||
],
|
||||
'config.logoutEndpoint': [
|
||||
{
|
||||
required: true,
|
||||
message: t('views.system.authentication.oidc.logoutEndpointPlaceholder'),
|
||||
trigger: 'blur'
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
const submit = async (formEl: FormInstance | undefined, test?: string) => {
|
||||
if (!formEl) return
|
||||
await formEl.validate((valid, fields) => {
|
||||
if (valid) {
|
||||
authApi.putAuthSetting(form.value.auth_type, form.value, loading).then((res) => {
|
||||
MsgSuccess(t('common.saveSuccess'))
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function getDetail() {
|
||||
authApi.getAuthSetting(form.value.auth_type, loading).then((res: any) => {
|
||||
if (res.data && JSON.stringify(res.data) !== '{}') {
|
||||
form.value = res.data
|
||||
if (
|
||||
form.value.config.fieldMapping === '' ||
|
||||
form.value.config.fieldMapping === undefined
|
||||
) {
|
||||
form.value.config.fieldMapping = '{"username": "preferred_username", "email": "email"}'
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
getDetail()
|
||||
})
|
||||
</script>
|
||||
<style lang="scss" scoped></style>
|
||||
|
|
@ -0,0 +1,236 @@
|
|||
<template>
|
||||
<div v-loading="loading" class="scan-height">
|
||||
<el-scrollbar>
|
||||
<div v-for="item in platforms" :key="item.key" class="mb-16">
|
||||
<el-card class="border-none mb-16" shadow="none">
|
||||
<div class="flex-between">
|
||||
<div class="flex align-center">
|
||||
<img :src="item.logoSrc" alt="" width="24px" />
|
||||
<h5 class="ml-8">{{ item.name }}</h5>
|
||||
<el-tag v-if="item.isValid" type="success" class="ml-8"
|
||||
>{{ $t('views.system.authentication.scanTheQRCode.effective') }}
|
||||
</el-tag>
|
||||
</div>
|
||||
<div>
|
||||
<el-button type="primary" v-if="!item.isValid" @click="showDialog(item)"
|
||||
>{{ $t('views.system.authentication.scanTheQRCode.access') }}
|
||||
</el-button>
|
||||
<span v-if="item.isValid">
|
||||
<span class="mr-4">{{
|
||||
item.isActive
|
||||
? $t('views.system.authentication.scanTheQRCode.alreadyTurnedOn')
|
||||
: $t('views.system.authentication.scanTheQRCode.notEnabled')
|
||||
}}</span>
|
||||
<el-switch
|
||||
size="small"
|
||||
v-model="item.isActive"
|
||||
:disabled="!item.isValid"
|
||||
@change="changeStatus(item)"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<el-collapse-transition>
|
||||
<div v-if="item.isValid" class="border-t mt-16">
|
||||
<el-row :gutter="12" class="mt-16">
|
||||
<el-col v-for="(value, key) in item.config" :key="key" :span="12">
|
||||
<el-text type="info">{{ formatFieldName(key, item) }}</el-text>
|
||||
<div class="mt-4 mb-16 flex align-center">
|
||||
<span
|
||||
v-if="key !== 'app_secret'"
|
||||
class="vertical-middle lighter break-all ellipsis-1"
|
||||
>{{ value }}</span
|
||||
>
|
||||
<span
|
||||
v-if="key === 'app_secret' && !showPassword[item.key]?.[key]"
|
||||
class="vertical-middle lighter break-all ellipsis-1"
|
||||
>************</span
|
||||
>
|
||||
<span
|
||||
v-if="key === 'app_secret' && showPassword[item.key]?.[key]"
|
||||
class="vertical-middle lighter break-all ellipsis-1"
|
||||
>{{ value }}</span
|
||||
>
|
||||
<el-button type="primary" text @click="() => copyClick(value)">
|
||||
<AppIcon iconName="app-copy" />
|
||||
</el-button>
|
||||
<el-button
|
||||
v-if="key === 'app_secret'"
|
||||
type="primary"
|
||||
text
|
||||
@click="toggleShowPassword(item.key)"
|
||||
>
|
||||
<el-icon v-if="key === 'app_secret' && !showPassword[item.key]?.[key]">
|
||||
<Hide />
|
||||
</el-icon>
|
||||
<el-icon v-if="key === 'app_secret' && showPassword[item.key]?.[key]">
|
||||
<View />
|
||||
</el-icon>
|
||||
</el-button>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-button type="primary" @click="showDialog(item)">
|
||||
{{ $t('common.edit') }}
|
||||
</el-button>
|
||||
<el-button @click="validateConnection(item)">
|
||||
{{ $t('views.system.authentication.scanTheQRCode.validate') }}
|
||||
</el-button>
|
||||
</div>
|
||||
</el-collapse-transition>
|
||||
</el-card>
|
||||
</div>
|
||||
<EditModel ref="EditModelRef" @refresh="refresh" />
|
||||
</el-scrollbar>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { reactive, ref, onMounted } from 'vue'
|
||||
import { copyClick } from '@/utils/clipboard'
|
||||
import EditModel from './EditModal.vue'
|
||||
import platformApi from '@/api/system-settings/platform-source'
|
||||
import { MsgError, MsgSuccess } from '@/utils/message'
|
||||
import { t } from '@/locales'
|
||||
|
||||
interface PlatformConfig {
|
||||
[key: string]: string
|
||||
}
|
||||
|
||||
interface Platform {
|
||||
key: string
|
||||
logoSrc: string
|
||||
name: string
|
||||
isActive: boolean
|
||||
isValid: boolean
|
||||
config: PlatformConfig
|
||||
}
|
||||
|
||||
const EditModelRef = ref()
|
||||
const loading = ref(false)
|
||||
const platforms = reactive<Platform[]>(initializePlatforms())
|
||||
const showPassword = reactive<{ [platformKey: string]: { [key: string]: boolean } }>({})
|
||||
|
||||
onMounted(() => {
|
||||
getPlatformInfo()
|
||||
})
|
||||
|
||||
function initializePlatforms(): Platform[] {
|
||||
return [
|
||||
createPlatform('wecom', t('views.system.authentication.scanTheQRCode.wecom')),
|
||||
createPlatform('dingtalk', t('views.system.authentication.scanTheQRCode.dingtalk')),
|
||||
createPlatform('lark', t('views.system.authentication.scanTheQRCode.lark'))
|
||||
]
|
||||
}
|
||||
|
||||
function createPlatform(key: string, name: string): Platform {
|
||||
let logo = ''
|
||||
switch (key) {
|
||||
case 'wecom':
|
||||
logo = 'wechat-work'
|
||||
break
|
||||
case 'dingtalk':
|
||||
logo = 'dingtalk'
|
||||
break
|
||||
case 'lark':
|
||||
logo = 'lark'
|
||||
break
|
||||
default:
|
||||
logo = '' // 默认值
|
||||
break
|
||||
}
|
||||
|
||||
const config = {
|
||||
...(key === 'wecom' ? { corp_id: '', agent_id: '' } : { app_key: '' }),
|
||||
app_secret: '',
|
||||
callback_url: ''
|
||||
}
|
||||
|
||||
return {
|
||||
key,
|
||||
logoSrc: new URL(`../../../assets/scan/logo_${logo}.svg`, import.meta.url).href,
|
||||
name,
|
||||
isActive: false,
|
||||
isValid: false,
|
||||
config
|
||||
}
|
||||
}
|
||||
|
||||
function formatFieldName(key?: any, item?: Platform): string {
|
||||
const fieldNames: { [key: string]: string } = {
|
||||
corp_id: 'Corp ID',
|
||||
app_key: item?.key != 'lark' ? 'APP Key' : 'App ID',
|
||||
app_secret: 'APP Secret',
|
||||
agent_id: 'Agent ID',
|
||||
callback_url: t('views.application.applicationAccess.callback')
|
||||
}
|
||||
return (
|
||||
fieldNames[key as keyof typeof fieldNames] ||
|
||||
(key ? key.charAt(0).toUpperCase() + key.slice(1) : '')
|
||||
)
|
||||
}
|
||||
|
||||
function getPlatformInfo() {
|
||||
loading.value = true
|
||||
platformApi.getPlatformInfo(loading).then((res: any) => {
|
||||
if (res) {
|
||||
platforms.forEach((platform) => {
|
||||
const data = res.data.find((item: any) => item.auth_type === platform.key)
|
||||
if (data) {
|
||||
Object.assign(platform, {
|
||||
isValid: data.is_valid,
|
||||
isActive: data.is_active,
|
||||
config: data.config
|
||||
})
|
||||
if (platform.key === 'dingtalk') {
|
||||
const { corp_id, app_key, app_secret } = platform.config
|
||||
platform.config = {
|
||||
corp_id,
|
||||
app_key,
|
||||
app_secret,
|
||||
callback_url: platform.config.callback_url
|
||||
}
|
||||
}
|
||||
showPassword[platform.key] = {}
|
||||
showPassword[platform.key]['app_secret'] = false
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function validateConnection(currentPlatform: Platform) {
|
||||
platformApi.validateConnection(currentPlatform, loading).then((res: any) => {
|
||||
res.data
|
||||
? MsgSuccess(t('views.system.authentication.scanTheQRCode.validateSuccess'))
|
||||
: MsgError(t('views.system.authentication.scanTheQRCode.validateFailed'))
|
||||
})
|
||||
}
|
||||
|
||||
function refresh() {
|
||||
getPlatformInfo()
|
||||
}
|
||||
|
||||
function changeStatus(currentPlatform: Platform) {
|
||||
platformApi.updateConfig(currentPlatform, loading).then((res: any) => {
|
||||
MsgSuccess(t('common.saveSuccess'))
|
||||
})
|
||||
}
|
||||
|
||||
function toggleShowPassword(platformKey: string) {
|
||||
if (!showPassword[platformKey]) {
|
||||
showPassword[platformKey] = {}
|
||||
}
|
||||
showPassword[platformKey]['app_secret'] = !showPassword[platformKey]['app_secret']
|
||||
}
|
||||
|
||||
function showDialog(platform: Platform) {
|
||||
EditModelRef.value?.open(platform)
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.scan-height {
|
||||
height: calc(100vh - var(--app-header-height) - var(--app-view-padding) * 2 - 70px);
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,77 @@
|
|||
<template>
|
||||
<div class="authentication-setting p-16-24">
|
||||
<h4 class="mb-16">{{ $t('views.system.authentication.title') }}</h4>
|
||||
|
||||
<el-tabs v-model="activeName" class="mt-4" @tab-click="handleClick">
|
||||
<template v-for="(item, index) in tabList" :key="index">
|
||||
<el-tab-pane :label="item.label" :name="item.name">
|
||||
<component :is="item.component" />
|
||||
</el-tab-pane>
|
||||
</template>
|
||||
</el-tabs>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import LDAP from './component/LDAP.vue'
|
||||
import CAS from './component/CAS.vue'
|
||||
import OIDC from './component/OIDC.vue'
|
||||
import SCAN from './component/SCAN.vue'
|
||||
import OAuth2 from './component/OAuth2.vue'
|
||||
import { t } from '@/locales'
|
||||
import useStore from '@/stores'
|
||||
|
||||
const { user } = useStore()
|
||||
const router = useRouter()
|
||||
|
||||
const activeName = ref('LDAP')
|
||||
const tabList = [
|
||||
{
|
||||
label: t('views.system.authentication.ldap.title'),
|
||||
name: 'LDAP',
|
||||
component: LDAP,
|
||||
},
|
||||
{
|
||||
label: t('views.system.authentication.cas.title'),
|
||||
name: 'CAS',
|
||||
component: CAS,
|
||||
},
|
||||
{
|
||||
label: t('views.system.authentication.oidc.title'),
|
||||
name: 'OIDC',
|
||||
component: OIDC,
|
||||
},
|
||||
{
|
||||
label: t('views.system.authentication.oauth2.title'),
|
||||
name: 'OAuth2',
|
||||
component: OAuth2,
|
||||
},
|
||||
{
|
||||
label: t('views.system.authentication.scanTheQRCode.title'),
|
||||
name: 'SCAN',
|
||||
component: SCAN,
|
||||
},
|
||||
]
|
||||
|
||||
function handleClick() {}
|
||||
|
||||
onMounted(() => {
|
||||
if (user.isExpire()) {
|
||||
router.push({ path: `/application` })
|
||||
}
|
||||
})
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.authentication-setting__main {
|
||||
background-color: var(--app-view-bg-color);
|
||||
box-sizing: border-box;
|
||||
min-width: 700px;
|
||||
height: calc(100vh - var(--app-header-height) - var(--app-view-padding) * 2 - 70px);
|
||||
box-sizing: border-box;
|
||||
:deep(.form-container) {
|
||||
width: 70%;
|
||||
margin: 0 auto;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,199 @@
|
|||
<template>
|
||||
<el-drawer v-model="visible" size="60%">
|
||||
<template #header>
|
||||
<h4>{{ title }}</h4>
|
||||
</template>
|
||||
<h4 class="title-decoration-1 mb-16 mt-8">{{ $t('common.info') }}</h4>
|
||||
<el-form
|
||||
ref="userFormRef"
|
||||
:model="userForm"
|
||||
:rules="rules"
|
||||
label-position="top"
|
||||
require-asterisk-position="right"
|
||||
@submit.prevent
|
||||
:close-on-click-modal="false"
|
||||
:close-on-press-escape="false"
|
||||
>
|
||||
<el-form-item
|
||||
:prop="isEdit ? '' : 'username'"
|
||||
:label="$t('views.userManage.form.username.label')"
|
||||
>
|
||||
<el-input
|
||||
v-model="userForm.username"
|
||||
:placeholder="$t('views.userManage.form.username.placeholder')"
|
||||
maxlength="20"
|
||||
show-word-limit
|
||||
:disabled="isEdit"
|
||||
>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('views.userManage.form.nick_name.label')">
|
||||
<el-input
|
||||
v-model="userForm.nick_name"
|
||||
:placeholder="$t('views.userManage.form.nick_name.placeholder')"
|
||||
maxlength="64"
|
||||
show-word-limit
|
||||
>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('views.userManage.form.email.label')" prop="email">
|
||||
<el-input
|
||||
type="email"
|
||||
v-model="userForm.email"
|
||||
:placeholder="$t('views.userManage.form.email.placeholder')"
|
||||
>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('views.userManage.form.phone.label')">
|
||||
<el-input
|
||||
v-model="userForm.phone"
|
||||
:placeholder="$t('views.userManage.form.phone.placeholder')"
|
||||
>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
:label="$t('views.userManage.form.password.label')"
|
||||
prop="password"
|
||||
v-if="!isEdit"
|
||||
>
|
||||
<el-input
|
||||
type="password"
|
||||
v-model="userForm.password"
|
||||
:placeholder="$t('views.userManage.form.password.placeholder')"
|
||||
show-password
|
||||
>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
:label="$t('views.userManage.form.password.label')"
|
||||
prop="password"
|
||||
v-if="!isEdit"
|
||||
>
|
||||
<el-input
|
||||
type="password"
|
||||
v-model="userForm.password"
|
||||
:placeholder="$t('views.userManage.form.password.placeholder')"
|
||||
show-password
|
||||
>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click.prevent="visible = false"> {{ $t('common.cancel') }} </el-button>
|
||||
<el-button type="primary" @click="submit(userFormRef)" :loading="loading">
|
||||
{{ $t('common.save') }}
|
||||
</el-button>
|
||||
</template>
|
||||
</el-drawer>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive, watch } from 'vue'
|
||||
import type { FormInstance } from 'element-plus'
|
||||
import userManageApi from '@/api/user/user-manage'
|
||||
import { MsgSuccess } from '@/utils/message'
|
||||
import { t } from '@/locales'
|
||||
const props = defineProps({
|
||||
title: String,
|
||||
})
|
||||
|
||||
const emit = defineEmits(['refresh'])
|
||||
|
||||
const userFormRef = ref()
|
||||
const userForm = ref<any>({
|
||||
username: '',
|
||||
email: '',
|
||||
password: '',
|
||||
phone: '',
|
||||
nick_name: '',
|
||||
})
|
||||
|
||||
const rules = reactive({
|
||||
username: [
|
||||
{
|
||||
required: true,
|
||||
message: t('views.userManage.form.username.requiredMessage'),
|
||||
trigger: 'blur',
|
||||
},
|
||||
{
|
||||
min: 6,
|
||||
max: 20,
|
||||
message: t('views.userManage.form.username.lengthMessage'),
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
email: [
|
||||
{
|
||||
required: true,
|
||||
message: t('views.userManage.form.email.requiredMessage'),
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
password: [
|
||||
{
|
||||
required: true,
|
||||
message: t('views.userManage.form.password.requiredMessage'),
|
||||
trigger: 'blur',
|
||||
},
|
||||
{
|
||||
min: 6,
|
||||
max: 20,
|
||||
message: t('views.userManage.form.password.lengthMessage'),
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
})
|
||||
const visible = ref<boolean>(false)
|
||||
const loading = ref(false)
|
||||
const isEdit = ref(false)
|
||||
|
||||
watch(visible, (bool) => {
|
||||
if (!bool) {
|
||||
userForm.value = {
|
||||
username: '',
|
||||
email: '',
|
||||
password: '',
|
||||
phone: '',
|
||||
nick_name: '',
|
||||
}
|
||||
isEdit.value = false
|
||||
userFormRef.value?.clearValidate()
|
||||
}
|
||||
})
|
||||
|
||||
const open = (data: any) => {
|
||||
if (data) {
|
||||
userForm.value['id'] = data.id
|
||||
userForm.value.username = data.username
|
||||
userForm.value.email = data.email
|
||||
userForm.value.password = data.password
|
||||
userForm.value.phone = data.phone
|
||||
userForm.value.nick_name = data.nick_name
|
||||
isEdit.value = true
|
||||
}
|
||||
visible.value = true
|
||||
}
|
||||
|
||||
const submit = async (formEl: FormInstance | undefined) => {
|
||||
if (!formEl) return
|
||||
await formEl.validate((valid, fields) => {
|
||||
if (valid) {
|
||||
if (isEdit.value) {
|
||||
userManageApi.putUserManage(userForm.value.id, userForm.value, loading).then((res) => {
|
||||
emit('refresh')
|
||||
MsgSuccess(t('common.editSuccess'))
|
||||
visible.value = false
|
||||
})
|
||||
} else {
|
||||
userManageApi.postUserManage(userForm.value, loading).then((res) => {
|
||||
emit('refresh')
|
||||
MsgSuccess(t('common.createSuccess'))
|
||||
visible.value = false
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
defineExpose({ open })
|
||||
</script>
|
||||
<style lang="scss" scoped></style>
|
||||
|
|
@ -0,0 +1,133 @@
|
|||
<template>
|
||||
<el-dialog :title="$t('views.userManage.setting.updatePwd')" v-model="dialogVisible">
|
||||
<el-form
|
||||
ref="userFormRef"
|
||||
:model="userForm"
|
||||
:rules="rules"
|
||||
label-position="top"
|
||||
require-asterisk-position="right"
|
||||
@submit.prevent
|
||||
:close-on-click-modal="false"
|
||||
:close-on-press-escape="false"
|
||||
>
|
||||
<el-form-item :label="$t('views.userManage.form.new_password.label')" prop="password">
|
||||
<el-input
|
||||
type="password"
|
||||
v-model="userForm.password"
|
||||
:placeholder="$t('views.userManage.form.new_password.placeholder')"
|
||||
show-password
|
||||
>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('views.userManage.form.re_password.label')" prop="re_password">
|
||||
<el-input
|
||||
type="password"
|
||||
v-model="userForm.re_password"
|
||||
:placeholder="$t('views.userManage.form.re_password.placeholder')"
|
||||
show-password
|
||||
>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click.prevent="dialogVisible = false"> {{ $t('common.cancel') }} </el-button>
|
||||
<el-button type="primary" @click="submit(userFormRef)" :loading="loading">
|
||||
{{ $t('common.save') }}
|
||||
</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive, watch } from 'vue'
|
||||
import useStore from '@/stores'
|
||||
import type { FormInstance, FormRules } from 'element-plus'
|
||||
import type { ResetPasswordRequest } from '@/api/type/user'
|
||||
import userManageApi from '@/api/user/user-manage'
|
||||
import { MsgSuccess } from '@/utils/message'
|
||||
import { t } from '@/locales'
|
||||
const emit = defineEmits(['refresh'])
|
||||
|
||||
const { user } = useStore()
|
||||
|
||||
const userFormRef = ref()
|
||||
const userForm = ref<any>({
|
||||
password: '',
|
||||
re_password: ''
|
||||
})
|
||||
|
||||
const rules = reactive<FormRules<ResetPasswordRequest>>({
|
||||
password: [
|
||||
{
|
||||
required: true,
|
||||
message: t('views.userManage.form.new_password.requiredMessage'),
|
||||
trigger: 'blur'
|
||||
},
|
||||
{
|
||||
min: 6,
|
||||
max: 20,
|
||||
message: t('views.userManage.form.password.lengthMessage'),
|
||||
trigger: 'blur'
|
||||
}
|
||||
],
|
||||
re_password: [
|
||||
{
|
||||
required: true,
|
||||
message: t('views.userManage.form.re_password.requiredMessage'),
|
||||
trigger: 'blur'
|
||||
},
|
||||
{
|
||||
min: 6,
|
||||
max: 20,
|
||||
message: t('views.userManage.form.password.lengthMessage'),
|
||||
trigger: 'blur'
|
||||
},
|
||||
{
|
||||
validator: (rule, value, callback) => {
|
||||
if (userFormRef.value.password != userFormRef.value.re_password) {
|
||||
callback(new Error(t('views.userManage.form.re_password.validatorMessage')))
|
||||
} else {
|
||||
callback()
|
||||
}
|
||||
},
|
||||
trigger: 'blur'
|
||||
}
|
||||
]
|
||||
})
|
||||
const dialogVisible = ref<boolean>(false)
|
||||
const loading = ref(false)
|
||||
const userId = ref('')
|
||||
|
||||
watch(dialogVisible, (bool) => {
|
||||
if (!bool) {
|
||||
userForm.value = {
|
||||
password: '',
|
||||
re_password: ''
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const open = (data: any) => {
|
||||
userId.value = data.id
|
||||
dialogVisible.value = true
|
||||
userFormRef.value?.clearValidate()
|
||||
}
|
||||
|
||||
const submit = async (formEl: FormInstance | undefined) => {
|
||||
if (!formEl) return
|
||||
await formEl.validate((valid, fields) => {
|
||||
if (valid) {
|
||||
userManageApi.putUserManagePassword(userId.value, userForm.value, loading).then((res) => {
|
||||
emit('refresh')
|
||||
user.profile()
|
||||
MsgSuccess(t('views.userManage.tip.updatePwdSuccess'))
|
||||
dialogVisible.value = false
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
defineExpose({ open })
|
||||
</script>
|
||||
<style lang="scss" scoped></style>
|
||||
|
|
@ -0,0 +1,261 @@
|
|||
<template>
|
||||
<div class="p-16-24">
|
||||
<h2 class="mb-16">{{ $t('views.userManage.title') }}</h2>
|
||||
<el-card>
|
||||
<div class="flex-between mb-16">
|
||||
<el-button type="primary" @click="createUser()">{{
|
||||
$t('views.userManage.createUser')
|
||||
}}</el-button>
|
||||
<div class="flex-between complex-search">
|
||||
<el-select
|
||||
class="complex-search__left"
|
||||
v-model="search_type"
|
||||
style="width: 120px"
|
||||
@change="search_type_change"
|
||||
>
|
||||
<el-option :label="$t('views.login.loginForm.username.label')" value="name" />
|
||||
</el-select>
|
||||
<el-input
|
||||
v-if="search_type === 'name'"
|
||||
v-model="search_form.name"
|
||||
@change="getList"
|
||||
:placeholder="$t('common.searchBar.placeholder')"
|
||||
style="width: 220px"
|
||||
clearable
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<app-table
|
||||
class="mt-16"
|
||||
:data="userTableData"
|
||||
:pagination-config="paginationConfig"
|
||||
@sizeChange="handleSizeChange"
|
||||
@changePage="getList"
|
||||
v-loading="loading"
|
||||
>
|
||||
<el-table-column prop="nick_name" :label="$t('views.userManage.form.nick_name.label')" />
|
||||
<el-table-column prop="username" :label="$t('views.userManage.form.username.label')" />
|
||||
<el-table-column prop="is_active" :label="$t('common.status.label')">
|
||||
<template #default="{ row }">
|
||||
<div v-if="row.is_active" class="flex align-center">
|
||||
<el-icon class="color-success mr-8" style="font-size: 16px"
|
||||
><SuccessFilled
|
||||
/></el-icon>
|
||||
<span class="color-secondary">
|
||||
{{ $t('common.status.enabled') }}
|
||||
</span>
|
||||
</div>
|
||||
<div v-else class="flex align-center">
|
||||
<AppIcon iconName="app-disabled" class="color-secondary mr-8"></AppIcon>
|
||||
<span class="color-secondary">
|
||||
{{ $t('common.status.disabled') }}
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column
|
||||
prop="email"
|
||||
:label="$t('views.userManage.form.email.label')"
|
||||
show-overflow-tooltip
|
||||
>
|
||||
<template #default="{ row }">
|
||||
{{ row.email || '-' }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="phone" :label="$t('views.userManage.form.phone.label')">
|
||||
<template #default="{ row }">
|
||||
{{ row.phone || '-' }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="source" :label="$t('views.userManage.source.label')">
|
||||
<template #default="{ row }">
|
||||
{{
|
||||
row.source === 'LOCAL'
|
||||
? $t('views.userManage.source.local')
|
||||
: row.source === 'wecom'
|
||||
? $t('views.userManage.source.wecom')
|
||||
: row.source === 'lark'
|
||||
? $t('views.userManage.source.lark')
|
||||
: row.source === 'dingtalk'
|
||||
? $t('views.userManage.source.dingtalk')
|
||||
: row.source === 'OAUTH2' || row.source === 'OAuth2'
|
||||
? 'OAuth2'
|
||||
: row.source
|
||||
}}
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column :label="$t('common.createTime')" width="180">
|
||||
<template #default="{ row }">
|
||||
{{ datetimeFormat(row.create_time) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column :label="$t('common.operation')" width="160" align="left" fixed="right">
|
||||
<template #default="{ row }">
|
||||
<span @click.stop>
|
||||
<el-switch
|
||||
:disabled="row.role === 'ADMIN'"
|
||||
size="small"
|
||||
v-model="row.is_active"
|
||||
:before-change="() => changeState(row)"
|
||||
/>
|
||||
</span>
|
||||
<el-divider direction="vertical" />
|
||||
<span class="mr-8">
|
||||
<el-button type="primary" text @click.stop="editUser(row)" :title="$t('common.edit')">
|
||||
<el-icon><EditPen /></el-icon>
|
||||
</el-button>
|
||||
</span>
|
||||
|
||||
<span class="mr-8">
|
||||
<el-button
|
||||
type="primary"
|
||||
text
|
||||
@click.stop="editPwdUser(row)"
|
||||
:title="$t('views.userManage.setting.updatePwd')"
|
||||
>
|
||||
<el-icon><Lock /></el-icon>
|
||||
</el-button>
|
||||
</span>
|
||||
<span>
|
||||
<el-button
|
||||
:disabled="row.role === 'ADMIN'"
|
||||
type="primary"
|
||||
text
|
||||
@click.stop="deleteUserManage(row)"
|
||||
:title="$t('common.delete')"
|
||||
>
|
||||
<el-icon><Delete /></el-icon>
|
||||
</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</app-table>
|
||||
</el-card>
|
||||
<UserDrawer :title="title" ref="UserDrawerRef" @refresh="refresh" />
|
||||
<UserPwdDialog ref="UserPwdDialogRef" @refresh="refresh" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { onMounted, ref, reactive, watch } from 'vue'
|
||||
import UserDrawer from './component/UserDrawer.vue'
|
||||
import UserPwdDialog from './component/UserPwdDialog.vue'
|
||||
import userManageApi from '@/api/user/user-manage'
|
||||
import { datetimeFormat } from '@/utils/time'
|
||||
import { MsgSuccess, MsgConfirm } from '@/utils/message'
|
||||
import { t } from '@/locales'
|
||||
const search_type = ref('name')
|
||||
const search_form = ref<{
|
||||
name: string
|
||||
}>({
|
||||
name: '',
|
||||
})
|
||||
|
||||
const UserDrawerRef = ref()
|
||||
const UserPwdDialogRef = ref()
|
||||
const loading = ref(false)
|
||||
|
||||
const paginationConfig = reactive({
|
||||
current_page: 1,
|
||||
page_size: 20,
|
||||
total: 0,
|
||||
})
|
||||
|
||||
const userTableData = ref<any[]>([])
|
||||
|
||||
const search_type_change = () => {
|
||||
search_form.value = { name: '' }
|
||||
}
|
||||
function handleSizeChange() {
|
||||
paginationConfig.current_page = 1
|
||||
getList()
|
||||
}
|
||||
|
||||
function getList() {
|
||||
return userManageApi
|
||||
.getUserManage(paginationConfig, search_form.value.name, loading)
|
||||
.then((res) => {
|
||||
userTableData.value = res.data.records
|
||||
paginationConfig.total = res.data.total
|
||||
})
|
||||
}
|
||||
|
||||
function changeState(row: any) {
|
||||
const obj = {
|
||||
is_active: !row.is_active,
|
||||
}
|
||||
const str = obj.is_active ? t('common.status.enableSuccess') : t('common.status.disableSuccess')
|
||||
userManageApi
|
||||
.putUserManage(row.id, obj, loading)
|
||||
.then((res) => {
|
||||
getList()
|
||||
MsgSuccess(str)
|
||||
return true
|
||||
})
|
||||
.catch(() => {
|
||||
return false
|
||||
})
|
||||
}
|
||||
|
||||
const title = ref('')
|
||||
function editUser(row: any) {
|
||||
title.value = t('views.userManage.editUser')
|
||||
UserDrawerRef.value.open(row)
|
||||
}
|
||||
|
||||
function createUser() {
|
||||
title.value = t('views.userManage.createUser')
|
||||
UserDrawerRef.value.open(1)
|
||||
// common.asyncGetValid(ValidType.User, ValidCount.User, loading).then(async (res: any) => {
|
||||
// if (res?.data) {
|
||||
// title.value = t('views.userManage.createUser')
|
||||
// UserDrawerRef.value.open()
|
||||
// } else if (res?.code === 400) {
|
||||
// MsgConfirm(t('common.tip'), t('views.userManage.tip.professionalMessage'), {
|
||||
// cancelButtonText: t('common.confirm'),
|
||||
// confirmButtonText: t('common.professional'),
|
||||
// })
|
||||
// .then(() => {
|
||||
// window.open('https://maxkb.cn/pricing.html', '_blank')
|
||||
// })
|
||||
// .catch(() => {})
|
||||
// }
|
||||
// })
|
||||
}
|
||||
|
||||
function deleteUserManage(row: any) {
|
||||
MsgConfirm(
|
||||
`${t('views.user.delete.confirmTitle')}${row.username} ?`,
|
||||
t('views.user.delete.confirmMessage'),
|
||||
{
|
||||
confirmButtonText: t('common.confirm'),
|
||||
confirmButtonClass: 'danger',
|
||||
},
|
||||
)
|
||||
.then(() => {
|
||||
loading.value = true
|
||||
userManageApi.delUserManage(row.id, loading).then(() => {
|
||||
MsgSuccess(t('common.deleteSuccess'))
|
||||
getList()
|
||||
})
|
||||
})
|
||||
.catch(() => {})
|
||||
}
|
||||
|
||||
function editPwdUser(row: any) {
|
||||
UserPwdDialogRef.value.open(row)
|
||||
}
|
||||
|
||||
function refresh() {
|
||||
getList()
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
getList()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
|
|
@ -51,31 +51,8 @@
|
|||
>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
:label="$t('views.userManage.form.password.label')"
|
||||
prop="password"
|
||||
v-if="!isEdit"
|
||||
>
|
||||
<el-input
|
||||
type="password"
|
||||
v-model="userForm.password"
|
||||
:placeholder="$t('views.userManage.form.password.placeholder')"
|
||||
show-password
|
||||
>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
:label="$t('views.userManage.form.password.label')"
|
||||
prop="password"
|
||||
v-if="!isEdit"
|
||||
>
|
||||
<el-input
|
||||
type="password"
|
||||
v-model="userForm.password"
|
||||
:placeholder="$t('views.userManage.form.password.placeholder')"
|
||||
show-password
|
||||
>
|
||||
</el-input>
|
||||
<el-form-item label="默认密码" v-if="!isEdit">
|
||||
<span>MaxKB@123</span>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
|
|
|
|||
|
|
@ -207,6 +207,8 @@ function editUser(row: any) {
|
|||
}
|
||||
|
||||
function createUser() {
|
||||
title.value = t('views.userManage.createUser')
|
||||
UserDrawerRef.value.open()
|
||||
// common.asyncGetValid(ValidType.User, ValidCount.User, loading).then(async (res: any) => {
|
||||
// if (res?.data) {
|
||||
// title.value = t('views.userManage.createUser')
|
||||
|
|
|
|||
Loading…
Reference in New Issue