parent
46d88a255a
commit
99edde20a3
@ -0,0 +1,86 @@
|
||||
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
||||
import { api, getPoints } from "../../../../api";
|
||||
import { Button, Modal } from "antd";
|
||||
import { MakeWorkingTable } from "./MakeWorkingTable";
|
||||
import { useEffect, useState } from "react";
|
||||
import { usePopup } from "../../../../stores/usePopup";
|
||||
import { useUpdateStatus } from "../../../../hooks/useUpdateStatus";
|
||||
import { STATUSES } from "../../../../config";
|
||||
|
||||
const useUpdatePostamatId = () => {
|
||||
return useMutation({
|
||||
mutationFn: (params) => {
|
||||
return api.put(
|
||||
`/api/placement_points/update_postamat_id?${params.toString()}`
|
||||
);
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const MakeWorkingModal = ({ selectedIds, onClose, onSuccess }) => {
|
||||
const { data } = useQuery(["make-working-table", selectedIds], async () => {
|
||||
const params = new URLSearchParams({
|
||||
page: 1,
|
||||
page_size: 100,
|
||||
"location_ids[]": selectedIds,
|
||||
});
|
||||
|
||||
return await getPoints(params);
|
||||
});
|
||||
|
||||
const [dataSource, setDataSource] = useState([]);
|
||||
|
||||
useEffect(() => {
|
||||
setDataSource(data?.results);
|
||||
}, [data]);
|
||||
|
||||
const queryClient = useQueryClient();
|
||||
const { setPopup } = usePopup();
|
||||
|
||||
const { mutateAsync: updatePostamatId } = useUpdatePostamatId();
|
||||
|
||||
const { mutateAsync: updateStatus } = useUpdateStatus({});
|
||||
|
||||
const handleUpdate = () => {
|
||||
const updatePostamatPromises = dataSource.map((it) => {
|
||||
const params = new URLSearchParams({
|
||||
id: it.id,
|
||||
postamat_id: it.postamat_id,
|
||||
});
|
||||
|
||||
return updatePostamatId(params);
|
||||
});
|
||||
|
||||
const updateStatusParams = new URLSearchParams({
|
||||
status: STATUSES.working,
|
||||
"location_ids[]": selectedIds,
|
||||
});
|
||||
|
||||
const updateStatusPromise = updateStatus(updateStatusParams);
|
||||
|
||||
Promise.all([...updatePostamatPromises, updateStatusPromise]).then(() => {
|
||||
queryClient.invalidateQueries(["on-approval-points"]);
|
||||
setPopup(null);
|
||||
onSuccess();
|
||||
onClose();
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<Modal
|
||||
open={true}
|
||||
title="Укажите идентификаторы постаматов"
|
||||
onCancel={onClose}
|
||||
width={800}
|
||||
footer={[
|
||||
<Button key="ok-button" type="primary" onClick={handleUpdate}>
|
||||
Обновить статус
|
||||
</Button>,
|
||||
]}
|
||||
>
|
||||
{dataSource && (
|
||||
<MakeWorkingTable data={dataSource} onChange={setDataSource} />
|
||||
)}
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
@ -0,0 +1,156 @@
|
||||
import { Form, InputNumber, Table as AntdTable } from "antd";
|
||||
import React, { useContext, useEffect, useRef, useState } from "react";
|
||||
import { columns as defaultColumns } from "./columns";
|
||||
import "./style.css";
|
||||
|
||||
const EditableContext = React.createContext(null);
|
||||
|
||||
const EditableRow = ({ index, ...props }) => {
|
||||
const [form] = Form.useForm();
|
||||
|
||||
return (
|
||||
<Form form={form} component={false}>
|
||||
<EditableContext.Provider value={form}>
|
||||
<tr {...props} />
|
||||
</EditableContext.Provider>
|
||||
</Form>
|
||||
);
|
||||
};
|
||||
|
||||
const EditableCell = ({
|
||||
title,
|
||||
editable,
|
||||
children,
|
||||
dataIndex,
|
||||
record,
|
||||
handleSave,
|
||||
...restProps
|
||||
}) => {
|
||||
const [editing, setEditing] = useState(false);
|
||||
const inputRef = useRef(null);
|
||||
const form = useContext(EditableContext);
|
||||
|
||||
useEffect(() => {
|
||||
if (editing) {
|
||||
inputRef.current.focus();
|
||||
}
|
||||
}, [editing]);
|
||||
|
||||
const toggleEdit = () => {
|
||||
setEditing(!editing);
|
||||
form.setFieldsValue({
|
||||
[dataIndex]: record[dataIndex],
|
||||
});
|
||||
};
|
||||
|
||||
const save = async () => {
|
||||
try {
|
||||
const values = await form.validateFields();
|
||||
|
||||
toggleEdit();
|
||||
handleSave({
|
||||
...record,
|
||||
...values,
|
||||
});
|
||||
} catch (errInfo) {
|
||||
console.log("Save failed:", errInfo);
|
||||
}
|
||||
};
|
||||
|
||||
let childNode = children;
|
||||
|
||||
if (editable) {
|
||||
childNode = editing ? (
|
||||
<Form.Item
|
||||
style={{
|
||||
margin: 0,
|
||||
}}
|
||||
name={dataIndex}
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
message: `Укажите ${title}`,
|
||||
},
|
||||
]}
|
||||
>
|
||||
<InputNumber
|
||||
ref={inputRef}
|
||||
onPressEnter={save}
|
||||
onBlur={save}
|
||||
className="w-full"
|
||||
min={0}
|
||||
precision={0}
|
||||
/>
|
||||
</Form.Item>
|
||||
) : (
|
||||
<div
|
||||
className="editable-cell-value-wrap"
|
||||
style={{
|
||||
paddingRight: 24,
|
||||
}}
|
||||
onClick={toggleEdit}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return <td {...restProps}>{childNode}</td>;
|
||||
};
|
||||
|
||||
export const MakeWorkingTable = ({ data, onChange }) => {
|
||||
const handleSave = (row) => {
|
||||
const newData = [...data];
|
||||
const index = newData.findIndex((item) => row.id === item.id);
|
||||
const item = newData[index];
|
||||
newData.splice(index, 1, {
|
||||
...item,
|
||||
...row,
|
||||
});
|
||||
onChange(newData);
|
||||
};
|
||||
|
||||
const components = {
|
||||
body: {
|
||||
row: EditableRow,
|
||||
cell: EditableCell,
|
||||
},
|
||||
};
|
||||
|
||||
const columns = defaultColumns.map((col) => {
|
||||
if (!col.editable) {
|
||||
return col;
|
||||
}
|
||||
|
||||
return {
|
||||
...col,
|
||||
onCell: (record) => ({
|
||||
record,
|
||||
editable: col.editable,
|
||||
dataIndex: col.dataIndex,
|
||||
title: col.title,
|
||||
handleSave,
|
||||
}),
|
||||
};
|
||||
});
|
||||
|
||||
const SCROLL = {
|
||||
y: "max-content",
|
||||
x: "max-content",
|
||||
};
|
||||
|
||||
return (
|
||||
<AntdTable
|
||||
components={components}
|
||||
size="small"
|
||||
pagination={false}
|
||||
dataSource={data}
|
||||
columns={columns}
|
||||
rowKey="id"
|
||||
sticky={true}
|
||||
rowClassName={() => "editable-row"}
|
||||
className="!max-w-full"
|
||||
scroll={SCROLL}
|
||||
/>
|
||||
);
|
||||
};
|
||||
@ -0,0 +1,40 @@
|
||||
import { STATUS_LABEL_MAPPER } from "../../../../config";
|
||||
|
||||
export const columns = [
|
||||
{
|
||||
title: "Id",
|
||||
dataIndex: "id",
|
||||
key: "id",
|
||||
width: 50,
|
||||
},
|
||||
{
|
||||
title: "Адрес",
|
||||
dataIndex: "address",
|
||||
key: "address",
|
||||
width: 200,
|
||||
},
|
||||
{
|
||||
title: "Категория",
|
||||
dataIndex: "category",
|
||||
key: "category",
|
||||
width: "120px",
|
||||
ellipsis: true,
|
||||
},
|
||||
{
|
||||
title: "Статус",
|
||||
dataIndex: "status",
|
||||
key: "status",
|
||||
width: "120px",
|
||||
ellipsis: true,
|
||||
render: (_, record) => {
|
||||
return STATUS_LABEL_MAPPER[record.status];
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "Id постамата",
|
||||
dataIndex: "postamat_id",
|
||||
key: "postamat_id",
|
||||
width: "120px",
|
||||
editable: true,
|
||||
},
|
||||
];
|
||||
@ -0,0 +1,17 @@
|
||||
.editable-cell {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.editable-cell-value-wrap {
|
||||
padding: 5px 12px;
|
||||
cursor: pointer;
|
||||
border: 1px solid #d9d9d9;
|
||||
border-radius: 4px;
|
||||
min-height: 24px;
|
||||
}
|
||||
|
||||
.editable-row:hover .editable-cell-value-wrap {
|
||||
padding: 5px 12px;
|
||||
border: 1px solid #d9d9d9;
|
||||
border-radius: 2px;
|
||||
}
|
||||
@ -1,12 +1,6 @@
|
||||
import { STATUS_LABEL_MAPPER } from "../../../config";
|
||||
import { STATUS_LABEL_MAPPER } from "../../config";
|
||||
|
||||
export const columns = [
|
||||
{
|
||||
title: "Id",
|
||||
dataIndex: "id",
|
||||
key: "id",
|
||||
width: 50,
|
||||
},
|
||||
{
|
||||
title: "Адрес",
|
||||
dataIndex: "address",
|
||||
Loading…
Reference in new issue