workMeeting.vue 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648
  1. <template>
  2. <div class="workMeeting">
  3. <div class="page-query-core">
  4. <query
  5. :show="['company', 'floor', 'time']"
  6. :query-data.sync="queryData"
  7. :reset="reset"
  8. :floor-options="floorOptions"
  9. :search="search"
  10. ></query>
  11. </div>
  12. <div class="page-query-core">
  13. <card :title="'核心指标'">
  14. <CoreData :data-list="coreData"></CoreData>
  15. </card>
  16. </div>
  17. <div style="margin-top: 12px">
  18. <a-row>
  19. <a-col :span="24">
  20. <div class="workMeeting-left ioc-card-content">
  21. <card title="会议分析" v-show="chartShow.timeLine" style="padding-bottom: 15px">
  22. <a-row>
  23. <a-col :span="2">
  24. <a-menu
  25. style="width: 100%"
  26. :default-selected-keys="defaultSelectedKeys"
  27. mode="inline"
  28. @click="huiyiClick"
  29. >
  30. <!-- style="width: 100px" -->
  31. <!-- :open-keys.sync="openKeys" -->
  32. <template v-for="(value, key) in roomInfo">
  33. <a-menu-item
  34. v-for="item in value"
  35. :key="item.value"
  36. v-if="key == queryData.floorId"
  37. >
  38. {{ item.value }}
  39. </a-menu-item>
  40. </template>
  41. </a-menu>
  42. </a-col>
  43. <a-col :span="3">
  44. <div class="week-box" v-for="n in timeArr" :key="n.weekday">
  45. <div class="week">{{ n.weekday }}</div>
  46. <div class="date">{{ n.date }}</div>
  47. </div>
  48. </a-col>
  49. <a-col :span="19">
  50. <timeline
  51. v-if="showMeetingLine"
  52. v-for="(value, key, index) in meetingInfo"
  53. :key="index"
  54. :select="currCheckMeeting"
  55. v-bind="{
  56. startTime: 8,
  57. endTime: 18,
  58. huiyiInfo: value,
  59. }"
  60. :style="{ height: '60px' }"
  61. ></timeline>
  62. </a-col>
  63. </a-row>
  64. <div class="workMeeting-left-detail">
  65. <a-descriptions :column="2" :colon="false">
  66. <a-descriptions-item>
  67. <template #label>
  68. <span class="workMeeting-left-detail-label"
  69. >会议主题:</span
  70. >
  71. </template>
  72. <div class="workMeeting-left-detail-content">
  73. {{ currMeeting.subject }}
  74. </div>
  75. </a-descriptions-item>
  76. <a-descriptions-item>
  77. <template #label>
  78. <span class="workMeeting-left-detail-label"
  79. >会议配置:</span
  80. >
  81. </template>
  82. <div
  83. class="workMeeting-left-detail-content"
  84. v-if="currMeeting.subject"
  85. >
  86. 智慧场景策略配置
  87. </div>
  88. </a-descriptions-item>
  89. <a-descriptions-item>
  90. <template #label>
  91. <span class="workMeeting-left-detail-label"
  92. >预约部门:</span
  93. >
  94. </template>
  95. <div class="workMeeting-left-detail-content">
  96. {{ deptData[currMeeting.deptId] }}
  97. </div>
  98. </a-descriptions-item>
  99. <a-descriptions-item>
  100. <template #label>
  101. <span class="workMeeting-left-detail-label"
  102. >会议成本:</span
  103. >
  104. </template>
  105. <div
  106. class="workMeeting-left-detail-content"
  107. style="background-color: #ffffff"
  108. v-if="currMeeting.subject"
  109. >
  110. 30元/小时
  111. </div>
  112. </a-descriptions-item>
  113. <a-descriptions-item>
  114. <template #label>
  115. <span class="workMeeting-left-detail-label"
  116. >参会人员:</span
  117. >
  118. </template>
  119. <div
  120. style="width: 100%; vertical-align: top"
  121. v-if="currMeeting.subject"
  122. >
  123. <div
  124. style="
  125. display: inline-block;
  126. vertical-align: top;
  127. margin: 1px 3px;
  128. "
  129. >
  130. <a-avatar
  131. src="https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png"
  132. />
  133. <div>张三</div>
  134. </div>
  135. <div
  136. style="
  137. display: inline-block;
  138. vertical-align: top;
  139. margin: 1px 3px;
  140. "
  141. >
  142. <a-avatar
  143. src="https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png"
  144. />
  145. <div>张雪峰</div>
  146. </div>
  147. <div
  148. style="
  149. display: inline-block;
  150. vertical-align: top;
  151. margin: 1px 3px;
  152. "
  153. >
  154. <a-avatar
  155. src="https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png"
  156. />
  157. <div>张明</div>
  158. </div>
  159. <div
  160. style="
  161. display: inline-block;
  162. vertical-align: top;
  163. margin: 1px 3px;
  164. "
  165. >
  166. <a-avatar
  167. src="https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png"
  168. />
  169. <div>李阳</div>
  170. </div>
  171. <div
  172. style="
  173. display: inline-block;
  174. vertical-align: top;
  175. margin: 1px 3px;
  176. "
  177. >
  178. <a-avatar
  179. src="https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png"
  180. />
  181. <div>王佳佳</div>
  182. </div>
  183. </div>
  184. </a-descriptions-item>
  185. <a-descriptions-item>
  186. <template #label>
  187. <span class="workMeeting-left-detail-label"
  188. >会议费用:</span
  189. >
  190. </template>
  191. <div
  192. class="workMeeting-left-detail-content"
  193. style="background-color: #ffffff"
  194. v-if="currMeeting.subject"
  195. >
  196. 35元/小时
  197. </div>
  198. </a-descriptions-item>
  199. </a-descriptions>
  200. </div>
  201. </card >
  202. <card title="会议分析" v-if="chartShow.usageAllPanel" style="padding-bottom: 15px">
  203. <MeetingTimeCharts
  204. :height="300"
  205. :queryData="queryData"
  206. ref="meetingTimeRef"
  207. ></MeetingTimeCharts>
  208. </card>
  209. <card title="会议分析" v-if="chartShow.usageFloorPanel" style="padding-bottom: 15px">
  210. <MeetingTimeFloorCharts
  211. :height="300"
  212. :queryData="queryData"
  213. ref="meetingTimeFloorRef"
  214. ></MeetingTimeFloorCharts>
  215. </card>
  216. </div>
  217. </a-col>
  218. <a-col :span="24" style="margin-top: 12px">
  219. <div class="workMeeting-right ioc-card-content">
  220. <card title="成本趋势" moduleType="智慧办公" mainTitleSize="20px">
  221. <template #sub-title>
  222. <div style="font-size: 16px; color: #4d4d4d; margin-top: 10px">
  223. 成本趋势: 成本集中
  224. </div>
  225. </template>
  226. <div class="cben" style="margin-bottom: 15px">
  227. <WorkMeetingCostTrend
  228. ref="WorkMeetingCostTrend"
  229. :queryData="queryData"
  230. :height="460"
  231. />
  232. </div>
  233. </card>
  234. </div>
  235. </a-col>
  236. <!-- <a-col :span="24" style="margin-top: 12px">
  237. <div
  238. class="workMeeting-left ioc-card-content"
  239. style="margin-bottom: 15px"
  240. >
  241. <card>
  242. <MeetingTimeCharts
  243. :height="300"
  244. :queryData="queryData"
  245. ></MeetingTimeCharts>
  246. </card>
  247. </div>
  248. </a-col> -->
  249. </a-row>
  250. </div>
  251. </div>
  252. </template>
  253. <script>
  254. import query from "@/components/common/query.vue";
  255. import card from "@/components/common/card.vue";
  256. import timeline from "@/components/common/timeLine.vue";
  257. import WorkMeetingCostTrend from "@/components/work/meeting/component/workMeetingCostTrend.vue";
  258. import MeetingTimeCharts from "@/components/scene/meeting/chart/meetingTimeCharts.vue";
  259. import MeetingTimeFloorCharts from "@/components/scene/meeting/chart/meetingTimeFloorCharts.vue";
  260. import apiWorkMeeting from "@/api/work/apiWorkMeeting";
  261. export default {
  262. components: {
  263. query,
  264. card,
  265. timeline,
  266. WorkMeetingCostTrend,
  267. MeetingTimeCharts,
  268. MeetingTimeFloorCharts,
  269. },
  270. data() {
  271. let timeRange = this.$util.dateUtil.getNearlyMonthRange();
  272. return {
  273. showMeetingLine: false,
  274. timeArr: [
  275. {
  276. id: 0,
  277. weekday: "周一",
  278. date: "",
  279. },
  280. {
  281. id: 1,
  282. weekday: "周二",
  283. date: "",
  284. },
  285. {
  286. id: 2,
  287. weekday: "周三",
  288. date: "",
  289. },
  290. {
  291. id: 3,
  292. weekday: "周四",
  293. date: "",
  294. },
  295. {
  296. id: 4,
  297. weekday: "周五",
  298. date: "",
  299. },
  300. ],
  301. deptData: {
  302. 0: "业务一部",
  303. 1: "业务二部",
  304. 2: "业务三部",
  305. },
  306. queryData: {
  307. companyId: "0",
  308. floorId: "0",
  309. timeRange: timeRange,
  310. },
  311. currRoom: "701",
  312. floorOptions: [
  313. {
  314. value: "7",
  315. label: "7F",
  316. },
  317. {
  318. value: "8",
  319. label: "8F",
  320. },
  321. {
  322. value: "9",
  323. label: "9F",
  324. },
  325. //{
  326. // value: '',
  327. // label: "全部"
  328. //},
  329. //{
  330. // value: '1',
  331. // label: "1F"
  332. //},
  333. //{
  334. // value: '10',
  335. // label: "10F"
  336. //},
  337. //{
  338. // value: '11',
  339. // label: "11F"
  340. //},{
  341. // value: '12',
  342. // label: "12F"
  343. //},{
  344. // value: '15',
  345. // label: "15F"
  346. //},{
  347. // value: '16',
  348. // label: "16F"
  349. //},{
  350. // value: '17',
  351. // label: "17F"
  352. //},{
  353. // value: '18',
  354. // label: "18F"
  355. //},{
  356. // value: '19',
  357. // label: "19F"
  358. //},{
  359. // value: '20',
  360. // label: "20F"
  361. //},{
  362. // value: '30',
  363. // label: "30F"
  364. //},
  365. ],
  366. columns: [
  367. { title: "序号", dataIndex: "index", key: "1", width: 48 },
  368. { title: "姓名", dataIndex: "name", key: "2", width: 60 },
  369. { title: "部门", dataIndex: "department", key: "3", width: 80 },
  370. { title: "最后进入时间", dataIndex: "time", key: "4", width: 90 },
  371. ],
  372. coreData: [
  373. {
  374. title: "会议室饱和度",
  375. num: "",
  376. unit: "%",
  377. historyDesc: "同比",
  378. historyNum: 0.4,
  379. },
  380. {
  381. title: "会议室占用率",
  382. num: "",
  383. unit: "%",
  384. historyDesc: "同比",
  385. historyNum: 0,
  386. },
  387. {
  388. title: "会议室成本(元)",
  389. num: 0,
  390. historyDesc: "同比",
  391. historyNum: 0,
  392. },
  393. {
  394. title: "会议室人均成本(元/人)",
  395. num: 0,
  396. historyDesc: "同比",
  397. historyNum: 0,
  398. },
  399. {
  400. type: 1,
  401. showStar: true,
  402. title: "值得关注",
  403. content: "",
  404. },
  405. ],
  406. defaultSelectedKeys: ["701", "801", "901"],
  407. tabsItemArr: [],
  408. roomInfo: {
  409. 7: [
  410. {
  411. label: "701",
  412. value: "701",
  413. },
  414. {
  415. label: "702",
  416. value: "702",
  417. },
  418. {
  419. label: "703",
  420. value: "703",
  421. },
  422. ],
  423. 8: [
  424. {
  425. label: "801",
  426. value: "801",
  427. },
  428. {
  429. label: "802",
  430. value: "802",
  431. },
  432. {
  433. label: "803",
  434. value: "803",
  435. },
  436. ],
  437. 9: [
  438. {
  439. label: "901",
  440. value: "901",
  441. },
  442. {
  443. label: "902",
  444. value: "902",
  445. },
  446. {
  447. label: "903",
  448. value: "903",
  449. },
  450. ],
  451. },
  452. meetingInfo: {},
  453. currMeeting: {},
  454. chartShow: {
  455. timeLine: false,
  456. usageFloorPanel: false,
  457. usageAllPanel: true,
  458. },
  459. };
  460. },
  461. mounted() {
  462. this.init();
  463. this.setDate();
  464. },
  465. watch: {},
  466. methods: {
  467. init() {
  468. this.$store.loadingStore().loadingWithApi(this.getCoreData(), 2000);
  469. },
  470. currCheckMeeting(val) {
  471. this.currMeeting = val;
  472. },
  473. setDate() {
  474. this.timeArr = this.timeArr.map((v) => {
  475. return {
  476. id: v.id,
  477. weekday: v.weekday,
  478. date: this.$moment().weekday(v.id).format("YYYY/MM/DD"),
  479. };
  480. });
  481. // for(let i=1;i<=5;i++){
  482. // this.timeArr.push({
  483. // weekday:this.$moment().weekday(i).format(),
  484. // date:this.$moment().weekday(i).format("YYYY/MM/DD")
  485. // })
  486. // }
  487. },
  488. reset() {},
  489. search() {
  490. this.chartShow.timeLine = false;
  491. this.chartShow.usageAllPanel = false;
  492. this.chartShow.usageFloorPanel = false;
  493. // 楼层选全部时展示使用时长面板
  494. if (this.queryData.floorId === "0") {
  495. this.chartShow.usageAllPanel = true;
  496. this.$nextTick(() => {
  497. this.$util.asyncPromise(
  498. this.getCoreData(),
  499. this.$refs.WorkMeetingCostTrend.getData(),
  500. this.$refs.meetingTimeRef.getData()
  501. // this.getMeetingRecordData()
  502. );
  503. });
  504. } else {
  505. let start = this.$moment(this.queryData.timeRange.startDate);
  506. let end = this.$moment(this.queryData.timeRange.endDate);
  507. let diff = end.diff(start, "days");
  508. if (diff > 1) {
  509. this.chartShow.usageFloorPanel = true;
  510. this.$nextTick(() => {
  511. this.$util.asyncPromise(
  512. this.getCoreData(),
  513. this.$refs.WorkMeetingCostTrend.getData(),
  514. this.$refs.meetingTimeFloorRef.getData()
  515. // this.getMeetingRecordData()
  516. );
  517. });
  518. } else {
  519. this.chartShow.timeLine = true;
  520. this.$util.asyncPromise(
  521. this.getCoreData(),
  522. this.$refs.WorkMeetingCostTrend.getData(),
  523. this.getMeetingRecordData()
  524. );
  525. }
  526. // 楼层选择具体楼层时 -- 起止时间差大于一天
  527. // 楼层选择具体楼层时,起止时间差小于一天
  528. }
  529. },
  530. // 会议记录
  531. getMeetingRecordData() {
  532. this.showMeetingLine = false;
  533. let params = {};
  534. Object.assign(params, this.queryData);
  535. params.timeRange = this.$util.dateUtil.getCurrWeekRange();
  536. let resultObj = {};
  537. let app = this;
  538. this.timeArr.forEach((i) => {
  539. resultObj[i.date] = [];
  540. });
  541. this.meetingInfo = resultObj;
  542. return apiWorkMeeting
  543. .getMeetingRecords(params)
  544. .then((res) => {
  545. let arr = res.filter((item) => item.room == this.currRoom);
  546. for (let i = 0; i < arr.length; i++) {
  547. let obj = app.$moment(arr[i].startTime).format("yyyy/MM/DD");
  548. resultObj[obj].push(arr[i]);
  549. }
  550. this.meetingInfo = resultObj;
  551. this.showMeetingLine = true;
  552. })
  553. .catch((err) => {
  554. this.showMeetingLine = true;
  555. });
  556. },
  557. huiyiClick(e) {
  558. //this.changeTab(e.key);
  559. this.currRoom = e.key;
  560. this.getMeetingRecordData();
  561. },
  562. //changeTab(index) {
  563. // this.tabsItemArr = this.tabsArr[index].content;
  564. //},
  565. // 核心指标
  566. getCoreData() {
  567. return apiWorkMeeting.getCoreData(this.queryData).then((res) => {
  568. this.coreData[0].num = res.list[0].value;
  569. this.coreData[0].historyNum = res.list[0].compare;
  570. this.coreData[1].num = res.list[1].value;
  571. this.coreData[1].historyNum = res.list[1].compare;
  572. this.coreData[2].num = res.list[2].value;
  573. this.coreData[2].historyNum = res.list[2].compare;
  574. this.coreData[3].num = res.list[3].value;
  575. this.coreData[3].historyNum = res.list[3].compare;
  576. this.coreData[4].content = res.worthAttention;
  577. });
  578. },
  579. },
  580. };
  581. </script>
  582. <style lang="less" scoped>
  583. .workMeeting {
  584. .workMeeting-left {
  585. background-color: #ffffff;
  586. padding: 2px 15px;
  587. border-radius: 4px;
  588. // margin-right: 6px;
  589. .ant-col-3 {
  590. .week-box {
  591. height: 60px;
  592. width: 100%;
  593. position: relative;
  594. color: rgb(77, 77, 77, 0.2);
  595. .week {
  596. width: 80%;
  597. height: 50%;
  598. position: absolute;
  599. top: 0;
  600. right: 0;
  601. display: flex;
  602. align-items: center;
  603. }
  604. .date {
  605. width: 80%;
  606. height: 50%;
  607. position: absolute;
  608. right: 0;
  609. bottom: 0;
  610. margin: 0 auto;
  611. }
  612. }
  613. }
  614. .workMeeting-left-detail {
  615. margin-top: 30px;
  616. padding: 0 20px;
  617. margin-bottom: 12px;
  618. .workMeeting-left-detail-label {
  619. vertical-align: top;
  620. color: #b2b2b2;
  621. }
  622. .workMeeting-left-detail-content {
  623. width: 100%;
  624. font-size: 12px;
  625. background-color: #f7f9fa;
  626. color: #999999;
  627. padding-left: 12px;
  628. }
  629. }
  630. }
  631. /deep/ .ant-descriptions-item {
  632. vertical-align: top;
  633. }
  634. /deep/ .ant-descriptions-item-content {
  635. width: 80%;
  636. line-height: 24px;
  637. }
  638. .workMeeting-right {
  639. background-color: #ffffff;
  640. padding: 2px 15px;
  641. border-radius: 4px;
  642. // margin-left: 6px;
  643. }
  644. }
  645. </style>