feat: 完成创建角色功能
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
import type { QueryRoleRequest } from "@/types/web/request"
|
import type { QueryRoleRequest } from "@/types/web/request"
|
||||||
import webClient from "@/service/web-client"
|
import webClient from "@/service/web-client"
|
||||||
import type { PageResponse, RoleResponse } from "@/types/web/response"
|
import type { PageResponse, RoleResponse } from "@/types/web/response"
|
||||||
|
import type { RoleFormValues } from "@/components/role-display-form"
|
||||||
|
|
||||||
export async function fetchRoles(
|
export async function fetchRoles(
|
||||||
request: QueryRoleRequest | null
|
request: QueryRoleRequest | null
|
||||||
@@ -24,3 +25,7 @@ export async function fetchRoles(
|
|||||||
const { data } = await webClient.get<RoleResponse>(`/roles?${params.toString()}`)
|
const { data } = await webClient.get<RoleResponse>(`/roles?${params.toString()}`)
|
||||||
return data
|
return data
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function addRole(request: RoleFormValues) {
|
||||||
|
return await webClient.post("/roles", request)
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
import type { FormInstance } from "antd"
|
||||||
|
import RoleDisplayForm, { type RoleFormValues } from "@/components/role-display-form"
|
||||||
|
|
||||||
|
export interface AddRoleDialogueProps {
|
||||||
|
form: FormInstance<RoleFormValues>
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function AddRoleDialogue({ form }: AddRoleDialogueProps) {
|
||||||
|
return (
|
||||||
|
<RoleDisplayForm
|
||||||
|
form={form}
|
||||||
|
initialValues={{
|
||||||
|
name: "",
|
||||||
|
code: "",
|
||||||
|
sort: 0,
|
||||||
|
description: null,
|
||||||
|
defaultValue: false,
|
||||||
|
status: "ACTIVE",
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
import type { FormInstance } from "antd"
|
||||||
|
import RoleDisplayForm, { type RoleFormValues } from "@/components/role-display-form"
|
||||||
|
|
||||||
|
export interface EditRoleDialogueProps {
|
||||||
|
form: FormInstance<RoleFormValues>
|
||||||
|
initialValues: RoleFormValues
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function EditRoleDialogue({ form, initialValues }: EditRoleDialogueProps) {
|
||||||
|
return <RoleDisplayForm form={form} initialValues={initialValues} />
|
||||||
|
}
|
||||||
@@ -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<RoleFormValues>
|
||||||
|
isAdding?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function RoleDisplayForm({ initialValues, form }: RoleDisplayFormProps) {
|
||||||
|
return (
|
||||||
|
<Form<RoleFormValues>
|
||||||
|
form={form}
|
||||||
|
initialValues={initialValues}
|
||||||
|
layout="vertical"
|
||||||
|
labelAlign="right"
|
||||||
|
validateTrigger="onBlur">
|
||||||
|
<Form.Item<RoleFormValues>
|
||||||
|
label="角色名称"
|
||||||
|
name="name"
|
||||||
|
rules={[{ required: true, message: "角色名称不能为空" }]}>
|
||||||
|
<Input />
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item<RoleFormValues>
|
||||||
|
label="角色编码"
|
||||||
|
name="code"
|
||||||
|
rules={[
|
||||||
|
{ required: true, message: "角色编码不能为空" },
|
||||||
|
{ pattern: /^[a-z-]+$/, message: "角色编码格式错误,仅支持小写英文字母及 '-'" },
|
||||||
|
]}>
|
||||||
|
<Input />
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item<RoleFormValues>
|
||||||
|
label="排序编码"
|
||||||
|
name="sort"
|
||||||
|
rules={[
|
||||||
|
{ required: true, message: "排序不能为空" },
|
||||||
|
{ type: "number", min: 0, max: Number.MAX_VALUE, message: "排序必须是正数" },
|
||||||
|
]}>
|
||||||
|
<InputNumber />
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item<RoleFormValues> label="是否为默认角色" name="defaultValue">
|
||||||
|
<Switch />
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item<RoleFormValues> label="角色状态" name="status">
|
||||||
|
<Select<Status> options={StatusOptions} />
|
||||||
|
</Form.Item>
|
||||||
|
</Form>
|
||||||
|
)
|
||||||
|
}
|
||||||
+50
-7
@@ -1,10 +1,10 @@
|
|||||||
import { useEffect, useState } from "react"
|
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 { App, Button, Form, Input, Select, Space, Switch, Table } from "antd"
|
||||||
import type { Role } from "@/types/entity"
|
import type { Role } from "@/types/entity"
|
||||||
import { RoleApi } from "@/api"
|
import { RoleApi } from "@/api"
|
||||||
import type { QueryRoleRequest } from "@/types/web/request"
|
import type { QueryRoleRequest } from "@/types/web/request"
|
||||||
import type { GeneralErrorResponse, RoleResponse } from "@/types/web/response"
|
import type { GeneralErrorResponse } from "@/types/web/response"
|
||||||
import {
|
import {
|
||||||
DeleteOutlined,
|
DeleteOutlined,
|
||||||
ExportOutlined,
|
ExportOutlined,
|
||||||
@@ -15,11 +15,15 @@ import {
|
|||||||
} from "@ant-design/icons"
|
} from "@ant-design/icons"
|
||||||
import type { QueryRoleForm } from "@/types/form"
|
import type { QueryRoleForm } from "@/types/form"
|
||||||
import type { Status } from "@/types/constant"
|
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() {
|
export default function RolePage() {
|
||||||
const { message } = App.useApp()
|
const { message, modal } = App.useApp()
|
||||||
|
|
||||||
const [queryForm] = Form.useForm<QueryRoleForm>()
|
const [queryForm] = Form.useForm<QueryRoleForm>()
|
||||||
|
const [addRoleForm] = Form.useForm<RoleFormValues>()
|
||||||
|
const [editRoleForm] = Form.useForm<RoleFormValues>()
|
||||||
const [roles, setRoles] = useState<Role[]>([])
|
const [roles, setRoles] = useState<Role[]>([])
|
||||||
const [pageNum, setPageNum] = useState<number>(1)
|
const [pageNum, setPageNum] = useState<number>(1)
|
||||||
const [pageSize, setPageSize] = useState<number>(10)
|
const [pageSize, setPageSize] = useState<number>(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<GeneralErrorResponse>(error)) {
|
||||||
|
void message.error(error.response?.data.message ?? "创建失败,请稍后再试")
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleAddRole = () => {
|
||||||
|
modal
|
||||||
|
.confirm({
|
||||||
|
title: "添加用户",
|
||||||
|
content: <AddRoleDialogue form={addRoleForm} />,
|
||||||
|
width: 600,
|
||||||
|
onOk: onAddRoleFinish,
|
||||||
|
})
|
||||||
|
.then(
|
||||||
|
() => {
|
||||||
|
addRoleForm.resetFields()
|
||||||
|
const formValues = queryForm.getFieldsValue()
|
||||||
|
queryRoles(pageNum, pageSize, formValues)
|
||||||
|
},
|
||||||
|
() => {
|
||||||
|
addRoleForm.resetFields()
|
||||||
|
console.error("用户取消添加角色")
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
queryRoles(pageNum, pageSize, null)
|
queryRoles(pageNum, pageSize, null)
|
||||||
}, [pageNum, pageSize])
|
}, [pageNum, pageSize])
|
||||||
@@ -94,19 +135,19 @@ export default function RolePage() {
|
|||||||
/>
|
/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item<QueryRoleForm>>
|
<Form.Item<QueryRoleForm>>
|
||||||
<Space.Compact>
|
<Space>
|
||||||
<Button color="primary" variant="solid" htmlType="submit" icon={<SearchOutlined />}>
|
<Button color="primary" variant="solid" htmlType="submit" icon={<SearchOutlined />}>
|
||||||
查询
|
查询
|
||||||
</Button>
|
</Button>
|
||||||
<Button color="orange" variant="solid" htmlType="reset" icon={<UndoOutlined />}>
|
<Button color="orange" variant="solid" htmlType="reset" icon={<UndoOutlined />}>
|
||||||
重置
|
重置
|
||||||
</Button>
|
</Button>
|
||||||
</Space.Compact>
|
</Space>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</Form>
|
</Form>
|
||||||
|
|
||||||
<Space size={8}>
|
<Space size={8}>
|
||||||
<Button variant="solid" type="primary" icon={<PlusOutlined />} onClick={() => {}}>
|
<Button variant="solid" type="primary" icon={<PlusOutlined />} onClick={handleAddRole}>
|
||||||
新增
|
新增
|
||||||
</Button>
|
</Button>
|
||||||
<Button variant="solid" danger icon={<DeleteOutlined />}>
|
<Button variant="solid" danger icon={<DeleteOutlined />}>
|
||||||
@@ -153,7 +194,9 @@ export default function RolePage() {
|
|||||||
render: (role: Role) => (
|
render: (role: Role) => (
|
||||||
<>
|
<>
|
||||||
<Space.Compact>
|
<Space.Compact>
|
||||||
<Button variant="solid">修改</Button>
|
<Button variant="solid" onClick={() => {}}>
|
||||||
|
修改
|
||||||
|
</Button>
|
||||||
<Button variant="solid" danger>
|
<Button variant="solid" danger>
|
||||||
删除
|
删除
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import axios, { type AxiosError } from "axios"
|
import axios, { type AxiosError } from "axios"
|
||||||
import dayjs from "dayjs"
|
import dayjs from "dayjs"
|
||||||
import store from "@/store"
|
import store from "@/store"
|
||||||
import type { GeneralErrorResponse } from "@/types"
|
|
||||||
import { HttpStatus } from "@/constant"
|
import { HttpStatus } from "@/constant"
|
||||||
import { logout } from "@/store/auth-slice"
|
import { logout } from "@/store/auth-slice"
|
||||||
|
import type { GeneralErrorResponse } from "@/types/web/response"
|
||||||
|
|
||||||
const webClient = axios.create({
|
const webClient = axios.create({
|
||||||
baseURL: import.meta.env.VITE_API_BASE_URL,
|
baseURL: import.meta.env.VITE_API_BASE_URL,
|
||||||
@@ -25,14 +25,17 @@ webClient.interceptors.request.use(
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
webClient.interceptors.response.use((response) => {
|
webClient.interceptors.response.use(
|
||||||
return response
|
(response) => {
|
||||||
}, (error: unknown) => {
|
return response
|
||||||
const err = error as AxiosError<GeneralErrorResponse>
|
},
|
||||||
if (err.response?.status == HttpStatus.UNAUTHORIZED) {
|
(error: unknown) => {
|
||||||
store.dispatch(logout())
|
const err = error as AxiosError<GeneralErrorResponse>
|
||||||
|
if (err.response?.status == HttpStatus.UNAUTHORIZED) {
|
||||||
|
store.dispatch(logout())
|
||||||
|
}
|
||||||
|
return Promise.reject(error as AxiosError)
|
||||||
}
|
}
|
||||||
return Promise.reject(error as AxiosError)
|
)
|
||||||
})
|
|
||||||
|
|
||||||
export default webClient
|
export default webClient
|
||||||
|
|||||||
@@ -12,3 +12,10 @@ export interface AntTreeSelectOption<T> {
|
|||||||
selectable?: boolean
|
selectable?: boolean
|
||||||
checkable?: boolean
|
checkable?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface AntSelectOptionItem {
|
||||||
|
label: string
|
||||||
|
value: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export type AntSelectOption = AntSelectOptionItem[]
|
||||||
|
|||||||
@@ -1,6 +1,18 @@
|
|||||||
|
import type { AntSelectOption } from "@/types/antd"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Status
|
* Status
|
||||||
*/
|
*/
|
||||||
export type Status = "ACTIVE" | "INACTIVE"
|
export type Status = "ACTIVE" | "INACTIVE"
|
||||||
|
|
||||||
export type UserStatus = Status | "LOCKED"
|
export type UserStatus = Status | "LOCKED"
|
||||||
|
|
||||||
|
export const StatusOptions: AntSelectOption = [
|
||||||
|
{ label: "已启用", value: "ACTIVE" },
|
||||||
|
{ label: "已停用", value: "INACTIVE" },
|
||||||
|
]
|
||||||
|
|
||||||
|
export const UserStatusOptions: AntSelectOption = [
|
||||||
|
...StatusOptions,
|
||||||
|
{ label: "已禁用", value: "LOCKED" },
|
||||||
|
]
|
||||||
|
|||||||
Reference in New Issue
Block a user