HoSoChung

mail@pastecode.io avatar
unknown
javascript
21 days ago
29 kB
3
Indexable
Never
import { useEffect, useRef, useState } from "react"
import {
    Button,
    DatePicker,
    Form,
    Space,
    Modal,
    Tag,
    Table,
    Row,
    Col,
    ConfigProvider,
    Flex,
    Divider,
    Input,
    Tooltip,
    Checkbox,
} from "antd"
import {
    PlusCircleOutlined,
    PushpinFilled,
    // UnorderedListOutlined,
    CommentOutlined,
    MenuFoldOutlined,
    MenuUnfoldOutlined,
    EditOutlined,
    PushpinOutlined,
    SearchOutlined,
    DeleteOutlined,
    FileZipOutlined,
} from "@ant-design/icons"
import moment from "moment/moment"
import axios from "@/axios"
import { listHoSoChung } from "@/api/DuAn/apiHoSoChung"
import { downloadFileHoSoChung } from "@/api/apiFile"
import message from "@/components/Commons/message"
import HoSoChungModal from "@/components/Organisms/DuAn/ThongTinChiTietDuAn/modal/HoSoChungModal"
import BookmarkHoSoModal from "@/components/Organisms/DuAn/ThongTinChiTietDuAn/modal/BookmarkHoSoModal"
import ChiTietHoSoModal from "@/components/Organisms/DuAn/ThongTinChiTietDuAn/modal/ChiTietHoSoModal"
import SelectGiaiDoan from "@/components/Atoms/Select/SelectGiaiDoan"
import ThemNhiemVuForm from "@/components/Organisms/NhiemVu/ThemNhiemVuForm"
import withRouter from "@/components/Commons/withRouter"
import useHandleExpand from "@/hook/useHandleExpand"
import XemChiTietFileTable from "./DrapDropUpload/XemChiTietFileTable"
import { quickChatFile } from "@/store/actions/chat.actions"
import { useDispatch } from "react-redux"
import { reloadSidebar } from "@/store/actions/actions"
import { Link, useSearchParams } from "react-router-dom"
import { renderIcon } from "@/utils/helpers"
import { APP_URL } from "@/env"
import { FooterTable, tableLocale } from "@/components/Commons/locale"
import SidebarHoSoChung from "@/components/Templates/VerticalLayouts/SidebarHoSoChung"
import BreadcrumbHoSoChung from "@/components/Commons/BreadcrumbHoSoChung"

const { RangePicker } = DatePicker

const HoSoChung = (props) => {
    const { name } = props.router.params
    const [searchParams] = useSearchParams()
    const phanLoai = searchParams.get("phan-loai")
    const loaiVanBan = searchParams.get("loai-van-ban")
    const NameLoaiVanBan = searchParams.get("name-loai-van-ban")
    const isFirstRun = useRef(true)
    const dispatch = useDispatch() // Sử dụng dispatch từ Redux
    const [loading, setLoading] = useState(false)
    const [loadingMap, setLoadingMap] = useState(false)
    const [form] = Form.useForm()
    const [dataSource, setDataSource] = useState(false)
    const [parameters, setParameters] = useState({
        keyword: "",
        sort: "desc",
        order: "created_at",
        limit: 10,
        page: 1,
        id_du_an: props.id,
        id_giai_doan: "",
        id_loai_van_ban: "",
        phan_loai_ho_so: "",
        tu_ngay: "",
        den_ngay: "",
    })
    const [totalRecord, setTotalRecord] = useState(0)
    const [isModalOpen, setIsModalOpen] = useState(false)
    const [isFinished, setIsFinished] = useState(false)
    const [idSelected, setIdSelected] = useState(null)
    const [collapsed, setCollapsed] = useState(false)
    const [modalBookmark, setModalBookmark] = useState(false)
    const [modalHoSo, setModalHoSo] = useState(false)
    const [modalGiaoViec, setModalGiaoViec] = useState(false)
    const [bookmarkData, setBookmarkData] = useState({
        idDuAn: props.id,
        idHoSo: null,
        ghiChu: "",
    })
    const [hoSoChungData] = useState({
        idDuAn: props.id,
        hoSo: [],
    })

    const toggleCollapsed = () => {
        setCollapsed(!collapsed)
    }
    const { expandedRowKeys, fileData, handleExpand } = useHandleExpand()
    const columns = [
        {
            key: "ky_hieu_van_ban",
            align: "start",
            title: "Số văn bản",
            dataIndex: "ky_hieu_van_ban",
            width: 120,
            fixed: true,
        },
        {
            title: "Hồ sơ",
            width: 180,
            ellipsis: true,
            render: (data) => (
                <Space>
                    <Tooltip title={data.bookmark_id ? data.bookmark_ghi_chu : "Click vào để đánh dấu"}>
                        <Button
                            onClick={() => {
                                setBookmarkData({
                                    ...bookmarkData,
                                    idHoSo: data.code,
                                    ghiChu: data.bookmark_ghi_chu,
                                })
                                toggleBookmark()
                            }}
                            type="text"
                            icon={
                                data.bookmark_id ? <PushpinFilled style={{ color: "#faad14" }} /> : <PushpinOutlined />
                            }
                        />
                    </Tooltip>

                    <Link to={`/DuAn/ThongTinChiTietDuAn/${props.id}/${name}/${data.id}/${data.file_id}`}>
                        {renderIcon(data.file_extension, APP_URL)}
                        <span className="text-justify ms-1">{`${data.file_name}`}</span>
                    </Link>
                </Space>
            ),
        },
        {
            key: "ngay_ban_hanh",
            align: "start",
            title: "Ngày ban hành",
            dataIndex: "ngay_ban_hanh",
            width: 120,
        },
        {
            key: "ten_giai_doan",
            align: "start",
            title: "Giai đoạn",
            dataIndex: "ten_giai_doan",
            width: 130,
        },
        {
            key: "hs_dieu_chinh",
            title: "Trạng thái",
            width: 100,
            fixed: "right",
            onCell: (record) => ({
                onClick: () => handleExpand(!expandedRowKeys.includes(record.key), record),
            }),
            render: (data, record) =>
                data.hs_dieu_chinh === 1 ? (
                    <Tag className="cursor-pointer" color="red">
                        {expandedRowKeys.includes(record.key) ? "Ẩn danh sách" : "Xem điều chỉnh"}
                    </Tag>
                ) : (
                    ""
                ),
        },
        {
            key: "moTa",
            align: "right",
            title: "Thao tác",
            fixed: "right",
            width: 70,
            render: (data) => (
                <Space>
                    <Tooltip title="Cập nhật">
                        <Button
                            type="primary"
                            icon={<EditOutlined />}
                            size={"small"}
                            onClick={() => {
                                setIdSelected(data.id)
                                toggleHoSo()
                            }}
                        />
                    </Tooltip>
                    {/* <Button
                        type="primary"
                        icon={<UnorderedListOutlined />}
                        size={"small"}
                        onClick={() => {
                            props.router.navigate(`/NhiemVu/ThemMoi/${props.id}/${data.code}`)
                        }}
                    /> */}
                    <Tooltip title="Thảo luận">
                        <Button
                            ghost
                            type="primary"
                            icon={<CommentOutlined />}
                            size={"small"}
                            onClick={() => {
                                dispatch(
                                    quickChatFile("ho_so", {
                                        code: data.code,
                                        file_name: data.file_name,
                                        file_extension: data.file_extension,
                                    }),
                                )
                            }}
                        />
                    </Tooltip>
                </Space>
            ),
        },
    ]

    const onLoadData = () => {
        setLoading(true)
        axios({
            method: "get",
            url: listHoSoChung(parameters),
        })
            .then((response) => {
                onLoadCompleted(response)
            })
            .finally(() => {
                setLoading(false)
            })
    }

    const onLoadCompleted = (response) => {
        let result = response.data
        let data = result.data
        let records = []
        for (let i = 0; i < data.length; i++) {
            records.push({
                key: data[i].id,
                stt: i + parameters.limit * parameters.page + 1 - parameters.limit,
                id: data[i].id,
                id_du_an: data[i].id_du_an,
                code: data[i].code,
                hs_dieu_chinh: data[i].hs_dieu_chinh,
                file_name: data[i].file_name,
                file_id: data[i].file_id,
                file_extension: data[i].file_extension,
                file_path: data[i].file_path,
                ky_hieu_van_ban: data[i].ky_hieu_van_ban,
                ngay_ban_hanh: data[i].ngay_ban_hanh ? moment(data[i].ngay_ban_hanh).format("DD/MM/YYYY") : "",
                noi_nhan: data[i].noi_nhan,
                nguoi_ky: data[i].nguoi_ky,
                ten_loai_van_ban: data[i].ten_loai_van_ban,
                ten_giai_doan: data[i].ten_giai_doan,
                ten_co_quan: data[i].ten_co_quan,
                id_phong_ban_ban_hanh: data[i].id_phong_ban_ban_hanh,
                bookmark_id: data[i].bookmark_id,
                bookmark_ghi_chu: data[i].bookmark_ghi_chu ? data[i].bookmark_ghi_chu : "",

                type: data[i].type,
                created_user: data[i].created_user,
                created_at: data[i].created_at ? moment(data[i].created_at).format("HH:mm DD/MM/YYYY") : "",
            })
        }
        setDataSource(records)
        setTotalRecord(result.total)
    }

    const onChangePage = (page, size) => {
        setParameters({
            ...parameters,
            page: page,
            limit: size,
        })
    }

    const showModal = (id) => {
        setIsModalOpen(true)
        setIdSelected(id)
    }

    const handleOk = () => {
        setIsModalOpen(false)
    }

    const handleCancel = () => {
        setIsModalOpen(false)
        setModalBookmark(false)
        setModalHoSo(false)
    }

    const handleFinished = () => {
        setIsFinished((prev) => !prev)
    }

    const toggleBookmark = () => {
        setModalBookmark(!modalBookmark)
    }

    const toggleHoSo = () => {
        setModalHoSo(!modalHoSo)
    }

    const toggleGiaoViec = () => {
        setModalGiaoViec(!modalGiaoViec)
    }
    const updateParameters = (values = []) => {
        const tu_ngay = values[0]?.value?.[0]?.format("YYYY-MM-DD") || ""
        const den_ngay = values[0]?.value?.[1]?.format("YYYY-MM-DD") || ""
        const id_giai_doan = values[1]?.value || ""
        const keyword = values[2]?.value || ""
        const bookmark = values[3]?.value || null
        setParameters((prevParameters) => {
            const newParams = {
                ...prevParameters,
                keyword,
                id_giai_doan,
                tu_ngay,
                den_ngay,
                bookmark,
            }

            if (JSON.stringify(newParams) !== JSON.stringify(prevParameters)) {
                return newParams
            } else {
                return prevParameters
            }
        })
    }

    useEffect(() => {
        if (isFirstRun.current) {
            isFirstRun.current = false
            return
        }

        const updateParameters = () => {
            setParameters((prevParameters) => {
                let newParams = { ...prevParameters }

                if (phanLoai) {
                    newParams.type = phanLoai === "tat-ca" ? "" : phanLoai
                    newParams.id_loai_van_ban = ""
                }

                if (loaiVanBan) {
                    newParams.type = ""
                    newParams.id_loai_van_ban = loaiVanBan === "tat-ca" ? "" : loaiVanBan
                }

                if (JSON.stringify(newParams) !== JSON.stringify(prevParameters)) {
                    return newParams
                }

                return prevParameters
            })
        }

        updateParameters()
    }, [phanLoai, loaiVanBan])

    useEffect(() => {
        if (parameters || isFinished) {
            onLoadData()
        }
    }, [parameters, isFinished])

    const titleBreadcrumb = () => {
        if (phanLoai) {
            switch (phanLoai) {
                case "tat-ca":
                    return "Tất cả"
                case "chung":
                    return "Hồ sơ chung"

                case "chu_truong_dau_tu":
                case "qd_dau_tu":
                case "quyet_dinh_phe_duyet_thiet_ke":
                case "qd_dieu_chinh_bo_sung":
                case "qd_phe_duyet_du_toan":
                    return "Đầu tư"

                case "ke_hoach_von":
                    return "Kế hoạch vốn"

                case "goi_thau":
                case "hop_dong":
                case "kh_lua_chon_nha_thau":
                    return "Kế hoạch lựa chọn nhà thầu"

                case "giai_phong_mat_bang":
                    return "Giải phóng mặt bằng"
                case "giai_ngan":
                    return "Giải ngân"
                case "quyet_toan":
                    return "Quyết toán"
                default:
                    break
            }
        }
        if (loaiVanBan) {
            return "Loại văn bản"
        }
    }
    const titleBreadcrumbSubItem = () => {
        if (loaiVanBan) {
            return NameLoaiVanBan
        } else {
            switch (phanLoai) {
                case "chu_truong_dau_tu":
                    return "Quyết định chủ trương đầu tư"
                case "qd_dau_tu":
                    return "Quyết định phê duyệt dự án"
                case "quyet_dinh_phe_duyet_thiet_ke":
                    return "Quyết định phê duyệt thiết kế"
                case "qd_dieu_chinh_bo_sung":
                    return "Quyết định bổ sung, điều chỉnh"
                case "qd_phe_duyet_du_toan":
                    return "Quyết định phê duyệt dự toán"
                case "goi_thau":
                    return "Gói thầu"
                case "hop_dong":
                    return "Hợp đồng"
                default:
                    break
            }
        }
    }
    const [selectedRowKeys, setSelectedRowKeys] = useState([])
    const [selectedRows, setSelectedRows] = useState([])

    const handleSelectAll = (checked) => {
        if (checked) {
            axios({
                method: "get",
                url: listHoSoChung({ id_du_an: props.id, limit: 0 }),
            }).then((response) => {
                const allRowKeys = response.data.map((item) => item.id)
                setSelectedRowKeys(allRowKeys)
                setSelectedRows(response.data) // Cập nhật selectedRows để tương ứng với selectedRowKeys
            })
        } else {
            setSelectedRowKeys([])
            setSelectedRows([])
        }
    }

    const onSelectChange = (newSelectedRowKeys, selectedRowsOnPage) => {
        const newSelectedRows = selectedRowsOnPage.map((row) => row.key)

        // Cập nhật selectedRowKeys
        const updatedSelectedRowKeys = [
            ...selectedRowKeys.filter((key) => !newSelectedRows.includes(key)),
            ...newSelectedRowKeys,
        ]

        setSelectedRowKeys(updatedSelectedRowKeys)

        // Cập nhật selectedRows
        const updatedSelectedRows = [
            ...selectedRows.filter((row) => !selectedRowsOnPage.find((selectedRow) => selectedRow.key === row.key)),
            ...selectedRowsOnPage,
        ]

        setSelectedRows(updatedSelectedRows)
    }

    const onSelectNone = () => {
        setSelectedRowKeys([])
        setSelectedRows([])
    }

    const handleDownloadFile = async () => {
        try {
            setLoadingMap(true)
            const formData = new FormData()
            selectedRowKeys.forEach((item) => {
                formData.append("id_file[]", item)
            })

            await axios({
                method: "post",
                data: formData,
                url: downloadFileHoSoChung(),
            })

            setSelectedRowKeys([])
            setSelectedRows([])
            message.success("Xoá dữ liệu thành công")
        } catch (error) {
            message.error(error.response?.data?.message || "Đã xảy ra lỗi")
        } finally {
            setLoadingMap(false)
        }
    }

    const rowSelection = {
        fixed: "left",
        selectedRowKeys,
        onChange: onSelectChange,
        onSelectNone,
        onSelectAll: handleSelectAll,
    }

    const hasSelected = selectedRowKeys.length > 0
    const selectedItemsCount = rowSelection.selectedRowKeys.length
    useEffect(() => {
        const savedSelectedRowKeys = JSON.parse(localStorage.getItem("selectedRowKeys")) || []
        const savedSelectedRows = JSON.parse(localStorage.getItem("selectedRows")) || []
        setSelectedRowKeys(savedSelectedRowKeys)
        setSelectedRows(savedSelectedRows)
    }, [])

    // Lưu dữ liệu vào localStorage khi selectedRowKeys và selectedRows thay đổi
    useEffect(() => {
        localStorage.setItem("selectedRowKeys", JSON.stringify(selectedRowKeys))
        localStorage.setItem("selectedRows", JSON.stringify(selectedRows))
    }, [selectedRowKeys, selectedRows])

    return (
        <div>
            <Form
                form={form}
                onFieldsChange={(_, allFields) => {
                    updateParameters(allFields)
                }}
            >
                <Flex justify="space-between" wrap>
                    <Button className="ms-2" type="primary" ghost onClick={toggleCollapsed}>
                        {collapsed ? <MenuUnfoldOutlined /> : <MenuFoldOutlined />}
                    </Button>
                    <Space size={[16, 16]} wrap>
                        <Form.Item name={"ThoiGianThucHien"} className="mb-0">
                            <RangePicker
                                name={"ThoiGianThucHien"}
                                style={{ width: "100%" }}
                                format="DD/MM/YYYY"
                                placeholder={["Ngày ban hành từ", "Đến ngày"]}
                                allowClear
                            />
                        </Form.Item>
                        <Form.Item name={"id_giai_doan"} className="mb-0">
                            <SelectGiaiDoan
                                placeholder={"Tìm theo giai đoạn"}
                                name={"id_giai_doan"}
                                size="middle"
                                style={{ minWidth: "200px" }}
                                allowClear
                            />
                        </Form.Item>

                        {/* <Form.Item name={"id_co_quan_ban_hanh"} className="mb-0">
                            <CoQuanKySelect
                                placeholder={"Cơ quan ban hành"}
                                name={"id_co_quan_ban_hanh"}
                                style={{ minWidth: "300px" }}
                                allowClear
                            />
                        </Form.Item> */}

                        {/* <Form.Item name={"type"} className="mb-0">
                            <NhomHoSoSelect
                                placeholder={"Nhóm hồ sơ"}
                                name={"type"}
                                style={{ minWidth: "240px" }}
                                allowClear
                            />
                        </Form.Item> */}
                        <Form.Item name={"keyword"} className="mb-0">
                            <Input
                                allowClear
                                suffix={<SearchOutlined />}
                                name={"keyword"}
                                placeholder="Nhập từ khóa cần tìm"
                                style={{ minWidth: "376px" }}
                            />
                        </Form.Item>

                        <Form.Item name="bookmark" className="mb-0" valuePropName="checked">
                            <Checkbox name="bookmark">Tìm hồ sơ đánh dấu</Checkbox>
                        </Form.Item>
                        <Button size="middle" type="primary" icon={<PlusCircleOutlined />} onClick={() => showModal(0)}>
                            Thêm
                        </Button>
                    </Space>
                </Flex>
            </Form>
            <Divider />
            <Row>
                <Col md={collapsed ? 2 : 5}>
                    <BreadcrumbHoSoChung
                        className="mb-1"
                        title={titleBreadcrumb()}
                        breadcrumbItem={titleBreadcrumbSubItem()}
                    />
                    <SidebarHoSoChung inlineCollapsed={collapsed} />
                </Col>
                <Col md={collapsed ? 22 : 19}>
                    <Flex justify="space-between">
                        <div>
                            {selectedItemsCount ? (
                                <span>
                                    Đã chọn
                                    <b className="mx-1">
                                        {selectedItemsCount}/{totalRecord}
                                    </b>
                                    hồ sơ
                                </span>
                            ) : (
                                ""
                            )}
                        </div>
                        <Space>
                            {selectedItemsCount ? (
                                <Button
                                    className="text-danger fw-bold"
                                    type="text"
                                    onClick={onSelectNone}
                                    disabled={!hasSelected}
                                    loading={loading}
                                    icon={<DeleteOutlined />}
                                >
                                    Bỏ chọn tất cả
                                </Button>
                            ) : (
                                ""
                            )}

                            <Tooltip title={!selectedItemsCount ? "Chọn hồ sơ để xuất" : ""}>
                                <Button
                                    type="primary"
                                    onClick={handleDownloadFile}
                                    disabled={!hasSelected}
                                    loading={loadingMap}
                                    icon={<FileZipOutlined />}
                                >
                                    Xuất hồ sơ đã chọn
                                </Button>
                            </Tooltip>
                        </Space>
                    </Flex>
                    <ConfigProvider
                        theme={{
                            components: {
                                Table: {
                                    cellPaddingBlock: 9,
                                    borderColor: "#fff",
                                    headerSplitColor: "#fff",
                                    footerBg: "#fff",
                                    headerBg: "#fff",
                                },
                            },
                        }}
                    >
                        <Table
                            rowSelection={rowSelection}
                            // showHeader={false}
                            dataSource={dataSource}
                            columns={columns}
                            loading={loading}
                            onChangePage={onChangePage}
                            loadingSearch={loading}
                            locale={tableLocale(loading)}
                            // scroll={{ x: 1200 }}
                            scroll={{ x: 350 }}
                            // title={() => (

                            // )}
                            expandable={{
                                expandedRowRender: () => <XemChiTietFileTable data={fileData} />,
                                expandedRowKeys: expandedRowKeys,
                                onExpand: handleExpand,
                                showExpandColumn: false,
                                rowExpandable: (record) => record.hs_dieu_chinh === 1,
                            }}
                            pagination={false}
                            footer={() => (
                                <FooterTable
                                    total={totalRecord}
                                    name={"hồ sơ"}
                                    onChangePage={onChangePage}
                                    current={parameters.page}
                                />
                            )}
                        />
                    </ConfigProvider>
                </Col>
            </Row>
            {isModalOpen && (
                <HoSoChungModal
                    id={idSelected}
                    idDuAn={props.id}
                    title={"hồ sơ dự án"}
                    open={isModalOpen}
                    onOk={handleOk}
                    onCancel={handleCancel}
                    onFinished={handleFinished}
                />
            )}
            {modalHoSo && (
                <Modal
                    width={800}
                    title={"Hồ sơ dự án"}
                    open={modalHoSo}
                    classNames={{
                        header: "bg-light p-3 border-bottom",
                        body: "px-3 py-2",
                        footer: "p-3 border-top",
                    }}
                    footer={null}
                    maskClosable={true}
                    onCancel={toggleHoSo}
                >
                    <ChiTietHoSoModal
                        idHoSo={idSelected}
                        idDuAn={props.id}
                        title={"hồ sơ dự án"}
                        onCancel={toggleHoSo}
                        onFinished={() => {
                            toggleHoSo()
                            onLoadData()
                        }}
                    />
                </Modal>
            )}
            {bookmarkData && (
                <BookmarkHoSoModal
                    bookmarkData={bookmarkData}
                    title={"Đánh dấu hồ sơ"}
                    open={modalBookmark}
                    onOk={toggleBookmark}
                    onCancel={toggleBookmark}
                    onFinished={() => {
                        onLoadData()
                    }}
                />
            )}
            {modalGiaoViec && (
                <Modal
                    width={800}
                    title={"Tạo nhiệm vụ"}
                    open={modalGiaoViec}
                    classNames={{
                        header: "bg-light p-3 border-bottom",
                        body: "px-3 py-2",
                        footer: "p-3 border-top",
                    }}
                    footer={null}
                    maskClosable={true}
                    onCancel={toggleGiaoViec}
                >
                    <ThemNhiemVuForm
                        hoSoChung={hoSoChungData}
                        title={"hồ sơ dự án"}
                        onCancel={toggleGiaoViec}
                        onFinished={() => {
                            toggleGiaoViec()
                            onLoadData()
                            dispatch(reloadSidebar())
                        }}
                    />
                </Modal>
            )}
        </div>
    )
}

export default withRouter(HoSoChung)
Leave a Comment