SmsCheckWorkloadList.vue 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774
  1. <template>
  2. <div>
  3. <a-row :gutter="16" style="height: 1622px">
  4. <a-col :span="5" style="height: 100%;">
  5. <a-card title="任务选择" :bordered="false" style="height: 100%">
  6. <a-directory-tree
  7. style="height: auto"
  8. v-model:expandedKeys="expandedKeys"
  9. v-model:selectedKeys="selectedKeys"
  10. multiple
  11. :tree-data="treeData"
  12. @expand="onExpand"
  13. @select="onTreeNodeSelect"
  14. ></a-directory-tree>
  15. </a-card>
  16. </a-col>
  17. <!--筛选条件-->
  18. <a-col :span="19">
  19. <a-form layout="inline">
  20. <a-row :gutter="24">
  21. <a-col :xl="16" :lg="7" :md="8" :sm="24">
  22. <a-form-item label="稽核工作日期范围">
  23. <a-range-picker @change="handleChange" v-model:value="taskDate"/>
  24. <a-radio-group @change="changeReportDate()" style="padding-left: 10px" v-model:value="latestDate" button-style="solid">
  25. <a-radio-button value="7">最近7天</a-radio-button>
  26. <a-radio-button value="30">最近30天</a-radio-button>
  27. <a-radio-button value="180">最近180天</a-radio-button>
  28. </a-radio-group>
  29. </a-form-item>
  30. </a-col>
  31. </a-row>
  32. </a-form>
  33. </a-col>
  34. <a-col :span="5" style="padding-top: 10px">
  35. <a-card>
  36. <a-statistic
  37. title="未完善客户数量"
  38. :value="toImproveUser"
  39. :precision="0"
  40. suffix="个"
  41. :value-style="{ color: '#fa073f' }"
  42. style="margin-right: 50px"
  43. >
  44. <template #prefix>
  45. <arrow-up-outlined/>
  46. </template>
  47. </a-statistic>
  48. </a-card>
  49. </a-col>
  50. <a-col :span="5" style="padding-top: 10px">
  51. <a-card>
  52. <a-statistic
  53. title="待整改客户数量"
  54. :value="tobeRectified"
  55. :precision="0"
  56. suffix="个"
  57. :value-style="{ color: '#810320' }"
  58. style="margin-right: 50px"
  59. >
  60. <template #prefix>
  61. <arrow-up-outlined/>
  62. </template>
  63. </a-statistic>
  64. </a-card>
  65. </a-col>
  66. <a-col :span="5" style="padding-top: 10px">
  67. <a-card>
  68. <a-statistic
  69. title="待稽核客户数量"
  70. :value="toBeAudited"
  71. :precision="0"
  72. suffix="个"
  73. :value-style="{ color: '#0a0a09' }"
  74. style="margin-right: 50px"
  75. >
  76. <template #prefix>
  77. <arrow-up-outlined/>
  78. </template>
  79. </a-statistic>
  80. </a-card>
  81. </a-col>
  82. <a-col :span="4" style="padding-top: 10px">
  83. <a-card>
  84. <a-statistic
  85. title="稽核通过客户数量"
  86. :value="auditPassed"
  87. :precision="0"
  88. suffix="个"
  89. :value-style="{ color: '#3f8600' }"
  90. style="margin-right: 50px"
  91. >
  92. <template #prefix>
  93. <arrow-up-outlined/>
  94. </template>
  95. </a-statistic>
  96. </a-card>
  97. </a-col>
  98. <a-col :span="19" style="top: 10px">
  99. <a-card title="稽核概况统计" :bordered="false">
  100. <div id="statusRefusePie" ref="statusRefusePie" style="width:100%;height:370px"></div>
  101. </a-card>
  102. </a-col>
  103. <a-col :span="19" style="padding-top: 30px">
  104. <a-card title="稽核历史异常分析" :bordered="false">
  105. <div id="statusAuditPie" ref="statusAuditPie" style="width:50%;height:370px;float: left"></div>
  106. <div id="statusAuditHistogram" ref="statusAuditHistogram" style="width:50%;height:370px;left: 50%"></div>
  107. </a-card>
  108. </a-col>
  109. <a-col :span="19" style="top: 10px">
  110. <a-card title="稽核历史异常时间分布" :bordered="false">
  111. <div id="abnormalCreateTimeTrend" ref="abnormalCreateTimeTrend" style="width:100%;height:370px"></div>
  112. </a-card>
  113. </a-col>
  114. </a-row>
  115. </div>
  116. <!-- 查询区域 -->
  117. </template>
  118. <script>
  119. import moment from 'moment';
  120. import {getAction} from "@api/manage";
  121. import * as echarts from 'echarts';
  122. export default {
  123. name: 'SmsCheckWorkLogList',
  124. data() {
  125. return {
  126. description: '稽核工作日志管理页面',
  127. taskDate: '',
  128. url: {
  129. "statusRefuse": "/smsCheck/customerInfo/status/refuse",
  130. "taskList": "/smsCheck/task/list",
  131. "dateList": "/smsCheck/task/year/list",
  132. //基本信息 规范信息 附件资料 异常稽核统计
  133. "checkStateCount": "/smsCheck/workLog/check/state/count",
  134. "abnormalCreateTime": "/smsCheck/workLog/check/abnormal/count",
  135. //用户工作量接口
  136. "findStaffNoCount" : "/smsCheck/workLog/find/staff/no/count"
  137. },
  138. // '1': '未完善',
  139. statusMap: {
  140. '0': '未完善',
  141. '2': '待稽核',
  142. '4': '待整改',
  143. "5": '稽核通过',
  144. },
  145. abnormalMap: {
  146. "basicCheckState": "基本信息异常",
  147. "standardState": "规范信息异常",
  148. "dataState": "附件资料异常异常"
  149. },
  150. $statusRefusePie: "",
  151. $abnormalCheckPie: "",
  152. $abnormalCheckHistogram: "",
  153. $abnormalCreateTimeTrend: "",
  154. toImproveUser: 0,
  155. latestDate: '180',
  156. toBeAudited: 0,
  157. tobeRectified: 0,
  158. auditPassed: 0,
  159. treeData: [],
  160. expandedKeys: ['2022', '2022-10'],
  161. selectedKeys: {},
  162. statusAuditPieData: [],
  163. canvas: {},
  164. taskId:null,
  165. }
  166. },
  167. created() {
  168. const waterMarkText = '智慧运营系统';
  169. this.canvas = document.createElement('canvas');
  170. const ctx = this.canvas.getContext('2d');
  171. this.canvas.width = this.canvas.height = 100;
  172. ctx.textAlign = 'center';
  173. ctx.textBaseline = 'middle';
  174. ctx.globalAlpha = 0.08;
  175. ctx.font = '20px Microsoft Yahei';
  176. ctx.translate(50, 50);
  177. ctx.rotate(-Math.PI / 4);
  178. ctx.fillText(waterMarkText, 0, 0);
  179. //初始化日期 默认最近180天
  180. this.taskDate = [this.getRecentDay(parseInt(this.latestDate)), this.getRecentDay(0)]
  181. //稽核任务列表(树)
  182. this.taskList();
  183. //稽核概况统计
  184. this.statusRefuse();
  185. //稽核工作量
  186. //稽核历史异常分析
  187. this.checkStateCount(this.url.checkStateCount);
  188. this.abnormalCreateTime();
  189. },
  190. computed: {},
  191. methods: {
  192. changeReportDate(a, event){
  193. //当前 value this.latestDatec
  194. //console.log(this.latestDate)
  195. this.taskDate = [this.getRecentDay(parseInt(this.latestDate)), this.getRecentDay(0)]
  196. this.statusRefuse(this.taskId);
  197. this.checkStateCount(this.url.checkStateCount, this.taskId);
  198. this.abnormalCreateTime(this.taskId);
  199. },
  200. handleChange(value,model){
  201. this.taskDate = model
  202. // model 当前value
  203. this.statusRefuse(this.taskId);
  204. this.checkStateCount(this.url.checkStateCount, this.taskId);
  205. this.abnormalCreateTime(this.taskId);
  206. },
  207. abnormalCreateTime(infoId) {
  208. let taskDate = this.taskDate;
  209. let queryParam = {
  210. "startDate": taskDate[0],
  211. "endDate": taskDate[1],
  212. "infoId": infoId
  213. }
  214. getAction(this.url.abnormalCreateTime, queryParam).then(res => {
  215. if (res.success) {
  216. let data = [];
  217. let resultList = res.resultList;
  218. for (var i in resultList) {
  219. let resultListElement = resultList[i];
  220. let time = resultListElement.createTime;
  221. let count = parseInt(resultListElement.count);
  222. data.push([time, count])
  223. }
  224. let dateList = data.map(function (item) {
  225. return item[0];
  226. });
  227. let valueList = data.map(function (item) {
  228. return item[1];
  229. });
  230. this.abnormalCreateTimetrend(dateList, valueList)
  231. }
  232. }).finally(() => {
  233. })
  234. },
  235. abnormalCreateTimetrend(dateList, valueList) {
  236. let option = {
  237. title: {
  238. text: '稽核异常数量',
  239. left: 'center',
  240. },
  241. lineStyle: {
  242. color: '#5a6fc0'
  243. },
  244. backgroundColor: {
  245. type: 'pattern',
  246. image: this.canvas,
  247. repeat: 'repeat'
  248. },
  249. visualMap: [
  250. {
  251. show: false,
  252. type: 'continuous',
  253. seriesIndex: 0,
  254. min: 0,
  255. max: 400
  256. },
  257. {
  258. show: false,
  259. type: 'continuous',
  260. seriesIndex: 1,
  261. dimension: 0,
  262. min: 0,
  263. max: dateList.length - 1
  264. }
  265. ],
  266. tooltip: {
  267. trigger: 'axis'
  268. },
  269. legend: {
  270. data: ['稽核异常']
  271. },
  272. grid: {
  273. left: '3%',
  274. right: '4%',
  275. bottom: '3%',
  276. containLabel: true
  277. },
  278. toolbox: {
  279. feature: {
  280. saveAsImage: {}
  281. }
  282. },
  283. xAxis: {
  284. type: 'category',
  285. boundaryGap: false,
  286. data: dateList
  287. },
  288. yAxis: {
  289. type: 'value'
  290. },
  291. series: [
  292. {
  293. name: '异常数',
  294. type: 'line',
  295. stack: 'Total',
  296. data: valueList
  297. }
  298. ]
  299. };
  300. this.$abnormalCreateTimeTrend = echarts.init(document.getElementById('abnormalCreateTimeTrend'))
  301. this.$abnormalCreateTimeTrend.setOption(option)
  302. },
  303. checkStateCount(url, taskId) {
  304. let taskDate = this.taskDate;
  305. let queryParam = {
  306. "startDate": taskDate[0],
  307. "endDate": taskDate[1],
  308. "infoId": taskId
  309. }
  310. getAction(url, queryParam).then(res => {
  311. if (res.success) {
  312. let resultList = res.resultList;
  313. let pieData = [];
  314. let histogramSource = ['资料驳回分布']
  315. let dimensions = ['product']
  316. for (var i in resultList) {
  317. let resultListElement = resultList[i];
  318. let name = resultListElement.name;
  319. let state = resultListElement.state;
  320. let count = resultListElement.count;
  321. if (state === "2") {
  322. var abnormalMapElement = this.abnormalMap[name];
  323. if (abnormalMapElement != null && abnormalMapElement != undefined) {
  324. pieData.push({
  325. "name": abnormalMapElement,
  326. "value": count
  327. })
  328. dimensions.push(abnormalMapElement.toString())
  329. histogramSource.push(parseInt(count));
  330. }
  331. }
  332. }
  333. this.checkStatePie(pieData);
  334. this.checkStateHistogram(dimensions, histogramSource)
  335. }
  336. }).finally(() => {
  337. })
  338. },
  339. checkStateHistogram(dimensions, source) {
  340. let option = {
  341. backgroundColor: {
  342. type: 'pattern',
  343. image: this.canvas,
  344. repeat: 'repeat'
  345. },
  346. legend: {},
  347. tooltip: {},
  348. dataset: {
  349. source: [
  350. dimensions,
  351. source
  352. ]
  353. },
  354. xAxis: {type: 'category'},
  355. yAxis: {},
  356. // Declare several bar series, each will be mapped
  357. // to a column of dataset.source by default.
  358. series: [{type: 'bar'}, {type: 'bar'}, {type: 'bar'}]
  359. };
  360. this.$abnormalCheckHistogram = echarts.init(document.getElementById('statusAuditHistogram'))
  361. this.$abnormalCheckHistogram.setOption(option)
  362. },
  363. checkStatePie(data) {
  364. let option = {
  365. tooltip: {
  366. trigger: 'item'
  367. },
  368. backgroundColor: {
  369. type: 'pattern',
  370. image: this.canvas,
  371. repeat: 'repeat'
  372. },
  373. /*title: [
  374. {
  375. text: '异常类型占比',
  376. //subtext: '总计 ' + builderJson.all + " 稽核通过 " + builderJson.charts["稽核通过"],
  377. left: '25%',
  378. textAlign: 'center'
  379. },
  380. ],*/
  381. legend: {
  382. top: '5%',
  383. left: 'center'
  384. },
  385. series: [
  386. {
  387. name: '',
  388. type: 'pie',
  389. radius: ['40%', '70%'],
  390. avoidLabelOverlap: false,
  391. itemStyle: {
  392. borderRadius: 10,
  393. borderColor: '#fff',
  394. borderWidth: 2
  395. },
  396. label: {
  397. show: false,
  398. position: 'center'
  399. },
  400. emphasis: {
  401. label: {
  402. show: true,
  403. fontSize: '40',
  404. fontWeight: 'bold'
  405. }
  406. },
  407. labelLine: {
  408. show: false
  409. },
  410. data: data
  411. }
  412. ]
  413. };
  414. this.$abnormalCheckPie = echarts.init(document.getElementById('statusAuditPie'))
  415. this.$abnormalCheckPie.setOption(option)
  416. },
  417. //树点击事件
  418. onTreeNodeSelect(id) {
  419. if (id && id.length > 0) {
  420. if (id == "all") {
  421. this.statusRefuse();
  422. this.checkStateCount(this.url.checkStateCount);
  423. this.abnormalCreateTime();
  424. this.taskId = null;
  425. return;
  426. }
  427. let split = id[0].split("key-");
  428. if (split.length == 2) {
  429. let taskId = split[1];
  430. this.statusRefuse(taskId);
  431. this.checkStateCount(this.url.checkStateCount, taskId);
  432. this.abnormalCreateTime(taskId);
  433. this.taskId = id;
  434. }
  435. }
  436. },
  437. onExpand(expandedKeys) {
  438. this.expandedKeys = expandedKeys;
  439. },
  440. taskDateList(taskData) {
  441. getAction(this.url["dateList"]).then(res => {
  442. if (res.success) {
  443. let result = res.result;
  444. let years = result[0];
  445. let months = result[1];
  446. let YearLevel = {}
  447. let monthLevel = {}
  448. for (var i in years) {
  449. let year = years[i].yearTime;
  450. let children = {
  451. "title": year,
  452. "key": year,
  453. "children": []
  454. }
  455. YearLevel[year] = children
  456. }
  457. for (var j in months) {
  458. let month = months[j].monthTime;
  459. let splitElement = month.split("-")[0];
  460. let children = {
  461. "title": month,
  462. "key": month,
  463. "children": []
  464. }
  465. YearLevel[splitElement].children.push(children)
  466. }
  467. for (var k in taskData) {
  468. let taskDatum = taskData[k];
  469. let taskStartTime = taskDatum.taskStartTime;
  470. if (taskStartTime != null && taskStartTime != undefined) {
  471. let children = {
  472. "title": taskDatum.taskName + "[" + taskDatum.customerCount + "]",
  473. "key": "key" + "-" + taskDatum.id,
  474. "isLeaf": true,
  475. }
  476. let strings = taskStartTime.split("-");
  477. let year = strings[0];
  478. let month = strings[0] + "-" + strings[1];
  479. for (var z in YearLevel[year].children) {
  480. let title = YearLevel[year].children[z].title;
  481. if (title == month) {
  482. YearLevel[year].children[z].children.push(children);
  483. break;
  484. }
  485. }
  486. }
  487. }
  488. let allChildren = {
  489. "title": "全部任务",
  490. "key": "all",
  491. "children": []
  492. }
  493. for (var u in YearLevel) {
  494. this.treeData.push(YearLevel[u])
  495. }
  496. this.treeData.push(allChildren)
  497. this.treeData = this.treeData.reverse();
  498. }
  499. }
  500. )
  501. },
  502. //任务列表数据
  503. taskList() {
  504. let queryParam = {
  505. pageNo: 1,
  506. pageSize: 1000000,
  507. }
  508. getAction(this.url["taskList"], queryParam).then(res => {
  509. if (res.success) {
  510. let records = res.result.records;
  511. //稽核任务菜单
  512. this.taskDateList(records);
  513. }
  514. })
  515. },
  516. //查询各类型稽核进度
  517. statusRefuse(taskId) {
  518. let taskDate = this.taskDate;
  519. let queryParam = {
  520. "startDate": taskDate[0],
  521. "endDate": taskDate[1],
  522. "taskId": taskId
  523. }
  524. if (taskDate.length = 2) {
  525. getAction(this.url["statusRefuse"], queryParam).then(res => {
  526. if (res.success) {
  527. let builderJson = {};
  528. let columnDate = {};
  529. let pieDate = {};
  530. let all = 0;
  531. let resultList = res.resultList;
  532. for (var i in resultList) {
  533. let resultListElement = resultList[i];
  534. let status = this.statusMap[resultListElement.checkState];
  535. if (status != undefined && status != null) {
  536. all = all + resultListElement.count
  537. columnDate[status] = resultListElement.count
  538. }
  539. }
  540. builderJson = {
  541. "all": all,
  542. "charts": columnDate,
  543. "ie": 9743
  544. }
  545. this.statusRefusePie(builderJson)
  546. }
  547. })
  548. }
  549. },
  550. statusRefusePie(builderJson) {
  551. if (builderJson.charts["稽核通过"] == null || builderJson.charts["稽核通过"] == undefined) {
  552. builderJson.charts["稽核通过"] = 0;
  553. }
  554. if (builderJson.charts["未完善"] == null || builderJson.charts["未完善"] == undefined) {
  555. builderJson.charts["未完善"] = 0;
  556. }
  557. if (builderJson.charts["待稽核"] == null || builderJson.charts["待稽核"] == undefined) {
  558. builderJson.charts["待稽核"] = 0;
  559. }
  560. if (builderJson.charts["待整改"] == null || builderJson.charts["待整改"] == undefined) {
  561. builderJson.charts["待整改"] = 0;
  562. }
  563. this.toImproveUser = builderJson.charts["未完善"];
  564. this.toBeAudited = builderJson.charts["待稽核"];
  565. this.tobeRectified = builderJson.charts["待整改"];
  566. this.auditPassed = builderJson.charts["稽核通过"];
  567. let option = {
  568. backgroundColor: {
  569. type: 'pattern',
  570. image: this.canvas,
  571. repeat: 'repeat'
  572. },
  573. tooltip: {},
  574. title: [
  575. {
  576. text: '稽核完成进度',
  577. subtext: '总计 ' + builderJson.all + " 稽核通过 " + builderJson.charts["稽核通过"],
  578. left: '25%',
  579. textAlign: 'center'
  580. },
  581. {
  582. text: '稽核类型占比',
  583. subtext: '总计 ' + builderJson.all,
  584. left: '75%',
  585. textAlign: 'center'
  586. }
  587. ],
  588. grid: [
  589. {
  590. top: 50,
  591. width: '50%',
  592. bottom: '5%',
  593. left: 10,
  594. containLabel: true
  595. },
  596. {
  597. top: 50,
  598. width: '50%',
  599. bottom: '5%',
  600. left: 10,
  601. containLabel: true
  602. }
  603. ],
  604. xAxis: [
  605. {
  606. type: 'value',
  607. max: builderJson.all,
  608. splitLine: {
  609. show: false
  610. }
  611. }
  612. ],
  613. yAxis: [
  614. {
  615. type: 'category',
  616. data: Object.keys(builderJson.charts),
  617. axisLabel: {
  618. interval: 0,
  619. rotate: 30
  620. },
  621. splitLine: {
  622. show: false
  623. }
  624. }
  625. ],
  626. series: [
  627. {
  628. type: 'bar',
  629. stack: 'chart',
  630. z: 3,
  631. label: {
  632. position: 'right',
  633. show: true
  634. },
  635. data: Object.keys(builderJson.charts).map(function (key) {
  636. return builderJson.charts[key];
  637. }),
  638. itemStyle: {
  639. normal: {
  640. //这里是颜色
  641. color: function (params) {
  642. //注意,如果颜色太少的话,后面颜色不会自动循环,最好多定义几个颜色
  643. var colorList = ['#5c6fc4', '#f0be47', '#d2232c', '#81c463', '#BBFFAA', '#749f83', '#ca8622'];
  644. return colorList[params.dataIndex]
  645. }
  646. }
  647. }
  648. },
  649. {
  650. type: 'bar',
  651. stack: 'chart',
  652. silent: true,
  653. itemStyle: {
  654. color: '#eee'
  655. },
  656. data: Object.keys(builderJson.charts).map(function (key) {
  657. return builderJson.all - builderJson.charts[key];
  658. }),
  659. },
  660. {
  661. type: 'pie',
  662. radius: [0, '80%'],
  663. center: ['75%', '55%'],
  664. data: Object.keys(builderJson.charts).map(function (key) {
  665. return {
  666. name: key,
  667. value: builderJson.charts[key]
  668. };
  669. }),
  670. itemStyle: {
  671. normal: {
  672. //这里是颜色
  673. color: function (params) {
  674. //注意,如果颜色太少的话,后面颜色不会自动循环,最好多定义几个颜色
  675. var colorList = ['#5a6fc0', '#f0be47', '#d2232c', '#81c463', '#BBFFAA', '#749f83', '#ca8622'];
  676. return colorList[params.dataIndex]
  677. }
  678. }
  679. }
  680. },
  681. ]
  682. };
  683. this.$statusRefusePie = echarts.init(document.getElementById('statusRefusePie'))
  684. this.$statusRefusePie.setOption(option)
  685. },
  686. getRecentDay: function (n) {
  687. let day = moment(new Date())
  688. .subtract(n, "days")
  689. .format("YYYY-MM-DD");
  690. return day;
  691. },
  692. }
  693. }
  694. </script>
  695. <style scoped>
  696. </style>