Files
photo-live/apps/admin/src/views/system/users/UserEditDialog.vue
T
2026-09-20 20:26:53 +08:00

130 lines
4.4 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!-- 编辑用户治理属性对话框: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>