index.tsx 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422
  1. import React, { useEffect, useMemo, useState } from 'react'
  2. import Helmet from 'react-helmet'
  3. import Container, { ContainerBody } from 'components/Container'
  4. import Box from 'components/Box'
  5. import { Button, DatePicker, message, Progress, Select, Table } from 'antd'
  6. import { ColumnProps } from 'antd/lib/table'
  7. import { IReport } from 'containers/DataGovernanceAuaitAnalysis/types'
  8. import api from 'utils/api'
  9. import request from 'utils/request'
  10. import styles from './index.less'
  11. import { AnalysisReportDetailModal } from 'containers/DataGovernanceAuaitAnalysis/AnalysisReportDetailModal'
  12. import { IClassification } from 'containers/DataGovernanceQualityAudit/types'
  13. import moment, { Moment } from 'moment'
  14. import * as querystring from 'querystring'
  15. export default function DataGovernanceAuaitAnalysis(props: {
  16. location: Location
  17. }) {
  18. const qs: any = querystring.decode(
  19. props?.location?.search?.replace('?', '') ?? ''
  20. )
  21. const [tableLoading, setTableLoading] = useState(false)
  22. const [detailVisible, setDetailVisible] = useState(false)
  23. const [detailForm, setDetailForm] = useState<IReport>()
  24. const [reports, setReports] = useState<IReport[]>([])
  25. const [classifications, setClassifications] = useState<IClassification[]>([])
  26. const [systemId, setSystemId] = useState<number>(
  27. qs.systemId ? Number(qs.systemId) : null
  28. )
  29. const [time, setTime] = useState<[Moment, Moment]>([
  30. qs.starTime ? moment(qs.starTime) : moment(),
  31. qs.endTime ? moment(qs.endTime) : moment()
  32. ])
  33. const workbench = useMemo(() => {
  34. const total = reports
  35. .map(
  36. (item) =>
  37. item.accuracyCorrect ??
  38. item.accuracyError ??
  39. item.integrityCorrect ??
  40. item.integrityError ??
  41. item.normativeCorrect ??
  42. item.normativeError ??
  43. item.uniformityCorrect ??
  44. item.uniformityError ??
  45. 0
  46. )
  47. .reduce((c, n) => c + n, 0)
  48. const totalCorrect = reports
  49. .map(
  50. (item) =>
  51. item.accuracyCorrect ??
  52. item.integrityCorrect ??
  53. item.normativeCorrect ??
  54. item.uniformityCorrect ??
  55. 0
  56. )
  57. .reduce((c, n) => c + n, 0)
  58. // 完整性
  59. const integrityCorrect = reports
  60. .map((item) => item.integrityCorrect ?? 0)
  61. .reduce((c, n) => c + n, 0)
  62. const integrityTotal = reports
  63. .map((item) => item.integrityCorrect ?? item.integrityError)
  64. .reduce((c, n) => c + n, 0)
  65. // 一致性
  66. const uniformityCorrect = reports
  67. .map((item) => item.uniformityCorrect ?? 0)
  68. .reduce((c, n) => c + n, 0)
  69. const uniformityTotal = reports
  70. .map((item) => item.uniformityCorrect ?? item.uniformityError)
  71. .reduce((c, n) => c + n, 0)
  72. // 规范性
  73. const normativeCorrect = reports
  74. .map((item) => item.normativeCorrect ?? 0)
  75. .reduce((c, n) => c + n, 0)
  76. const normativeTotal = reports
  77. .map((item) => item.normativeCorrect ?? item.normativeError)
  78. .reduce((c, n) => c + n, 0)
  79. // 准确性
  80. const accuracyCorrect = reports
  81. .map((item) => item.accuracyCorrect ?? 0)
  82. .reduce((c, n) => c + n, 0)
  83. const accuracyTotal = reports
  84. .map((item) => item.accuracyCorrect ?? item.accuracyError)
  85. .reduce((c, n) => c + n, 0)
  86. return [
  87. {
  88. title: '总概率',
  89. rateLabel: '正确率',
  90. rateValue: ((totalCorrect / total || 0) * 100).toFixed(2) ?? '',
  91. countLabel: '正确数量',
  92. countValue: totalCorrect ?? 0,
  93. totalLabel: '总数据量',
  94. totalValue: total ?? 0,
  95. color: '#1890ff'
  96. },
  97. {
  98. title: '完整性',
  99. rateLabel: '正确率',
  100. rateValue:
  101. ((integrityCorrect / integrityTotal || 0) * 100).toFixed(2) ?? '',
  102. countLabel: '正确数量',
  103. countValue: integrityCorrect,
  104. totalLabel: '总数据量',
  105. totalValue: integrityTotal,
  106. color: '#52c41a'
  107. },
  108. {
  109. title: '一致性',
  110. rateLabel: '正确率',
  111. rateValue:
  112. ((uniformityCorrect / uniformityTotal || 0) * 100).toFixed(2) ?? '',
  113. countLabel: '正确数量',
  114. countValue: uniformityCorrect,
  115. totalLabel: '总数据量',
  116. totalValue: uniformityTotal,
  117. color: '#fa8c16'
  118. },
  119. {
  120. title: '规范性',
  121. rateLabel: '正确率',
  122. rateValue:
  123. ((normativeCorrect / normativeTotal || 0) * 100).toFixed(2) ?? '',
  124. countLabel: '正确数量',
  125. countValue: normativeCorrect,
  126. totalLabel: '总数据量',
  127. totalValue: normativeTotal,
  128. color: '#1890ff'
  129. },
  130. {
  131. title: '准确性',
  132. rateLabel: '正确率',
  133. rateValue:
  134. ((accuracyCorrect / accuracyTotal || 0) * 100).toFixed(2) ?? '',
  135. countLabel: '正确数量',
  136. countValue: accuracyCorrect,
  137. totalLabel: '总数据量',
  138. totalValue: accuracyTotal,
  139. color: '#722ed1'
  140. }
  141. ]
  142. }, [reports])
  143. const tableColumns: Array<ColumnProps<IReport>> = [
  144. {
  145. title: '任务名称',
  146. dataIndex: 'taskName'
  147. },
  148. {
  149. title: '稽查时间',
  150. dataIndex: 'auditorTime'
  151. },
  152. {
  153. title: '系统名称',
  154. dataIndex: 'typeName'
  155. },
  156. {
  157. title: '元数据名称',
  158. dataIndex: 'metadataName'
  159. },
  160. {
  161. title: '完整性',
  162. children: [
  163. {
  164. title: '正确数量',
  165. dataIndex: 'integrityCorrect'
  166. },
  167. {
  168. title: '错误数量',
  169. dataIndex: 'integrityError'
  170. },
  171. {
  172. title: '正确率',
  173. dataIndex: 'integrityCorrectProbability'
  174. },
  175. {
  176. title: '错误率',
  177. dataIndex: 'integrityErrorProbability'
  178. }
  179. ]
  180. },
  181. {
  182. title: '一致性',
  183. children: [
  184. {
  185. title: '正确数量',
  186. dataIndex: 'uniformityCorrect'
  187. },
  188. {
  189. title: '错误数量',
  190. dataIndex: 'uniformityError'
  191. },
  192. {
  193. title: '正确率',
  194. dataIndex: 'uniformityCorrectProbability'
  195. },
  196. {
  197. title: '错误率',
  198. dataIndex: 'uniformityErrorProbability'
  199. }
  200. ]
  201. },
  202. {
  203. title: '规范性',
  204. children: [
  205. {
  206. title: '正确数量',
  207. dataIndex: 'normativeCorrect'
  208. },
  209. {
  210. title: '错误数量',
  211. dataIndex: 'normativeError'
  212. },
  213. {
  214. title: '正确率',
  215. dataIndex: 'normativeCorrectProbability'
  216. },
  217. {
  218. title: '错误率',
  219. dataIndex: 'normativeErrorProbability'
  220. }
  221. ]
  222. },
  223. {
  224. title: '准确性',
  225. children: [
  226. {
  227. title: '正确数量',
  228. dataIndex: 'accuracyCorrect'
  229. },
  230. {
  231. title: '错误数量',
  232. dataIndex: 'accuracyError'
  233. },
  234. {
  235. title: '正确率',
  236. dataIndex: 'accuracyCorrectProbability'
  237. },
  238. {
  239. title: '错误率',
  240. dataIndex: 'accuracyErrorProbability'
  241. }
  242. ]
  243. },
  244. {
  245. title: '操作',
  246. fixed: 'right',
  247. width: 50,
  248. render: (_, data) => (
  249. <span
  250. onClick={() => {
  251. setDetailVisible(true)
  252. setDetailForm(data)
  253. }}
  254. >
  255. 详情
  256. </span>
  257. )
  258. }
  259. ]
  260. const queryReports = async function(id?: number) {
  261. const sysId = id || systemId
  262. if (!sysId || !time) {
  263. return
  264. }
  265. try {
  266. setTableLoading(true)
  267. const selfTime = time.map((t) => t.format('YYYY-MM-DD'))
  268. const data = await request(
  269. `${api.qualityReport}?systemId=${sysId}&starTime=${selfTime[0]}&endTime=${selfTime[1]}`,
  270. {
  271. method: 'GET'
  272. }
  273. )
  274. // @ts-ignore
  275. setReports(data?.payload ?? [])
  276. } finally {
  277. setTableLoading(false)
  278. }
  279. }
  280. const querySystem = async() => {
  281. try {
  282. setTableLoading(true)
  283. const data = await request(`${api.getAuditClassification}`, {
  284. method: 'GET'
  285. })
  286. // @ts-ignore
  287. setClassifications(data?.payload ?? [])
  288. // @ts-ignore
  289. if (!systemId) {
  290. setSystemId(data?.payload?.[0].id)
  291. }
  292. // @ts-ignore
  293. queryReports(systemId || data?.payload?.[0].id)
  294. } finally {
  295. setTableLoading(false)
  296. }
  297. }
  298. const handleQuery = () => {
  299. if (!systemId || !time) {
  300. message.info({ content: '请输入主题或时间' })
  301. return
  302. }
  303. queryReports()
  304. }
  305. useEffect(() => {
  306. querySystem()
  307. }, [])
  308. return (
  309. <Container>
  310. <Helmet title="稽核分析" />
  311. <ContainerBody>
  312. <Box>
  313. <Box.Header>
  314. <Box.Title>稽核分析</Box.Title>
  315. </Box.Header>
  316. <div style={{ padding: 20 }} />
  317. <Box.Body>
  318. <div className={styles['audit-analysiss-search-content']}>
  319. <div>
  320. <span>系统选择:</span>
  321. <Select
  322. value={systemId}
  323. style={{ width: 200 }}
  324. onChange={(e) => setSystemId(e)}
  325. >
  326. {classifications.map((c) => (
  327. <Select.Option key={c.id} value={c.id}>
  328. {c.name}
  329. </Select.Option>
  330. ))}
  331. </Select>
  332. </div>
  333. <div>
  334. <span>时间选择:</span>
  335. <DatePicker.RangePicker
  336. value={time}
  337. onChange={(e) => setTime(e)}
  338. format="YYYY-MM-DD"
  339. />
  340. </div>
  341. <Button onClick={handleQuery}>查询</Button>
  342. </div>
  343. <div className={styles['audit-analysiss-card-content']}>
  344. {workbench?.map((item, idx) => (
  345. <div
  346. key={item.title}
  347. className={styles['audit-analysiss-card-item']}
  348. >
  349. <div className={styles['audit-analysiss-card-item-title']}>
  350. {item.title}
  351. </div>
  352. <div className={styles['audit-analysiss-card-item-rate']}>
  353. <div
  354. className={styles['audit-analysiss-card-item-rate-label']}
  355. >
  356. <span>正确率</span>
  357. <span>{item.rateValue ?? '-'}%</span>
  358. </div>
  359. <Progress
  360. showInfo={false}
  361. strokeColor={item.color}
  362. percent={Number(item.rateValue ?? 0)}
  363. />
  364. </div>
  365. <div className={styles['audit-analysiss-card-item-number']}>
  366. <div
  367. className={
  368. styles['audit-analysiss-card-item-number-count']
  369. }
  370. >
  371. <span>正确数量</span>
  372. <span>{item.countValue ?? '-'}</span>
  373. </div>
  374. <div
  375. className={
  376. styles['audit-analysiss-card-item-number-total']
  377. }
  378. >
  379. <span>总数据量</span>
  380. <span>{item.totalValue ?? '-'}</span>
  381. </div>
  382. </div>
  383. </div>
  384. ))}
  385. </div>
  386. <Table
  387. style={{ flex: 1 }}
  388. bordered
  389. rowKey="id"
  390. loading={tableLoading}
  391. dataSource={reports}
  392. columns={tableColumns}
  393. pagination={false}
  394. />
  395. <div style={{ padding: 20 }} />
  396. <AnalysisReportDetailModal
  397. visible={detailVisible}
  398. tableColumns={tableColumns}
  399. formView={detailForm}
  400. />
  401. </Box.Body>
  402. </Box>
  403. </ContainerBody>
  404. </Container>
  405. )
  406. }