618d1d796c
Co-Authored-By: Claude Code <noreply@anthropic.com>
130 lines
4.4 KiB
Vue
130 lines
4.4 KiB
Vue
<!-- 编辑用户治理属性对话框: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>
|