Skip to content

Latest commit

 

History

History
406 lines (377 loc) · 23.7 KB

File metadata and controls

406 lines (377 loc) · 23.7 KB

用户管理页 userManagement

本文档是 KE04-example-permission--auth-and-rbac.md 的拆分文件

- **示例代码来源**:下文示例代码均从官方示例中抽取。 - **复用原则**:生成用户管理页面时若有疑问,应优先直接复用本示例中的写法(变量命名、API 调用顺序、组件配置等),避免自行发挥。

用户管理页 userManagement

前端视图:完整的 CRUD 操作示例

**必须确保删除、编辑、创建功能完整可用**:生成用户管理页面时,必须严格按照以下关键流程实现,禁止遗漏关键步骤。

CRUD 关键流程

操作 关键步骤 代码要点
删除 克隆数据 → 打开确认对话框 → 删除实体和映射 → 清空对象 → 刷新表格 → 关闭对话框 → 提示成功 deleteUserBody = nasl.util.Clone(current.item.user); LcapUserEntity.delete(deleteUserBody.id); LcapUserDeptMappingEntity.deleteBy((_) => (_.userId == deleteUserBody.userId)); $refs.el_table_1.reload();
编辑 设置 isUpdate=true → 重置表单 → 克隆数据 → 保存当前用户名 → 获取用户名列表 → 加载主管列表 → 处理主管数据 → 打开对话框 → 验证表单 → 克隆输入 → 调用更新逻辑 → 刷新表格 → 提示成功 isUpdate = true; $refs.el_form_1.resetForm(); input = nasl.util.Clone(current.item.user); currentName = current.item.user.userName; getUserNameList(); selectLeaders = app.logics.LcapLoadUserManagementSelect(...); app.logics.LcapUpdateNormalUser(inputCopy, true);
创建 设置 isUpdate=false → 重置表单 → 清空输入 → 设置默认值 → 获取用户名列表 → 加载主管列表 → 打开对话框 → 验证表单 → 克隆输入 → 调用创建逻辑 → 刷新表格 → 提示成功 isUpdate = false; $refs.el_form_1.resetForm(); nasl.util.Clear(input, 'deep'); input.source = app.enums.UserSourceEnum['Normal']; getUserNameList(); app.logics.LcapCreateNormalUser(inputCopy);

关键细节

- **$View**:`auth` 必须为 `true`;`authDescription` 建议与 title 一致。 - **用户名唯一性校验**:创建和编辑时都必须调用 `getUserNameList()`,编辑时需排除当前用户名:`if (isUpdate) nasl.util.Remove(userNameList, currentName);`,表单验证使用 `nasl.validation.unique(userNameList)` - **编辑时用户名禁用**:用户名输入框必须设置 `disabled={isUpdate}`,禁止修改用户名 - **密码字段条件显示**:仅在创建且普通登录时显示:`$if={!isUpdate && input.source == app.enums.UserSourceEnum['Normal']}` - **修改密码独立对话框**:使用 `el_dialog_2`,调用 `LcapUpdateNormalUser(input, false)`,需包含密码确认字段 - **删除权限控制**:删除按钮必须禁用当前登录用户:`disabled={current.item.user.userName == nasl.auth.userInfo.UserName}` - **数据克隆**:操作前必须使用 `nasl.util.Clone()` 克隆数据,避免直接修改原始对象 - **编辑时处理主管**:检查主管是否存在,不存在则清空:`if (!nasl.util.HasValue(app.logics.LcapGetUserNameByUserId(input.directLeaderId))) { input.directLeaderId = ''; }` - **编辑成功后更新本地数据**:调用更新逻辑后,更新 `currentUser.user = input`(如需要) - **ElFormTreeSelect**:建议加上 `virtualize={false}`。 - **ElDialog 的 slot 与按钮**:`slotHeader`、`slotFooter` 必须使用 **`(current) =>`** 形式(即带参数的箭头函数),勿使用 `() =>`。弹窗内「确定」「取消」等按钮的 `onClick` 必须使用 **`function click() { ... return; }`** 形式。 $View({ title: '用户管理', description: '用户账号的创建、编辑、删除及角色分配管理', crumb: '用户管理', auth: true, authDescription: '用户管理', isIndex: true, }) export function userManagement() { let input: app.dataSources.defaultDS.entities.LcapUser; let filter: app.dataSources.defaultDS.entities.LcapUser; let isUpdate: Boolean; let deleteUserBody: app.dataSources.defaultDS.entities.LcapUser; let userNameList: List; let currentName: String; let adminName: String; let confirmPassword: String; let currentUser: { user: app.dataSources.defaultDS.entities.LcapUser, userDept: app.dataSources.defaultDS.entities.LcapUserDeptMapping, dept: app.dataSources.defaultDS.entities.LcapDepartment, deptUser: String }; let selectLeaders: List<{ lcapUser: app.dataSources.defaultDS.entities.LcapUser }>;
onCreated(function created() {
    nasl.util.Clear(filter, 'deep');
})

/* 提交创建或修改 */
function submit() {
    getUserNameList();
    if (!$refs.el_form_1.validated().valid) return;
    let inputCopy = nasl.util.Clone(input);

    if (isUpdate) {
        currentUser.user.directLeaderId = input.directLeaderId;
        currentUser.user.displayName = input.displayName;
        currentUser.user.email = input.email;
        currentUser.user.phone = input.phone;
        currentUser.user.source = input.source;
        currentUser.user.status = input.status;
        currentUser.user.userName = input.userName;
        currentUser.deptUser = app.logics.LcapGetUserNameByUserId(input.directLeaderId);
        app.logics.LcapUpdateNormalUser(inputCopy, true);
        nasl.ui.showMessage('修改成功');
    } else {
        app.logics.LcapCreateNormalUser(inputCopy);
        nasl.ui.showMessage('创建成功');
        $refs.el_table_1.reload();
    }
    $refs.el_dialog_1.close();
}

/* 获取用户名列表(用于唯一性校验) */
function getUserNameList() {
    userNameList = app.logics.LcapGetUserNameList(input.userName);
    if (isUpdate) {
        nasl.util.Remove(userNameList, currentName);
    }
}

return <>
    {/* 创建/编辑用户弹窗 */}
    <ElDialog ref="el_dialog_1"
        closeOnClickModal={false}
        width="30%"
        style="padding-left:24px;padding-right:24px;padding-top:24px;padding-bottom:24px;min-width:400px;"
        slotHeader={(current) => <ElFlex mode="flex" direction="vertical" justify="start" alignment="start" wrap={false}>
            <ElText $if={!isUpdate} text="创建普通用户" />
            <ElText $if={isUpdate} text="修改用户" />
        </ElFlex>}
        slotFooter={(current) => <ElFlex direction="horizontal" mode="flex" alignment="start" justify="center" wrap={false} gutter={16}>
            <ElButton $if={isUpdate} text="提交修改" type="primary" onClick={function click() { submit(); return; }} />
            <ElButton $if={!isUpdate} text="立即新增" type="primary" onClick={function click() { submit(); return; }} />
        </ElFlex>}>
        <ElForm ref="el_form_1"
            showMessage={true}
            labelPosition="right"
            scrollToError={true}
            labelWidth={80}
            inlineMessage={false}>
            <ElFlex direction="horizontal" mode="block" style="margin-bottom:24px;">
                <ElFormInput
                    modelValue={$sync(input.userName)}
                    rules={[nasl.validation.filled(), nasl.validation.unique(userNameList), nasl.validation.maxLength(50)]}
                    isRequired={true}
                    clearable={!isUpdate}
                    placeholder="请输入用户名"
                    maxlength={50}
                    disabled={isUpdate}
                    onBlur={function blur() {
                        input.userName = nasl.util.Trim(input.userName);
                    }}
                    slotLabel={(current) => <ElText text="用户名" />} />
            </ElFlex>
            <ElFlex direction="horizontal" mode="block" style="margin-bottom:24px;">
                <ElFormInput
                    $if={!isUpdate && input.source == app.enums.UserSourceEnum['Normal']}
                    modelValue={$sync(input.password)}
                    rules={[nasl.validation.filled(), nasl.validation.rangeLength(8, 12), nasl.validation.regex(new RegExp('^[\\w-]+$', ""))]}
                    isRequired={true}
                    clearable={true}
                    placeholder="请输入8-12位普通登录密码"
                    type="password"
                    slotLabel={(current) => <ElText text="密码" />} />
            </ElFlex>
            <ElFlex direction="horizontal" mode="block" style="margin-bottom:24px;">
                <ElFormInput
                    modelValue={$sync(input.phone)}
                    rules={[nasl.validation.mobile('zh-CN', false)]}
                    placeholder="请输入手机号"
                    clearable={true}
                    slotLabel={(current) => <ElText text="手机号" />} />
            </ElFlex>
            <ElFlex direction="horizontal" mode="block" style="margin-bottom:24px;">
                <ElFormInput
                    modelValue={$sync(input.email)}
                    rules={[nasl.validation.email()]}
                    placeholder="请输入邮箱"
                    clearable={true}
                    slotLabel={(current) => <ElText text="邮箱" />} />
            </ElFlex>
            <ElFlex direction="horizontal" mode="block" style="margin-bottom:24px;">
                <ElFormInput
                    modelValue={$sync(input.displayName)}
                    rules={[nasl.validation.maxLength(50)]}
                    maxlength={50}
                    placeholder="请输入昵称"
                    clearable={true}
                    slotLabel={(current) => <ElText text="昵称" />} />
            </ElFlex>
            <ElFlex direction="horizontal" mode="block" style="margin-bottom:24px;">
                <ElFormSelect
                    $if={isUpdate}
                    modelValue={$sync(input.status)}
                    dataSource={nasl.util.EnumToList<app.enums.UserStatusEnum>()}
                    textField="text"
                    valueField="item"
                    placeholder="请选择用户状态"
                    clearable={true}
                    disabled={(nasl.auth.userInfo.UserName == adminName) && (currentName == adminName)}
                    isRequired={true}
                    rules={[nasl.validation.filled()]}
                    filterable={true}
                    virtualize={true}
                    slotLabel={(current) => <ElText text="状态" />} />
            </ElFlex>
            <ElFlex direction="horizontal" mode="block" style="margin-bottom:24px;">
                <ElFormInput
                    modelValue={nasl.util.EnumItemToText(input.source)}
                    placeholder="普通登录"
                    clearable={false}
                    disabled={true}
                    slotLabel={(current) => <ElText text="用户来源" />} />
            </ElFlex>
            <ElFlex direction="horizontal" mode="block">
                <ElFormSelect
                    modelValue={$sync(input.directLeaderId)}
                    dataSource={selectLeaders}
                    textField="lcapUser.userName"
                    valueField="lcapUser.userId"
                    placeholder="请选择直属主管"
                    clearable={true}
                    filterable={true}
                    virtualize={true}
                    slotLabel={(current) => <ElText text="直属主管" />} />
            </ElFlex>
        </ElForm>
    </ElDialog>

    {/* 修改密码弹窗 */}
    <ElDialog ref="el_dialog_2"
        closeOnClickModal={false}
        width="30%"
        style="padding-left:24px;padding-right:24px;padding-top:24px;padding-bottom:24px;"
        slotHeader={(current) => <ElText text="修改密码" />}
        slotFooter={(current) => <ElFlex direction="horizontal" mode="flex" alignment="start" justify="center" wrap={false} gutter={16}>
            <ElButton text="确定" type="primary" onClick={function click() {
                if (!$refs.el_form_2.validated().valid) return;
                app.logics.LcapUpdateNormalUser(input, false);
                $refs.el_dialog_2.close();
                nasl.ui.showMessage('修改成功');
            }} />
            <ElButton text="取消" type="" onClick={function click() { $refs.el_dialog_2.close(); return; }} />
        </ElFlex>}>
        <ElForm ref="el_form_2"
            showMessage={!isUpdate}
            scrollToError={true}
            labelWidth={80}>
            <ElFlex direction="horizontal" mode="block" style="margin-bottom:24px;">
                <ElFormInput
                    modelValue={$sync(input.password)}
                    rules={[nasl.validation.filled(), nasl.validation.rangeLength(8, 12), nasl.validation.regex(new RegExp('^[\\w-]+$', ""))]}
                    isRequired={true}
                    clearable={true}
                    placeholder="请输入8-12位普通登录密码"
                    type="password"
                    slotLabel={(current) => <ElText text="新密码" />} />
            </ElFlex>
            <ElFlex direction="horizontal" mode="block">
                <ElFormInput
                    modelValue={$sync(confirmPassword)}
                    rules={[nasl.validation.filled(), nasl.validation.confirmed(input.password)]}
                    isRequired={true}
                    clearable={true}
                    placeholder="请确认您的密码"
                    type="password"
                    slotLabel={(current) => <ElText text="确认密码" />} />
            </ElFlex>
        </ElForm>
    </ElDialog>

    {/* 删除确认 */}
    <ElMessageBox ref="el_message_box_1"
        type="confirm"
        iconType="warning"
        title="删除用户"
        showCancelButton={true}
        closeOnClickModal={false}
        onConfirm={function confirm() {
            app.dataSources.defaultDS.entities.LcapUserEntity.delete(deleteUserBody.id);
            app.dataSources.defaultDS.entities.LcapUserDeptMappingEntity.deleteBy((_) => (_.userId == deleteUserBody.userId));
            nasl.util.Clear(deleteUserBody, 'shallow');
            $refs.el_table_1.reload();
            $refs.el_message_box_1.close();
            nasl.ui.showMessage('删除成功');
        }}
        onCancel={function cancel() {
            $refs.el_message_box_1.close();
            return;
        }}>
        <ElText text={`该用户相关的角色关联关系都会被删除!

确认删除用户:${deleteUserBody.userName}?`} />

    {/* 页面主体 */}
    <ElFlex direction="horizontal" mode="block" style="width:100%;">
        <ElFlex mode="flex" direction="vertical" justify="start" alignment="start" wrap={false} gutter={18}
            style="background-color:#FFFFFF;padding-top:20px;padding-bottom:20px;padding-left:20px;padding-right:20px;border-top-left-radius:8px;border-bottom-left-radius:8px;border-top-right-radius:8px;border-bottom-right-radius:8px;margin-bottom:16px; --custom-start: auto; box-shadow: 0px 2px 12px rgba(0, 0, 0, .06);">
            <ElText text="用户管理" style="font-weight:bold;font-size:18px;color:#333333;" />
            <ElFlex direction="horizontal" mode="flex" justify="start" alignment="center" wrap={true} gutter={24} widthStretch="false">
                <ElText text="用户名" />
                <ElInput placeholder="请输入用户名" modelValue={$sync(filter.userName)} size="default" clearable={true} />
                <ElText text="手机号" />
                <ElInput placeholder="请输入手机号" modelValue={$sync(filter.phone)} clearable={true} />
                <ElFlex direction="horizontal" mode="flex" justify="start" alignment="start" gutter={8}>
                    <ElButton text="查 询" type="primary" onClick={function click(event) { $refs.el_table_1.reload(); return;}} />
                    <ElButton text="重 置" type="" onClick={function click(event) { nasl.util.Clear(filter, 'deep'); return;}} />
                </ElFlex>
            </ElFlex>
        </ElFlex>
        <ElFlex mode="block" gutter={18} direction="vertical"
            style="background-color:#FFFFFF;padding-top:20px;padding-bottom:20px;padding-left:20px;padding-right:20px;border-top-left-radius:8px;border-bottom-left-radius:8px;border-top-right-radius:8px;border-bottom-right-radius:8px;margin-bottom:60px; --custom-start: auto; box-shadow: 0px 2px 12px rgba(0, 0, 0, .06);min-height: calc(100vh - 330px);">
            <ElFlex direction="horizontal" widthStretch="false" mode="flex" wrap={false} justify="end" alignment="center" style="width:100%;margin-bottom:16px;">
                <ElButton text="创建普通用户" type="primary" icon="Plus"
                    onClick={function click(event) {
                        $refs.el_form_1.resetForm();
                        isUpdate = false;
                        nasl.util.Clear(input, 'deep');
                        input.source = app.enums.UserSourceEnum['Normal'];
                        getUserNameList();
                        selectLeaders = app.logics.LcapLoadUserManagementSelect(input.userId, null);
                        $refs.el_dialog_1.open();
                        return;
                    }} />
            </ElFlex>
            <ElTable ref="el_table_1"
                widthStretch="false"
                dataSource={app.logics.LcapGetUserTableView($self.currentPage, $self.pageSize, filter)}
                border={false}
                pagination={true}
                columnConfig={false}
                stripe={true}
                showTotal={true}
                showJumper={true}
                defaultPageSize={20}
                defaultOrder="descending"
                defaultField="user.createdTime"
                rowKey="user.userId"
                pageSizes="[10,20,50]"
                style="width:100%;">

                <ElTableColumn prop="user.userId" type="index" style="width: 60px;"
                    slotDefault={(current) => <ElText text={current.index + 1} />}
                    slotHeader={(current) => <ElText text="序号" />} />

                <ElTableColumn
                    slotDefault={(current) => <ElText text={current.item.user.userName} />}
                    slotHeader={(current) => <ElText text="用户名" />} />

                <ElTableColumn
                    slotDefault={(current) => <ElText text={current.item.user.phone} />}
                    slotHeader={(current) => <ElText text="手机号" />} />

                <ElTableColumn
                    slotDefault={(current) => <ElText text={current.item.user.email} />}
                    slotHeader={(current) => <ElText text="邮箱" />} />

                <ElTableColumn
                    slotDefault={(current) => <ElText text={current.item.user.displayName} />}
                    slotHeader={(current) => <ElText text="昵称" />} />

                <ElTableColumn
                    slotDefault={(current) => <ElText text={current.item.deptUser} />}
                    slotHeader={(current) => <ElText text="直属主管" />} />

                <ElTableColumn
                    slotDefault={(current) => <ElText text={current.item.dept.name} />}
                    slotHeader={(current) => <ElText text="部门" />} />

                <ElTableColumn style="width: 120px;"
                    slotDefault={(current) => <ElFlex mode="flex" wrap={false} direction="horizontal" justify="start" alignment="start">
                        <ElTag $if={current.item.user.status == app.enums.UserStatusEnum['Normal']}
                            text="正常" type="success" effect="light" />
                        <ElTag $if={current.item.user.status == app.enums.UserStatusEnum['Forbidden']}
                            text="禁用" type="danger" effect="light" />
                    </ElFlex>}
                    slotHeader={(current) => <ElText text="状态" />} />

                <ElTableColumn
                    slotDefault={(current) => <ElFlex direction="horizontal" mode="block">
                        <ElText text={nasl.util.EnumItemToText(current.item.user.source)} />
                    </ElFlex>}
                    slotHeader={(current) => <ElText text="登录方式" />} />

                <ElTableColumn style="width: 180px;"
                    slotDefault={(current) => <ElFlex direction="horizontal" gutter={12} mode="flex" wrap={false} justify="start" alignment="center">
                        <ElLink text="编辑" type="primary"
                            disabled={(nasl.auth.userInfo.UserName != adminName) && (current.item.user.userName == adminName)}
                            onClick={function click() {
                                $refs.el_form_1.resetForm();
                                isUpdate = true;
                                currentUser = current.item;
                                input = nasl.util.Clone(current.item.user);
                                currentName = current.item.user.userName;
                                getUserNameList();
                                selectLeaders = app.logics.LcapLoadUserManagementSelect(input.userId, null);
                                if (nasl.util.HasValue(app.logics.LcapGetUserNameByUserId(input.directLeaderId))) {
                                } else {
                                    input.directLeaderId = '';
                                }
                                $refs.el_dialog_1.open();
                            }} />
                        <ElLink $if={current.item.user.source == app.enums.UserSourceEnum['Normal']}
                            text="修改密码" type="primary"
                            disabled={current.item.user.userName == adminName}
                            onClick={function click() {
                                $refs.el_form_2.resetForm();
                                input = nasl.util.Clone(current.item.user);
                                confirmPassword = null;
                                $refs.el_dialog_2.open();
                            }} />
                        <ElLink text="删除" type="danger"
                            disabled={(current.item.user.userName == nasl.auth.userInfo.UserName) || (current.item.user.userName == adminName)}
                            onClick={function click() {
                                deleteUserBody = nasl.util.Clone(current.item.user);
                                $refs.el_message_box_1.open();
                            }} />
                    </ElFlex>}
                    slotHeader={(current) => <ElText text="操作" />} />
            </ElTable>
        </ElFlex>
    </ElFlex>
</>

}