feat(admin): account governance and user sync pages
Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,129 @@
|
||||
<!-- 编辑用户治理属性对话框:role/localLocked/displayName(sourceStatus 只读展示)。
|
||||
自我保护:自身行禁用角色与锁定编辑(服务端 400 双保险——http 层已本地化)。 -->
|
||||
<template>
|
||||
<ElDialog
|
||||
v-model="visible"
|
||||
:title="$t('usersManage.edit.title', { account: user?.account ?? '' })"
|
||||
width="520px"
|
||||
destroy-on-close
|
||||
data-test="user-edit-dialog"
|
||||
>
|
||||
<ElForm :model="form" label-width="120px">
|
||||
<ElFormItem :label="$t('usersManage.list.colAccount')">
|
||||
<span class="text-gray-500">{{ user?.account }}</span>
|
||||
</ElFormItem>
|
||||
<ElFormItem :label="$t('usersManage.list.colRole')">
|
||||
<ElSelect
|
||||
v-model="form.role"
|
||||
:disabled="isSelf"
|
||||
style="width: 200px"
|
||||
data-test="user-edit-role"
|
||||
>
|
||||
<ElOption value="staff" :label="$t('usersManage.role.staff')" />
|
||||
<ElOption value="admin" :label="$t('usersManage.role.admin')" />
|
||||
</ElSelect>
|
||||
</ElFormItem>
|
||||
<ElFormItem :label="$t('usersManage.list.colDisplayName')" :error="fieldErrors.displayName">
|
||||
<ElInput
|
||||
v-model="form.displayName"
|
||||
:placeholder="$t('usersManage.edit.displayNamePlaceholder')"
|
||||
data-test="user-edit-name"
|
||||
/>
|
||||
</ElFormItem>
|
||||
<ElFormItem :label="$t('usersManage.list.colLocalLocked')">
|
||||
<div class="flex flex-col gap-1">
|
||||
<ElSwitch v-model="form.localLocked" :disabled="isSelf" data-test="user-edit-locked" />
|
||||
<span class="text-gray-400 text-xs">{{ $t('usersManage.edit.lockedHint') }}</span>
|
||||
</div>
|
||||
</ElFormItem>
|
||||
</ElForm>
|
||||
|
||||
<ElAlert
|
||||
v-if="isSelf"
|
||||
type="info"
|
||||
:closable="false"
|
||||
:title="$t('usersManage.edit.selfGuardHint')"
|
||||
data-test="user-edit-self-hint"
|
||||
/>
|
||||
|
||||
<template #footer>
|
||||
<ElButton data-test="user-edit-cancel" @click="visible = false">
|
||||
{{ $t('common.cancel') }}
|
||||
</ElButton>
|
||||
<ElButton type="primary" :loading="submitting" data-test="user-edit-submit" @click="submit">
|
||||
{{ $t('usersManage.edit.submit') }}
|
||||
</ElButton>
|
||||
</template>
|
||||
</ElDialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, reactive, ref, watch } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { fetchUpdateAdminUser } from '@/api/adminUsers'
|
||||
import { buildUserUpdatePayload } from '@/utils/system/userAdmin'
|
||||
import { useUserStore } from '@/store/modules/user'
|
||||
|
||||
const props = defineProps<{
|
||||
/** 编辑目标(null 时对话框不应打开) */
|
||||
user: Api.AdminUser.Item | null
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'update:modelValue', value: boolean): void
|
||||
(e: 'saved', user: Api.AdminUser.Item): void
|
||||
}>()
|
||||
|
||||
const visible = defineModel<boolean>({ default: false })
|
||||
const { t } = useI18n()
|
||||
const userStore = useUserStore()
|
||||
|
||||
const form = reactive({
|
||||
role: 'staff' as Api.AdminUser.Role,
|
||||
displayName: '',
|
||||
localLocked: false
|
||||
})
|
||||
const fieldErrors = reactive({ displayName: '' })
|
||||
const submitting = ref(false)
|
||||
|
||||
/** 自身行:角色/锁定禁改(服务端同口径 400;displayName 自改放行) */
|
||||
const isSelf = computed(
|
||||
() => props.user !== null && props.user.account === (userStore.info?.userName ?? '')
|
||||
)
|
||||
|
||||
watch(visible, (open) => {
|
||||
if (!open || !props.user) return
|
||||
form.role = props.user.role
|
||||
form.displayName = props.user.displayName
|
||||
form.localLocked = props.user.localLocked
|
||||
fieldErrors.displayName = ''
|
||||
})
|
||||
|
||||
async function submit(): Promise<void> {
|
||||
if (!props.user) return
|
||||
fieldErrors.displayName = ''
|
||||
const payload = buildUserUpdatePayload(props.user, {
|
||||
role: form.role,
|
||||
displayName: form.displayName,
|
||||
localLocked: form.localLocked
|
||||
})
|
||||
if (Object.keys(payload).length === 0) {
|
||||
// 无变更:不制造服务端 no-op(幂等返回也不落审计,前端直接收口)
|
||||
ElMessage.info(t('usersManage.edit.noChanges'))
|
||||
visible.value = false
|
||||
return
|
||||
}
|
||||
submitting.value = true
|
||||
try {
|
||||
const updated = await fetchUpdateAdminUser(props.user.id, payload)
|
||||
ElMessage.success(t('usersManage.edit.success'))
|
||||
emit('saved', updated)
|
||||
visible.value = false
|
||||
} catch {
|
||||
// 错误已由 http 层统一弹出(ElMessage),此处仅吸收避免未处理拒绝
|
||||
} finally {
|
||||
submitting.value = false
|
||||
}
|
||||
}
|
||||
</script>
|
||||
Reference in New Issue
Block a user