допилил функционал, связанный с получением фильтрованных секций, мелкие правки

This commit is contained in:
dyakonovr 2024-04-03 19:09:28 +04:00
parent 5476b11fb5
commit eac5e0b896
13 changed files with 132 additions and 74 deletions

View File

@ -123,3 +123,4 @@
</body>
<script type="module" src="/src/index.tsx"></script>
</html>

View File

@ -13,6 +13,7 @@ import ThreadsList from "./components/Thread/List";
import ThreadCreate from "./components/Thread/Create";
import MessagesList from "./components/Message/List";
import MessageCreate from "./components/Message/Create";
import ThreadEdit from "./components/Thread/Edit";
function App() {
return (
@ -39,7 +40,7 @@ function App() {
name="threads"
list={<ThreadsList />}
create={<ThreadCreate />}
// edit={<SectionEdit />}
edit={<ThreadEdit />}
/>
<Resource name="messages" list={<MessagesList />} create={<MessageCreate />} />
</Admin>

View File

@ -0,0 +1,8 @@
import axios from "axios";
import { ISection } from "../components/Section/section.type";
export async function getSectionsFilteredList(params?: string) {
return await axios.get<ISection[]>(
`http://localhost:5000/api/sections/get-filtered-list?${params}`
);
}

View File

@ -1,16 +1,17 @@
import { Create, ReferenceInput, SelectInput, SimpleForm, TextInput } from "react-admin";
import { Create, SelectInput, SimpleForm, TextInput } from "react-admin";
import { useFilteredSectionsList } from "../../hooks/useFilteredSectionsList";
function SectionCreate() {
const { filteredSectionsList } = useFilteredSectionsList();
return (
<Create>
<SimpleForm>
<TextInput source="name" fullWidth />
<ReferenceInput source="root_section_id" reference="sections">
<SelectInput optionText="name" fullWidth />
</ReferenceInput>
<SelectInput source="root_section_id" fullWidth choices={filteredSectionsList} />
</SimpleForm>
</Create>
);
};
}
export default SectionCreate;
export default SectionCreate;

View File

@ -1,28 +1,22 @@
import {
Edit,
ReferenceInput,
SelectInput,
SimpleForm,
TextInput,
useGetRecordId,
useGetRecordId
} from "react-admin";
import Title from "../Title";
import { useFilteredSectionsList } from "../../hooks/useFilteredSectionsList";
function SectionEdit() {
const recordId = useGetRecordId();
const { filteredSectionsList } = useFilteredSectionsList(`id=${recordId}`);
return (
<Edit title={<Title prefixText="Роль" />} actions={false}>
<SimpleForm>
<TextInput source="name" fullWidth />
<ReferenceInput
source="root_section_id"
reference="sections"
filter={{ id: recordId }}
>
<SelectInput optionText="name" fullWidth />
</ReferenceInput>
<SelectInput source="root_section_id" fullWidth choices={filteredSectionsList} />
</SimpleForm>
</Edit>
);

View File

@ -0,0 +1,5 @@
export interface ISection {
id: number;
name: string;
root_section_id: number | null;
}

View File

@ -6,19 +6,16 @@ import {
TextInput,
required
} from "react-admin";
import { useFilteredSectionsList } from "../../hooks/useFilteredSectionsList";
function ThreadCreate() {
const { filteredSectionsList } = useFilteredSectionsList(`onlyEndSections=true`);
return (
<Create>
<SimpleForm>
<TextInput source="name" fullWidth />
<ReferenceInput
source="section_id"
reference="sections"
filter={{ onlyEndSections: true }}
>
<SelectInput optionText="name" fullWidth validate={required()} />
</ReferenceInput>
<SelectInput source="section_id" fullWidth choices={filteredSectionsList} />
<ReferenceInput source="creator_id" reference="users">
<SelectInput optionText="nickname" fullWidth validate={required()} />
</ReferenceInput>

View File

@ -4,28 +4,24 @@ import {
SelectInput,
SimpleForm,
TextInput,
useGetRecordId,
required
} from "react-admin";
import Title from "../Title";
import { useFilteredSectionsList } from "../../hooks/useFilteredSectionsList";
function SectionEdit() {
const recordId = useGetRecordId();
function ThreadEdit() {
const { filteredSectionsList } = useFilteredSectionsList(`onlyEndSections=true`);
return (
<Edit title={<Title prefixText="Роль" />} actions={false}>
<Edit actions={false}>
<SimpleForm>
<TextInput source="name" fullWidth />
<ReferenceInput
source="root_section_id"
reference="sections"
filter={{ id: recordId }}
>
<SelectInput optionText="name" fullWidth />
<SelectInput source="section_id" fullWidth choices={filteredSectionsList} />
<ReferenceInput source="creator_id" reference="users">
<SelectInput optionText="nickname" fullWidth validate={required()} />
</ReferenceInput>
</SimpleForm>
</Edit>
);
}
export default SectionEdit;
export default ThreadEdit;

View File

@ -49,6 +49,7 @@ export default {
[params.target]: params.id,
}),
};
const url = `${apiUrl}/${resource}/many-references?${stringify(query)}`;
const { data: responseData } = await axios.get(url);

View File

@ -0,0 +1,16 @@
import { useEffect, useState } from "react";
import { ISection } from "../components/Section/section.type";
import { getSectionsFilteredList } from "../api/get-sections-filtered-list";
export const useFilteredSectionsList = (queryParams?: string) => {
const [filteredSectionsList, setFilteredSectionsList] = useState<ISection[]>([]);
useEffect(() => {
(async () => {
const response = await getSectionsFilteredList(queryParams);
setFilteredSectionsList(response.data);
})();
}, []);
return { filteredSectionsList };
}

View File

@ -1,6 +1,7 @@
import { Op, type Order } from "sequelize";
import { QueryTypes, type Order } from "sequelize";
import Section from "../../models/section.model";
import { ApiErrorHandler } from "../../error/api-error.handler";
import { sequelize } from "../../db";
import type { ISectionDto } from "./section.dto";
import type { NextFunction, Request, Response } from "express";
import type {
@ -12,12 +13,6 @@ import type {
class SectionController {
getAll = async (req: Request, res: Response, next: NextFunction) => {
try {
// Сюда приходит id текущего товара при редактировании,
// чтобы не возвращать его в списке
const filter: FilterQueryParamType = req.query.filter
? JSON.parse(req.query.filter.toString())
: {};
const range: RangeQueryParamType = req.query.range
? JSON.parse(req.query.range.toString())
: [0, 10];
@ -28,38 +23,80 @@ class SectionController {
const sections = await Section.findAndCountAll({
offset: range[0],
limit: range[1] - range[0] + 1,
order: [sort] as Order,
where: {
id: {
[Op.ne]: filter && filter.id ? filter.id : null
}
}
order: [sort] as Order
});
// if (filter.onlyEndSections) {
// console.log('!');
// const endSections = sections.rows.filter(async (section) => {
// const innerSections = await Section.findAll({
// where: {
// root_section_id: section.id
// }
// });
// console.log(section.dataValues.name, innerSections.length);
// return innerSections.length === 0;
// });
// console.log(endSections);
// return res.json({ data: endSections, total: endSections.length });
// }
return res.json({ data: sections.rows, total: sections.count });
} catch (error) {
next(ApiErrorHandler.internal((error as Error).message));
}
};
getFillteredList = async (req: Request, res: Response, next: NextFunction) => {
try {
// Сюда приходит id текущего товара при редактировании,
// чтобы не возвращать его в списке
// или же флаг onlyEndSections
// const filter: { onlyEndSections: boolean } | { id: number } = req.query.filter
// ? JSON.parse(req.query.filter.toString())
// : {};
const currentSectionId: number = req.query.id
? JSON.parse(req.query.id.toString())
: -1;
const onlyEndSections: boolean = req.query.onlyEndSections
? JSON.parse(req.query.onlyEndSections.toString())
: false;
// const range: RangeQueryParamType = req.query.range
// ? JSON.parse(req.query.range.toString())
// : [0, 10];
// const sort: SortQueryParamType = req.query.sort
// ? JSON.parse(req.query.sort.toString())
// : ["id", "ASC"];
if (onlyEndSections === true) {
const endSections = await sequelize.query(
`
SELECT * FROM sections
WHERE id NOT IN (SELECT DISTINCT root_section_id FROM sections
WHERE root_section_id IS NOT NULL);
`,
{ type: QueryTypes.SELECT }
);
return res.json(endSections);
}
// const sections = await Section.findAndCountAll({
// offset: range[0],
// limit: range[1] - range[0] + 1,
// order: [sort] as Order,
// include: {
// model: Thread,
// required: false,
// where: { id: null }
// },
// where: {
// id: {
// [Op.ne]: filter && "id" in filter ? filter.id : null
// }
// }
// });
const sections = await sequelize.query(
`SELECT * FROM sections WHERE id != ${currentSectionId} AND id NOT IN
(SELECT DISTINCT section_id FROM threads) AND
(root_section_id IS NULL OR root_section_id != ${currentSectionId});`,
{ type: QueryTypes.SELECT }
);
return res.json(sections);
} catch (error) {
next(ApiErrorHandler.internal((error as Error).message));
}
};
getMany = async (
req: Request,
res: Response<{ data: Section[] }>,
@ -119,7 +156,7 @@ class SectionController {
const { name, root_section_id } = req.body;
const section = await Section.findByPk(id);
if (!section) return next(ApiErrorHandler.internal("Такой роли не найдено"));
if (!section) return next(ApiErrorHandler.internal("Такой секции не найдено"));
section.name = name;
section.root_section_id = root_section_id;

View File

@ -106,17 +106,17 @@ class ThreadController {
delete = async (
req: Request<{ id: number }>,
res: Response<Section>,
res: Response<Thread>,
next: NextFunction
) => {
try {
const { id } = req.params;
const section = await Section.findByPk(id);
if (!section) return next(ApiErrorHandler.internal("Такой роли не найдено"));
const thread = await Thread.findByPk(id);
if (!thread) return next(ApiErrorHandler.internal("Такой роли не найдено"));
await section.destroy();
await thread.destroy();
return res.json(section);
return res.json(thread);
} catch (error) {
next(ApiErrorHandler.internal((error as Error).message));
}

View File

@ -6,6 +6,7 @@ const sectionRouter = Router();
sectionRouter.post("/", SectionController.create);
sectionRouter.get("/", SectionController.getAll);
sectionRouter.get("/get-many", SectionController.getMany);
sectionRouter.get("/get-filtered-list", SectionController.getFillteredList);
sectionRouter.get("/:id", SectionController.getById);
sectionRouter.put("/:id", SectionController.update);
sectionRouter.delete("/delete-many", SectionController.deleteMany);