HoSoChung
unknown
javascript
a year ago
29 kB
10
Indexable
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)
Editor is loading...
Leave a Comment