index.vue 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509
  1. <template>
  2. <div class="boxswai">
  3. <div class="boxnei flex flex-d-c">
  4. <el-menu :default-active="activeIndex"
  5. class="el-menu-demo"
  6. mode="horizontal"
  7. text-color='black'
  8. active-text-color='#1684FC'
  9. @select="handleSelect"
  10. >
  11. <el-menu-item index="1" v-model="activeIndex">我的待办工单</el-menu-item>
  12. <el-menu-item index="2" v-model="activeIndex">所有代办工单</el-menu-item>
  13. </el-menu>
  14. <div class="information flex1">
  15. <el-collapse v-show="activeIndex == 1">
  16. <el-collapse-item
  17. :name="item.title"
  18. v-for="(item,key) in collapseData1"
  19. :key="key"
  20. >
  21. <template slot="title">
  22. <i
  23. class="el-icon-chat-dot-round"
  24. style="fontSize:18px;margin-right:10px;"
  25. > </i>{{item.title}}
  26. </template>
  27. <div>
  28. <el-button
  29. type="text"
  30. style="color:rgb(65, 80, 88);"
  31. @click="openPreview(item)"
  32. >立即处理</el-button>
  33. </div>
  34. <div>
  35. <el-button
  36. type="text"
  37. @click="ignore(key)"
  38. v-throttle="3000"
  39. style="color:rgb(65, 80, 88);"
  40. >忽略</el-button>
  41. </div>
  42. </el-collapse-item>
  43. </el-collapse>
  44. <el-collapse v-show="activeIndex==2">
  45. <el-collapse-item
  46. :name="item.title"
  47. v-for="(item,key) in collapseData2"
  48. :key="key"
  49. >
  50. <template slot="title">
  51. <i
  52. class="el-icon-chat-dot-round"
  53. style="fontSize:18px;margin-right:10px;"
  54. > </i>{{item.title}}
  55. </template>
  56. <div v-show="item.operation">
  57. <div>
  58. <el-button
  59. type="text"
  60. style="color:rgb(65, 80, 88);"
  61. @click="openPreview(item)"
  62. >立即处理</el-button>
  63. </div>
  64. <div>
  65. <el-button
  66. type="text"
  67. v-throttle="3000"
  68. @click="ignore2(key)"
  69. style="color:rgb(65, 80, 88);"
  70. >忽略</el-button>
  71. </div>
  72. </div>
  73. </el-collapse-item>
  74. </el-collapse>
  75. </div>
  76. <el-row :gutter="20" class="mg-t-20">
  77. <el-col :span="8">
  78. <div class="chart-title">证书统计(总计{{pfxAmount}}个)</div>
  79. <div id="container"></div>
  80. </el-col>
  81. <el-col :span="8">
  82. <div class="chart-title">人员账户统计(总计{{personAmount}}位)</div>
  83. <div id="container2"></div>
  84. </el-col>
  85. <el-col :span="8">
  86. <div class="chart-title" style="margin-left: 5%;">
  87. <span>维护类型统计汇总</span>
  88. <el-select v-model="projectId" placeholder="请选择项目" size="small" @change="selectProjectOpinion" style="width:340px">
  89. <el-option
  90. v-for="item in projectList"
  91. :key="item.id"
  92. :label="item.projectName"
  93. :value="item.id"
  94. ></el-option>
  95. </el-select>
  96. </div>
  97. <div id="container3"></div>
  98. </el-col>
  99. </el-row>
  100. <el-dialog
  101. title=""
  102. :visible.sync="imgVisible"
  103. append-to-body
  104. width="80%">
  105. <div class="mg-b-20">{{curNew.projectName}}——{{curNew.contractName}}</div>
  106. <div class="mg-b-20">问题描述:{{curNew.opinionContent}}</div>
  107. <div class="mg-b-20">
  108. <span class="mg-r-20">反馈人员:{{curNew.submitUserName}}</span>
  109. <span class="mg-r-20">电话:{{curNew.submitPhone}}</span>
  110. <span class="mg-r-20">岗位:{{curNew.submitUserRole}}</span>
  111. </div>
  112. <div class="mg-b-20">反馈时间:{{curNew.manageTime}}</div>
  113. <el-carousel trigger="click" height="500px" :autoplay="false" style="text-align:center;">
  114. <el-carousel-item v-for="item in curNew.fileUrl" :key="item">
  115. <el-image :src="item" fit="scale-down" style="height:500px;" :preview-src-list="curNew.fileUrl"></el-image>
  116. </el-carousel-item>
  117. </el-carousel>
  118. <span slot="footer" class="dialog-footer">
  119. <el-button @click="imgVisible = false">取 消</el-button>
  120. <el-button type="primary" @click="toDisposeView">处 理</el-button>
  121. </span>
  122. </el-dialog>
  123. <el-dialog
  124. :visible.sync="dialogVisible"
  125. width="600px"
  126. append-to-body
  127. :close-on-click-modal="false"
  128. >
  129. <div class="flex jc-al-c">
  130. <span class="mg-r-20 titl-font" style="font-size: 16px;margin-right:20px;width:180px;text-align:right;font-weight: 900;">提交进度</span>
  131. <el-select v-model="curRow.currentLink" placeholder="请选择" @change="operationMethods">
  132. <el-option label="进入人工预处理环境" :value="2"/>
  133. <el-option label="已解决" :value="3"/>
  134. </el-select>
  135. </div>
  136. <div style="margin-top:40px;" class="flex jc-al-c" v-show="operation.show">
  137. <span style="font-size: 16px;margin-right:20px;width:180px;text-align:right;font-weight: 900;">*预计处理截止时间</span>
  138. <el-date-picker v-model="operation.manageTime" type="date" format="yyyy-MM-dd" value-format="yyyy-MM-dd" placeholder="选择日期" :picker-options="setDateRange"/>
  139. </div>
  140. <span slot="footer" class="dialog-footer">
  141. <el-button @click="dialogVisible = false">取 消</el-button>
  142. <el-button type="primary" @click="submissionProgress">确 定</el-button>
  143. </span>
  144. </el-dialog>
  145. </div>
  146. </div>
  147. </template>
  148. <script>
  149. // 引入统计图
  150. import { Area, Column, Pie } from '@antv/g2plot';
  151. import { queryBusinessUserOpinion, queryBusinessUserOpinionAll, queryProjectUserAmount, queryProjectPfx, queryOpinionTypeAmount, queryOpinionDetails, isIgnore, manageUserOperationStatus } from '@/api/news/news.js';
  152. export default {
  153. data () {
  154. return {
  155. setDateRange: {
  156. disabledDate: time => {
  157. return time.getTime() < Date.now() - 8.64e7
  158. }
  159. },
  160. LineData: [],//折线统计图数据
  161. ColumnData: [],//条形统计图数据
  162. personAmount: 0,
  163. PieData: [],//饼图统计图数据
  164. activeIndex: '1',
  165. collapseData1: [],//
  166. collapseData2: [],//
  167. userOpinionTypeList:[],
  168. projectList:[],
  169. projectId:'',
  170. imgVisible:false,
  171. dialogVisible: false,
  172. curNew:{},
  173. curRow:{},
  174. operation: {
  175. manageTime: '',
  176. show: false
  177. },
  178. pieObj:null,
  179. pfxAmount: 0,
  180. cancel: true
  181. }
  182. },
  183. methods: {
  184. operationMethods () {
  185. this.operation.show = this.curRow.currentLink == 2;
  186. if (!this.operation.show) {
  187. this.operation.manageTime = '';
  188. }
  189. },
  190. toDisposeView(){
  191. this.dialogVisible = true;
  192. this.operationMethods();
  193. },
  194. async submissionProgress(){
  195. if (this.curRow.currentLink == 2) {
  196. if (this.operation.manageTime) {
  197. await this.manageUserOperationStatus({
  198. currentLinkId: this.curRow.currentLinkId,
  199. currentLink: this.curRow.currentLink,
  200. newNumber: this.curRow.newNumber,
  201. userOpinionId: this.curRow.userOpinionId,
  202. manageTime: this.operation.manageTime
  203. })
  204. } else {
  205. this.$message({
  206. type: 'error',
  207. message: '请设置预计处理截止时间'
  208. })
  209. }
  210. } else {
  211. await this.manageUserOperationStatus({
  212. currentLinkId: this.curRow.currentLinkId,
  213. currentLink: this.curRow.currentLink,
  214. newNumber: this.curRow.newNumber,
  215. userOpinionId: this.curRow.userOpinionId
  216. })
  217. }
  218. if(this.cancel){
  219. this.$confirm('是否前往消息区继续处理?', '提示', {
  220. confirmButtonText: '确定',
  221. cancelButtonText: '取消',
  222. type: 'warning'
  223. }).then(() => {
  224. this.$router.push({
  225. path: '/news/news'
  226. });
  227. }).catch(() => {
  228. this.cancel = false;
  229. });
  230. }
  231. },
  232. async manageUserOperationStatus (da) {//业务人员提交环节操作
  233. const { data: res } = await manageUserOperationStatus(da)
  234. if (res.code == 200) {
  235. this.dialogVisible = false
  236. this.imgVisible = false;
  237. this.$message({
  238. type: 'success',
  239. message: '提交成功!'
  240. })
  241. //重新刷新列表
  242. if(this.activeIndex == 2){
  243. await this.queryBusinessUserOpinionAll();
  244. } else {
  245. await this.queryBusinessUserOpinion();
  246. }
  247. }
  248. },
  249. async openPreview(row){
  250. const { data : res } = await queryOpinionDetails({userOpinionId : row.userOpinionId});
  251. if(res.code == 200){
  252. this.curNew = res.data;
  253. }
  254. this.curRow = row;
  255. this.imgVisible = true;
  256. },
  257. selectProjectOpinion(){
  258. let _this = this;
  259. _this.PieData = [];
  260. this.userOpinionTypeList.forEach(obj => {
  261. if(obj.projectId == _this.projectId){
  262. let problemType = obj.problemType;
  263. let problemTypeAmount = obj.problemTypeAmount;
  264. problemType.forEach((name, index) => {
  265. _this.PieData.push({type : name, value : Number(problemTypeAmount[index])});
  266. });
  267. }
  268. })
  269. this.pieObj.changeData(_this.PieData);
  270. },
  271. async handleSelect (key) {
  272. if (key == 2) {
  273. await this.queryBusinessUserOpinionAll();
  274. } else {
  275. await this.queryBusinessUserOpinion();
  276. }
  277. this.activeIndex = key
  278. },
  279. async queryBusinessUserOpinion () {//获取我的消息
  280. const { data: res } = await queryBusinessUserOpinion({
  281. current: 1,
  282. size: 999999
  283. })
  284. if (res.code == 200) {
  285. this.collapseData1 = res.data.userOpinionFlowList
  286. this.menuTag = res.data.operation
  287. if(this.collapseData1.length < 1){
  288. this.handleSelect('2')
  289. }
  290. }
  291. },
  292. async queryBusinessUserOpinionAll () {
  293. const { data: res } = await queryBusinessUserOpinionAll({
  294. current: 1,
  295. size: 999999
  296. })
  297. if (res.code == 200) {
  298. this.collapseData2 = res.data.userOpinionFlowList;
  299. }
  300. },
  301. ignore (key) {
  302. this.isIgnore(this.collapseData1[key].userOpinionId);
  303. this.collapseData1.splice(this.collapseData1.indexOf(this.collapseData1[key]), 1);
  304. if(this.collapseData2.length > 0){
  305. let removeIndex = -1;
  306. this.collapseData2.forEach((vo,index) => {
  307. if(this.collapseData1[key].userOpinionId = vo.userOpinionId){
  308. removeIndex = index;
  309. }
  310. });
  311. if(removeIndex > -1){
  312. this.collapseData2.splice(removeIndex, 1);
  313. }
  314. }
  315. },
  316. ignore2 (key) {
  317. this.isIgnore(this.collapseData2[key].userOpinionId);
  318. this.collapseData2.splice(this.collapseData2.indexOf(this.collapseData2[key]), 1);
  319. if(this.collapseData1.length > 0){
  320. let removeIndex = -1;
  321. this.collapseData1.forEach((vo,index) => {
  322. if(this.collapseData2[key].userOpinionId = vo.userOpinionId){
  323. removeIndex = index;
  324. }
  325. });
  326. if(removeIndex > -1){
  327. this.collapseData1.splice(removeIndex, 1);
  328. }
  329. }
  330. },
  331. async isIgnore(userOpinionId){
  332. const {data : res} = await isIgnore({userOpinionId : userOpinionId});
  333. },
  334. async LineV () {
  335. await this.queryProjectPfx();
  336. const line = new Area('container', {
  337. data: this.LineData,
  338. xField: 'project',
  339. yField: 'value',
  340. seriesField: 'category',
  341. isStack:false,
  342. legend: {
  343. position: 'bottom',
  344. },
  345. autoFit:true,
  346. scrollbar: {
  347. type: 'vertical'
  348. }
  349. });
  350. line.render();
  351. },
  352. async ColumnV () {
  353. await this.queryProjectUserAmount();
  354. const columnPlot = new Column('container2', {
  355. data: this.ColumnData,
  356. isGroup: true,
  357. xField: 'project',
  358. yField: 'value',
  359. seriesField: 'category',
  360. /** 设置颜色 */
  361. //color: ['#1ca9e6', '#f88c24'],
  362. /** 设置间距 */
  363. // marginRatio: 0.1,
  364. label: {
  365. // 可手动配置 label 数据标签位置
  366. position: 'middle', // 'top', 'middle', 'bottom'
  367. // 可配置附加的布局方法
  368. layout: [
  369. // 柱形图数据标签位置自动调整
  370. { type: 'interval-adjust-position' },
  371. // 数据标签防遮挡
  372. { type: 'interval-hide-overlap' },
  373. // 数据标签文颜色自动调整
  374. { type: 'adjust-color' },
  375. ],
  376. },
  377. legend: {
  378. position: 'bottom',
  379. },
  380. });
  381. columnPlot.render();
  382. },
  383. async PieV () {
  384. await this.queryOpinionTypeAmount();
  385. const piePlot = new Pie('container3', {
  386. appendPadding: 10,
  387. data: this.PieData,
  388. angleField: 'value',
  389. colorField: 'type',
  390. radius: 0.75,
  391. label: {
  392. type: 'spider',
  393. labelHeight: 28,
  394. content: '{name}\n{value}',
  395. },
  396. interactions: [{ type: 'element-selected' }, { type: 'element-active' }],
  397. legend: {
  398. position: 'bottom',
  399. },
  400. });
  401. piePlot.render();
  402. this.pieObj = piePlot;
  403. },
  404. //获取人员账户
  405. async queryProjectUserAmount(){
  406. const {data : res} = await queryProjectUserAmount();
  407. let records = res.data.projectUserAmountVOList;
  408. records.forEach(vo => {
  409. this.ColumnData.push({"category": "施工方","project": vo.projectName,"value": vo.contractor});
  410. this.ColumnData.push({"category": "监理方","project": vo.projectName,"value": vo.supervision});
  411. this.ColumnData.push({"category": "指挥部","project": vo.projectName,"value": vo.owner});
  412. });
  413. this.personAmount = res.data.projectUserAmount;
  414. },
  415. //证书统计
  416. async queryProjectPfx(){
  417. let _this = this;
  418. const {data : res} = await queryProjectPfx();
  419. let pfxList = res.data.pfxList;
  420. pfxList.forEach(vo => {
  421. _this.LineData.push({"category": "个人证书","project": vo.projectName,"value": Number(vo.personalCount)});
  422. _this.LineData.push({"category": "企业证书","project": vo.projectName,"value": Number(vo.enterpriseCount)});
  423. });
  424. this.pfxAmount = res.data.pfxAmount;
  425. },
  426. //维护类型统计汇总
  427. async queryOpinionTypeAmount(){
  428. let _this = this;
  429. const {data : res} = await queryOpinionTypeAmount();
  430. this.userOpinionTypeList = res.data.userOpinionList;
  431. this.projectList = res.data.projectInfos;
  432. let userOpinion = this.userOpinionTypeList[0];
  433. let problemType = userOpinion.problemType;
  434. let problemTypeAmount = userOpinion.problemTypeAmount;
  435. this.projectId = userOpinion.projectId;
  436. problemType.forEach((name, index) => {
  437. _this.PieData.push({type : name, value : Number(problemTypeAmount[index])});
  438. });
  439. }
  440. },
  441. created () {
  442. this.queryBusinessUserOpinion();
  443. },
  444. mounted () {
  445. this.LineV()
  446. this.ColumnV()
  447. this.PieV()
  448. }
  449. }
  450. </script>
  451. <style lang="scss" scoped>
  452. .el-menu.el-menu--horizontal {
  453. display: flex;
  454. justify-content: center;
  455. }
  456. .el-menu-item,
  457. .el-submenu__title {
  458. line-height: 40px;
  459. height: 40px;
  460. }
  461. .el-menu-item {
  462. padding: 0px;
  463. margin: 0 20px;
  464. }
  465. .information {
  466. margin-top: 20px;
  467. background-color: #faf8fd;
  468. box-sizing: border-box;
  469. border-radius: 4px;
  470. overflow: auto;
  471. }
  472. .el-collapse {
  473. border: none;
  474. }
  475. /deep/.el-collapse-item__header {
  476. background-color: #faf8fd;
  477. border-bottom: none;
  478. box-sizing: border-box;
  479. padding-left: 20px;
  480. color: red;
  481. }
  482. /deep/.el-collapse-item__content {
  483. background-color: #f7f7f7;
  484. box-sizing: border-box;
  485. padding-left: 20px;
  486. padding-bottom: 0px;
  487. }
  488. .visualization {
  489. height: calc(60% - 60px);
  490. }
  491. .chart-title{
  492. margin-bottom: 20px;
  493. font-weight: 700;
  494. font-size: 18px;
  495. color: rgba(119, 40, 245, 0.85);
  496. }
  497. </style>