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>
|