AppMain.vue 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576
  1. <template>
  2. <section class="app-main">
  3. <!-- -->
  4. <transition name="fade-transform" mode="out-in">
  5. <div>
  6. <router-view v-slot="{ Component }">
  7. <!-- <keep-alive>
  8. <component v-if="!keep" :is="Component" />
  9. </keep-alive> v-if="keep"-->
  10. <component :is="Component" />
  11. </router-view>
  12. <!-- <keep-alive exclude="nocatch">
  13. <router-view :key="key" v-if="needKeep" />
  14. </keep-alive>
  15. <router-view v-if="!needKeep" :key="key" /> -->
  16. </div>
  17. </transition>
  18. <serviceRemind />
  19. <div style="z-index: 5000">
  20. <el-dialog
  21. :visible.sync="guideVisible"
  22. width="680px"
  23. :modal="false"
  24. v-if="guideList.length > 0"
  25. append-to-body
  26. class="dialogGuide"
  27. >
  28. <template #title>
  29. <div class="dialogHead">
  30. <h2 class="guideH2">您需要完成以下设置</h2>
  31. <el-divider class="guideLine"></el-divider>
  32. </div>
  33. </template>
  34. <div class="guideWrap">
  35. <div class="guideItem" v-for="guide in guideList" :key="guide.name">
  36. <p>
  37. <span class="guideTitle">{{ guide.name }}</span>
  38. <el-button
  39. class="guideSet"
  40. type="text"
  41. @click="gotoSet(guide)"
  42. v-if="permission(guide.permission)"
  43. >立即设置 >></el-button
  44. >
  45. <span v-else>您暂无此设置权限,请联系机构管理员</span>
  46. </p>
  47. <p class="guideDesc">{{ guide.desc }}</p>
  48. </div>
  49. <!-- <el-button
  50. type="primary"
  51. style="width: 100%"
  52. @click="guideVisible = false"
  53. >暂不设置</el-button
  54. > -->
  55. </div>
  56. </el-dialog>
  57. </div>
  58. <div
  59. class="optionBtn"
  60. v-if="!outOptionvisible && isShowBtn"
  61. @click="openOptionMual"
  62. >
  63. 操作手册
  64. </div>
  65. <!-- <div class="chart-join">
  66. <el-badge :is-dot="noReadNum > 0 ? true : false" class="item">
  67. <svg
  68. t="1659606821949"
  69. class="icon optionMessage"
  70. viewBox="0 0 1024 1024"
  71. version="1.1"
  72. xmlns="http://www.w3.org/2000/svg"
  73. p-id="3078"
  74. width="48"
  75. height="48"
  76. @click="onOpenChatRoom"
  77. >
  78. <path
  79. d="M512 796a456.672 456.672 0 0 1-74.768-6.4L262 896V718.976C170.64 654.832 112 556.48 112 446 112 252.704 291.088 96 512 96s400 156.704 400 350S732.912 796 512 796z m0-650c-193.296 0-350 134.32-350 300 0 101.664 59.2 191.344 149.376 245.6l-1.6 115.968 117.68-70.736a404.8 404.8 0 0 0 84.544 9.168c193.296 0 350-134.304 350-300S705.296 146 512 146zM336 400a48 48 0 1 1-48 48 48 48 0 0 1 48-48z m176 0a48 48 0 1 1-48 48 48 48 0 0 1 48-48z m176 0a48 48 0 1 1-48 48 48 48 0 0 1 48-48z"
  80. p-id="3079"
  81. ></path>
  82. </svg>
  83. </el-badge>
  84. </div> -->
  85. <el-drawer
  86. title="操作手册"
  87. :visible.sync="outOptionvisible"
  88. size="410px"
  89. :append-to-body="true"
  90. >
  91. <el-divider class="outOptionLine"></el-divider>
  92. <div class="drawerWrap">
  93. <el-form :model="form" :inline="true">
  94. <el-form-item>
  95. <el-input
  96. style="width: 265px !important"
  97. v-model="form.search"
  98. placeholder="请输入菜单名"
  99. clearable
  100. @clear="getMUal()"
  101. ></el-input>
  102. </el-form-item>
  103. <el-form-item>
  104. <el-button @click="getMUal()" type="danger">搜索</el-button>
  105. </el-form-item>
  106. <br />
  107. <!-- <div class="topline"></div> -->
  108. <div
  109. v-for="(item, index) in optionList"
  110. :key="index"
  111. class="line"
  112. @click="openDetail(item)"
  113. >
  114. <el-row>
  115. <el-col :span="23">{{ item.name }}</el-col>
  116. <el-col :span="1"><i class="el-icon-arrow-right"></i></el-col>
  117. </el-row>
  118. </div>
  119. </el-form>
  120. </div>
  121. </el-drawer>
  122. <el-drawer
  123. :title="activeRow.name"
  124. :append-to-body="true"
  125. v-if="activeRow"
  126. :visible.sync="innerDrawer"
  127. size="410px"
  128. custom-class="innerDrawer"
  129. >
  130. <p class="submitTitle">更新时间: {{ activeRow.updateTime }}</p>
  131. <el-tabs v-model="activeName" type="card" @tab-click="handleClick">
  132. <el-tab-pane label="操作流程" name="first">
  133. <div class="optionWrap">
  134. <el-image
  135. ref="previewImg"
  136. class="previewImg"
  137. :src="activeImg"
  138. :preview-src-list="[activeImg]"
  139. style="display: none"
  140. ></el-image>
  141. <div class="ql-editor" v-html="activeRow.opFlow"></div>
  142. </div>
  143. </el-tab-pane>
  144. <el-tab-pane label="功能规则" name="second">
  145. <div class="optionWrap">
  146. <div class="ql-editor" v-html="activeRow.funRule"></div>
  147. </div>
  148. </el-tab-pane>
  149. </el-tabs>
  150. </el-drawer>
  151. <el-drawer
  152. :append-to-body="true"
  153. :visible.sync="chatVisible"
  154. size="910px"
  155. :class="loadChatDom ? '' : 'drawer-container'"
  156. custom-class="innerDrawer"
  157. :withHeader="false"
  158. >
  159. <chat-model ref="chatModel" @close="chatVisible = false" />
  160. </el-drawer>
  161. </section>
  162. </template>
  163. <script>
  164. import notKeepAliveList from "@/router/notKeepAliveList";
  165. import serviceRemind from "@/components/serviceRemind"; // 续费弹窗
  166. import { permission } from "@/utils/directivePage";
  167. import { guideList } from "@/constant/guide";
  168. import chatModel from "./modal/chat-model";
  169. import {
  170. getSysManualList,
  171. getSysManualMenuIds
  172. } from "@/views/operationManual/api";
  173. import "quill/dist/quill.core.css";
  174. import "quill/dist/quill.snow.css";
  175. import "quill/dist/quill.bubble.css";
  176. import { core, CoreEvent } from "./imkit";
  177. import * as RongIMLib from "@rongcloud/imlib-next";
  178. import { custom_service } from "./modal/chat.js";
  179. // 接入时需要将 '请更换您应用的 appkey' 替换为您的应用的 appkey
  180. // let libOption = { appkey: "c9kqb3rdc451j" };
  181. let libOption = {
  182. appkey: /online/.test(location.href) ? "6tnym1br6pv07" : "c9kqb3rdc451j"
  183. }; // 线上的
  184. // 初始化 SDK
  185. core.init({
  186. service: custom_service,
  187. libOption: libOption,
  188. conversationPullCount: 20
  189. });
  190. export default {
  191. name: "AppMain",
  192. data() {
  193. return {
  194. guideVisible: false,
  195. guideList: [],
  196. outOptionvisible: false,
  197. optionList: [],
  198. form: {},
  199. activeRow: null,
  200. innerDrawer: false,
  201. activeName: "first",
  202. allIdList: [],
  203. isShow: false,
  204. activeImg: null,
  205. loadChatDom: false,
  206. chatVisible: true,
  207. noReadNum: 0 // 消息未读数
  208. };
  209. },
  210. components: { serviceRemind, chatModel },
  211. computed: {
  212. key() {
  213. return this.$route.path;
  214. },
  215. needKeep() {
  216. return !notKeepAliveList.includes(this.$route.path);
  217. },
  218. cachedViews() {
  219. return this.$store.state.tagsView.cachedViews;
  220. },
  221. keep() {
  222. return this.$route.meta.noCache * 1; // 0是缓存 1是不缓存
  223. },
  224. isShowBtn() {
  225. return this.allIdList.indexOf(this.$route.meta.id + "") != -1;
  226. }
  227. },
  228. async mounted() {
  229. this.chatVisible = false;
  230. setTimeout(() => {
  231. this.loadChatDom = true;
  232. }, 1000);
  233. // console.log(this.$ref.chatModel);
  234. this.$bus.$on("showguide", obj => {
  235. this.guideList = [];
  236. obj.forEach(element => {
  237. if (guideList[element]) {
  238. this.guideList.push(guideList[element]);
  239. }
  240. });
  241. this.guideVisible = true;
  242. });
  243. try {
  244. const res = await getSysManualMenuIds();
  245. this.allIdList = res.data.split(",");
  246. } catch (e) {}
  247. this.init();
  248. // 获取未读数
  249. this.$bus.$on("getNoReadNum", obj => {
  250. console.log(obj, "getNoReadNum");
  251. this.getNoReadMessage(obj);
  252. });
  253. this.$bus.$on("openChart", status => {
  254. this.chatVisible = status || false;
  255. });
  256. },
  257. beforeDestroy() {
  258. this.$bus.$off("showguide", () => {});
  259. this.$bus.$off("getNoReadNum", () => {});
  260. // core.off(CoreEvent.MESSAGES, this.handleMessages);
  261. const Events = RongIMLib.Events;
  262. RongIMLib.removeEventListener(Events.MESSAGES, this.handleMessages);
  263. },
  264. methods: {
  265. init() {
  266. core.connect(this.$store.state.user.imToken).then(res => {
  267. if (res.code === RongIMLib.ErrorCode.SUCCESS) {
  268. console.log("链接成功, 链接用户 id 为: ", res.data.userId);
  269. // this.isConnect = true;
  270. this.getNoReadMessage(true);
  271. } else {
  272. console.warn("链接失败, code:", res.code);
  273. }
  274. });
  275. const Events = RongIMLib.Events;
  276. RongIMLib.addEventListener(Events.MESSAGES, this.handleMessages);
  277. // RongIMLib.addEventListener(Events.MESSAGE_RECEIPT_RESPONSE, message => {
  278. // console.log("121212", message);
  279. // });
  280. },
  281. handleMessages(newMessage) {
  282. console.log(newMessage, "newMessage");
  283. this.getNoReadMessage(true);
  284. },
  285. onOpenChatRoom() {
  286. this.chatVisible = true;
  287. this.$bus.$emit("scrollToBottom");
  288. this.getNoReadMessage(true);
  289. },
  290. getNoReadMessage(status) {
  291. if (status || this.chatVisible) {
  292. RongIMLib.getTotalUnreadCount().then(res => {
  293. if (res.code === 0) {
  294. console.log(res.code, res);
  295. this.noReadNum = res.data || 0;
  296. this.$bus.$emit("getShowNums", this.noReadNum);
  297. } else {
  298. console.log(res.code, res.msg, res);
  299. }
  300. });
  301. }
  302. },
  303. showInstructions() {
  304. this.isShow = !this.isShow;
  305. },
  306. // openIns() {
  307. // this.$refs.instructions.showInstructions();
  308. // },
  309. gotoSet(guide) {
  310. // console.log();
  311. this.$router.push({ path: guide.path });
  312. this.guideVisible = false;
  313. },
  314. permission(str) {
  315. return permission(str);
  316. },
  317. async openOptionMual() {
  318. // this.outOptionvisible = true;
  319. await this.getMUal();
  320. this.outOptionvisible = true;
  321. },
  322. async getMUal() {
  323. let menuId = this.$route.meta.id;
  324. try {
  325. const res = await getSysManualList({
  326. menuId,
  327. page: 1,
  328. rows: 9999,
  329. search: this.form.search
  330. });
  331. this.optionList = res.data.rows;
  332. console.log(this.$route);
  333. } catch (e) {
  334. console.log(e);
  335. }
  336. },
  337. openDetail(row) {
  338. // console.log(row);
  339. this.activeRow = row;
  340. this.innerDrawer = true;
  341. this.$nextTick(res => {
  342. Array.from(document.querySelectorAll("img")).forEach(img => {
  343. img.addEventListener("click", this.previewImg, true);
  344. });
  345. });
  346. },
  347. handleClick(val) {
  348. this.activeName = val.name;
  349. },
  350. previewImg(data) {
  351. let imgSrc = data.target.getAttribute("src");
  352. this.activeImg = imgSrc;
  353. this.$refs.previewImg.clickHandler();
  354. }
  355. },
  356. watch: {
  357. innerDrawer(val) {
  358. if (!val) {
  359. this.activeName = "first";
  360. }
  361. }
  362. }
  363. };
  364. </script>
  365. <style lang="scss" scoped>
  366. .drawer-container {
  367. display: none !important;
  368. }
  369. .previewImg {
  370. }
  371. ::v-deep .el-drawer__header {
  372. font-size: 20px;
  373. margin-bottom: 0px;
  374. line-height: 24px;
  375. color: rgba(0, 0, 0, 0.9);
  376. font-weight: bold;
  377. }
  378. .outOptionLine {
  379. margin: 20px 0 0 0;
  380. background-color: #e5e5e5;
  381. }
  382. .innerDrawer {
  383. .submitTitle {
  384. margin: 10px 0;
  385. font-size: 12px;
  386. padding: 0 20px;
  387. color: #999;
  388. }
  389. .optionWrap {
  390. box-sizing: border-box;
  391. width: 100%;
  392. padding: 10px 8px;
  393. ::v-deep img {
  394. width: 100%;
  395. cursor: pointer;
  396. }
  397. ::v-deep p {
  398. line-height: 28px;
  399. font-size: 14px !important;
  400. }
  401. ::v-deep .ql-video {
  402. width: 100%;
  403. }
  404. }
  405. }
  406. .optionBtn {
  407. width: 35px;
  408. background-color: var(--color-primary);
  409. color: #fff;
  410. position: fixed;
  411. right: 0;
  412. top: 250px;
  413. padding: 10px;
  414. border-radius: 8px;
  415. cursor: pointer;
  416. z-index: 3999;
  417. }
  418. .chart-join {
  419. position: fixed;
  420. right: 36px;
  421. bottom: 36px;
  422. z-index: 99;
  423. ::v-deep .el-badge__content {
  424. display: flex;
  425. align-items: center;
  426. }
  427. }
  428. .optionMessage {
  429. cursor: pointer;
  430. padding: 6px;
  431. width: 46px;
  432. height: 46px;
  433. box-sizing: border-box;
  434. border-radius: 50%;
  435. background-color: #fff;
  436. border: 1px solid #dcdfe6;
  437. z-index: 99;
  438. }
  439. ::v-deep .line {
  440. height: 40px;
  441. line-height: 40px;
  442. color: rgba(#666, 0.9);
  443. padding: 0 17px;
  444. overflow: hidden;
  445. // background-color: #f9f9f9;
  446. cursor: pointer;
  447. margin-bottom: 10px;
  448. position: relative;
  449. border-radius: 4px;
  450. &:hover {
  451. background-color: transparent;
  452. color: var(--color-primary);
  453. font-weight: 600;
  454. &::after {
  455. content: "";
  456. width: 100%;
  457. height: 100%;
  458. background-color: var(--color-primary);
  459. opacity: 0.05;
  460. position: absolute;
  461. left: 0;
  462. top: 0;
  463. }
  464. }
  465. }
  466. .drawerWrap {
  467. padding: 20px;
  468. .topline {
  469. border-top: 1px solid #dcdfe6;
  470. }
  471. }
  472. .guideLine {
  473. margin: 18px 0 0px;
  474. }
  475. .guideWrap {
  476. .guideH2 {
  477. font-size: 20px;
  478. font-weight: 600;
  479. color: #212121;
  480. line-height: 28px;
  481. }
  482. .guideItem {
  483. margin-bottom: 30px;
  484. .guideTitle {
  485. width: 160px;
  486. text-align: left;
  487. font-weight: bold;
  488. display: inline-block;
  489. font-size: 16px;
  490. font-weight: 600;
  491. color: #212121;
  492. line-height: 22px;
  493. margin-bottom: 10px;
  494. }
  495. .guideDesc {
  496. color: #666666;
  497. line-height: 20px;
  498. font-size: 14px;
  499. }
  500. .guideSet {
  501. font-size: 16px;
  502. }
  503. }
  504. }
  505. .dialogGuide {
  506. border-radius: 6px;
  507. ::v-deep .el-dialog__header {
  508. background-color: #fff;
  509. padding-top: 15px;
  510. padding-bottom: 0;
  511. .el-dialog__headerbtn {
  512. top: 28px;
  513. .el-icon {
  514. color: #999;
  515. font-size: 20px;
  516. // font-weight: bold;
  517. }
  518. }
  519. }
  520. .dialogHead {
  521. background-color: #fff;
  522. padding-top: 10px;
  523. }
  524. }
  525. /*设置字体的大小*/
  526. </style>
  527. <style scoped>
  528. .app-main {
  529. /*50 = navbar */
  530. /* height: calc(100vh - 80px); */
  531. /* height: 100vh; */
  532. padding-top: 90px;
  533. /* min-width: 1440px; */
  534. position: relative;
  535. /* overflow: auto; */
  536. box-sizing: border-box;
  537. margin-left: 20px;
  538. margin-top: 20px;
  539. }
  540. .fixed-header + .app-main {
  541. padding-top: 90px;
  542. }
  543. </style>
  544. <style lang="scss">
  545. // fix css style bug in open el-dialog
  546. .el-popup-parent--hidden {
  547. .fixed-header {
  548. // padding-right: 15px;
  549. }
  550. }
  551. .el-image-viewer__close {
  552. display: none !important;
  553. }
  554. </style>