допилил функционал, связанный с получением фильтрованных секций, мелкие правки
This commit is contained in:
parent
5476b11fb5
commit
eac5e0b896
@ -123,3 +123,4 @@
|
||||
</body>
|
||||
<script type="module" src="/src/index.tsx"></script>
|
||||
</html>
|
||||
|
||||
|
@ -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>
|
||||
|
8
client/src/api/get-sections-filtered-list.ts
Normal file
8
client/src/api/get-sections-filtered-list.ts
Normal 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}`
|
||||
);
|
||||
}
|
@ -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;
|
||||
|
@ -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>
|
||||
);
|
||||
|
5
client/src/components/Section/section.type.ts
Normal file
5
client/src/components/Section/section.type.ts
Normal file
@ -0,0 +1,5 @@
|
||||
export interface ISection {
|
||||
id: number;
|
||||
name: string;
|
||||
root_section_id: number | null;
|
||||
}
|
@ -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>
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
16
client/src/hooks/useFilteredSectionsList.tsx
Normal file
16
client/src/hooks/useFilteredSectionsList.tsx
Normal 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 };
|
||||
}
|
@ -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;
|
||||
|
@ -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));
|
||||
}
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user