Files
rmser/rmser-view/src/pages/DraftsList.tsx

234 lines
7.2 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// src/pages/DraftsList.tsx
import React, { useState } from "react";
import { useQuery } from "@tanstack/react-query";
import {
List,
Typography,
Tag,
Spin,
Empty,
DatePicker,
Flex,
message,
} from "antd";
import { useNavigate } from "react-router-dom";
import {
ArrowRightOutlined,
ThunderboltFilled,
HistoryOutlined,
FileTextOutlined,
} from "@ant-design/icons";
import dayjs, { Dayjs } from "dayjs";
import { api } from "../services/api";
import type { UnifiedInvoice } from "../services/types";
const { Title, Text } = Typography;
const { RangePicker } = DatePicker;
export const DraftsList: React.FC = () => {
const navigate = useNavigate();
// Состояние фильтра дат: по умолчанию последние 30 дней
const [dateRange, setDateRange] = useState<[Dayjs, Dayjs]>([
dayjs().subtract(30, "day"),
dayjs(),
]);
// Запрос данных с учетом дат (даты в ключе обеспечивают авто-перезапрос)
const {
data: invoices,
isLoading,
isError,
} = useQuery({
queryKey: [
"drafts",
dateRange[0].format("YYYY-MM-DD"),
dateRange[1].format("YYYY-MM-DD"),
],
queryFn: () =>
api.getDrafts(
dateRange[0].format("YYYY-MM-DD"),
dateRange[1].format("YYYY-MM-DD")
),
});
const getStatusTag = (item: UnifiedInvoice) => {
if (item.type === "SYNCED") {
return (
<Tag icon={<HistoryOutlined />} color="success">
Синхронизировано
</Tag>
);
}
switch (item.status) {
case "PROCESSING":
return <Tag color="blue">Обработка</Tag>;
case "READY_TO_VERIFY":
return <Tag color="orange">Проверка</Tag>;
case "COMPLETED":
return <Tag color="green">Готово</Tag>;
case "ERROR":
return <Tag color="red">Ошибка</Tag>;
case "CANCELED":
return <Tag color="default">Отменен</Tag>;
default:
return <Tag>{item.status}</Tag>;
}
};
const handleInvoiceClick = (item: UnifiedInvoice) => {
if (item.type === "SYNCED") {
message.info("История доступна только для просмотра");
return;
}
navigate(`/invoice/${item.id}`);
};
if (isError) {
return (
<div style={{ padding: 20 }}>
<Text type="danger">Ошибка загрузки списка накладных</Text>
</div>
);
}
return (
<div style={{ padding: "0 4px 20px" }}>
<Title level={4} style={{ marginTop: 16, marginBottom: 16 }}>
Накладные
</Title>
{/* Фильтр дат */}
<div
style={{
marginBottom: 16,
background: "#fff",
padding: 12,
borderRadius: 8,
}}
>
<Text
type="secondary"
style={{ display: "block", marginBottom: 8, fontSize: 12 }}
>
Период загрузки:
</Text>
<RangePicker
value={dateRange}
onChange={(dates) => dates && setDateRange([dates[0]!, dates[1]!])}
style={{ width: "100%" }}
allowClear={false}
format="DD.MM.YYYY"
/>
</div>
{isLoading ? (
<div style={{ textAlign: "center", padding: 40 }}>
<Spin size="large" />
</div>
) : !invoices || invoices.length === 0 ? (
<Empty description="Нет данных за выбранный период" />
) : (
<List
dataSource={invoices}
renderItem={(item) => {
const isSynced = item.type === "SYNCED";
return (
<List.Item
style={{
background: isSynced ? "#fafafa" : "#fff",
padding: 12,
marginBottom: 10,
borderRadius: 12,
cursor: isSynced ? "default" : "pointer",
border: isSynced ? "1px solid #f0f0f0" : "1px solid #e6f7ff",
boxShadow: "0 2px 4px rgba(0,0,0,0.02)",
display: "block",
}}
onClick={() => handleInvoiceClick(item)}
>
<Flex vertical gap={4}>
<Flex justify="space-between" align="start">
<Flex vertical>
<Flex align="center" gap={8}>
<Text strong style={{ fontSize: 16 }}>
{item.document_number || "Без номера"}
</Text>
{item.is_app_created && (
<ThunderboltFilled
style={{ color: "#faad14" }}
title="Создано в RMSer"
/>
)}
</Flex>
{item.incoming_number && (
<Text type="secondary" style={{ fontSize: 12 }}>
Вх. {item.incoming_number}
</Text>
)}
</Flex>
{getStatusTag(item)}
</Flex>
<Flex justify="space-between" style={{ marginTop: 4 }}>
<Flex gap={8} align="center">
<FileTextOutlined style={{ color: "#888" }} />
<Text type="secondary" style={{ fontSize: 13 }}>
{item.items_count} поз.
</Text>
<Text type="secondary" style={{ fontSize: 13 }}>
</Text>
<Text type="secondary" style={{ fontSize: 13 }}>
{dayjs(item.date_incoming).format("DD.MM.YYYY")}
</Text>
</Flex>
{item.store_name && (
<Tag
style={{
margin: 0,
maxWidth: 120,
overflow: "hidden",
textOverflow: "ellipsis",
}}
>
{item.store_name}
</Tag>
)}
</Flex>
<Flex
justify="space-between"
align="center"
style={{ marginTop: 8 }}
>
<Text
strong
style={{
fontSize: 17,
color: isSynced ? "#595959" : "#1890ff",
}}
>
{item.total_sum.toLocaleString("ru-RU", {
style: "currency",
currency: "RUB",
maximumFractionDigits: 0,
})}
</Text>
{!isSynced && (
<ArrowRightOutlined style={{ color: "#1890ff" }} />
)}
</Flex>
</Flex>
</List.Item>
);
}}
/>
)}
</div>
);
};