iam-audit-plan-tracking-view.vue 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507
  1. <template>
  2. <div :class="$style.mainDiv">
  3. <a-spin :spinning="spinning" :wrapper-class-name="$style.loadSpin">
  4. <div :class="$style.headerDiv">
  5. <!-- 选择年份下拉列表 -->
  6. <a-select
  7. :class="$style.yearSelect"
  8. :value="projectYear"
  9. :options="yearoptions"
  10. @change="changeYear"
  11. >
  12. </a-select>
  13. {{ projectYear }}年度{{ deptName }}计划跟踪表
  14. <!-- 导出按钮 -->
  15. <a-button
  16. type="primary"
  17. :class="$style.exportBtn"
  18. :loading="exporting"
  19. @click="exportExcel"
  20. >
  21. 导出
  22. </a-button>
  23. </div>
  24. <div :class="$style.contentDiv">
  25. <div :class="$style.bannerDiv">
  26. <div :class="$style.changeDiv">
  27. <div
  28. :class="[$style.currentDiv, selectType === 'curday' ? $style.selectd : '']"
  29. @click="changeSelectType('curday')"
  30. >
  31. 今天</div
  32. >
  33. <div
  34. :class="[$style.dayDiv, selectType === 'days' ? $style.selectd : '']"
  35. @click="changeSelectType('days')"
  36. >日</div
  37. >
  38. <div
  39. :class="[$style.weekDiv, selectType === 'weeks' ? $style.selectd : '']"
  40. @click="changeSelectType('weeks')"
  41. >周</div
  42. >
  43. <div
  44. :class="[$style.monthDiv, selectType === 'months' ? $style.selectd : '']"
  45. @click="changeSelectType('months')"
  46. >月</div
  47. >
  48. </div>
  49. <div :class="$style.colorDiv">
  50. <div :class="$style.outDiv"> <div :class="$style.planDiv"></div>计划 </div>
  51. <div :class="$style.outDiv"><div :class="$style.trueDiv"></div>实际</div>
  52. </div>
  53. </div>
  54. <div :class="$style.mainGantt">
  55. <!-- <div class="gantt"></div> -->
  56. <div class="gantt"></div>
  57. </div>
  58. </div>
  59. </a-spin>
  60. </div>
  61. </template>
  62. <script>
  63. import download from '@/common/services/download'
  64. import { Message } from 'ant-design-vue'
  65. import moment from 'moment'
  66. import { getUserInfo } from '@/common/store-mixin'
  67. import axios from '@/common/services/axios-instance'
  68. import components from './_import-components/iam-audit-plan-tracking-view-import'
  69. // 初始化方法
  70. function go(source, selectType, planYear) {
  71. window.$('.gantt').gantt({
  72. planYear: planYear,
  73. source: source,
  74. navigate: 'scroll', // buttons scroll
  75. scale: selectType, // months weeks days hours
  76. months: [
  77. '一月',
  78. '二月',
  79. '三月',
  80. '四月',
  81. '五月',
  82. '六月',
  83. '七月',
  84. '八月',
  85. '九月',
  86. '十月',
  87. '十一月',
  88. '十二月',
  89. ],
  90. dow: ['7', '1', '2', '3', '4', '5', '6'],
  91. maxScale: 'months',
  92. minScale: 'days',
  93. itemsPerPage: 50,
  94. onItemClick: function(data) {
  95. // alert(data)
  96. },
  97. onAddClick: function() {
  98. // alert('这里是无数据区域点击')
  99. },
  100. onRender: function() {},
  101. })
  102. }
  103. export default {
  104. name: 'IamAuditPlanTrackingView',
  105. metaInfo: {
  106. title: '计划跟踪',
  107. },
  108. components,
  109. data() {
  110. return {
  111. exporting: false,
  112. yearoptions: [],
  113. projectYear: null,
  114. deptName: '',
  115. selectType: 'weeks',
  116. source: [],
  117. curYear: new Date().getFullYear(),
  118. spinning: true,
  119. }
  120. },
  121. mounted() {
  122. // 获取发布的年份列表
  123. axios({
  124. url: `api/xcoa-mobile/v1/iamauditplan/getPlanYear`,
  125. }).then((res) => {
  126. if ((res.data === '') | (res.data.length === 0)) {
  127. this.projectYear = this.curYear
  128. Message.info('未获取到已结束审计计划信息', 1)
  129. this.spinning = false
  130. return
  131. }
  132. res.data.forEach((item) => {
  133. this.yearoptions.push({
  134. value: parseFloat(item),
  135. label: parseFloat(item) + '',
  136. })
  137. // 如果有当前年份,则直接展示当前年份份
  138. if (parseFloat(item) === this.curYear) {
  139. this.projectYear = this.curYear
  140. }
  141. })
  142. if (this.projectYear === null) {
  143. // 如果只有一个年份,则直接展示这个年份
  144. if (res.data.length === 1) {
  145. this.projectYear = parseFloat(res.data[0])
  146. }
  147. if (res.data.length === 0) {
  148. this.projectYear = this.curYear
  149. }
  150. }
  151. // 初始化数据
  152. this.initData()
  153. })
  154. // 初始化数据
  155. // this.deptName = getUserInfo().deptName
  156. axios({
  157. url: 'api/xcoa-mobile/v1/iam-statistics/getCurrUserGroup',
  158. method: 'get',
  159. }).then((res) => {
  160. this.deptName = res.data.name
  161. })
  162. },
  163. methods: {
  164. // 导出excel
  165. exportExcel() {
  166. this.exporting = true
  167. axios({
  168. url: `api/xcoa-mobile/v1/iam-statistics/exportPlanTrackingList`,
  169. data: {
  170. maxResults: -1,
  171. startPosition: 0,
  172. expressions: [
  173. { dataType: 'str', name: 'planYear', op: 'eq', stringValue: '' + this.projectYear },
  174. { dataType: 'str', name: 'flowState', op: 'eq', stringValue: '结束' },
  175. ],
  176. },
  177. method: 'post',
  178. responseType: 'blob',
  179. }).then((res) => {
  180. const url = URL.createObjectURL(res.data)
  181. const fname = this.projectYear + '年度' + this.deptName + '计划跟踪表.xls'
  182. download(url, fname)
  183. this.exporting = false
  184. })
  185. },
  186. // 切换显示模式
  187. changeSelectType(selectType) {
  188. if (this.projectYear === null) {
  189. Message.info('未获取到已结束审计计划信息', 1)
  190. return
  191. }
  192. // 如果不是显示今天,则重新加载
  193. if (selectType !== 'curday' && selectType !== this.selectType) {
  194. this.selectType = selectType
  195. this.spinning = true
  196. go(this.source, this.selectType, this.projectYear)
  197. this.spinning = false
  198. } else {
  199. // 跳转至今天
  200. this.selectType = selectType
  201. window.$('.nav-now').click()
  202. }
  203. },
  204. // 切换年份下拉框
  205. changeYear(value) {
  206. this.projectYear = value
  207. this.initData()
  208. },
  209. // 初始化数据
  210. initData() {
  211. this.spinning = true
  212. // 获取计划跟踪后台数据
  213. axios({
  214. url: `api/xcoa-mobile/v1/iam-statistics/getPlanTrackingList`,
  215. data: {
  216. maxResults: 9999,
  217. startPosition: 0,
  218. expressions: [
  219. { dataType: 'str', name: 'planYear', op: 'eq', stringValue: '' + this.projectYear },
  220. { dataType: 'str', name: 'flowState', op: 'eq', stringValue: '结束' },
  221. ],
  222. },
  223. method: 'post',
  224. }).then((res) => {
  225. // 如果选择的年份没有数据,则顺延向前一年
  226. if (res.data.data.length === 0) {
  227. axios({
  228. url: `api/xcoa-mobile/v1/iam-statistics/getPlanTrackingList`,
  229. data: {
  230. maxResults: 9999,
  231. startPosition: 0,
  232. expressions: [
  233. {
  234. dataType: 'str',
  235. name: 'planYear',
  236. op: 'eq',
  237. stringValue: '' + (this.projectYear - 1),
  238. },
  239. { dataType: 'str', name: 'flowState', op: 'eq', stringValue: '结束' },
  240. ],
  241. },
  242. method: 'post',
  243. }).then((res) => {
  244. if (res.data.data.length === 0) {
  245. Message.info(this.projectYear + '年或' + (this.projectYear - 1) + '年未发布审计计划')
  246. this.projectYear = this.curYear
  247. // 重新加载当前年内容
  248. // this.initData()
  249. this.spinning = false
  250. } else {
  251. Message.info(
  252. this.projectYear + '年未发布当年审计计划,自动跳转至' + (this.projectYear - 1)
  253. )
  254. this.projectYear--
  255. this.formatData(res.data)
  256. this.spinning = false
  257. }
  258. })
  259. } else {
  260. this.formatData(res.data)
  261. this.spinning = false
  262. }
  263. })
  264. },
  265. // 格式化数据
  266. formatData(data) {
  267. // 重新拼接数据
  268. this.source = data.data.map((item) => {
  269. const newitem = {
  270. name: item.name,
  271. url: '#' + item.url,
  272. desc: item.desc ? item.desc : '未启动',
  273. values: [],
  274. }
  275. item.values.forEach((planitem, index) => {
  276. if (index === 0) {
  277. newitem.values.push({
  278. dataObj: null,
  279. customClass: 'ganttRed',
  280. from: planitem.from,
  281. to: planitem.to,
  282. label: '',
  283. desc:
  284. '<div class="plan-hint-div">' +
  285. '<div>项目名称:' +
  286. item.name +
  287. '</div>' +
  288. '<div>项目负责人:' +
  289. planitem.desc.chargeUser.join(',') +
  290. '</div>' +
  291. '<div>项目组长:' +
  292. planitem.desc.projectUser.join(',') +
  293. '</div>' +
  294. '<div>计划起止日期:' +
  295. moment(planitem.desc.startDate).format('YYYY-MM-DD') +
  296. '至' +
  297. moment(planitem.desc.endDate).format('YYYY-MM-DD') +
  298. '</div>' +
  299. '</div>',
  300. })
  301. } else {
  302. // 有起止时间,才进行拼接
  303. if (planitem.from !== '') {
  304. let descText =
  305. '<div class="true-hint-div">' +
  306. '<div>项目名称:' +
  307. item.name +
  308. '</div>' +
  309. '<div>项目负责人:' +
  310. planitem.desc.chargeUser.join(',') +
  311. '</div>' +
  312. '<div>项目组长:' +
  313. planitem.desc.projectUser.join(',') +
  314. '</div>'
  315. // 如果有准备起始时间,才拼接
  316. if (planitem.desc.prepareStartDate && planitem.desc.prepareDndDate) {
  317. descText +=
  318. '<div>实际准备阶段:' +
  319. moment(planitem.desc.prepareStartDate).format('YYYY-MM-DD') +
  320. '至' +
  321. moment(planitem.desc.prepareDndDate).format('YYYY-MM-DD') +
  322. '</div>'
  323. } else {
  324. descText += '<div>实际准备阶段:</div>'
  325. }
  326. // 如果有实施起始时间,才拼接
  327. if (planitem.desc.effectStartDate && planitem.desc.effectEndDate) {
  328. descText +=
  329. '<div>实际实施阶段:' +
  330. moment(planitem.desc.effectStartDate).format('YYYY-MM-DD') +
  331. '至' +
  332. moment(planitem.desc.effectEndDate).format('YYYY-MM-DD') +
  333. '</div>'
  334. } else {
  335. descText += '<div>实际实施阶段:</div>'
  336. }
  337. // 如果有报告起始时间,才拼接
  338. if (planitem.desc.reportStartDate && planitem.desc.reportEndDate) {
  339. descText +=
  340. '<div>实际报告阶段:' +
  341. moment(planitem.desc.reportStartDate).format('YYYY-MM-DD') +
  342. '至' +
  343. moment(planitem.desc.reportEndDate).format('YYYY-MM-DD') +
  344. '</div>'
  345. } else {
  346. descText += '<div>实际报告阶段:</div>'
  347. }
  348. // 有提示才显示提示
  349. let islimit = false // 判断是否逾期
  350. if (planitem.desc.remind) {
  351. let remindStr = planitem.desc.remind.replace('提示:', '')
  352. if (remindStr.includes('逾期')) {
  353. islimit = true
  354. }
  355. if (remindStr.substring(0, 1) === ';') {
  356. remindStr = remindStr.substring(1, remindStr.length)
  357. }
  358. descText +=
  359. '<div ' +
  360. (islimit ? 'style="background:#ff4848 !important;color:white"' : '') +
  361. '>提&emsp;&emsp;示:' +
  362. remindStr +
  363. '</div>' +
  364. '</div>'
  365. } else {
  366. descText += '<div>提&emsp;&emsp;示:</div></div>'
  367. }
  368. newitem.values.push({
  369. dataObj: null,
  370. customClass: 'ganttGreen',
  371. from: planitem.from,
  372. to: planitem.to,
  373. label: '',
  374. desc: descText,
  375. })
  376. }
  377. }
  378. })
  379. return newitem
  380. })
  381. this.selectType = 'weeks'
  382. go(this.source, 'weeks', this.projectYear)
  383. },
  384. },
  385. }
  386. </script>
  387. <style module lang="scss">
  388. @use '@/common/design' as *;
  389. .main-div {
  390. // height: 100%;
  391. padding-bottom: 30px;
  392. background: #fff;
  393. .header-div {
  394. height: 90px;
  395. font-size: 25px;
  396. font-weight: bold;
  397. line-height: 90px;
  398. text-align: center;
  399. border-bottom: 8px solid #f0f2f5;
  400. .year-select {
  401. top: 30px;
  402. left: 2.5%;
  403. float: left;
  404. width: 80px;
  405. }
  406. .export-btn {
  407. top: 30px;
  408. right: 2.5%;
  409. float: right;
  410. }
  411. }
  412. .content-div {
  413. height: calc(100% - 90px);
  414. .main-gantt {
  415. height: calc(100% - 100px);
  416. // overflow: auto;
  417. }
  418. .banner-div {
  419. height: 80px;
  420. .color-div {
  421. display: inline-block;
  422. float: right;
  423. height: 80px;
  424. margin-right: 50px;
  425. .out-div {
  426. display: inline-block;
  427. line-height: 80px;
  428. .plan-div {
  429. float: left;
  430. width: 40px;
  431. height: 26px;
  432. margin: 26px 10px;
  433. background: #facd91;
  434. border-radius: 5px;
  435. }
  436. .true-div {
  437. float: left;
  438. width: 40px;
  439. height: 26px;
  440. margin: 26px 10px;
  441. background: #6cf37c;
  442. border-radius: 5px;
  443. }
  444. .limit-div {
  445. float: left;
  446. width: 40px;
  447. height: 26px;
  448. margin: 26px 10px;
  449. background: #ff4848;
  450. border-radius: 5px;
  451. }
  452. }
  453. }
  454. }
  455. }
  456. }
  457. .change-div {
  458. display: inline-flex;
  459. float: right;
  460. margin-top: 22px;
  461. margin-right: 2.5%;
  462. user-select: none;
  463. user-select: none;
  464. user-select: none;
  465. div {
  466. float: left;
  467. width: 50px;
  468. height: 33px;
  469. line-height: 30px;
  470. text-align: center;
  471. cursor: pointer;
  472. border: 1px solid #e9e9e9;
  473. border-left: none;
  474. }
  475. .current-div {
  476. width: 65px;
  477. border-left: 1px solid #e9e9e9;
  478. border-radius: 5px 0 0 5px;
  479. }
  480. .day-div {
  481. }
  482. .week-div {
  483. }
  484. .month-div {
  485. border-radius: 0 5px 5px 0;
  486. }
  487. .selectd {
  488. border: 1px solid #1890ff;
  489. }
  490. }
  491. .load-spin {
  492. height: 100%;
  493. :global(.ant-spin-container) {
  494. height: 100%;
  495. }
  496. }
  497. </style>