task-251(admin.html观感对齐): 用户管理补齐新建/编辑/角色+菜单授权弹窗(接线孤儿模块)
This commit is contained in:
@@ -0,0 +1,128 @@
|
||||
<script setup lang="ts">
|
||||
import { reactive, ref, watch } from 'vue'
|
||||
import type { AdminUser } from '@/types/admin'
|
||||
import { fillEditUserForm, validateEditUserForm, type EditUserForm, type EditUserFormErrors } from './user-edit-model'
|
||||
import { submitEditUser } from './user-edit-adapter'
|
||||
import { loadUserMenuAuth } from './user-menu-auth-api'
|
||||
import { showAdminFeedback } from '@/components/admin-feedback-ui'
|
||||
import { actionableErrorText } from '@/components/admin-feedback'
|
||||
import UserMenuAuthTree from './UserMenuAuthTree.vue'
|
||||
|
||||
const props = defineProps<{ modelValue: boolean; user: AdminUser | null; operatorSuper?: boolean }>()
|
||||
const emit = defineEmits<{ (e: 'update:modelValue', v: boolean): void; (e: 'updated'): void }>()
|
||||
|
||||
const form = reactive<EditUserForm>({ uid: 0, username: '', password: '', role: 'normal', columnIds: [], originalRole: '' })
|
||||
const errors = reactive<EditUserFormErrors>({})
|
||||
const busy = ref(false)
|
||||
const loadingAuth = ref(false)
|
||||
|
||||
watch(
|
||||
() => props.modelValue,
|
||||
(open) => {
|
||||
if (!open || !props.user) return
|
||||
const base = fillEditUserForm(props.user)
|
||||
form.uid = base.uid
|
||||
form.username = base.username
|
||||
form.password = ''
|
||||
form.role = base.role
|
||||
form.columnIds = []
|
||||
form.originalRole = base.originalRole
|
||||
errors.password = undefined
|
||||
void refreshAuth()
|
||||
},
|
||||
)
|
||||
|
||||
async function refreshAuth(): Promise<void> {
|
||||
if (!props.user) return
|
||||
loadingAuth.value = true
|
||||
try {
|
||||
const { checkedIds } = await loadUserMenuAuth(props.user.id)
|
||||
form.columnIds = checkedIds
|
||||
} catch (error) {
|
||||
showAdminFeedback(actionableErrorText(error), 'error')
|
||||
} finally {
|
||||
loadingAuth.value = false
|
||||
}
|
||||
}
|
||||
|
||||
function close(): void {
|
||||
emit('update:modelValue', false)
|
||||
}
|
||||
|
||||
async function save(): Promise<void> {
|
||||
const { valid, errors: errs } = validateEditUserForm(form)
|
||||
Object.assign(errors, errs)
|
||||
if (!valid) return
|
||||
busy.value = true
|
||||
try {
|
||||
await submitEditUser(form)
|
||||
showAdminFeedback('更新成功', 'success')
|
||||
emit('updated')
|
||||
close()
|
||||
} catch (error) {
|
||||
showAdminFeedback(actionableErrorText(error), 'error')
|
||||
} finally {
|
||||
busy.value = false
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<el-dialog
|
||||
:model-value="modelValue"
|
||||
title="编辑用户"
|
||||
width="640px"
|
||||
:close-on-click-modal="false"
|
||||
destroy-on-close
|
||||
@update:model-value="(v: boolean) => emit('update:modelValue', v)"
|
||||
>
|
||||
<el-form label-position="top" @submit.prevent>
|
||||
<el-form-item label="用户名">
|
||||
<el-input :model-value="form.username" readonly />
|
||||
</el-form-item>
|
||||
<el-form-item label="新密码(不修改可留空)" :error="errors.password">
|
||||
<el-input
|
||||
v-model="form.password"
|
||||
type="password"
|
||||
show-password
|
||||
autocomplete="new-password"
|
||||
placeholder="留空则不修改密码"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="operatorSuper" label="角色">
|
||||
<el-radio-group v-model="form.role">
|
||||
<el-radio-button value="normal">普通账号</el-radio-button>
|
||||
<el-radio-button value="admin">管理员</el-radio-button>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="props.user && props.user.creatorUsername" label="所属管理员">
|
||||
<el-input :model-value="props.user.creatorUsername" readonly />
|
||||
</el-form-item>
|
||||
<el-form-item label="菜单权限(勾选上级菜单会继承全部子菜单)">
|
||||
<div class="auth-tree-box">
|
||||
<UserMenuAuthTree v-model:checked="form.columnIds" />
|
||||
<div v-if="loadingAuth" class="auth-loading">菜单权限加载中…</div>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click="close">取消</el-button>
|
||||
<el-button type="primary" :loading="busy" @click="save">保存</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.auth-tree-box {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
border: 1px solid var(--el-border-color);
|
||||
border-radius: 9px;
|
||||
padding: 8px;
|
||||
}
|
||||
.auth-loading {
|
||||
margin-top: 6px;
|
||||
font-size: 12px;
|
||||
color: var(--admin-muted);
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user