index.tsx 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408
  1. import React, { useEffect, useState } from 'react'
  2. import Container, { ContainerBody } from 'components/Container'
  3. import Helmet from 'react-helmet'
  4. import Box from 'components/Box'
  5. import styles from 'containers/DataManagerView/index.less'
  6. import {
  7. Button,
  8. Divider,
  9. Dropdown,
  10. Icon,
  11. Menu,
  12. message,
  13. Popconfirm,
  14. Spin,
  15. Table
  16. } from 'antd'
  17. import classnames from 'classnames'
  18. import request from 'utils/request'
  19. import api from 'utils/api'
  20. import { ColumnProps } from 'antd/lib/table'
  21. import {
  22. IClassification,
  23. IQualityTask
  24. } from 'containers/DataGovernanceQualityAudit/types'
  25. import ClassificationsFormModal from 'containers/DataGovernanceQualityAudit/components/ClassificationsFormModal'
  26. import QualityTaskFormModal from 'containers/DataGovernanceQualityAudit/components/QualityTaskFormModal'
  27. import ScheduleFormModal from 'containers/DataGovernanceQualityAudit/components/ScheduleFormModal'
  28. import header from 'containers/Display/Editor/Header'
  29. export default function DataGovernanceQualityAudit() {
  30. const [tableLoading, setTableLoading] = useState(false)
  31. const [treeLoading, setTreeLoading] = useState(false)
  32. const [selectedKey, setSelectedKey] = useState<number>()
  33. const [qualityTasks, setQualityTasks] = useState<IQualityTask[]>([])
  34. const [qtVisible, setQtVisible] = useState(false)
  35. const [qtLoading, setQtLoading] = useState(false)
  36. // eslint-disable-next-line no-undef
  37. const [qtForm, setQtForm] = useState<Partial<IQualityTask>>({})
  38. const [classifications, setClassifications] = useState<IClassification[]>([])
  39. const [cfVisible, setCfVisible] = useState(false)
  40. const [cfLoading, setCfLoading] = useState(false)
  41. const [cfForm, setCfForm] = useState<IClassification>({})
  42. const [scVisible, setScVisible] = useState(false)
  43. const [scLoading, setSCLoading] = useState(false)
  44. const [scForm, setSCForm] = useState<IClassification>({})
  45. const tableColumns: Array<ColumnProps<IQualityTask>> = [
  46. {
  47. title: '任务名称',
  48. dataIndex: 'taskName'
  49. },
  50. {
  51. title: '元数据名称',
  52. dataIndex: 'metadataName'
  53. },
  54. {
  55. title: '稽核字段个数',
  56. dataIndex: 'auditorCount'
  57. },
  58. {
  59. title: '操作',
  60. render: (_, data) => (
  61. <>
  62. <a
  63. onClick={() => {
  64. setQtVisible(true)
  65. setQtForm(data)
  66. }}
  67. >
  68. 编辑
  69. </a>
  70. <Divider type='vertical' />
  71. <Dropdown
  72. overlay={
  73. <Menu>
  74. <Menu.Item
  75. key='0'
  76. onClick={() => {
  77. setQtForm(data)
  78. setScVisible(true)
  79. }}
  80. >
  81. 设置调度
  82. </Menu.Item>
  83. <Menu.Item key='1'>
  84. <Popconfirm
  85. title='确定立即稽查吗?'
  86. placement='bottom'
  87. onConfirm={() => handleSetDispatchRightNow(data)}
  88. >
  89. <a>立即稽查</a>
  90. </Popconfirm>
  91. </Menu.Item>
  92. <Menu.Item key='3'>
  93. <Popconfirm
  94. title='确定删除?'
  95. placement='bottom'
  96. onConfirm={() => handleDeleteTask(data.id)}
  97. >
  98. <a>删除</a>
  99. </Popconfirm>
  100. </Menu.Item>
  101. </Menu>
  102. }
  103. >
  104. <a>
  105. {' '}
  106. 更多 <Icon type='down' />
  107. </a>
  108. </Dropdown>
  109. </>
  110. )
  111. }
  112. ]
  113. const handleEditTreeItem = (form: IClassification) => {
  114. setCfForm(form)
  115. setCfVisible(true)
  116. }
  117. const handleDeleteTreeItem = async(c: IClassification) => {
  118. try {
  119. setTreeLoading(true)
  120. const data = await request(`${api.deleteAuditClassification}${c.id}`, {
  121. method: 'DELETE'
  122. })
  123. // @ts-ignore
  124. if (data?.header?.code === 200) {
  125. message.success({ content: '删除成功' })
  126. await queryClassifications()
  127. } else {
  128. // @ts-ignore
  129. // tslint:disable-next-line:no-unused-expression
  130. data?.header?.msg && message.error({ content: data?.header?.msg })
  131. }
  132. } finally {
  133. setTreeLoading(false)
  134. }
  135. }
  136. const renderTree = (catalogues: IClassification[]) => (
  137. <>
  138. {catalogues.map((c, idx) => (
  139. <div
  140. key={c.id ?? idx}
  141. className={classnames(styles.treeNode, {
  142. [styles.treeNodeSelected]: selectedKey === c.id
  143. })}
  144. >
  145. <span
  146. className={styles.treeNodeLeft}
  147. onClick={() => {
  148. setSelectedKey(c.id)
  149. }}
  150. >
  151. <Icon type='file' />
  152. {c.name}
  153. </span>
  154. <Dropdown
  155. overlay={() => (
  156. <Menu>
  157. <Menu.Item key='0' onClick={() => handleEditTreeItem(c)}>
  158. 编辑
  159. </Menu.Item>
  160. <Menu.Item key='1'>
  161. <Popconfirm
  162. title='确定删除?'
  163. placement='bottom'
  164. onConfirm={() => handleDeleteTreeItem(c)}
  165. >
  166. <a>删除</a>
  167. </Popconfirm>
  168. </Menu.Item>
  169. </Menu>
  170. )}
  171. trigger={['click']}
  172. >
  173. <Icon type='more' />
  174. </Dropdown>
  175. </div>
  176. ))}
  177. </>
  178. )
  179. const handleSetDispatchRightNow = async(data: IQualityTask) => {
  180. try {
  181. setTableLoading(true)
  182. const result = await request(`${api.setDispatchRightNow}${data.id}`, {
  183. method: 'GET'
  184. })
  185. // @ts-ignore
  186. if (result.header.code === 200) {
  187. message.success({ content: '立即稽核完成' })
  188. } else {
  189. // @ts-ignore
  190. // tslint:disable-next-line:no-unused-expression
  191. result?.header?.msg && message.error({ content: result.header.msg })
  192. }
  193. } finally {
  194. setTableLoading(false)
  195. }
  196. }
  197. const handleDispatch = async(form) => {
  198. try {
  199. setTableLoading(true)
  200. setSCLoading(true)
  201. const result = await request(`${api.setDispatch}${qtForm.id}`, {
  202. method: 'PUT',
  203. data: {
  204. cronExpression: form.cronExpression,
  205. startDate: form.startDate[0].format('YYYY-MM-DD hh:mm:ss'),
  206. endDate: form.startDate[1].format('YYYY-MM-DD hh:mm:ss'),
  207. periodUnit: form.periodUnit,
  208. jobStatus: form.jobStatus ? 'started' : 'new'
  209. }
  210. })
  211. // @ts-ignore
  212. if (result.header.code === 200) {
  213. message.success({ content: '设置调度成功' })
  214. queryQualityTasks()
  215. }
  216. } finally {
  217. setTableLoading(false)
  218. setSCLoading(false)
  219. }
  220. }
  221. const queryClassifications = async() => {
  222. try {
  223. setTreeLoading(true)
  224. const data = await request(api.getAuditClassification, { method: 'GET' })
  225. // @ts-ignore
  226. setClassifications(data?.payload ?? [])
  227. // @ts-ignore
  228. setSelectedKey(data?.payload?.[0]?.id)
  229. } finally {
  230. setTreeLoading(false)
  231. }
  232. }
  233. const queryQualityTasks = async() => {
  234. try {
  235. setTableLoading(true)
  236. const data = await request(`${api.getQualityTask}?pId=${selectedKey}`, {
  237. method: 'GET'
  238. })
  239. // @ts-ignore
  240. setQualityTasks(data?.payload ?? [])
  241. } finally {
  242. setTableLoading(false)
  243. }
  244. }
  245. const handleSaveCfForm = async(form: IClassification) => {
  246. try {
  247. setCfLoading(true)
  248. const url = cfForm.id
  249. ? api.updateAuditClassification + cfForm.id
  250. : api.createAuditClassification
  251. const result = await request(url, {
  252. method: cfForm.id ? 'PUT' : 'POST',
  253. data: { ...cfForm, ...form }
  254. })
  255. // @ts-ignore
  256. if (result?.header?.code === 200) {
  257. setCfVisible(false)
  258. await queryClassifications()
  259. }
  260. } finally {
  261. setCfLoading(false)
  262. }
  263. }
  264. const handleSaveQtForm = async(view) => {
  265. try {
  266. setQtLoading(true)
  267. const url = qtForm?.id
  268. ? api.updateQualityTask + qtForm?.id
  269. : api.createQualityTask
  270. const result = await request(url, {
  271. method: qtForm?.id ? 'PUT' : 'POST',
  272. data: { ...qtForm, ...view }
  273. })
  274. // @ts-ignore
  275. if (result?.header?.code === 200) {
  276. setQtVisible(false)
  277. await queryQualityTasks()
  278. }
  279. } finally {
  280. setQtLoading(false)
  281. }
  282. }
  283. const handleDeleteTask = async(id: number) => {
  284. try {
  285. setTableLoading(true)
  286. const data = await request(`${api.deleteQualityTask}${id}`, {
  287. method: 'DELETE'
  288. })
  289. // @ts-ignore
  290. if (data.header.code === 200) {
  291. message.success({ content: '删除成功' })
  292. queryQualityTasks()
  293. }
  294. } finally {
  295. setTableLoading(false)
  296. }
  297. }
  298. useEffect(() => {
  299. queryClassifications()
  300. }, [])
  301. useEffect(() => {
  302. if (selectedKey) {
  303. queryQualityTasks()
  304. }
  305. }, [selectedKey])
  306. return (
  307. <Container>
  308. <Helmet title='质量稽核' />
  309. <ContainerBody>
  310. <Box>
  311. <Box.Header>
  312. <Box.Title>质量稽核</Box.Title>
  313. </Box.Header>
  314. <Box.Body>
  315. <div className={styles.treeTableContainer}>
  316. <div className={styles.treeContainer}>
  317. <div className={styles.treeTitle}>
  318. <h6>数据质量</h6>
  319. <div
  320. className={styles.treePlusNode}
  321. onClick={() => {
  322. setCfForm({})
  323. setCfVisible(true)
  324. }}
  325. >
  326. <Icon type='plus' />
  327. </div>
  328. </div>
  329. <div className={styles.treeContent}>
  330. <Spin spinning={treeLoading}>
  331. {renderTree(classifications)}
  332. </Spin>
  333. </div>
  334. </div>
  335. <div style={{ flex: 1 }}>
  336. <div style={{ padding: '0 0 20px' }}>
  337. <Button
  338. type='primary'
  339. icon='plus'
  340. onClick={() => {
  341. setQtVisible(true)
  342. setQtForm(null)
  343. }}
  344. >
  345. 新增
  346. </Button>
  347. </div>
  348. <Table
  349. style={{ flex: 1 }}
  350. bordered
  351. rowKey='id'
  352. loading={tableLoading}
  353. dataSource={qualityTasks}
  354. columns={tableColumns}
  355. pagination={false}
  356. // onChange={this.tableChange}
  357. />
  358. </div>
  359. </div>
  360. <br />
  361. </Box.Body>
  362. </Box>
  363. </ContainerBody>
  364. <ClassificationsFormModal
  365. visible={cfVisible}
  366. formView={cfForm}
  367. onSave={handleSaveCfForm}
  368. loading={cfLoading}
  369. onCancel={() => setCfVisible(false)}
  370. />
  371. <QualityTaskFormModal
  372. pId={selectedKey}
  373. visible={qtVisible}
  374. formView={qtForm}
  375. onSave={handleSaveQtForm}
  376. loading={qtLoading}
  377. onCancel={() => setQtVisible(false)}
  378. />
  379. <ScheduleFormModal
  380. visible={scVisible}
  381. loading={scLoading}
  382. formView={scForm}
  383. onSave={handleDispatch}
  384. onCancel={() => setScVisible(false)}
  385. />
  386. </Container>
  387. )
  388. }