123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470 |
- import AuditContent from '@/components/AuditContent'
- import { ZhAuditBackButton, ZhCloseButton, ZhSubmitButton, ZhUploadButton } from '@/components/Button'
- import DatePicker from '@/components/DatePicker'
- import Header from '@/components/Header'
- import Slot from '@/components/Header/slot'
- import OssUploadModal from '@/components/OssUpload'
- import SvgIcon from '@/components/SvgIcon'
- import { userStore } from '@/store/mobx'
- import { iDetailState } from '@/types/auditDetail'
- import { iFile } from '@/types/file'
- import { iAuditor } from '@/types/safe'
- import { iUserInfo } from '@/types/setting'
- import { apiDelFile, apiGetFileList, apiSaveFileInfo } from '@/utils/common/api'
- import { auditProgress } from '@/utils/common/constStatus'
- import consts from '@/utils/consts'
- import { dayjsFormat } from '@/utils/util'
- import { Button, Input, message, Pagination, Tooltip } from 'antd'
- import locale from 'antd/es/date-picker/locale/zh_CN'
- import dayjs from 'dayjs'
- import React, { useEffect, useState, useMemo } from 'react'
- import { RouteComponentProps } from 'react-router'
- import { apiGetSafeDetail, apiResfulSafeAudit } from './api'
- import AuditModal from '@/pages/Quality/Content/Info/Detail/components/Modal'
- import styles from './index.module.scss'
- import Authorization from '@/components/Authorization'
- const { TextArea } = Input
- interface iModalObj {
- ossModal: boolean
- auditModal: boolean
- auditType: string
- curPage: number
- loading: boolean
- }
- const Detail: React.FC<RouteComponentProps> = props => {
- const { id = '' } = props.location.state as any
- const [ modalObj, setModalObj ] = useState<iModalObj>({
- ossModal: false,
- auditModal: false,
- auditType: '',
- loading: false,
- curPage: 1
- })
- const [ detail, setDetail ] = useState<iDetailState>({
- auditName: '',
- uid: '',
- auditors: [],
- bidsectionId: '',
- code: '',
- createTime: new Date().toDateString(),
- demand: '',
- file: { fileList: [], total: 0 },
- id: '',
- inspection: '',
- inspectionDetail: '',
- position: '',
- status: 0,
- checkOrder: { // 整改单
- name: '',
- status: 0,
- opinion: '',
- create_time: new Date().toDateString()
- },
- auditHistory: [],
- rectifiedInfo: [],
- latestAuditor: {
- auditId: '',
- auditOrder: 0,
- bidsectionId: '',
- dataId: '',
- dataType: 0,
- id: '',
- progress: '',
- projectId: '',
- status: 0
- },
- times: 0
- })
- const isEdited = useMemo(() => {
- return !!detail.status
- }, [ detail.status ])
- useEffect(() => {
- initData()
- }, [])
- const initData = async () => {
- const { code = -1, data = {} } = await apiGetSafeDetail(id)
- if (code === consts.RET_CODE.SUCCESS) {
- setDetail({ ...detail, ...data })
- }
- if (!userStore.groupList.length) {
- userStore.getGroupList()
- }
- }
- const onCreate = async (fileList: iFile[]) => {
- const { code = -1 } = await apiSaveFileInfo(fileList, consts.DATA_TYPE.SAFE, detail.id)
- if (code === consts.RET_CODE.SUCCESS) {
- const newFiles = detail.file.fileList.concat(
- fileList.map(file => {
- return { ...file, accountName: userStore.userInfo.name }
- })
- )
- setDetail({ ...detail, file: { ...detail.file, total: newFiles.length } })
- await fileListChange(modalObj.curPage)
- }
- }
- const onOssModalShow = (show: boolean) => setModalObj({ ...modalObj, ossModal: show })
- const fileListChange = async (pageNo: number = 1, pageSize: number = 10) => {
- const { code = -1, data, total } = await apiGetFileList(consts.DATA_TYPE.SAFE, detail.id, pageNo, pageSize)
- if (code === consts.RET_CODE.SUCCESS) {
- setModalObj({ ...modalObj, curPage: pageNo, ossModal: false })
- setDetail({ ...detail, file: { ...detail.file, fileList: data, total } })
- }
- }
- const delFile = async (id: string, isLast: boolean) => {
- const { code = -1 } = await apiDelFile(id)
- if (code === consts.RET_CODE.SUCCESS) {
- await fileListChange(isLast ? modalObj.curPage - 1 : modalObj.curPage)
- isLast && (setModalObj({ ...modalObj, curPage: modalObj.curPage - 1 }))
- }
- }
- const addAuditor = (type: string, user: iUserInfo) => {
- if (detail.auditors.find(item => item.progress === (type === 'check' ? '0' : '2') && item.auditId === user.id)) {
- return message.error('该审批组下已存在该审批人,请勿重复添加')
- }
- if (type === 'check') {
- const newAuditors = detail.auditors
- const len = detail.auditors.filter((item: iAuditor) => item.progress === '0').length
- newAuditors.push({
- id: '',
- mobile: '',
- audit_id: user.id,
- audit_order: len + 1,
- position: user.position,
- progress: '0',
- name: user.name,
- accountGroup: user.accountGroup,
- company: user.company,
- status: 0
- })
- setDetail({ ...detail, auditors: newAuditors })
- } else {
- const newAuditors = detail.auditors
- const len = detail.auditors.filter((item: iAuditor) => item.progress === '2').length
- newAuditors.push({
- id: '',
- audit_id: user.id,
- mobile: '',
- auditOrder: len + 1,
- position: user.position,
- progress: '2',
- name: user.name,
- accountGroup: user.accountGroup,
- company: user.company,
- status: 0
- })
- setDetail({ ...detail, auditors: newAuditors })
- }
- }
- const delAuditor = (id: string, progress: string) => {
- const newAuditors = detail.auditors.filter(item => item.progress !== progress)
- const auditor = detail.auditors.find(item => item.progress === progress && item.audit_id !== id)
- if (auditor) {
- newAuditors.push(auditor)
- }
- setDetail({ ...detail, auditors: newAuditors })
- }
- const btnClick = (type: string) => {
- if (type === 'start') {
- if (!detail.inspectionDetail || !detail.demand) {
- return message.error('现场检查情况或处理要求措施不能为空')
- }
- }
- if (type === 'pass' && detail.latestAuditor.progress === '1' && !detail.checkOrder.opinion) {
- return message.error('请填写整改单')
- }
- setModalObj({ ...modalObj, auditType: type, auditModal: true })
- }
- const onModalConfirm = (values?: object) => {
- let payload: any = { safe_id: detail.id, bidsection_id: detail.bidsectionId, ...values }
- if (modalObj.auditType === 'start') {
- payload.inspection = detail.inspection
- payload.inspectionDetail = detail.inspectionDetail
- payload.demand = detail.demand
- payload.createTime = detail.createTime
- payload.auditors = detail.auditors.filter(item => item.progress === '0').map(item => item.audit_id)
- payload.reAuditors = detail.auditors.filter(item => item.progress === '2').map(item => item.audit_id)
- payload.times = detail.times
- if (!payload.auditors.length || !payload.reAuditors.length) {
- return message.error('审批人或复查人不能为空')
- }
- }
- if (modalObj.auditType === 'delete') {
- payload = { id: detail.id }
- }
- if (modalObj.auditType === 'pass' || modalObj.auditType === 'back') {
- payload.id = detail.latestAuditor.id
- if (detail.latestAuditor.progress === '1') {
- // if (!detail.checkOrder.opinion) {
- // return message.error("请填写整改单")
- // } else {
- // }
- payload.rectifiedInfo = detail.checkOrder.opinion
- }
- }
- if (modalObj.auditType === 'close') {
- payload.id = detail.latestAuditor.id
- }
- apiResful(modalObj.auditType, payload)
- }
- const apiResful = async (type: string, payload: any) => {
- setModalObj({ ...modalObj, loading: true })
- const { code } = await apiResfulSafeAudit(type, payload)
- if (code === consts.RET_CODE.SUCCESS) {
- setModalObj({ ...modalObj, auditModal: false, loading: false })
- if (type === 'delete') {
- props.history.goBack()
- } else {
- initData()
- }
- } else {
- setModalObj({ ...modalObj, loading: false })
- }
- }
- const renderHeaderBtn = (status: number) => {
- if (!detail.latestAuditor.auditId && userStore.userInfo.id !== detail.uid) return null
- if (detail.latestAuditor.auditId && userStore.userInfo.id !== detail.latestAuditor.auditId) return null
- if (!status) {
- return (
- <div className="pi-flex-row pi-align-center">
- <Authorization type="safe" auth="delete">
- <ZhCloseButton size="small" onClick={() => btnClick('delete')}>删除巡检</ZhCloseButton>
- </Authorization>
- <ZhSubmitButton size="small" className="pi-mg-left-5" onClick={() => btnClick('start')}>提交审批</ZhSubmitButton>
- </div>
- )
- } else if (status === auditProgress.checking || status === auditProgress.checkNo) {
- return (
- <div className="pi-flex-row pi-align-center">
- <Button type="primary" danger size="small" onClick={() => btnClick('close')}>关闭</Button>
- <ZhAuditBackButton size="small" className="pi-mg-left-5" onClick={() => btnClick('back')}>审批退回</ZhAuditBackButton>
- <ZhSubmitButton size="small" className="pi-mg-left-5" onClick={() => btnClick('pass')}>审批通过</ZhSubmitButton>
- </div>
- )
- } else if (status === auditProgress.checked) {
- return (
- <div className="pi-flex-row pi-align-center">
- <ZhAuditBackButton size="small" onClick={() => btnClick('back')}>审批退回</ZhAuditBackButton>
- <ZhSubmitButton size="small" className="pi-mg-left-5" onClick={() => btnClick('pass')}>整改完成</ZhSubmitButton>
- </div>
- )
- }
- }
- const modalProps = { visible: modalObj.auditModal, loading: modalObj.loading, type: modalObj.auditType }
- const auditData = { auditors: detail.auditors, auditHistory: detail.auditHistory, status: detail.status, uName: detail.auditName, uid: detail.uid }
- return (
- <div className="wrap-contaniner">
- <Header title="安全巡检">
- <Slot position="right">
- {renderHeaderBtn(detail.status)}
- </Slot>
- </Header>
- <div className={styles.detailContainer}>
- <div className={styles.content}>
- <h4 className={styles.header}>{detail.code}</h4>
- <table className="pi-table pi-bordered">
- <thead>
- <tr>
- <th colSpan={2} className="pi-text-center">
- 安全巡检单
- </th>
- </tr>
- </thead>
- <tbody>
- <tr>
- <th style={{ width: '150px' }}>检查项目</th>
- <td>
- {
- isEdited ? <span>{detail.inspection}</span> : <TextArea value={detail.inspection} onChange={(e) => { setDetail({ ...detail, inspection: e.currentTarget.value }) }} />
- }
- </td>
- </tr>
- <tr>
- <th style={{ width: '150px' }}>现场检查情况</th>
- <td>
- {
- isEdited ? <span>{detail.inspectionDetail}</span> : <TextArea value={detail.inspectionDetail} onChange={(e) => { setDetail({ ...detail, inspectionDetail: e.currentTarget.value }) }} />
- }
- </td>
- </tr>
- <tr>
- <th style={{ width: '150px' }}>处理要求及措施</th>
- <td>
- {
- isEdited ? <span>{detail.demand}</span> : <TextArea value={detail.demand} onChange={(e) => { setDetail({ ...detail, demand: e.currentTarget.value }) }} />
- }
- </td>
- </tr>
- <tr>
- <th style={{ width: '150px' }}>检查日期</th>
- <td>
- {
- isEdited ? <span>{detail.createTime && dayjsFormat(detail.createTime, 'YYYY-MM-DD')}</span> :
- <DatePicker
- size="small"
- locale={locale}
- allowClear={false}
- value={dayjs(detail.createTime)}
- onChange={value => setDetail({ ...detail, createTime: value?.format() })} />
- }
- </td>
- </tr>
- <tr>
- <th style={{ width: '150px' }}>质检员</th>
- <td>{detail.auditName}</td>
- </tr>
- </tbody>
- </table>
- {
- detail.status === auditProgress.checked && detail.latestAuditor.auditId === userStore.userInfo.id ?
- <table className="pi-table pi-bordered">
- <thead>
- <tr>
- <th colSpan={2} className="pi-text-center">
- 整改单
- </th>
- </tr>
- </thead>
- <tbody>
- <tr>
- <th style={{ width: '150px' }}>整改情况</th>
- <td>
- <TextArea value={detail.checkOrder.opinion} onChange={(e) => setDetail({ ...detail, checkOrder: { ...detail.checkOrder, opinion: e.currentTarget.value } })} />
- </td>
- </tr>
- <tr>
- <th style={{ width: '150px' }}>整改日期</th>
- <td>
- <DatePicker
- size="small"
- locale={locale}
- allowClear={false}
- value={dayjs(detail.checkOrder.create_time)}
- onChange={value => setDetail({ ...detail, checkOrder: { ...detail.checkOrder, create_time: value?.format() } })} />
- </td>
- </tr>
- <tr>
- <th style={{ width: '150px' }}>整改人</th>
- <td>{detail.auditors.find(item => item.progress === '1')?.name}</td>
- </tr>
- </tbody>
- </table>
- : detail.rectifiedInfo.map(item => (
- <table className="pi-table pi-bordered" key={item.create_time}>
- <thead>
- <tr>
- <th colSpan={2} className="pi-text-center">
- 整改单
- </th>
- </tr>
- </thead>
- <tbody>
- <tr>
- <th style={{ width: '150px' }}>整改情况</th>
- <td>{item.opinion}</td>
- </tr>
- <tr>
- <th style={{ width: '150px' }}>整改日期</th>
- <td>{dayjsFormat(item.create_time, 'YYYY-MM-DD')}</td>
- </tr>
- <tr>
- <th style={{ width: '150px' }}>整改人</th>
- <td>{item.name}</td>
- </tr>
- </tbody>
- </table>
- ))
- }
- <table className="pi-table pi-bordered mt-3">
- <thead>
- <tr>
- <th />
- <th className="pi-text-center">附件</th>
- <th className="pi-text-center">上传者</th>
- <th className="pi-text-center" style={{ width: 200 }}>
- 上传时间
- </th>
- <th className="pi-text-center">操作</th>
- </tr>
- </thead>
- <tbody>
- <tr>
- <td colSpan={5}>
- <ZhUploadButton size="small" icon={<SvgIcon type="xxh-cloud-upload" />} onClick={() => setModalObj({ ...modalObj, ossModal: true })}>
- 上传附件
- </ZhUploadButton>
- </td>
- </tr>
- {detail.file.fileList?.map((file, idx) => (
- <tr key={idx}>
- <td className="pi-width-70">{idx + 1}</td>
- <td style={{ width: 383, maxWidth: 383, overflow: 'hidden', whiteSpace: 'nowrap', textOverflow: 'ellipsis' }}>
- <a href={consts.OSS_PATH.REVIEW + file.filepath} target="_blank" rel="noopener noreferrer">
- {file.filename}
- </a>
- </td>
- <td className="pi-text-center pi-width-100">{file.accountName}</td>
- <td className="pi-text-center">{dayjsFormat(file.createTime)}</td>
- <td className="pi-text-center pi-width-90">
- <Tooltip title="移除">
- <Button size="small" type="text" icon={<SvgIcon type="xxh-times-circle1" />} style={{ color: '#df3f45' }} onClick={() => delFile(file.id, !idx)} />
- </Tooltip>
- </td>
- </tr>
- ))}
- {detail.file.total > consts.PAGE_SIZE ? (
- <tr>
- <td colSpan={5} className="pi-text-right">
- <Pagination
- current={modalObj.curPage}
- size="small"
- pageSize={consts.PAGE_SIZE}
- hideOnSinglePage={true}
- total={detail.file.total}
- onChange={(page, pageSize) => fileListChange(page, pageSize)} />
- </td>
- </tr>
- ) : null}
- </tbody>
- </table>
- <AuditContent data={auditData} onSelect={addAuditor} onDelete={delAuditor} />
- </div>
- </div>
- <OssUploadModal
- visible={modalObj.ossModal}
- onCancel={() => setModalObj({ ...modalObj, ossModal: false })}
- onCreate={onCreate}
- onShow={onOssModalShow} />
- <AuditModal
- type="safe"
- modalObj={modalProps}
- onCancel={() => setModalObj({ ...modalObj, auditModal: false })}
- onCreate={onModalConfirm}
- auditors={detail.auditors}
- curAuditor={detail.latestAuditor} />
- </div>
- )
- }
- export default Detail
|