提交 c36c6000 authored 作者: 王鹏飞's avatar 王鹏飞

refactor(admin): migrate books classify module

上级 d238f10c
import { message } from "antd";
import request from "@/utils/request";
import type { ClassifyQuery } from "./query";
async function post(path: string, data: Record<string, unknown>, notify = false) {
try {
const response = (await request.post(
path,
new URLSearchParams(data as Record<string, string>).toString(),
)) as { data?: { code?: number; data?: any; message?: string } };
if (response.data?.code === 200) {
if (notify) message.success(response.data.message);
return response.data.data;
}
message.error(response.data?.message || "数据获取失败!");
} catch {}
return false;
}
export const getClassifyList = (query: ClassifyQuery) => post("/book/category/getList", query);
export const addCategory = (data: Record<string, unknown>) =>
post("/book/category/add", data, true);
export const getCategory = (id: string | number) => post("/book/category/getInfoById", { id });
export const editCategory = (data: Record<string, unknown>) =>
post("/book/category/edit", data, true);
export const deleteCategory = (id: string | number) => post("/book/category/del", { id }, true);
export const changeCategorySort = (data: Record<string, unknown>) =>
post("/book/category/changeSort", data, true);
import type { Dayjs } from "dayjs";
export interface ClassifyFilters {
name?: string;
time?: [Dayjs | null, Dayjs | null] | null;
}
export interface ClassifyQuery {
page: number;
page_size: number;
name?: string;
start_time?: number;
end_time?: number;
}
export function buildClassifyQuery(
page: number,
pageSize: number,
filters: ClassifyFilters,
): ClassifyQuery {
const query: ClassifyQuery = { page, page_size: pageSize };
if (filters.name) query.name = filters.name;
if (filters.time?.[0] && filters.time[1]) {
query.start_time = filters.time[0].startOf("day").unix();
query.end_time = filters.time[1].endOf("day").unix();
}
return query;
}
import { Navigate, useRoutes } from "react-router";
import ClassifyView from "./views/ClassifyView";
export default function ClassifyRoutes() {
return useRoutes([
{ index: true, Component: ClassifyView },
{ path: "*", element: <Navigate to="/books/classify" /> },
]);
}
import { useCallback, useEffect, useRef, useState } from "react";
import { getClassifyList } from "./api";
import { buildClassifyQuery, type ClassifyFilters, type ClassifyQuery } from "./query";
export function useClassifyList() {
const [filters, setFilters] = useState<ClassifyFilters>({});
const [applied, setApplied] = useState<ClassifyFilters>({});
const [page, setPage] = useState(1);
const [pageSize, setPageSize] = useState(10);
const [rows, setRows] = useState<any[]>([]);
const [total, setTotal] = useState(0);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<Error | null>(null);
const last = useRef<ClassifyQuery>(buildClassifyQuery(1, 10, {}));
const load = useCallback(async (query: ClassifyQuery) => {
last.current = query;
setLoading(true);
setError(null);
try {
const result: any = await getClassifyList(query);
if (!result) throw new Error("请求失败");
setRows(result.list || []);
setTotal(result.total || 0);
} catch (e) {
setError(e instanceof Error ? e : new Error("请求失败"));
} finally {
setLoading(false);
}
}, []);
useEffect(() => {
void load(last.current);
}, [load]);
const run = (p: number, s: number, f: ClassifyFilters) => void load(buildClassifyQuery(p, s, f));
const search = () => {
setApplied(filters);
setPage(1);
run(1, pageSize, filters);
};
return {
filters,
setFilters,
page,
pageSize,
rows,
total,
loading,
error,
search,
reset: () => {
setFilters({});
setApplied({});
setPage(1);
run(1, pageSize, {});
},
refresh: () => {
setApplied(filters);
run(page, pageSize, filters);
},
retry: () => void load(last.current),
reloadFirst: search,
changePage: (p: number) => {
setPage(p);
run(p, pageSize, applied);
},
changePageSize: (s: number) => {
setPage(1);
setPageSize(s);
run(1, s, applied);
},
};
}
import { App, Button, DatePicker, Drawer, Form, Input, Space } from "antd";
import type { ColumnsType } from "antd/es/table";
import { useState } from "react";
import { useSelector } from "react-redux";
import { AppList, type AppListFilterItem } from "@/shared/components/AppList";
import { addCategory, deleteCategory, editCategory, getCategory } from "../api";
import type { ClassifyFilters } from "../query";
import { useClassifyList } from "../useClassifyList";
const { RangePicker } = DatePicker;
const items: AppListFilterItem<ClassifyFilters>[] = [
{
name: "name",
label: "分类名称",
render: (field) => (
<Input
allowClear
placeholder="请输入分类名称"
value={field.value || ""}
onChange={(e) => field.onChange(e.target.value)}
/>
),
},
{
name: "time",
label: "创建时间",
render: (field) => (
<RangePicker value={field.value} onChange={(value) => field.onChange(value)} />
),
},
];
export default function ClassifyView() {
const list = useClassifyList();
const { modal } = App.useApp();
const { operationPermissionsList = [] } = useSelector((state: any) => state.user);
const [open, setOpen] = useState(false);
const [id, setId] = useState<any>("");
const [form] = Form.useForm();
const edit = async (value: any) => {
setId(value);
const data = await getCategory(value);
if (data) form.setFieldsValue(data);
setOpen(true);
};
const submit = async (values: any) => {
const result = id ? await editCategory({ ...values, id }) : await addCategory(values);
if (result) {
setOpen(false);
list.reloadFirst();
}
};
const columns: ColumnsType<any> = [
"ID:id",
"分类名称:name",
"创建时间:create_time",
"更新时间:update_time",
"排序:sort",
].map((item) => {
const [title, dataIndex] = item.split(":");
return { title, key: dataIndex, dataIndex, align: "center" };
});
columns.push({
title: "操作",
key: "handle",
render: (_, row) => (
<Space>
{operationPermissionsList.includes("/books/classify/getInfoById") && (
<Button onClick={() => edit(row.id)}>编辑</Button>
)}
{operationPermissionsList.includes("/books/classify/del") && (
<Button
onClick={() =>
modal.confirm({
title: "提示",
content: "分类将永久删除,是否继续?",
onOk: async () => {
if (await deleteCategory(row.id)) list.reloadFirst();
},
})
}
>
删除
</Button>
)}
</Space>
),
});
return (
<div className="classify">
<AppList
rowKey="id"
columns={columns}
data={{ rows: list.rows, total: list.total, loading: list.loading, error: list.error }}
filters={{
value: list.filters,
items,
onChange: list.setFilters,
onSearch: list.search,
onReset: list.reset,
onRefresh: list.refresh,
}}
pagination={{
page: list.page,
pageSize: list.pageSize,
pageSizeOptions: [10, 20, 30, 40],
onChange: list.changePage,
onPageSizeChange: list.changePageSize,
}}
toolbar={
operationPermissionsList.includes("/books/classify/add") ? (
<Button
type="primary"
ghost
onClick={() => {
setId("");
form.resetFields();
setOpen(true);
}}
>
添加
</Button>
) : null
}
onRetry={list.retry}
/>
<Drawer placement="right" open={open} mask={false} onClose={() => setOpen(false)}>
<Form form={form} onFinish={submit} labelCol={{ span: 6 }}>
<Form.Item
name="name"
label="分类名称"
rules={[{ required: true, message: "请输入分类名称" }]}
>
<Input placeholder="请输入分类名称" />
</Form.Item>
<Form.Item name="sort" label="排序" rules={[{ required: true, message: "请输入排序" }]}>
<Input placeholder="请输入排序" />
</Form.Item>
<Form.Item wrapperCol={{ offset: 6, span: 16 }} style={{ textAlign: "center" }}>
<Space size={20}>
{operationPermissionsList.includes("/books/classify/edit") && (
<Button onClick={() => setOpen(false)}>取消</Button>
)}
{operationPermissionsList.includes("/books/classify/edit") && (
<Button type="primary" htmlType="submit">
提交
</Button>
)}
</Space>
</Form.Item>
</Form>
</Drawer>
</div>
);
}
...@@ -10,7 +10,7 @@ const ChapterManagement = lazy(() => import("@/pages/books/section/index")); ...@@ -10,7 +10,7 @@ const ChapterManagement = lazy(() => import("@/pages/books/section/index"));
const AuditLayout = lazy(() => import("@/pages/books/audit/index")); const AuditLayout = lazy(() => import("@/pages/books/audit/index"));
const AuditTable = lazy(() => import("@/pages/books/audit/table")); const AuditTable = lazy(() => import("@/pages/books/audit/table"));
const AuditDetail = lazy(() => import("@/pages/books/audit/detail")); const AuditDetail = lazy(() => import("@/pages/books/audit/detail"));
const Classify = lazy(() => import("@/pages/books/classify/index")); const ClassifyRoutes = lazy(() => import("./classify/routes"));
const Label = lazy(() => import("@/pages/books/label/index")); const Label = lazy(() => import("@/pages/books/label/index"));
const SaleLayout = lazy(() => import("@/pages/books/sale/index")); const SaleLayout = lazy(() => import("@/pages/books/sale/index"));
const SaleTable = lazy(() => import("@/pages/books/sale/table")); const SaleTable = lazy(() => import("@/pages/books/sale/table"));
...@@ -21,9 +21,7 @@ const QuestionBank = lazy(() => import("@/pages/books/question-bank/index")); ...@@ -21,9 +21,7 @@ const QuestionBank = lazy(() => import("@/pages/books/question-bank/index"));
const Discussion = lazy(() => import("@/pages/books/discussion/index")); const Discussion = lazy(() => import("@/pages/books/discussion/index"));
const OrderManagementLayout = lazy(() => import("@/pages/books/order-management/index")); const OrderManagementLayout = lazy(() => import("@/pages/books/order-management/index"));
const OrderTable = lazy(() => import("@/pages/books/order-management/tab/table")); const OrderTable = lazy(() => import("@/pages/books/order-management/tab/table"));
const SaleStatistics = lazy( const SaleStatistics = lazy(() => import("@/pages/books/order-management/tab/salesStatistics"));
() => import("@/pages/books/order-management/tab/salesStatistics"),
);
const Design = lazy(() => import("@/pages/books/design/index")); const Design = lazy(() => import("@/pages/books/design/index"));
export default function BooksRoutes() { export default function BooksRoutes() {
...@@ -51,7 +49,7 @@ export default function BooksRoutes() { ...@@ -51,7 +49,7 @@ export default function BooksRoutes() {
{ path: "detail", Component: AuditDetail }, { path: "detail", Component: AuditDetail },
], ],
}, },
{ path: "classify", Component: Classify }, { path: "classify/*", Component: ClassifyRoutes },
{ path: "label", Component: Label }, { path: "label", Component: Label },
{ {
path: "sale", path: "sale",
......
Markdown 格式
0% 或
您添加了 0 人 到此讨论。请谨慎行事。
请先完成此评论的编辑!
请 注册 或者 后发表评论