Compare commits
3 Commits
main
...
b0ccd8f832
| Author | SHA1 | Date | |
|---|---|---|---|
| b0ccd8f832 | |||
| 3b0bd56001 | |||
| 8aaad677b6 |
@@ -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,11 @@ export async function fetchRoles(
|
||||
const { data } = await webClient.get<RoleResponse>(`/roles?${params.toString()}`)
|
||||
return data
|
||||
}
|
||||
|
||||
export async function addRole(request: RoleFormValues) {
|
||||
return await webClient.post("/roles", request)
|
||||
}
|
||||
|
||||
export async function editRole(request: RoleFormValues) {
|
||||
return await webClient.put("/roles", request)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
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={{
|
||||
id: null,
|
||||
name: "",
|
||||
code: "",
|
||||
sort: 0,
|
||||
description: null,
|
||||
defaultValue: false,
|
||||
status: "ACTIVE",
|
||||
}}
|
||||
mode="add"
|
||||
/>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
import type { FormInstance } from "antd"
|
||||
import RoleDisplayForm, { type RoleFormValues } from "@/components/role-display-form"
|
||||
import type { Role } from "@/types/entity"
|
||||
|
||||
export interface EditRoleDialogueProps {
|
||||
form: FormInstance<RoleFormValues>
|
||||
initialValues: RoleFormValues
|
||||
}
|
||||
|
||||
export default function EditRoleDialogue({ form, initialValues }: EditRoleDialogueProps) {
|
||||
return <RoleDisplayForm form={form} initialValues={initialValues} mode="edit" />
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
import { App, Form, type FormInstance, Input, InputNumber, Select, Switch } from "antd"
|
||||
import { type Status, StatusOptions } from "@/types/constant"
|
||||
import type { FormMode } from "@/types/form"
|
||||
import { useEffect, useMemo } from "react"
|
||||
|
||||
/**
|
||||
* Role form values.
|
||||
*/
|
||||
export interface RoleFormValues {
|
||||
id: number | string | null
|
||||
name: string
|
||||
code: string
|
||||
sort: number
|
||||
defaultValue: boolean
|
||||
description: string | null
|
||||
status: Status
|
||||
}
|
||||
|
||||
/**
|
||||
* Component props.
|
||||
*/
|
||||
export interface RoleDisplayFormProps {
|
||||
initialValues?: RoleFormValues
|
||||
form: FormInstance<RoleFormValues>
|
||||
mode: FormMode
|
||||
}
|
||||
|
||||
export default function RoleDisplayForm({ initialValues, form, mode }: RoleDisplayFormProps) {
|
||||
const isEditing = useMemo<boolean>(() => mode == "edit", [mode])
|
||||
|
||||
// Initialise form values
|
||||
useEffect(() => {
|
||||
if (initialValues) {
|
||||
form.setFieldsValue(initialValues)
|
||||
} else {
|
||||
form.resetFields()
|
||||
}
|
||||
}, [initialValues, form])
|
||||
|
||||
return (
|
||||
<Form<RoleFormValues>
|
||||
form={form}
|
||||
initialValues={initialValues}
|
||||
layout="vertical"
|
||||
labelAlign="right"
|
||||
validateTrigger="onBlur">
|
||||
<Form.Item<RoleFormValues> label="角色编号" hidden={!isEditing} name="id">
|
||||
<Input disabled />
|
||||
</Form.Item>
|
||||
<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 disabled={isEditing}/>
|
||||
</Form.Item>
|
||||
<Form.Item<RoleFormValues> label="角色状态" name="status">
|
||||
<Select<Status> options={StatusOptions} />
|
||||
</Form.Item>
|
||||
</Form>
|
||||
)
|
||||
}
|
||||
+95
-8
@@ -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,17 @@ 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"
|
||||
import EditRoleDialogue from "@/components/edit-role-dialogue"
|
||||
import { addRole } from "@/api/role"
|
||||
|
||||
export default function RolePage() {
|
||||
const { message } = App.useApp()
|
||||
const { message, modal } = App.useApp()
|
||||
|
||||
const [queryForm] = Form.useForm<QueryRoleForm>()
|
||||
const [addRoleForm] = Form.useForm<RoleFormValues>()
|
||||
const [editRoleForm] = Form.useForm<RoleFormValues>()
|
||||
const [roles, setRoles] = useState<Role[]>([])
|
||||
const [pageNum, setPageNum] = useState<number>(1)
|
||||
const [pageSize, setPageSize] = useState<number>(10)
|
||||
@@ -36,7 +42,7 @@ export default function RolePage() {
|
||||
|
||||
RoleApi.fetchRoles(queryRoleRequest)
|
||||
.then((response) => {
|
||||
console.log("role response", response)
|
||||
// console.log("role response", response)
|
||||
setPageNum(response.pageable.pageNumber + 1)
|
||||
setPageSize(response.pageable.pageSize)
|
||||
setTotalElementCount(response.totalElements)
|
||||
@@ -55,6 +61,85 @@ 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("用户取消添加角色")
|
||||
}
|
||||
)
|
||||
.finally(() => {
|
||||
addRoleForm.resetFields()
|
||||
})
|
||||
}
|
||||
|
||||
const onEditRoleFinish = async () => {
|
||||
try {
|
||||
const values = await editRoleForm.validateFields()
|
||||
// console.log(values)
|
||||
await RoleApi.editRole(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 handleEditRole = (role: Role) => {
|
||||
modal
|
||||
.confirm({
|
||||
title: "修改用户",
|
||||
content: <EditRoleDialogue form={editRoleForm} initialValues={role} />,
|
||||
width: 600,
|
||||
onOk: onEditRoleFinish,
|
||||
})
|
||||
.then(
|
||||
() => {
|
||||
const formValues = queryForm.getFieldsValue()
|
||||
queryRoles(pageNum, pageSize, formValues)
|
||||
},
|
||||
() => {
|
||||
console.error("用户取消添加角色")
|
||||
}
|
||||
)
|
||||
.finally(() => {
|
||||
editRoleForm.resetFields()
|
||||
})
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
queryRoles(pageNum, pageSize, null)
|
||||
}, [pageNum, pageSize])
|
||||
@@ -94,19 +179,19 @@ export default function RolePage() {
|
||||
/>
|
||||
</Form.Item>
|
||||
<Form.Item<QueryRoleForm>>
|
||||
<Space.Compact>
|
||||
<Space>
|
||||
<Button color="primary" variant="solid" htmlType="submit" icon={<SearchOutlined />}>
|
||||
查询
|
||||
</Button>
|
||||
<Button color="orange" variant="solid" htmlType="reset" icon={<UndoOutlined />}>
|
||||
重置
|
||||
</Button>
|
||||
</Space.Compact>
|
||||
</Space>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
|
||||
<Space size={8}>
|
||||
<Button variant="solid" type="primary" icon={<PlusOutlined />} onClick={() => {}}>
|
||||
<Button variant="solid" type="primary" icon={<PlusOutlined />} onClick={handleAddRole}>
|
||||
新增
|
||||
</Button>
|
||||
<Button variant="solid" danger icon={<DeleteOutlined />}>
|
||||
@@ -153,7 +238,9 @@ export default function RolePage() {
|
||||
render: (role: Role) => (
|
||||
<>
|
||||
<Space.Compact>
|
||||
<Button variant="solid">修改</Button>
|
||||
<Button variant="solid" onClick={() => handleEditRole(role)}>
|
||||
修改
|
||||
</Button>
|
||||
<Button variant="solid" danger>
|
||||
删除
|
||||
</Button>
|
||||
|
||||
@@ -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) => {
|
||||
webClient.interceptors.response.use(
|
||||
(response) => {
|
||||
return response
|
||||
}, (error: unknown) => {
|
||||
},
|
||||
(error: unknown) => {
|
||||
const err = error as AxiosError<GeneralErrorResponse>
|
||||
if (err.response?.status == HttpStatus.UNAUTHORIZED) {
|
||||
store.dispatch(logout())
|
||||
}
|
||||
return Promise.reject(error as AxiosError)
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
export default webClient
|
||||
|
||||
@@ -12,3 +12,10 @@ export interface AntTreeSelectOption<T> {
|
||||
selectable?: 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
|
||||
*/
|
||||
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" },
|
||||
]
|
||||
|
||||
@@ -3,6 +3,8 @@ import type { CountryCode as RegionAbbreviation } from "libphonenumber-js"
|
||||
import type { Status } from "@/types/constant"
|
||||
import type { Dayjs } from "dayjs"
|
||||
|
||||
export type FormMode = "add" | "edit"
|
||||
|
||||
export interface UserFormValues extends Omit<
|
||||
User,
|
||||
"id" | "password" | "regionAbbreviation" | "departmentId" | "positionId" | "createdAt" | "updatedAt"
|
||||
|
||||
Reference in New Issue
Block a user