初始提交:OCI 面板前端(含 GenAI 网关一期)
This commit is contained in:
@@ -0,0 +1,233 @@
|
||||
<script setup lang="ts">
|
||||
import { NCheckbox, NInput, useMessage } from 'naive-ui'
|
||||
import { computed, reactive, ref, watch } from 'vue'
|
||||
|
||||
import {
|
||||
createUser,
|
||||
getIdentitySetting,
|
||||
getUserDetail,
|
||||
updateUser,
|
||||
type UpdateUserBody,
|
||||
} from '@/api/tenant'
|
||||
import FormField from '@/components/FormField.vue'
|
||||
import FormModal from '@/components/FormModal.vue'
|
||||
import type { IamUser, IamUserDetail } from '@/types/api'
|
||||
|
||||
// user 非空即编辑模式:打开时拉取域档案预填充,提交只发送与原值不同的字段
|
||||
const props = defineProps<{ show: boolean; cfgId: number; user?: IamUser | null }>()
|
||||
const emit = defineEmits<{ 'update:show': [boolean]; created: [] }>()
|
||||
|
||||
const message = useMessage()
|
||||
const submitting = ref(false)
|
||||
// 域开启「用户需要提供主电子邮件地址」时邮箱必填
|
||||
const emailRequired = ref(false)
|
||||
// 编辑模式的域档案;加载失败保持 null,降级为「留空不修改、勾选仅添加」
|
||||
const detail = ref<IamUserDetail | null>(null)
|
||||
const detailLoading = ref(false)
|
||||
|
||||
const blank = {
|
||||
name: '',
|
||||
givenName: '',
|
||||
familyName: '',
|
||||
email: '',
|
||||
description: '',
|
||||
grantDomainAdmin: false,
|
||||
addToAdminGroup: false,
|
||||
}
|
||||
const form = reactive({ ...blank })
|
||||
const editing = computed(() => !!props.user)
|
||||
// 经典 IAM 用户不在身份域中,姓名与管理员状态均不可操作
|
||||
const classicUser = computed(() => editing.value && !!detail.value && !detail.value.inDomain)
|
||||
|
||||
watch(
|
||||
() => props.show,
|
||||
(v) => {
|
||||
if (!v) return
|
||||
Object.assign(form, blank)
|
||||
detail.value = null
|
||||
if (props.user) {
|
||||
form.name = props.user.name
|
||||
form.email = props.user.email
|
||||
form.description = props.user.description
|
||||
void loadDetail(props.user.id)
|
||||
}
|
||||
void loadIdentitySetting()
|
||||
},
|
||||
)
|
||||
|
||||
async function loadIdentitySetting() {
|
||||
try {
|
||||
emailRequired.value = (await getIdentitySetting(props.cfgId)).primaryEmailRequired
|
||||
} catch {
|
||||
emailRequired.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 拉取域档案并回填表单;返回时弹窗已切到别的用户则丢弃结果
|
||||
async function loadDetail(userId: string) {
|
||||
detailLoading.value = true
|
||||
try {
|
||||
const d = await getUserDetail(props.cfgId, userId)
|
||||
if (props.user?.id !== userId) return
|
||||
detail.value = d
|
||||
if (!d.inDomain) return
|
||||
form.givenName = d.givenName
|
||||
form.familyName = d.familyName
|
||||
form.grantDomainAdmin = d.isDomainAdmin
|
||||
form.addToAdminGroup = d.inAdminGroup
|
||||
} catch {
|
||||
if (props.user?.id === userId)
|
||||
message.warning('用户详情加载失败:姓名留空表示不修改,管理员选项仅执行添加')
|
||||
} finally {
|
||||
if (props.user?.id === userId) detailLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const nameRequired = computed(() => !editing.value || !!detail.value?.inDomain)
|
||||
|
||||
const nameHint = computed(() => {
|
||||
if (!editing.value || detailLoading.value) return undefined
|
||||
if (classicUser.value) return '经典 IAM 用户不支持修改姓名'
|
||||
if (!detail.value) return '详情加载失败:留空表示不修改,仅身份域用户可改姓名'
|
||||
return undefined
|
||||
})
|
||||
|
||||
const adminHint = computed(() => {
|
||||
if (!editing.value)
|
||||
return form.grantDomainAdmin && form.addToAdminGroup
|
||||
? '同时勾选时先授予身份域管理员,再加入管理员组'
|
||||
: undefined
|
||||
if (detailLoading.value) return '正在加载当前管理员状态…'
|
||||
if (classicUser.value) return '经典 IAM 用户不在身份域中,无法调整管理员角色与组'
|
||||
if (!detail.value) return '详情加载失败:仅执行添加操作,不会撤销已有的管理员角色或组成员'
|
||||
return '已按当前状态勾选;取消勾选保存后将撤销对应的管理员角色 / 组成员'
|
||||
})
|
||||
|
||||
const canSubmit = computed(() => {
|
||||
const emailOk = !emailRequired.value || !!form.email.trim()
|
||||
if (!editing.value)
|
||||
return !!form.name.trim() && !!form.givenName.trim() && !!form.familyName.trim() && emailOk
|
||||
if (detailLoading.value) return false
|
||||
if (detail.value?.inDomain && (!form.givenName.trim() || !form.familyName.trim())) return false
|
||||
return emailOk
|
||||
})
|
||||
|
||||
// 编辑只提交与原值不同的字段;域档案在手时管理员勾选与当前状态比对,取消勾选即撤销
|
||||
function buildUpdateBody(u: IamUser): UpdateUserBody {
|
||||
const body: UpdateUserBody = {}
|
||||
if (form.email.trim() !== u.email) body.email = form.email.trim()
|
||||
if (form.description.trim() !== u.description) body.description = form.description.trim()
|
||||
if (classicUser.value) return body
|
||||
const d = detail.value
|
||||
if (d?.inDomain) {
|
||||
if (form.givenName.trim() !== d.givenName) body.givenName = form.givenName.trim()
|
||||
if (form.familyName.trim() !== d.familyName) body.familyName = form.familyName.trim()
|
||||
if (form.grantDomainAdmin !== d.isDomainAdmin) body.grantDomainAdmin = form.grantDomainAdmin
|
||||
if (form.addToAdminGroup !== d.inAdminGroup) body.addToAdminGroup = form.addToAdminGroup
|
||||
return body
|
||||
}
|
||||
if (form.givenName.trim()) body.givenName = form.givenName.trim()
|
||||
if (form.familyName.trim()) body.familyName = form.familyName.trim()
|
||||
if (form.grantDomainAdmin) body.grantDomainAdmin = true
|
||||
if (form.addToAdminGroup) body.addToAdminGroup = true
|
||||
return body
|
||||
}
|
||||
|
||||
async function submitEdit(u: IamUser) {
|
||||
const body = buildUpdateBody(u)
|
||||
if (!Object.keys(body).length) {
|
||||
emit('update:show', false)
|
||||
return
|
||||
}
|
||||
await updateUser(props.cfgId, u.id, body)
|
||||
message.success(`用户「${u.name}」已更新`)
|
||||
}
|
||||
|
||||
async function submitCreate() {
|
||||
const created = await createUser(props.cfgId, {
|
||||
name: form.name.trim(),
|
||||
givenName: form.givenName.trim(),
|
||||
familyName: form.familyName.trim(),
|
||||
email: form.email.trim() || undefined,
|
||||
description: form.description.trim() || undefined,
|
||||
grantDomainAdmin: form.grantDomainAdmin,
|
||||
addToAdminGroup: form.addToAdminGroup,
|
||||
})
|
||||
message.success(`用户「${created.name}」已创建,可再执行「重置密码」下发初始密码`)
|
||||
}
|
||||
|
||||
async function submit() {
|
||||
if (!canSubmit.value) return
|
||||
submitting.value = true
|
||||
try {
|
||||
if (props.user) await submitEdit(props.user)
|
||||
else await submitCreate()
|
||||
emit('update:show', false)
|
||||
emit('created')
|
||||
} catch (e) {
|
||||
message.error(e instanceof Error ? e.message : editing.value ? '更新失败' : '创建失败')
|
||||
} finally {
|
||||
submitting.value = false
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<FormModal
|
||||
:show="show"
|
||||
:title="editing ? `修改用户 · ${user?.name ?? ''}` : '添加用户'"
|
||||
:submitting="submitting"
|
||||
:submit-disabled="!canSubmit"
|
||||
:submit-text="editing ? '保存' : '创建'"
|
||||
@update:show="emit('update:show', $event)"
|
||||
@submit="submit"
|
||||
>
|
||||
<FormField v-if="!editing" label="用户名" required>
|
||||
<NInput v-model:value="form.name" placeholder="new-user" @keyup.enter="submit" />
|
||||
</FormField>
|
||||
<div class="grid grid-cols-2 gap-3 max-md:grid-cols-1">
|
||||
<FormField label="名字" :required="nameRequired" :hint="nameHint">
|
||||
<NInput
|
||||
v-model:value="form.givenName"
|
||||
placeholder="First name"
|
||||
:disabled="classicUser"
|
||||
:loading="detailLoading"
|
||||
/>
|
||||
</FormField>
|
||||
<FormField label="姓氏" :required="nameRequired">
|
||||
<NInput
|
||||
v-model:value="form.familyName"
|
||||
placeholder="Last name"
|
||||
:disabled="classicUser"
|
||||
:loading="detailLoading"
|
||||
/>
|
||||
</FormField>
|
||||
</div>
|
||||
<FormField
|
||||
label="邮箱"
|
||||
:required="emailRequired"
|
||||
:hint="
|
||||
emailRequired
|
||||
? '域已开启「用户需要提供主电子邮件地址」,必须填写'
|
||||
: '用于接收欢迎邮件与找回密码'
|
||||
"
|
||||
>
|
||||
<NInput v-model:value="form.email" placeholder="user@example.com" />
|
||||
</FormField>
|
||||
<FormField label="备注" :hint="editing ? undefined : '留空默认取「名字 姓氏」'">
|
||||
<NInput v-model:value="form.description" placeholder="可选" />
|
||||
</FormField>
|
||||
<div class="mb-2 flex flex-col gap-1.5">
|
||||
<NCheckbox
|
||||
v-model:checked="form.grantDomainAdmin"
|
||||
:disabled="classicUser || detailLoading"
|
||||
>
|
||||
{{ editing ? '身份域管理员' : '添加到身份域管理员' }}
|
||||
</NCheckbox>
|
||||
<NCheckbox v-model:checked="form.addToAdminGroup" :disabled="classicUser || detailLoading">
|
||||
{{ editing ? '管理员组(Administrators)成员' : '添加到管理员组(Administrators)' }}
|
||||
</NCheckbox>
|
||||
<div v-if="adminHint" class="text-xs text-ink-3">{{ adminHint }}</div>
|
||||
</div>
|
||||
</FormModal>
|
||||
</template>
|
||||
Reference in New Issue
Block a user