index.tsx 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370
  1. import { GroupItem } from '@/pages/Quality/Content/Info/Detail/components/AuditContent'
  2. import Authorization from '@/components/Authorization'
  3. import { ZhAuditBackButton, ZhButton, ZhCloseButton, ZhSubmitButton } from '@/components/Button'
  4. import { tenderStore, userStore } from '@/store/mobx'
  5. import { iAuditor, iLatestAuditorState } from '@/types/safe'
  6. import { iAccountGroupItem, iUserInfo } from '@/types/setting'
  7. import { getUserGroup } from '@/utils/common/user'
  8. import { Button, Form, Input, message, Modal, Popover } from 'antd'
  9. import React, { ChangeEvent, useEffect, useMemo, useState } from 'react'
  10. import SvgIcon from '@/components/SvgIcon'
  11. interface iAuditModalProps {
  12. type: 'safe' | 'quality'
  13. onCancel: () => void
  14. modalObj: {
  15. visible: boolean
  16. type: string
  17. loading: boolean
  18. }
  19. auditors: iAuditor[]
  20. onCreate: (values?: any) => void
  21. curAuditor: iLatestAuditorState
  22. }
  23. interface iModalObjState {
  24. searchValue: string
  25. visible: boolean
  26. auditType: string
  27. }
  28. const AuditModal: React.FC<iAuditModalProps> = props => {
  29. const [ form ] = Form.useForm()
  30. const { modalObj: { visible, type, loading }, onCancel, onCreate, auditors, curAuditor, type: auditType } = props
  31. const [ modal, setModal ] = useState<iModalObjState>({
  32. searchValue: '',
  33. visible: false,
  34. auditType: ''
  35. })
  36. // 当前审批人是否是审批组的最后一个审核人
  37. const isLastAuditor = useMemo(() => {
  38. if (curAuditor.progress !== '0') return false
  39. const len = auditors.filter(item => item.progress === '0').length
  40. if (len && auditors.filter(item => item.progress === '0')[len - 1].audit_id === userStore.userInfo.id) {
  41. return true
  42. }
  43. return false
  44. }, [ auditors, type, curAuditor ])
  45. const [ groups, setGroups ] = useState<Array<iAccountGroupItem>>([])
  46. const [ user, setUser ] = useState<iUserInfo>({
  47. account: '',
  48. accountGroup: 0,
  49. company: '',
  50. csrf: '',
  51. enable: 0,
  52. id: '',
  53. isAdmin: 0,
  54. mobile: '',
  55. name: '',
  56. password: '',
  57. position: '',
  58. projectId: '',
  59. role: '',
  60. telephone: ''
  61. })
  62. const comfirmBtnClick = () => {
  63. form.validateFields().then(values => {
  64. form.resetFields()
  65. if (user.id) {
  66. values.audit_id = user.id
  67. }
  68. if (type === 'pass' && isLastAuditor && curAuditor.progress === '0' && !user.id) {
  69. return message.error('请指定整改人')
  70. }
  71. if (type === 'back' && !user.id) {
  72. return message.error('请选择退回流程')
  73. }
  74. setUser({ ...user, id: '' })
  75. onCreate(values)
  76. })
  77. }
  78. useEffect(() => {
  79. if (visible && type === 'pass') {
  80. if(curAuditor.progress === '1') {
  81. form.setFieldsValue({ opinion: '已按要求整改完成。' })
  82. }
  83. if (isLastAuditor && auditors.findIndex(item => item.progress === '1') !== -1) {
  84. const auditor = auditors.find(item => item.progress === '1')
  85. console.log('auditor', auditor)
  86. auditor && (setUser({ ...user, id: auditor.audit_id, company: auditor.company, name: auditor.name, position: auditor.position }))
  87. }
  88. isLastAuditor && initGroupList()
  89. }
  90. if (visible && type === 'back') {
  91. if (curAuditor.progress === '1') {
  92. const len = auditors.filter(item => item.progress === '0').length
  93. const lastChecker = auditors.filter(item => item.progress === '0')[len - 1]
  94. setUser({ ...user, id: lastChecker.id, name: lastChecker.name })
  95. } else {
  96. const newGroup = initAuditBackGroup()
  97. setGroups(newGroup)
  98. }
  99. }
  100. }, [ visible ])
  101. const initGroupList = async (serach?: string) => {
  102. const data = await getUserGroup({ name: serach, bidsectionId: tenderStore.bid })
  103. setGroups(data)
  104. }
  105. const textObj = {
  106. start: {
  107. title: '提交审批',
  108. okText: '确认提交'
  109. },
  110. delete: {
  111. title: '删除巡检',
  112. okText: '确认删除'
  113. },
  114. close: {
  115. title: '审批关闭',
  116. okText: '确认关闭'
  117. },
  118. back: {
  119. title: '审批退回',
  120. okText: '确认退回'
  121. },
  122. pass: {
  123. title: curAuditor.progress === '1' ? '整改完成' : '审批通过',
  124. okText: curAuditor.progress === '1' ? '整改完成' : '确认通过'
  125. }
  126. }
  127. // 初始化审批退回下拉选择框
  128. const initAuditBackGroup = () => {
  129. const newGroup: iAccountGroupItem[] = []
  130. for (let index = 0; index < 3; index++) {
  131. if (index === 0) {
  132. const newAuditors = auditors
  133. .filter(item => item.progress === '' && item.audit_order < curAuditor.auditOrder)
  134. .map(item => {
  135. return mapUser(item.name, item.id, item.position, item.company, item.mobile)
  136. })
  137. newGroup.push({ value: '检查人', children: newAuditors })
  138. }
  139. if (index === 1) {
  140. const newAuditors = auditors
  141. .filter(item => item.progress === '0' && item.audit_order < curAuditor.auditOrder)
  142. .map(item => {
  143. return mapUser(item.name, item.id, item.position, item.company, item.mobile)
  144. })
  145. newGroup.push({ value: '审批', children: newAuditors })
  146. }
  147. if (index === 2) {
  148. const newAuditors = auditors
  149. .filter(item => item.progress === '1' && item.audit_order < curAuditor.auditOrder)
  150. .map(item => {
  151. return mapUser(item.name, item.id, item.position, item.company, item.mobile)
  152. })
  153. newGroup.push({ value: '整改', children: newAuditors })
  154. }
  155. }
  156. function mapUser(name: string, id: string, position: string, company: string, mobile: string) {
  157. return {
  158. account: '',
  159. accountGroup: 0,
  160. company,
  161. csrf: '',
  162. enable: 0,
  163. id,
  164. isAdmin: 0,
  165. mobile,
  166. name,
  167. password: '',
  168. position,
  169. projectId: '',
  170. role: '',
  171. telephone: ''
  172. }
  173. }
  174. return newGroup
  175. }
  176. const renderOkBtn = (type: string) => {
  177. if (type === 'start' || type === 'pass') {
  178. return (
  179. <ZhSubmitButton size="small" onClick={comfirmBtnClick} loading={loading}>
  180. {textObj[type]?.okText}
  181. </ZhSubmitButton>
  182. )
  183. } else if (type === 'delete') {
  184. return (
  185. <Authorization type={auditType} auth="delete">
  186. <Button danger size="small" onClick={comfirmBtnClick} loading={loading}>
  187. {textObj[type]?.okText}
  188. </Button>
  189. </Authorization>
  190. )
  191. } else if (type === 'close') {
  192. return (
  193. <Button danger size="small" onClick={comfirmBtnClick} loading={loading}>
  194. {textObj[type]?.okText}
  195. </Button>
  196. )
  197. } else if (type === 'back') {
  198. return (
  199. <ZhAuditBackButton size="small" onClick={comfirmBtnClick} loading={loading}>
  200. {textObj[type]?.okText}
  201. </ZhAuditBackButton>
  202. )
  203. }
  204. }
  205. const search = (value: string) => {
  206. if (value != modal.searchValue) {
  207. setModal({ ...modal, searchValue: value })
  208. initGroupList(value)
  209. }
  210. }
  211. const change = (e: ChangeEvent) => {
  212. e.persist()
  213. const target = e.target as HTMLTextAreaElement
  214. if (!target.value) {
  215. initGroupList()
  216. }
  217. }
  218. const itemSelectHandler = (item: iUserInfo, type: string = '') => {
  219. setUser({ ...user, ...item })
  220. setModal({ ...modal, visible: false, auditType: type })
  221. }
  222. const handleVisibleChange = (visible: boolean) => {
  223. setModal({ ...modal, visible })
  224. }
  225. const showPopover = () => {
  226. setModal({ ...modal, visible: true })
  227. }
  228. const handleModalCancel = () => {
  229. setUser({ ...user, id: '' })
  230. onCancel()
  231. }
  232. return (
  233. <Modal
  234. visible={visible}
  235. title={textObj[type]?.title}
  236. onCancel={handleModalCancel}
  237. getContainer={false}
  238. footer={
  239. <div className="pi-justify-end">
  240. <ZhCloseButton size="small" onClick={handleModalCancel} className="pi-mg-right-5">
  241. 关闭
  242. </ZhCloseButton>
  243. {renderOkBtn(type)}
  244. </div>
  245. }>
  246. <Form form={form} layout="vertical">
  247. {type === 'back' ? (
  248. <>
  249. {curAuditor.progress !== '1' ? (
  250. <Popover
  251. content={groups.map(item => (
  252. <GroupItem {...item} key={item.value} onSelect={(item: iUserInfo, type?: string) => itemSelectHandler(item, type)} />
  253. ))}
  254. overlayClassName="popover-card"
  255. trigger="click"
  256. visible={modal.visible}
  257. onVisibleChange={visible => handleVisibleChange(visible)}
  258. placement="bottomLeft">
  259. <ZhButton size="small" onClick={showPopover}>
  260. <span>选择退回流程</span>
  261. <SvgIcon type="xxh-caret-down" />
  262. </ZhButton>
  263. </Popover>
  264. ) : null}
  265. {user.id ? (
  266. <>
  267. <div className="pi-bordered pi-warning">
  268. <span>已选择退回流程: </span>
  269. <span>{user.name}</span>
  270. </div>
  271. <Form.Item name="opinion" label="审批意见">
  272. <Input.TextArea rows={5} />
  273. </Form.Item>
  274. </>
  275. ) : null}
  276. </>
  277. ) : null}
  278. {type === 'delete' ? (
  279. <>
  280. <p className="mb-2">删除后,数据无法恢复,请谨慎操作。</p>
  281. <p className="mb-2">
  282. 请在下方文本框输入文本「<span className="pi-red">确认删除本次巡检</span>」,以此确认删除操作。
  283. </p>
  284. <Form.Item
  285. name="warningText"
  286. rules={[
  287. () => ({
  288. validator(rule, value) {
  289. if (!value || value !== '确认删除本次巡检') {
  290. return Promise.reject('请按照提示信息进行删除操作!')
  291. }
  292. return Promise.resolve()
  293. }
  294. })
  295. ]}>
  296. <Input placeholder="输入文本, 确认删除" />
  297. </Form.Item>
  298. </>
  299. ) : null}
  300. {type === 'start' ? <p>请确认审批流程及信息无误。</p> : null}
  301. {type === 'close' ? (
  302. <>
  303. <Form.Item name="opinion" label="审批意见">
  304. <Input.TextArea rows={5} />
  305. </Form.Item>
  306. <p className="pi-warning">审批关闭,将直接停止该巡检流程。</p>
  307. </>
  308. ) : null}
  309. {type === 'pass' ? (
  310. <>
  311. <Form.Item name="opinion" label={curAuditor.progress === '1' ? '整改意见' : "审批意见"}>
  312. <Input.TextArea rows={5} />
  313. </Form.Item>
  314. {isLastAuditor && curAuditor.progress === '0' ? (
  315. <Popover
  316. title={<Input.Search size="small" placeholder="姓名/手机 检索" onSearch={search} onChange={e => change(e)} />}
  317. content={groups.map(item => (
  318. <GroupItem {...item} key={item.value} onSelect={(item: iUserInfo, type?: string) => itemSelectHandler(item, type)} />
  319. ))}
  320. overlayClassName="popover-card"
  321. trigger="click"
  322. visible={modal.visible}
  323. onVisibleChange={visible => handleVisibleChange(visible)}
  324. placement="bottomLeft">
  325. <ZhButton size="small" onClick={showPopover}>
  326. 指派整改人
  327. </ZhButton>
  328. </Popover>
  329. ) : null}
  330. {user.id && isLastAuditor ? (
  331. <p className="pi-bordered pi-pd-8 pi-mg-top-5">
  332. <span>已指派整改人: </span>
  333. <span>
  334. {user.name}-{user.position}-{user.company}
  335. </span>
  336. </p>
  337. ) : null}
  338. </>
  339. ) : null}
  340. </Form>
  341. </Modal>
  342. )
  343. }
  344. export default AuditModal