From 8aaad677b6d94ece7168b15e8b7935ca37154ab3 Mon Sep 17 00:00:00 2001 From: siujamo Date: Fri, 26 Dec 2025 16:00:40 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=AE=8C=E6=88=90=E5=88=9B=E5=BB=BA?= =?UTF-8?q?=E8=A7=92=E8=89=B2=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/role/index.ts | 5 ++ src/components/add-role-dialogue/index.tsx | 22 +++++++ src/components/edit-role-dialogue/index.tsx | 11 ++++ src/components/role-display-form/index.tsx | 66 +++++++++++++++++++++ src/page/role/index.tsx | 57 +++++++++++++++--- src/service/web-client/index.ts | 21 ++++--- src/types/antd/index.ts | 7 +++ src/types/constant/index.ts | 12 ++++ 8 files changed, 185 insertions(+), 16 deletions(-) create mode 100644 src/components/add-role-dialogue/index.tsx create mode 100644 src/components/edit-role-dialogue/index.tsx create mode 100644 src/components/role-display-form/index.tsx diff --git a/src/api/role/index.ts b/src/api/role/index.ts index df036ac..0c0602d 100644 --- a/src/api/role/index.ts +++ b/src/api/role/index.ts @@ -1,6 +1,7 @@ import type { QueryRoleRequest } from "@/types/web/request" import webClient from "@/service/web-client" import type { PageResponse, RoleResponse } from "@/types/web/response" +import type { RoleFormValues } from "@/components/role-display-form" export async function fetchRoles( request: QueryRoleRequest | null @@ -24,3 +25,7 @@ export async function fetchRoles( const { data } = await webClient.get(`/roles?${params.toString()}`) return data } + +export async function addRole(request: RoleFormValues) { + return await webClient.post("/roles", request) +} diff --git a/src/components/add-role-dialogue/index.tsx b/src/components/add-role-dialogue/index.tsx new file mode 100644 index 0000000..2e3fc2c --- /dev/null +++ b/src/components/add-role-dialogue/index.tsx @@ -0,0 +1,22 @@ +import type { FormInstance } from "antd" +import RoleDisplayForm, { type RoleFormValues } from "@/components/role-display-form" + +export interface AddRoleDialogueProps { + form: FormInstance +} + +export default function AddRoleDialogue({ form }: AddRoleDialogueProps) { + return ( + + ) +} diff --git a/src/components/edit-role-dialogue/index.tsx b/src/components/edit-role-dialogue/index.tsx new file mode 100644 index 0000000..e4169e9 --- /dev/null +++ b/src/components/edit-role-dialogue/index.tsx @@ -0,0 +1,11 @@ +import type { FormInstance } from "antd" +import RoleDisplayForm, { type RoleFormValues } from "@/components/role-display-form" + +export interface EditRoleDialogueProps { + form: FormInstance + initialValues: RoleFormValues +} + +export default function EditRoleDialogue({ form, initialValues }: EditRoleDialogueProps) { + return +} diff --git a/src/components/role-display-form/index.tsx b/src/components/role-display-form/index.tsx new file mode 100644 index 0000000..9b9b771 --- /dev/null +++ b/src/components/role-display-form/index.tsx @@ -0,0 +1,66 @@ +import { App, Form, type FormInstance, Input, InputNumber, Select, Switch } from "antd" +import { type Status, StatusOptions } from "@/types/constant" + +/** + * Role form values. + */ +export interface RoleFormValues { + name: string + code: string + sort: number + defaultValue: boolean + description: string | null + status: Status +} + +/** + * Component props. + */ +export interface RoleDisplayFormProps { + initialValues?: RoleFormValues + isEditing?: boolean + form: FormInstance + isAdding?: boolean +} + +export default function RoleDisplayForm({ initialValues, form }: RoleDisplayFormProps) { + return ( + + form={form} + initialValues={initialValues} + layout="vertical" + labelAlign="right" + validateTrigger="onBlur"> + + label="角色名称" + name="name" + rules={[{ required: true, message: "角色名称不能为空" }]}> + + + + label="角色编码" + name="code" + rules={[ + { required: true, message: "角色编码不能为空" }, + { pattern: /^[a-z-]+$/, message: "角色编码格式错误,仅支持小写英文字母及 '-'" }, + ]}> + + + + label="排序编码" + name="sort" + rules={[ + { required: true, message: "排序不能为空" }, + { type: "number", min: 0, max: Number.MAX_VALUE, message: "排序必须是正数" }, + ]}> + + + label="是否为默认角色" name="defaultValue"> + + + label="角色状态" name="status"> + options={StatusOptions} /> + + + ) +} diff --git a/src/page/role/index.tsx b/src/page/role/index.tsx index e8b4cf8..e3c5b76 100644 --- a/src/page/role/index.tsx +++ b/src/page/role/index.tsx @@ -1,10 +1,10 @@ import { useEffect, useState } from "react" -import type { AxiosError } from "axios" +import axios, { type AxiosError } from "axios" import { App, Button, Form, Input, Select, Space, Switch, Table } from "antd" import type { Role } from "@/types/entity" import { RoleApi } from "@/api" import type { QueryRoleRequest } from "@/types/web/request" -import type { GeneralErrorResponse, RoleResponse } from "@/types/web/response" +import type { GeneralErrorResponse } from "@/types/web/response" import { DeleteOutlined, ExportOutlined, @@ -15,11 +15,15 @@ import { } from "@ant-design/icons" import type { QueryRoleForm } from "@/types/form" import type { Status } from "@/types/constant" +import AddRoleDialogue from "@/components/add-role-dialogue" +import type { RoleFormValues } from "@/components/role-display-form" export default function RolePage() { - const { message } = App.useApp() + const { message, modal } = App.useApp() const [queryForm] = Form.useForm() + const [addRoleForm] = Form.useForm() + const [editRoleForm] = Form.useForm() const [roles, setRoles] = useState([]) const [pageNum, setPageNum] = useState(1) const [pageSize, setPageSize] = useState(10) @@ -55,6 +59,43 @@ export default function RolePage() { ) } + const onAddRoleFinish = async () => { + try { + const values = await addRoleForm.validateFields() + await RoleApi.addRole(values) + void message.success(`角色 ${values.name} 创建成功`) + return true + } catch (error: unknown) { + if (error instanceof Error && error.message.includes("Validation Failed")) { + return false + } else if (axios.isAxiosError(error)) { + void message.error(error.response?.data.message ?? "创建失败,请稍后再试") + } + return false + } + } + + const handleAddRole = () => { + modal + .confirm({ + title: "添加用户", + content: , + width: 600, + onOk: onAddRoleFinish, + }) + .then( + () => { + addRoleForm.resetFields() + const formValues = queryForm.getFieldsValue() + queryRoles(pageNum, pageSize, formValues) + }, + () => { + addRoleForm.resetFields() + console.error("用户取消添加角色") + } + ) + } + useEffect(() => { queryRoles(pageNum, pageSize, null) }, [pageNum, pageSize]) @@ -94,19 +135,19 @@ export default function RolePage() { /> > - + - + - + diff --git a/src/service/web-client/index.ts b/src/service/web-client/index.ts index 5e933ba..b4f80b6 100644 --- a/src/service/web-client/index.ts +++ b/src/service/web-client/index.ts @@ -1,9 +1,9 @@ import axios, { type AxiosError } from "axios" import dayjs from "dayjs" import store from "@/store" -import type { GeneralErrorResponse } from "@/types" import { HttpStatus } from "@/constant" import { logout } from "@/store/auth-slice" +import type { GeneralErrorResponse } from "@/types/web/response" const webClient = axios.create({ baseURL: import.meta.env.VITE_API_BASE_URL, @@ -25,14 +25,17 @@ webClient.interceptors.request.use( } ) -webClient.interceptors.response.use((response) => { - return response -}, (error: unknown) => { - const err = error as AxiosError - if (err.response?.status == HttpStatus.UNAUTHORIZED) { - store.dispatch(logout()) +webClient.interceptors.response.use( + (response) => { + return response + }, + (error: unknown) => { + const err = error as AxiosError + if (err.response?.status == HttpStatus.UNAUTHORIZED) { + store.dispatch(logout()) + } + return Promise.reject(error as AxiosError) } - return Promise.reject(error as AxiosError) -}) +) export default webClient diff --git a/src/types/antd/index.ts b/src/types/antd/index.ts index a90422c..3320e3b 100644 --- a/src/types/antd/index.ts +++ b/src/types/antd/index.ts @@ -12,3 +12,10 @@ export interface AntTreeSelectOption { selectable?: boolean checkable?: boolean } + +export interface AntSelectOptionItem { + label: string + value: string +} + +export type AntSelectOption = AntSelectOptionItem[] diff --git a/src/types/constant/index.ts b/src/types/constant/index.ts index 839087b..4083fb8 100644 --- a/src/types/constant/index.ts +++ b/src/types/constant/index.ts @@ -1,6 +1,18 @@ +import type { AntSelectOption } from "@/types/antd" + /** * Status */ export type Status = "ACTIVE" | "INACTIVE" export type UserStatus = Status | "LOCKED" + +export const StatusOptions: AntSelectOption = [ + { label: "已启用", value: "ACTIVE" }, + { label: "已停用", value: "INACTIVE" }, +] + +export const UserStatusOptions: AntSelectOption = [ + ...StatusOptions, + { label: "已禁用", value: "LOCKED" }, +]