Files
yunhaifinance/frontend/src/pages/PurchaseRequestsPage.tsx
T

925 lines
31 KiB
TypeScript
Raw Normal View History

/**
* 采购申请页面
* 遵循设计方案:采购-付款-物流-退库一体化流程设计方案.md
* 章节:二、采购申请页面改造
*
* 简化后的采购申请表单:
* - 不再录入供应商(询价前未知)
* - 不再录入商品明细(询价后确定)
* - 仅填写需求描述和预计金额
* - 新增需求日期字段
*/
import React, { useState, useEffect } from 'react'
import { useNavigate, useLocation } from 'react-router-dom'
import {
Table, Button, Modal, Form, Input, Select, message, Space, Tag, Card,
Row, Col, DatePicker, InputNumber, Popconfirm, Tabs, Empty, Spin, Descriptions, Upload
} from 'antd'
import {
PlusOutlined, EditOutlined, DeleteOutlined,
CheckOutlined, CloseOutlined, EyeOutlined, UndoOutlined, UploadOutlined
} from '@ant-design/icons'
import type { ColumnsType } from 'antd/es/table'
import dayjs from 'dayjs'
interface PurchaseRequest {
id: number
code: string
request_code: string
project_id: number
project_name?: string
applicant: string
request_date: string
expense_category: string
total_amount: number
currency: string
status: string
remark?: string
attachments?: string
purchase_type: string
brief_description: string
expected_date: string
created_at: string
updated_at: string
}
interface Project {
id: number
name: string
}
const PurchaseRequestsPage: React.FC = () => {
const [purchaseRequests, setPurchaseRequests] = useState<PurchaseRequest[]>([])
const [completedRequests, setCompletedRequests] = useState<PurchaseRequest[]>([])
const [activeTab, setActiveTab] = useState('active')
const [loading, setLoading] = useState(false)
const [projects, setProjects] = useState<Project[]>([])
const [selectedProjectId, setSelectedProjectId] = useState<number | null>(null)
const [selectedStatus, setSelectedStatus] = useState<string | null>(null)
const [modalVisible, setModalVisible] = useState(false)
const [detailModalVisible, setDetailModalVisible] = useState(false)
const [editingRequest, setEditingRequest] = useState<PurchaseRequest | null>(null)
const [viewingRequest, setViewingRequest] = useState<PurchaseRequest | null>(null)
const [currentEditingStatus, setCurrentEditingStatus] = useState<string>('')
const [purchaseType, setPurchaseType] = useState<'inventory' | 'project'>('inventory')
const [currency, setCurrency] = useState<string>('CNY')
const [attachments, setAttachments] = useState<any[]>([])
const [form] = Form.useForm()
const navigate = useNavigate()
const location = useLocation()
const exchangeRates = {
CNY: 1,
USD: 7.2,
LAK: 0.0004,
THB: 0.2
}
const fetchPurchaseRequests = async () => {
setLoading(true)
try {
const params = new URLSearchParams()
if (selectedProjectId) params.append('project_id', selectedProjectId.toString())
if (selectedStatus) params.append('status', selectedStatus)
const response = await fetch(`/api/purchase-requests?${params}`)
const data = await response.json()
if (data.success) {
const active = data.data.filter((item: PurchaseRequest) =>
['pending_edit', 'pending', 'withdrawn'].includes(item.status))
const completed = data.data.filter((item: PurchaseRequest) =>
['approved', 'executed'].includes(item.status))
setPurchaseRequests(active)
setCompletedRequests(completed)
} else {
message.error('获取采购申请列表失败')
}
} catch (error) {
console.error('获取采购申请列表失败:', error)
message.error('获取采购申请列表失败')
} finally {
setLoading(false)
}
}
const fetchProjects = async () => {
try {
const response = await fetch('/api/projects')
const data = await response.json()
if (data.success) {
setProjects(data.data)
}
} catch (error) {
console.error('获取项目列表失败:', error)
}
}
const fetchRequestDetail = async (id: number) => {
try {
const response = await fetch(`/api/purchase-requests/${id}`)
const data = await response.json()
if (data.success) {
setViewingRequest(data.data)
setDetailModalVisible(true)
} else {
message.error('获取采购申请详情失败')
}
} catch (error) {
console.error('获取采购申请详情失败:', error)
message.error('获取采购申请详情失败')
}
}
useEffect(() => {
fetchProjects()
}, [])
useEffect(() => {
fetchPurchaseRequests()
}, [selectedProjectId, selectedStatus])
useEffect(() => {
const state = location.state as { formValues?: any, fromPurchaseRequest?: boolean }
let formValues = state?.formValues
if (!formValues) {
const storedValues = sessionStorage.getItem('purchaseRequestFormValues')
if (storedValues) {
formValues = JSON.parse(storedValues)
sessionStorage.removeItem('purchaseRequestFormValues')
}
}
if (formValues || state?.fromPurchaseRequest) {
setTimeout(() => {
if (formValues) {
const values = {
...formValues,
request_date: formValues.request_date ? dayjs(formValues.request_date) : undefined,
expected_date: formValues.expected_date ? dayjs(formValues.expected_date) : undefined
}
form.setFieldsValue(values)
}
setModalVisible(true)
}, 100)
}
}, [location.state, form])
const handleCreate = () => {
setEditingRequest(null)
setPurchaseType('inventory')
form.resetFields()
form.setFieldsValue({
purchase_type: 'inventory',
request_date: dayjs(),
expected_date: dayjs().add(7, 'day'),
currency: 'CNY',
expense_category: 'material',
applicant: '系统管理员',
total_amount: 0,
attachments: []
})
setAttachments([])
setCurrentEditingStatus('')
setModalVisible(true)
}
const handleEdit = async (record: PurchaseRequest) => {
try {
const response = await fetch(`/api/purchase-requests/${record.id}`)
const data = await response.json()
if (data.success && data.data) {
const fullRecord = data.data
setEditingRequest(fullRecord)
setPurchaseType(fullRecord.purchase_type as 'inventory' | 'project')
setCurrentEditingStatus(fullRecord.status)
let attachmentsArray: any[] = []
if (fullRecord.attachments) {
if (typeof fullRecord.attachments === 'string') {
attachmentsArray = fullRecord.attachments.split(',').map((url: string) => ({
url: url,
name: url.split('/').pop() || '',
uid: url,
status: 'done'
}))
} else if (Array.isArray(fullRecord.attachments)) {
attachmentsArray = fullRecord.attachments
}
}
setAttachments(attachmentsArray)
setModalVisible(true)
setTimeout(() => {
form.resetFields()
form.setFieldsValue({
purchase_type: fullRecord.purchase_type || 'inventory',
project_id: fullRecord.project_id,
request_date: fullRecord.request_date ? dayjs(fullRecord.request_date) : dayjs(),
expected_date: fullRecord.expected_date ? dayjs(fullRecord.expected_date) : undefined,
applicant: fullRecord.applicant,
brief_description: fullRecord.brief_description,
remark: fullRecord.remark,
expense_category: fullRecord.expense_category || 'material',
currency: fullRecord.currency || 'CNY',
total_amount: fullRecord.total_amount || 0,
attachments: attachmentsArray
})
}, 100)
} else {
message.error('获取采购申请详情失败')
}
} catch (error) {
console.error('获取采购申请详情失败:', error)
message.error('获取采购申请详情失败')
}
}
const handleDelete = async (id: number) => {
try {
const response = await fetch(`/api/purchase-requests/${id}`, { method: 'DELETE' })
const data = await response.json()
if (data.success) {
message.success('删除成功')
fetchPurchaseRequests()
} else {
message.error('删除失败')
}
} catch (error) {
console.error('删除失败:', error)
message.error('删除失败')
}
}
const handleSave = async () => {
try {
const values = await form.validateFields()
const saveStatus = currentEditingStatus || 'pending_edit'
const attachmentsUrl = attachments && attachments.length > 0
? attachments.map((file: any) => file.url).join(',')
: ''
const requestData = {
...values,
request_date: values.request_date.format('YYYY-MM-DD'),
expected_date: values.expected_date ? values.expected_date.format('YYYY-MM-DD') : null,
applicant: '系统管理员',
status: saveStatus,
attachments: attachmentsUrl
}
let response
if (editingRequest) {
response = await fetch(`/api/purchase-requests/${editingRequest.id}`, {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(requestData)
})
} else {
response = await fetch('/api/purchase-requests', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(requestData)
})
}
const data = await response.json()
if (data.success) {
message.success(editingRequest ? '保存成功' : '创建成功')
if (!editingRequest) {
setEditingRequest(data.data)
}
setSelectedStatus(null)
fetchPurchaseRequests()
setModalVisible(false)
} else {
message.error(editingRequest ? '保存失败' : '创建失败')
}
} catch (error) {
console.error('保存失败:', error)
}
}
const handleFormSubmit = async () => {
try {
const values = await form.validateFields()
const attachmentsUrl = attachments && attachments.length > 0
? attachments.map((file: any) => file.url).join(',')
: ''
const requestData = {
...values,
request_date: values.request_date.format('YYYY-MM-DD'),
expected_date: values.expected_date ? values.expected_date.format('YYYY-MM-DD') : null,
applicant: '系统管理员',
status: 'pending_edit',
attachments: attachmentsUrl
}
let response
let purchaseRequestId: number
let data
if (editingRequest) {
response = await fetch(`/api/purchase-requests/${editingRequest.id}`, {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(requestData)
})
data = await response.json()
purchaseRequestId = editingRequest.id
} else {
response = await fetch('/api/purchase-requests', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(requestData)
})
data = await response.json()
if (data.success) {
purchaseRequestId = data.data.id
}
}
if (data.success && purchaseRequestId) {
const submitResponse = await fetch(`/api/purchase-requests/${purchaseRequestId}/submit`, {
method: 'POST'
})
const submitData = await submitResponse.json()
if (submitData.success) {
message.success(editingRequest ? '提交成功' : '创建并提交成功')
setModalVisible(false)
setSelectedStatus(null)
fetchPurchaseRequests()
} else {
message.error('提交失败')
}
} else {
message.error(editingRequest ? '保存失败' : '创建失败')
}
} catch (error) {
console.error('提交失败:', error)
message.error('提交失败')
}
}
const handleWithdraw = async (id: number) => {
try {
const response = await fetch(`/api/purchase-requests/${id}/withdraw`, { method: 'POST' })
const data = await response.json()
if (data.success) {
message.success('撤回成功')
setSelectedStatus(null)
fetchPurchaseRequests()
} else {
message.error('撤回失败')
}
} catch (error) {
console.error('撤回失败:', error)
message.error('撤回失败')
}
}
const handleApprove = async (id: number) => {
try {
const response = await fetch(`/api/purchase-requests/${id}/approve`, { method: 'POST' })
const data = await response.json()
if (data.success) {
message.success(data.message || '审批通过成功')
setSelectedStatus(null)
fetchPurchaseRequests()
} else {
message.error('审批通过失败')
}
} catch (error) {
console.error('审批通过失败:', error)
message.error('审批通过失败')
}
}
const handleReject = async (id: number) => {
try {
const response = await fetch(`/api/purchase-requests/${id}/reject`, { method: 'POST' })
const data = await response.json()
if (data.success) {
message.success('驳回成功')
setSelectedStatus(null)
fetchPurchaseRequests()
} else {
message.error('驳回失败')
}
} catch (error) {
console.error('驳回失败:', error)
message.error('驳回失败')
}
}
const getStatusTag = (status: string) => {
const statusMap: Record<string, { color: string; text: string }> = {
pending_edit: { color: 'default', text: '待编辑' },
pending: { color: 'blue', text: '待审批' },
approved: { color: 'green', text: '已审批' },
executed: { color: 'purple', text: '已执行' },
withdrawn: { color: 'orange', text: '已撤回' }
}
const info = statusMap[status] || { color: 'default', text: status }
return <Tag color={info.color}>{info.text}</Tag>
}
const columns: ColumnsType<PurchaseRequest> = [
{
title: '事由',
dataIndex: 'brief_description',
key: 'brief_description',
width: 180,
ellipsis: true,
render: (v: string, r: PurchaseRequest) => (
<a onClick={() => fetchRequestDetail(r.id)} style={{ fontWeight: 500 }}>{v || '-'}</a>
)
},
{
title: '项目',
dataIndex: 'project_name',
key: 'project_name',
width: 120,
ellipsis: true,
render: (v: string) => v || '-'
},
{
title: '分类',
dataIndex: 'expense_category',
key: 'expense_category',
width: 80,
render: (category) => {
const categoryMap: Record<string, string> = {
material: '材料',
equipment: '设备',
pole: '电杆',
other: '其他'
}
return <Tag size="small">{categoryMap[category] || category}</Tag>
}
},
{
title: '预计金额',
dataIndex: 'total_amount',
key: 'total_amount',
width: 130,
align: 'right',
render: (amount, record) => (
<span style={{ fontWeight: 500, color: '#999' }}>
{record.currency} {amount?.toLocaleString('zh-CN', { minimumFractionDigits: 2, maximumFractionDigits: 2 }) || '0.00'}
</span>
)
},
{
title: '需求日期',
dataIndex: 'expected_date',
key: 'expected_date',
width: 100,
render: (date) => date ? dayjs(date).format('MM-DD') : '-'
},
{
title: '状态',
dataIndex: 'status',
key: 'status',
width: 90,
align: 'center',
render: getStatusTag
},
{
title: '申请日期',
dataIndex: 'request_date',
key: 'request_date',
width: 100,
render: (date) => date ? dayjs(date).format('MM-DD') : '-'
},
{
title: '申请人',
dataIndex: 'applicant',
key: 'applicant',
width: 90
},
{
title: '编号',
dataIndex: 'request_code',
key: 'request_code',
width: 150,
ellipsis: true,
render: (v: string) => <span style={{ fontSize: 12, color: '#999' }}>{v || '-'}</span>
},
{
title: '操作',
key: 'actions',
width: 200,
fixed: 'right',
render: (_, record) => (
<Space size={4}>
<Button
size="small"
type="text"
icon={<EyeOutlined />}
onClick={() => fetchRequestDetail(record.id)}
/>
{record.status === 'pending' && (
<>
<Button
size="small"
type="text"
icon={<CheckOutlined />}
onClick={() => handleApprove(record.id)}
style={{ color: '#52c41a' }}
>
通过
</Button>
<Button
size="small"
type="text"
icon={<CloseOutlined />}
onClick={() => handleReject(record.id)}
danger
>
驳回
</Button>
<Button
size="small"
type="text"
icon={<UndoOutlined />}
onClick={() => handleWithdraw(record.id)}
>
撤回
</Button>
</>
)}
{(record.status === 'withdrawn' || record.status === 'pending_edit') && (
<>
<Button
size="small"
type="primary"
icon={<EditOutlined />}
onClick={() => handleEdit(record)}
>
编辑
</Button>
<Popconfirm
title="确定要删除吗?"
onConfirm={() => handleDelete(record.id)}
>
<Button size="small" type="text" danger icon={<DeleteOutlined />} />
</Popconfirm>
</>
)}
</Space>
)
}
]
return (
<div style={{ padding: 24 }}>
<div style={{ marginBottom: 24 }}>
<h2 style={{ marginBottom: 8 }}>采购申请</h2>
<p style={{ color: '#888', marginBottom: 0 }}>管理公司采购申请(简化版:仅填写需求描述和预计金额)</p>
</div>
<Card extra={<Button type="primary" icon={<PlusOutlined />} onClick={handleCreate}>新建采购申请</Button>}>
<Tabs activeKey={activeTab} onChange={setActiveTab}>
<Tabs.TabPane tab="活跃申请" key="active">
<Row gutter={16} style={{ marginBottom: 16 }}>
<Col span={6}>
<Select
placeholder="选择项目筛选"
allowClear
style={{ width: '100%' }}
onChange={(value) => setSelectedProjectId(value)}
>
{projects.map(project => (
<Select.Option key={project.id} value={project.id}>
{project.name}
</Select.Option>
))}
</Select>
</Col>
<Col span={6}>
<Select
placeholder="选择状态筛选"
allowClear
style={{ width: '100%' }}
onChange={(value) => setSelectedStatus(value)}
>
<Select.Option value="pending">待审批</Select.Option>
<Select.Option value="withdrawn">已撤回</Select.Option>
<Select.Option value="pending_edit">待编辑</Select.Option>
</Select>
</Col>
</Row>
<Table
columns={columns}
dataSource={purchaseRequests}
rowKey="id"
loading={loading}
pagination={{ pageSize: 20 }}
size="small"
scroll={{ x: 1200 }}
/>
</Tabs.TabPane>
<Tabs.TabPane tab="已完成" key="completed">
<Row gutter={16} style={{ marginBottom: 16 }}>
<Col span={6}>
<Select
placeholder="选择项目筛选"
allowClear
style={{ width: '100%' }}
onChange={(value) => setSelectedProjectId(value)}
>
{projects.map(project => (
<Select.Option key={project.id} value={project.id}>
{project.name}
</Select.Option>
))}
</Select>
</Col>
</Row>
<Table
columns={columns}
dataSource={completedRequests}
rowKey="id"
loading={loading}
pagination={{ pageSize: 20 }}
size="small"
scroll={{ x: 1200 }}
/>
</Tabs.TabPane>
</Tabs>
</Card>
{/* 编辑/新建弹窗 - 简化版 */}
<Modal
title={editingRequest ? '编辑采购申请' : '新建采购申请'}
open={modalVisible}
onCancel={() => setModalVisible(false)}
footer={[
<Button key="cancel" onClick={() => setModalVisible(false)}>取消</Button>,
<Button key="save" onClick={handleSave}>保存</Button>,
<Button key="submit" type="primary" onClick={handleFormSubmit}>提交审批</Button>
]}
width={700}
>
<Form form={form} layout="vertical">
<Row gutter={16}>
<Col span={12}>
<Form.Item
name="purchase_type"
label="采购类型"
rules={[{ required: true, message: '请选择采购类型' }]}
>
<Select
placeholder="请选择采购类型"
onChange={(value) => setPurchaseType(value as 'inventory' | 'project')}
>
<Select.Option value="inventory">库存采购</Select.Option>
<Select.Option value="project">项目采购</Select.Option>
</Select>
</Form.Item>
</Col>
<Col span={12}>
{purchaseType === 'project' && (
<Form.Item
name="project_id"
label="关联项目"
rules={[{ required: true, message: '项目采购必须关联项目' }]}
>
<Select placeholder="请选择项目" allowClear>
{projects.map(project => (
<Select.Option key={project.id} value={project.id}>
{project.name}
</Select.Option>
))}
</Select>
</Form.Item>
)}
</Col>
</Row>
<Row gutter={16}>
<Col span={12}>
<Form.Item
name="applicant"
label="申请人"
initialValue="系统管理员"
rules={[{ required: true, message: '请输入申请人' }]}
>
<Input placeholder="请输入申请人" disabled />
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
name="request_date"
label="申请日期"
rules={[{ required: true, message: '请选择申请日期' }]}
>
<DatePicker style={{ width: '100%' }} />
</Form.Item>
</Col>
</Row>
<Form.Item
name="brief_description"
label="事由描述"
rules={[
{ required: true, message: '请输入事由描述' },
{ max: 100, message: '事由描述不能超过100个字符' }
]}
>
<Input.TextArea
rows={2}
placeholder="请简要描述采购需求(如:采购XX项目所需电缆、电杆等材料)"
maxLength={100}
showCount
/>
</Form.Item>
<Row gutter={16}>
<Col span={8}>
<Form.Item
name="expense_category"
label="支出分类"
rules={[{ required: true, message: '请选择支出分类' }]}
>
<Select placeholder="请选择支出分类">
<Select.Option value="material">材料</Select.Option>
<Select.Option value="equipment">设备</Select.Option>
<Select.Option value="pole">电杆</Select.Option>
<Select.Option value="other">其他</Select.Option>
</Select>
</Form.Item>
</Col>
<Col span={8}>
<Form.Item
name="total_amount"
label="预计金额"
rules={[{ required: true, message: '请输入预计金额' }]}
>
<InputNumber
style={{ width: '100%' }}
placeholder="预计金额"
min={0}
precision={2}
/>
</Form.Item>
</Col>
<Col span={8}>
<Form.Item
name="currency"
label="币种"
rules={[{ required: true, message: '请选择币种' }]}
>
<Select placeholder="请选择币种" onChange={(value) => setCurrency(value)}>
<Select.Option value="CNY">人民币</Select.Option>
<Select.Option value="USD">美元</Select.Option>
<Select.Option value="LAK">老挝基普</Select.Option>
<Select.Option value="THB">泰铢</Select.Option>
</Select>
</Form.Item>
</Col>
</Row>
<Row gutter={16}>
<Col span={12}>
<Form.Item
name="expected_date"
label="需求日期"
rules={[{ required: true, message: '请选择需求日期' }]}
>
<DatePicker style={{ width: '100%' }} placeholder="期望到货日期" />
</Form.Item>
</Col>
</Row>
<Form.Item name="remark" label="备注">
<Input.TextArea rows={2} placeholder="请输入备注(选填)" />
</Form.Item>
<Form.Item name="attachments" label="附件">
<Upload
name="file"
listType="text"
maxCount={5}
accept=".pdf,.doc,.docx,.xlsx,.xls,.jpg,.jpeg,.png"
fileList={attachments}
onChange={(info) => {
if (info.file.status === 'removed') {
const updatedAttachments = attachments.filter(item => item.uid !== info.file.uid)
setAttachments(updatedAttachments)
form.setFieldsValue({ attachments: updatedAttachments })
}
}}
customRequest={async (options) => {
const { onSuccess, onError, file } = options
const formData = new FormData()
formData.append('file', file as File)
try {
const response = await fetch('/api/upload/single', {
method: 'POST',
body: formData
})
const data = await response.json()
if (data.success && data.data) {
const fileInfo = {
...data.data,
name: (file as File).name,
uid: (file as any).uid,
status: 'done'
}
const updatedAttachments = [...attachments, fileInfo]
setAttachments(updatedAttachments)
form.setFieldsValue({ attachments: updatedAttachments })
onSuccess(fileInfo)
} else {
onError(new Error('上传失败'))
}
} catch (error) {
onError(error)
}
}}
onPreview={(file) => {
window.open(file.url, '_blank')
}}
>
<Button icon={<UploadOutlined />}>选择文件</Button>
</Upload>
</Form.Item>
</Form>
</Modal>
{/* 详情弹窗 */}
<Modal
title="采购申请详情"
open={detailModalVisible}
onCancel={() => setDetailModalVisible(false)}
footer={[<Button key="close" onClick={() => setDetailModalVisible(false)}>关闭</Button>]}
width={700}
>
{viewingRequest && (
<div>
<Card style={{ marginBottom: 16 }}>
<Descriptions bordered column={2}>
<Descriptions.Item label="申请编号" span={1}>{viewingRequest.request_code || viewingRequest.code}</Descriptions.Item>
<Descriptions.Item label="状态" span={1}>{getStatusTag(viewingRequest.status)}</Descriptions.Item>
<Descriptions.Item label="采购类型" span={1}>
{viewingRequest.purchase_type === 'project' ? '项目采购' : '库存采购'}
</Descriptions.Item>
<Descriptions.Item label="项目" span={1}>{viewingRequest.project_name || '-'}</Descriptions.Item>
<Descriptions.Item label="申请人" span={1}>{viewingRequest.applicant}</Descriptions.Item>
<Descriptions.Item label="申请日期" span={1}>{viewingRequest.request_date}</Descriptions.Item>
<Descriptions.Item label="事由描述" span={2}>{viewingRequest.brief_description || '-'}</Descriptions.Item>
<Descriptions.Item label="支出分类" span={1}>
{{
material: '材料',
equipment: '设备',
pole: '电杆',
other: '其他'
}[viewingRequest.expense_category] || viewingRequest.expense_category}
</Descriptions.Item>
<Descriptions.Item label="预计金额" span={1}>
<strong style={{ fontSize: 16, color: '#999' }}>
{viewingRequest.currency} {viewingRequest.total_amount?.toFixed(2) || '0.00'}
</strong>
</Descriptions.Item>
<Descriptions.Item label="需求日期" span={1}>
{viewingRequest.expected_date || '-'}
</Descriptions.Item>
<Descriptions.Item label="创建时间" span={1}>
{viewingRequest.created_at}
</Descriptions.Item>
{viewingRequest.remark && (
<Descriptions.Item label="备注" span={2}>{viewingRequest.remark}</Descriptions.Item>
)}
</Descriptions>
</Card>
</div>
)}
</Modal>
</div>
)
}
export default PurchaseRequestsPage