update:Dialog替换

This commit is contained in:
xiaozhu
2026-08-26 16:48:19 +08:00
parent d7f3db1cc4
commit e326cc1a93
16 changed files with 738 additions and 675 deletions
+83 -112
View File
@@ -1,24 +1,22 @@
import { useEffect, useState } from "react";
import { X } from "lucide-react";
import type {
PlatformPermission,
Role,
RoleCreatePayload,
RoleUpdatePayload,
} from "../../services/api";
import {
AppFormDialog,
dialogPrimaryButtonClass,
dialogSecondaryButtonClass,
} from "~/components/common/AppFormDialog";
import { Button } from "~/components/ui/button";
import {
formFieldClass,
formInputClass,
formTextareaClass,
modalBackdropClass,
modalCompactClass,
modalEyebrowClass,
modalFooterClass,
modalFormClass,
modalHeaderClass,
modalTitleClass,
} from "../platform/modalUi";
import { PermissionCheckboxList } from "./PermissionCheckboxList";
@@ -39,7 +37,6 @@ const EMPTY_FORM: RoleFormState = {
permission_codes: [],
};
/** 实时校验 role_code:空值不报错,提交时由必填拦截兜底。 */
function validateRoleCode(value: string): string {
const code = value.trim();
if (!code) return "";
@@ -58,13 +55,6 @@ function validateRoleCode(value: string): string {
return "";
}
const CLOSE_BUTTON_CLASS =
"size-[34px] rounded-[7px] border border-[#dfe6ed] bg-white hover:bg-[#f7faff] hover:border-[#b9c9da]";
const SECONDARY_BUTTON_CLASS =
"h-[37px] gap-[7px] rounded-md border-[#d8e1e9] bg-white px-[15px] text-xs font-[650] text-[#56687c]";
const PRIMARY_BUTTON_CLASS =
"h-[37px] gap-[7px] rounded-md border border-[#126ac3] bg-gradient-to-br from-[#1881e7] to-[#1268c9] px-[15px] text-xs font-[650] text-white shadow-[0_6px_15px_rgb(20_111_202/18%)] enabled:hover:from-[#1175d8] enabled:hover:to-[#0e5bad]";
export function RoleEditDialog({
open,
editing,
@@ -117,7 +107,6 @@ export function RoleEditDialog({
};
const toggleCreatePermission = (code: string): void => {
// 新建角色为非 admin,system:* 由后端守卫禁止;此处防御性拦截
if (code.startsWith("system:")) return;
setForm((current) => ({
...current,
@@ -143,7 +132,6 @@ export function RoleEditDialog({
}
const payload: RoleCreatePayload | RoleUpdatePayload = editing
? {
// 内置角色 role_name 锁定;description 可改
...(editing.is_builtin ? {} : { role_name: form.role_name.trim() }),
description: form.description.trim() || null,
}
@@ -156,108 +144,91 @@ export function RoleEditDialog({
onSubmit(payload);
};
if (!open) return null;
return (
<div className={modalBackdropClass} role="presentation">
<section className={modalCompactClass} role="dialog" aria-modal="true">
<div className={modalHeaderClass}>
<div>
<span className={modalEyebrowClass}>ROLE</span>
<h2 className={modalTitleClass}>{editing ? "编辑角色" : "新建角色"}</h2>
</div>
<Button
variant="ghost"
size="icon-sm"
type="button"
aria-label="关闭"
onClick={onClose}
className={CLOSE_BUTTON_CLASS}
>
<X size={16} />
</Button>
</div>
<form className={`${modalFormClass} role-create-form`} onSubmit={(event) => void handleSubmit(event)}>
{editing ? (
<label className={formFieldClass}>
<span></span>
<input
className={formInputClass}
disabled
value={form.role_code}
/>
</label>
) : (
<label className={formFieldClass}>
<span><span className="text-[#e74c3c]">*</span></span>
<input
className={formInputClass}
autoFocus
value={form.role_code}
onChange={handleRoleCodeChange}
placeholder="例如:qa_engineer"
/>
<span className="form-hint">
//线/2~64
</span>
{roleCodeError && <span className="role-error">{roleCodeError}</span>}
</label>
)}
<AppFormDialog
open={open}
onOpenChange={(nextOpen) => {
if (!nextOpen) onClose();
}}
eyebrow="ROLE"
title={editing ? "编辑角色" : "新建角色"}
>
<form className={`${modalFormClass} role-create-form`} onSubmit={(event) => void handleSubmit(event)}>
{editing ? (
<label className={formFieldClass}>
<span><span className="text-[#e74c3c]">*</span></span>
<span></span>
<input className={formInputClass} disabled value={form.role_code} />
</label>
) : (
<label className={formFieldClass}>
<span><span className="text-[#e74c3c]">*</span></span>
<input
className={formInputClass}
value={form.role_name}
disabled={editing !== null && editing.is_builtin}
onChange={(event) => setForm({ ...form, role_name: event.target.value })}
placeholder="请输入角色名称"
autoFocus
value={form.role_code}
onChange={handleRoleCodeChange}
placeholder="例如:qa_engineer"
/>
{editing !== null && editing.is_builtin && (
<span className="form-hint"></span>
)}
<span className="form-hint">
//线/2~64
</span>
{roleCodeError && <span className="role-error">{roleCodeError}</span>}
</label>
<label className={formFieldClass}>
<span></span>
<textarea
className={formTextareaClass}
value={form.description}
onChange={(event) => setForm({ ...form, description: event.target.value })}
placeholder="请输入角色描述(可选)"
/>
</label>
{!editing && (
<div className="permission-groups">
<div className="permission-group__title"></div>
<PermissionCheckboxList
permissions={permissions}
selected={form.permission_codes}
targetRoleCode=""
onToggle={toggleCreatePermission}
/>
</div>
)}
<label className={formFieldClass}>
<span><span className="text-[#e74c3c]">*</span></span>
<input
className={formInputClass}
value={form.role_name}
disabled={editing !== null && editing.is_builtin}
onChange={(event) => setForm({ ...form, role_name: event.target.value })}
placeholder="请输入角色名称"
/>
{editing !== null && editing.is_builtin && (
<span className="form-hint"></span>
)}
<div className={modalFooterClass}>
<Button
variant="outline"
size="sm"
type="button"
onClick={onClose}
className={SECONDARY_BUTTON_CLASS}
>
</Button>
<Button
variant="default"
size="sm"
type="submit"
disabled={saving}
className={PRIMARY_BUTTON_CLASS}
>
{saving ? "保存中…" : "保存"}
</Button>
</label>
<label className={formFieldClass}>
<span></span>
<textarea
className={formTextareaClass}
value={form.description}
onChange={(event) => setForm({ ...form, description: event.target.value })}
placeholder="请输入角色描述(可选)"
/>
</label>
{!editing && (
<div className="permission-groups">
<div className="permission-group__title"></div>
<PermissionCheckboxList
permissions={permissions}
selected={form.permission_codes}
targetRoleCode=""
onToggle={toggleCreatePermission}
/>
</div>
</form>
</section>
</div>
)}
<div className="mt-[3px] flex shrink-0 justify-end gap-2 border-t border-[#e8edf2] bg-white -mx-[22px] px-[22px] py-3.5">
<Button
variant="outline"
size="sm"
type="button"
onClick={onClose}
className={dialogSecondaryButtonClass}
>
</Button>
<Button
variant="default"
size="sm"
type="submit"
disabled={saving}
className={dialogPrimaryButtonClass}
>
{saving ? "保存中…" : "保存"}
</Button>
</div>
</form>
</AppFormDialog>
);
}