apply.vue 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583
  1. <template>
  2. <view class="apply-v">
  3. <view class="nav-bar-box">
  4. <uni-nav-bar :fixed="true" :statusBar="true" :border="false" left-icon="bars"
  5. @clickLeft="showSelectBox('left')" height="44px">
  6. <block #default>
  7. <view class="nav-left" @click="showSelectBox('center')">
  8. <view class="nav-left-text">{{ selectData.name }}</view>
  9. <uni-icons class="right-icons" type="down" color="#000000" size="14"
  10. v-if="userInfo.systemIds.length > 1" :class="{ 'select-right-icons': showSelect }" />
  11. </view>
  12. </block>
  13. </uni-nav-bar>
  14. </view>
  15. <view class="notice-warp" :style="{'top':topSearch,'height':noticeWarpH+'px'}">
  16. <view class="search-box">
  17. <u-search :placeholder="$t('app.apply.pleaseKeyword')" v-model="keyword" height="72"
  18. :show-action="false" @change="search" bg-color="#f0f2f6" shape="square">
  19. </u-search>
  20. </view>
  21. </view>
  22. <mescroll-body ref="mescrollRef" @down="downCallback" :down="downOption" :sticky="false" @up="upCallback"
  23. :up="upOption" :bottombar="false" @init="mescrollInit" :top="mescrollTop">
  24. <view class="common-block">
  25. <view class="caption u-flex">
  26. <text class="caption-left">常用菜单</text>
  27. <view class="u-flex" @click="openPage">
  28. <text class="caption-right">{{$t('common.moreText')}}</text>
  29. <u-icon name="arrow-right" size="24"></u-icon>
  30. </view>
  31. </view>
  32. <view class="u-flex u-flex-wrap">
  33. <view class="item u-flex-col u-col-center" v-for="(item, i) in usualList" :key="i"
  34. @click="handelClick(item)">
  35. <text class="u-font-40 item-icon" :class="item.icon"
  36. :style="{ background: item.iconBackground || '#008cff' }" />
  37. <text class="u-font-24 u-line-1 item-text">{{ item.fullName}}</text>
  38. </view>
  39. <view class="item u-flex-col u-col-center" @click="moreApp">
  40. <text class="u-font-40 item-icon more">+</text>
  41. <text class="u-font-24 u-line-1 item-text">添加</text>
  42. </view>
  43. </view>
  44. </view>
  45. <view class="workFlow-list">
  46. <view class="part" v-for="(item, i) in menuList" :key="i">
  47. <view class="caption u-line-1" v-if="item?.children?.length">
  48. {{ item.fullName }}
  49. </view>
  50. <view class="u-flex u-flex-wrap">
  51. <view class="item u-flex-col u-col-center" v-for="(child, ii) in item.children" :key="ii"
  52. @click="handelClick(child)">
  53. <text class="u-font-40 item-icon" :class="child.icon"
  54. :style="{ background: child.iconBackground || '#008cff' }" />
  55. <text class="u-font-24 u-line-1 item-text">{{child.fullName}}</text>
  56. </view>
  57. </view>
  58. </view>
  59. </view>
  60. </mescroll-body>
  61. <uni-popup ref="popup" background-color="#fff" @change="popupChange">
  62. <!-- #ifdef MP -->
  63. <view :style="{ 'margin-top': statusBarHeight + 226 + 'rpx' }"></view>
  64. <!-- #endif -->
  65. <!-- #ifndef MP -->
  66. <view :style="{ 'margin-top': statusBarHeight + 220+ 'rpx' }"></view>
  67. <!-- #endif -->
  68. <view class="notice-warp" :style="{'top':topSearch,'height':noticeWarpH+'px'}">
  69. <view class="search-box">
  70. <u-search :placeholder="$t('app.apply.pleaseKeyword')" v-model="systemKeyword" height="72"
  71. :show-action="false" @change="onSearchInput" bg-color="#f0f2f6" shape="square">
  72. </u-search>
  73. </view>
  74. </view>
  75. <view class="item popupItem">
  76. <view v-for="(item, index) in filteredList" :key="index" class="select-item"
  77. @click="selectItem(item, index)" v-if="filteredList.length">
  78. <text class="u-m-r-12 u-font-40"
  79. :class="[item.icon, { currentItem: item.id === userInfo.appSystemId }]" />
  80. <text class="item-text sysName"
  81. :class="{ currentItem: item.id === userInfo.appSystemId }">{{ item.name }}</text>
  82. <u-icon name="checkbox-mark " class="currentItem" v-if="item.id === userInfo.appSystemId"></u-icon>
  83. </view>
  84. </view>
  85. </uni-popup>
  86. <treeCollapse :show="showApply" v-if="showApply" :treeData="menuList" @change="handelClick">
  87. <!-- #ifdef APP -->
  88. <view :style="{ 'margin-top': statusBarHeight + 40 + 'rpx' }"></view>
  89. <!-- #endif -->
  90. </treeCollapse>
  91. </view>
  92. </template>
  93. <script>
  94. import {
  95. getMenuList,
  96. getUsualList,
  97. getChildList
  98. } from "@/api/apply/apply.js";
  99. import treeCollapse from '@/components/treeCollapse'
  100. import {
  101. setMajor,
  102. updatePassword,
  103. getSystemConfig,
  104. } from "@/api/common";
  105. import resources from "@/libs/resources.js";
  106. import MescrollMixin from "@/uni_modules/mescroll-uni/components/mescroll-uni/mescroll-mixins.js";
  107. import IndexMixin from "./mixin.js";
  108. import {
  109. useUserStore
  110. } from '@/store/modules/user'
  111. import {
  112. useChatStore
  113. } from '@/store/modules/chat'
  114. export default {
  115. mixins: [MescrollMixin, IndexMixin],
  116. components: {
  117. treeCollapse
  118. },
  119. data() {
  120. return {
  121. mescrollTop: 198,
  122. systemKeyword: '',
  123. showApply: false,
  124. topSearch: '80px',
  125. appTopHeight: 0,
  126. usualList: [],
  127. menuList: [],
  128. downOption: {
  129. use: true,
  130. auto: true,
  131. },
  132. upOption: {
  133. page: {
  134. num: 0,
  135. size: 50,
  136. time: null,
  137. },
  138. empty: {
  139. use: true,
  140. icon: resources.message.nodata,
  141. tip: this.$t('common.noData'),
  142. fixed: false,
  143. top: "560rpx",
  144. },
  145. textNoMore: this.$t('app.apply.noMoreData'),
  146. },
  147. keyword: "",
  148. statusBarHeight: "",
  149. userInfo: {
  150. systemIds: [],
  151. },
  152. showSelect: false,
  153. selectData: {
  154. name: "",
  155. id: "",
  156. },
  157. modelId: "",
  158. fullName: "",
  159. key: +new Date(),
  160. listChild: [],
  161. height: 0,
  162. noticeWarpH: 0
  163. };
  164. },
  165. computed: {
  166. baseURL() {
  167. return this.define.baseURL;
  168. },
  169. token() {
  170. return uni.getStorageSync('token')
  171. },
  172. report() {
  173. return this.define.report;
  174. },
  175. hasChildren() {
  176. let hasChildren = false
  177. for (let i = 0; i < this.menuList.length; i++) {
  178. if (this.menuList[i].children && this.menuList[i].children.length) {
  179. hasChildren = true
  180. break
  181. }
  182. }
  183. return hasChildren
  184. },
  185. filteredList() {
  186. return this.userInfo.systemIds.filter(item => {
  187. return item.name.includes(this.systemKeyword);
  188. });
  189. }
  190. },
  191. onShow() {
  192. this.keyword = "";
  193. this.systemKeyword = ''
  194. this.$nextTick(() => {
  195. this.mescroll.resetUpScroll();
  196. })
  197. },
  198. mounted() {
  199. this.getContentHeight()
  200. },
  201. onLoad() {
  202. uni.$on('updateUsualList', data => {
  203. this.getUsualList()
  204. })
  205. uni.$on('refresh', () => {
  206. this.menuList = [];
  207. this.mescroll.resetUpScroll();
  208. });
  209. },
  210. onUnload() {
  211. uni.$off("updateUsualList");
  212. },
  213. methods: {
  214. async getContentHeight() {
  215. const windowHeight = this.$u.sys().windowHeight;
  216. // 获取元素尺寸
  217. const [navBarHeight, noticeWarpRect, searchBoxRect, stickyBoxTabsRect] = await Promise.all([
  218. this.$uGetRect('.nav-bar-box'),
  219. this.$uGetRect('.notice-warp'),
  220. this.$uGetRect('.search-box')
  221. ]);
  222. // 计算高度
  223. const appTopHeight = navBarHeight.height;
  224. const searchBoxHeight = searchBoxRect.height;
  225. // 设置组件数据
  226. this.topSearch = `${appTopHeight}px`;
  227. this.appTopHeight = appTopHeight;
  228. this.noticeWarpH = `${searchBoxHeight}`;
  229. this.mescrollTop = appTopHeight + searchBoxHeight;
  230. // #ifdef MP
  231. this.mescrollTop = 54 + searchBoxHeight;
  232. // #endif
  233. },
  234. popupChange(e) {
  235. this.showSelect = e.show
  236. },
  237. showSelectBox(type) {
  238. if (type === 'center' && this.userInfo.systemIds.length > 1) {
  239. if (this.showApply) this.showApply = false
  240. if (this.showSelect) this.$refs.popup.close();
  241. this.$refs.popup.open('top')
  242. }
  243. if (type === 'left' && this.menuList.length) {
  244. if (this.showSelect) this.$refs.popup.close()
  245. this.showApply = !this.showApply;
  246. }
  247. },
  248. handelClick(item) {
  249. this.showApply = false
  250. if (item.type == 1) {
  251. getChildList(item.id).then(res => {
  252. this.listChild = res.data || []
  253. this.handleProperty(this.listChild)
  254. this.$nextTick(() => {
  255. uni.navigateTo({
  256. url: "/pages/apply/catalog/index?config=" +
  257. this.jnpf.base64.encode(JSON.stringify(this.listChild[0])),
  258. fail: (err) => {
  259. this.$u.toast("暂无此页面");
  260. },
  261. });
  262. })
  263. })
  264. return;
  265. }
  266. if (item.type == 2) {
  267. uni.navigateTo({
  268. url: item.urlAddress +
  269. "?menuId=" +
  270. item.id +
  271. "&fullName=" +
  272. item.fullName,
  273. fail: (err) => {
  274. this.$u.toast("暂无此页面");
  275. },
  276. });
  277. return;
  278. }
  279. if (item.type == 3 || item.type == 9) {
  280. this.modelId = item.moduleId;
  281. if (!item.moduleId) {
  282. this.$u.toast("暂无此页面");
  283. return;
  284. }
  285. uni.navigateTo({
  286. url: "/pages/apply/dynamicModel/index?config=" +
  287. this.jnpf.base64.encode(JSON.stringify(item)),
  288. fail: (err) => {
  289. this.$u.toast("暂无此页面");
  290. },
  291. });
  292. }
  293. if (item.type == 7 || item.type == 5) {
  294. let url =
  295. encodeURIComponent(item.urlAddress) + "&fullName=" + item.fullName;
  296. if (item.type == 5) {
  297. url = encodeURIComponent(
  298. `${this.report}/preview.html?id=${item.moduleId}&token=${this.token}&page=1&from=menu`
  299. );
  300. }
  301. if (!item.urlAddress && item.type == 7) {
  302. this.$u.toast("暂无此页面");
  303. return;
  304. }
  305. uni.navigateTo({
  306. url: "/pages/apply/externalLink/index?url=" +
  307. url +
  308. "&fullName=" +
  309. item.fullName +
  310. "&type=" +
  311. item.type,
  312. fail: (err) => {
  313. this.$u.toast("暂无此页面");
  314. },
  315. });
  316. return;
  317. }
  318. if (item.type == 8) {
  319. if (!item.urlAddress) {
  320. this.$u.toast("暂无此页面");
  321. return;
  322. }
  323. uni.navigateTo({
  324. url: "/pages/portal/scanPortal/index?id=" + item.moduleId + "&portalType=1&fullName=" +
  325. item.fullName,
  326. fail: (err) => {
  327. this.$u.toast("暂无此页面");
  328. },
  329. });
  330. return
  331. }
  332. },
  333. openPage() {
  334. uni.navigateTo({
  335. url: '/pages/commonPage/morePage/index?type=2',
  336. });
  337. },
  338. onSearchInput(value) {
  339. this.systemKeyword = value;
  340. },
  341. initSysList(res) {
  342. this.userInfo = res;
  343. if (this.userInfo.systemIds && this.userInfo.systemIds.length) {
  344. this.userInfo.systemIds.forEach((item) => {
  345. if (item.id == this.userInfo.appSystemId) this.selectData = item
  346. });
  347. }
  348. getSystemConfig().then((res) => {
  349. this.baseForm = res.data;
  350. });
  351. },
  352. processObject(obj) {
  353. const objectDataParsed = obj.objectData ? JSON.parse(obj.objectData) : {};
  354. const propertyJsonParsed = JSON.parse(obj.propertyJson);
  355. const moduleId = propertyJsonParsed.moduleId || "";
  356. this.$set(obj, "moduleId", moduleId);
  357. return {
  358. ...obj,
  359. ...objectDataParsed,
  360. };
  361. },
  362. getUsualList() {
  363. getUsualList(2).then((res) => {
  364. // 使用 map 方法处理 res.data.list 中的每个对象
  365. let list = res.data.list.map(o => (this.processObject(o))).slice(0, 11);
  366. // 更新 usualList
  367. this.usualList = [...list];
  368. });
  369. },
  370. upCallback(keyword) {
  371. let query = {
  372. keyword: this.keyword,
  373. };
  374. uni.showLoading({
  375. title: '正在加载',
  376. mask: true
  377. })
  378. const userStore = useUserStore()
  379. userStore.getCurrentUser().then((res) => {
  380. this.initSysList(res);
  381. this.getUsualList();
  382. getMenuList(query)
  383. .then((res) => {
  384. let list = res.data.list || [];
  385. this.mescroll.endSuccess(list.length);
  386. this.list = list.filter(o => o.children && o.children.length)
  387. this.menuList = this.list;
  388. this.handleProperty(this.list)
  389. uni.hideLoading()
  390. this.key = +new Date();
  391. this.mescroll.endSuccess(this.menuList.length, false);
  392. }).catch(() => {
  393. this.mescroll.endSuccess(0);
  394. this.mescroll.endErr();
  395. });
  396. });
  397. },
  398. handleProperty(list) {
  399. const loop = (par) => {
  400. par.map(o => {
  401. if (o?.propertyJson) {
  402. let propertyJson = JSON.parse(o.propertyJson);
  403. this.$set(o, "iconBackground", propertyJson.iconBackgroundColor || "");
  404. this.$set(o, "moduleId", propertyJson.moduleId || "");
  405. }
  406. if (o?.children && o?.children?.length) loop(o.children)
  407. })
  408. }
  409. loop(list)
  410. },
  411. search() {
  412. this.searchTimer && clearTimeout(this.searchTimer);
  413. this.searchTimer = setTimeout(() => {
  414. this.list = [];
  415. this.menuList = [];
  416. this.mescroll.resetUpScroll();
  417. }, 300);
  418. },
  419. moreApp() {
  420. uni.navigateTo({
  421. url: "/pages/commonPage/allApp/index?type=2",
  422. });
  423. },
  424. selectItem(item, index) {
  425. if (item.id === this.userInfo.appSystemId) return
  426. let query = {
  427. majorId: item.id,
  428. majorType: "System",
  429. menuType: 1,
  430. };
  431. setMajor(query).then((res) => {
  432. if (res.code == 200) {
  433. this.changeSelData(item, index);
  434. this.keyword = "";
  435. this.systemKeyword = "";
  436. this.$u.toast(res.msg);
  437. this.$nextTick(() => {
  438. this.mescroll.resetUpScroll();
  439. })
  440. }
  441. }).catch((err) => {
  442. this.$u.toast(err);
  443. setTimeout(() => {
  444. this.$nextTick(() => {
  445. this.mescroll.resetUpScroll();
  446. })
  447. }, 1200)
  448. });
  449. },
  450. changeSelData(item, index) {
  451. this.selectData = item
  452. this.userInfo.appSystemId = item.id
  453. this.$refs.popup.close()
  454. },
  455. getFullName(item) {
  456. if (!item.enCode) return item.name;
  457. return this.$t('routes.' + item.enCode.replace(/\./g, '-'));
  458. }
  459. },
  460. };
  461. </script>
  462. <style lang="scss">
  463. page {
  464. background-color: #f0f2f6;
  465. }
  466. .apply-v {
  467. .notice-warp {
  468. width: 100%;
  469. .search-box {
  470. height: 120rpx;
  471. padding: 0rpx 20rpx;
  472. display: flex;
  473. align-items: center;
  474. }
  475. }
  476. .common-block {
  477. background-color: #fff;
  478. margin: 20rpx 0;
  479. .caption {
  480. padding: 0 32rpx;
  481. line-height: 100rpx;
  482. justify-content: space-between;
  483. .caption-left {
  484. font-size: 36rpx;
  485. font-weight: bold;
  486. }
  487. .caption-right {}
  488. }
  489. .item {
  490. margin-bottom: 32rpx;
  491. width: 25%;
  492. .item-icon {
  493. width: 88rpx;
  494. height: 88rpx;
  495. margin-bottom: 8rpx;
  496. line-height: 82rpx;
  497. text-align: center;
  498. border-radius: 30rpx;
  499. color: #fff;
  500. font-size: 40rpx;
  501. &.more {
  502. background: #ececec;
  503. color: #666666;
  504. font-size: 50rpx;
  505. }
  506. }
  507. .item-text {
  508. width: 100%;
  509. text-align: center;
  510. padding: 0 16rpx;
  511. }
  512. }
  513. }
  514. .select-box {
  515. max-height: 600rpx;
  516. :deep(.u-drawer-content) {
  517. height: 100% !important;
  518. }
  519. }
  520. .popupItem {
  521. height: 400rpx;
  522. overflow-y: scroll;
  523. /* #ifdef APP-HARMONY */
  524. padding-top: 40rpx;
  525. /* #endif */
  526. }
  527. .item {
  528. .currentItem {
  529. color: #2979ff;
  530. }
  531. .select-item {
  532. height: 100rpx;
  533. display: flex;
  534. align-items: center;
  535. padding: 0 20rpx;
  536. font-size: 30rpx;
  537. color: #303133;
  538. text-align: left;
  539. position: relative;
  540. &::after {
  541. content: " ";
  542. position: absolute;
  543. left: 2%;
  544. top: 0;
  545. box-sizing: border-box;
  546. width: 96%;
  547. height: 1px;
  548. transform: scale(1, 0.3);
  549. border: 0 solid #e4e7ed;
  550. z-index: 2;
  551. border-bottom-width: 1px;
  552. }
  553. .sysName {
  554. flex: 1;
  555. overflow: auto;
  556. min-width: 0;
  557. }
  558. }
  559. }
  560. }
  561. </style>