HoSoChung
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