index.vue 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601
  1. <template>
  2. <u-navbar :autoBack="false" :placeholder="true" :safeAreaInsetTop="true" :bgColor="proxy.$settingStore.themeColor.color">
  3. <template #left>
  4. <view class="u-navbar__content__left__item" v-if="tenantIdList.length == 1">
  5. <view class="u-navbar__content__left__item__title">应用中心</view>
  6. </view>
  7. <view v-if="tenantIdList.length > 1 && accountState">
  8. <image class="unit-change" src="@/static/images/index/unitChange.png" @click="showLeftStateClick()"></image>
  9. </view>
  10. </template>
  11. <template #center>
  12. <view class="u-navbar__content__left__item"> </view>
  13. </template>
  14. <template #right>
  15. <view class="u-navbar__content__left__item">
  16. <text class="iconfont oaIcon-jiahao font20" @click="rightButtonClick()"></text>
  17. </view>
  18. </template>
  19. </u-navbar>
  20. <!-- <u-no-network :zIndex="10080" @disconnected="disconnected" @connected="connected" @retry="retry"></u-no-network> -->
  21. <oa-scroll
  22. customClass="scroll-height"
  23. :customStyle="{ height: `calc(100vh - (104px + ${proxy.$settingStore.StatusBarHeight} + ${proxy.$settingStore.tabBarHeight}))` }"
  24. :refresherLoad="false"
  25. :refresherEnabled="true"
  26. :refresherEnabledTitle="false"
  27. :refresherDefaultStyle="'none'"
  28. :refresherThreshold="44"
  29. :refresherBackground="'#f5f6f7'"
  30. @refresh="refresh"
  31. >
  32. <template #default>
  33. <view class="home-container">
  34. <!-- 右侧弹窗 -->
  35. <u-transition :show="dialogFlag" :duration="200" mode="fade">
  36. <view class="transition" @click="rightButtonClick()">
  37. <view class="transition-section" :style="{ top: `calc(44px + ${proxy.$settingStore.StatusBarHeight})` }">
  38. <view class="transition-section-content" @click="scanCode()">
  39. <text class="transition-section-content-icon iconfont oaIcon-saoyisao"></text>
  40. <view class="transition-section-content-text"> 扫一扫 </view>
  41. </view>
  42. </view>
  43. </view>
  44. </u-transition>
  45. <!-- 轮播图 -->
  46. <u-swiper v-if="state.swiperBool" :list="state.swiperList" :interval="state.swiperTime" indicatorMode="line" radius="0" height="160" indicator circular keyName="url" @click="swiperClick">
  47. </u-swiper>
  48. <image v-if="!state.swiperBool" style="width: 100%; height: 160px" src="@/static/images/index/banner1.png"></image>
  49. <!-- 天气 -->
  50. <!-- #ifdef APP-PLUS || MP-WEIXIN || H5 -->
  51. <oa-weather ref="oaWeatherRef"></oa-weather>
  52. <!-- #endif -->
  53. <!-- 最近使用宫格 -->
  54. <view class="grid-area bg-white" v-if="state.recentlyUsed.length > 0">
  55. <view class="grid-area_title">最近使用</view>
  56. <view class="grid-area_center cu-list grid col-5 no-border">
  57. <view class="grid-area_center_item cu-item justify-center align-center" @tap="navItemClick(item)" v-for="(item, index) in state.recentlyUsed.slice(0, 5)" :key="index">
  58. <image class="grid-area_center_item_image" :src="item.meta.icon"></image>
  59. <text class="grid-area_center_item_title">{{ item.meta.aliasTitle ? item.meta.aliasTitle : item.meta.title }}</text>
  60. </view>
  61. </view>
  62. </view>
  63. <!-- 常用功能宫格 -->
  64. <view class="grid-area bg-white">
  65. <view class="grid-area_title">常用功能</view>
  66. <view class="grid-area_center cu-list grid col-5 no-border">
  67. <view class="grid-area_center_item cu-item justify-center align-center" @tap="navItemClick(item)" v-for="(item, index) in state.cuIconList" :key="index">
  68. <image class="grid-area_center_item_image" :src="item.meta.icon"></image>
  69. <text class="grid-area_center_item_title">{{ item.meta.aliasTitle ? item.meta.aliasTitle : item.meta.title }}</text>
  70. </view>
  71. </view>
  72. </view>
  73. </view>
  74. </template>
  75. </oa-scroll>
  76. <uni-drawer ref="showLeft" mode="left" style="height: calc(100vh - 44px); width: 90%; margin-top: 44px">
  77. <view class="unit">
  78. <view class="unit-title">切换企业</view>
  79. <view :class="item.id == useStore.tenantId ? 'active' : ''" class="list" v-for="(item, index) in tenantIdList" :key="index" @click="changeTenantId(item.id)">
  80. <image class="list-image" src="@/static/images/index/unit-active.png" v-if="item.id == useStore.tenantId"></image>
  81. <image class="list-image" src="@/static/images/index/unit.png" v-if="item.id != useStore.tenantId"></image>
  82. <text class="list-name">{{ item.tenantName }}</text>
  83. <image class="list-right" src="@/static/images/index/right.png" v-if="item.id == useStore.tenantId"></image>
  84. <text class="list-state">默认企业</text>
  85. </view>
  86. </view>
  87. </uni-drawer>
  88. <oa-tabbar :tabbarValue="0" :tabbarList="proxy.$constData.homeTabbar"></oa-tabbar>
  89. </template>
  90. <script setup>
  91. /*----------------------------------依赖引入-----------------------------------*/
  92. import { onReady, onLoad, onShow, onNavigationBarButtonTap, onPullDownRefresh, onReachBottom } from "@dcloudio/uni-app";
  93. import { ref, onMounted, inject, shallowRef, reactive, getCurrentInstance, toRefs, nextTick } from "vue";
  94. /*----------------------------------接口引入-----------------------------------*/
  95. import { scan_push, getHomePageData, getFunctionalModuleStatistics, getAppRouters, qrCodeSend, getMobileBanner } from "@/api/index";
  96. /*----------------------------------组件引入-----------------------------------*/
  97. import config from "@/config";
  98. /*----------------------------------store引入-----------------------------------*/
  99. import { useStores, commonStores } from "@/store/modules/index";
  100. /*----------------------------------公共方法引入-----------------------------------*/
  101. import * as jwx from "@/utils/jssdk.js"; //引入js sdk的封装
  102. import { getToken, setToken, removeToken } from "@/utils/auth";
  103. import { storage, storageSystem } from "@/utils/storage"; // 公共方法引用
  104. import { getTenantByUser } from "@/api/system/user.js";
  105. import { decrypt } from "@/plugins/jsencrypt";
  106. /*----------------------------------公共变量-----------------------------------*/
  107. const { proxy } = getCurrentInstance();
  108. const useStore = useStores();
  109. const commonStore = commonStores();
  110. /*----------------------------------变量声明-----------------------------------*/
  111. const accountState = ref(false); // 有效账号状态(用于企业切换)
  112. const showLeft = ref(false); // 左侧菜单
  113. const showLeftState = ref(false); // 左侧菜单显示状态
  114. const tenantIdChange = ref(""); // 切换租户ID
  115. const tenantIdList = ref([]); // 租户ID列表
  116. const state = reactive({
  117. dialogFlag: false,
  118. swiperBool: false,
  119. swiperIndex: 0,
  120. swiperTime: 5000,
  121. swiperList: [],
  122. cuIconList: [],
  123. recentlyUsed: [],
  124. });
  125. const { dialogFlag } = toRefs(state);
  126. /**
  127. * @企业弹框切换
  128. */
  129. function showLeftStateClick() {
  130. showLeftState.value = !showLeftState.value;
  131. if (showLeftState.value) {
  132. showDrawer();
  133. } else {
  134. closeDrawer();
  135. }
  136. }
  137. // 单位打开窗口
  138. function showDrawer() {
  139. showLeft.value.open();
  140. }
  141. // 单位关闭窗口
  142. function closeDrawer(e) {
  143. showLeft.value.close();
  144. }
  145. //获取企业列表
  146. function getTenantList(id) {
  147. getTenantByUser(id).then((res) => {
  148. tenantIdList.value = res.data;
  149. if (storage.get("account")?.userName && storage.get("account")?.passWord) {
  150. accountState.value = true;
  151. }
  152. });
  153. }
  154. /**
  155. * @企业切换
  156. */
  157. function changeTenantId(id) {
  158. storage.set("tenantId", id);
  159. var info = JSON.parse(
  160. JSON.stringify({
  161. userName: storage.get("account")?.userName,
  162. passWord: storage.get("account")?.passWord,
  163. tenantId: id,
  164. })
  165. );
  166. useStore.LogOut().then(() => {
  167. //#ifdef APP-PLUS
  168. uni.navigateTo({
  169. url: "/pages/index",
  170. });
  171. //#endif
  172. //#ifndef APP-PLUS
  173. //#endif
  174. if (localStorage.getItem("type")) {
  175. wx.miniProgram.navigateTo({
  176. appId: "wxf5ad8734295d43f8",
  177. url: "/pages/login?type=logout",
  178. });
  179. } else {
  180. useStore
  181. .Login({
  182. username: decrypt(info.userName),
  183. password: decrypt(info.passWord),
  184. tenantId: id,
  185. method: "switch",
  186. cids: proxy.$settingStore.pushClientId || undefined,
  187. type: proxy.$common.isWechatMp() ? "wx" : "app",
  188. openId: proxy.$common.isWechatMp() ? localStorage.getItem("wxOpenId") : undefined,
  189. })
  190. .then(() => {
  191. // /** 获取用户信息 */
  192. useStore.SET_STORAGE_OBJECT_KEYS({ tenantId: id });
  193. proxy.$modal.closeLoading();
  194. useStore.GetInfo().then((res) => {
  195. proxy.$settingStore.initThemeColor(storageSystem.get("themeColor")); //初始化默认主题
  196. init();
  197. closeDrawer();
  198. });
  199. });
  200. }
  201. });
  202. }
  203. /**
  204. * @初始化
  205. */
  206. async function init(options) {
  207. if (useStore?.userId) {
  208. tenantIdChange.value = useStore.tenantId; //切换租户ID
  209. getTenantList(useStore.userId); //调用获取企业列表方法
  210. }
  211. //#ifdef H5
  212. await useStore.GetWxOpenId(2, options); //调用获取微信公众号openId
  213. //#endif
  214. setTimeout(() => {
  215. getAppRoutersData(); //调用路由信息接口
  216. getMobileBannerApi(); //调用banner图接口
  217. getLocation(); //调用获取地理位置方法
  218. }, 1000);
  219. //#ifdef APP-PLUS
  220. proxy.$settingStore.baseAppInfo(), setInterval(proxy.$settingStore.baseAppInfo, 1000 * 60 * 5); //动态获取用户设备信息
  221. proxy.$settingStore.openWebSocket(); //开启WebSocket
  222. //#endif
  223. }
  224. /**
  225. * @轮播图点击事件
  226. */
  227. function swiperClick(list) {
  228. if (typeof state.swiperList[list] == "object") {
  229. let linkType = state.swiperList[list].linkType;
  230. let url = state.swiperList[list].link;
  231. if (url) {
  232. if (linkType == 1) {
  233. uni.navigateTo({
  234. url: url,
  235. });
  236. } else {
  237. uni.navigateTo({
  238. url: "/pages/common/webview/index?url=" + url,
  239. });
  240. }
  241. }
  242. }
  243. }
  244. /**
  245. * @九宫格页面跳转
  246. */
  247. function navItemClick(item) {
  248. if (item.path) {
  249. item.sort = 0;
  250. state.recentlyUsed.push(item);
  251. state.recentlyUsed = proxy.$common.uniq(state.recentlyUsed, "path");
  252. state.recentlyUsed.filter((el) => {
  253. if (el.path === item.path) {
  254. el.meta.icon = item.meta.icon;
  255. el.meta.title = item.meta.title;
  256. el.sort++;
  257. }
  258. });
  259. state.recentlyUsed = proxy.$common.sortEvent(state.recentlyUsed, 1);
  260. storageSystem.set("homeList", state);
  261. if (item.path.indexOf("http") != -1) {
  262. uni.navigateTo({
  263. url: "/pages/common/webview/index?url=" + item.path,
  264. });
  265. } else {
  266. uni.navigateTo({
  267. url: item.path,
  268. });
  269. }
  270. } else {
  271. uni.showModal({
  272. title: "Tips",
  273. content: "此模块开发中~",
  274. showCancel: false,
  275. success: function (res) {
  276. if (res.confirm) {
  277. } else if (res.cancel) {
  278. }
  279. },
  280. });
  281. }
  282. }
  283. // function connected() {
  284. // refresh();
  285. // uni.setNavigationBarColor({
  286. // frontColor: "#FFFFFF", //字体颜色
  287. // });
  288. // }
  289. // function disconnected() {
  290. // uni.setNavigationBarColor({
  291. // frontColor: "#000000", //字体颜色
  292. // });
  293. // }
  294. /**
  295. * @scrollView刷新数据
  296. */
  297. function refresh() {
  298. getAppRoutersData(); //调用路由信息接口
  299. getMobileBannerApi(); //调用banner图接口
  300. getLocation(); //调用获取地理位置方法
  301. }
  302. /**
  303. * @扫码功能
  304. */
  305. function scanCode() {
  306. //#ifdef H5 || MP-WEIXIN
  307. jwx.configWeiXin((jweixin) => {
  308. jweixin.scanQRCode({
  309. needResult: 1, // 默认为0,扫描结果由微信处理,1则直接返回扫描结果,
  310. scanType: ["qrCode", "barCode"], // 可以指定扫二维码还是一维码,默认二者都有
  311. success: function (res) {
  312. setTimeout(function () {
  313. scan_push({ ercode: res.resultStr }).then((res) => {
  314. if (res.data.flag) {
  315. uni.showToast({
  316. title: "扫码成功",
  317. icon: "none",
  318. });
  319. }
  320. });
  321. }, 1000);
  322. },
  323. });
  324. });
  325. //#endif
  326. //#ifdef APP-PLUS
  327. uni.scanCode({
  328. autoZoom: false,
  329. scanType: ["qrCode"],
  330. success: (res) => {
  331. let list = JSON.parse(res.result);
  332. uni.showToast({
  333. title: "扫码成功",
  334. icon: "none",
  335. });
  336. qrCodeSend({
  337. qrCode: list.uid,
  338. tenantId: useStore.tenantId,
  339. userName: useStore.name,
  340. }).then((res) => {});
  341. },
  342. fail: (err) => {
  343. console.log("扫码失败", err);
  344. },
  345. complete: () => {
  346. console.log("扫码结束");
  347. },
  348. });
  349. //#endif
  350. }
  351. /**
  352. * @获取地理位置
  353. */
  354. function getLocation() {
  355. var latitude = proxy.$settingStore.deviceList.latitude;
  356. var longitude = proxy.$settingStore.deviceList.longitude;
  357. //#ifdef H5 || MP-WEIXIN
  358. // jwx.configWeiXin((jweixin) => {
  359. // // 微信公众号获取位置
  360. // jweixin.getLocation({
  361. // type: "gcj02", // 默认为wgs84的gps坐标,如果要返回直接给openLocation用的火星坐标,可传入'gcj02'
  362. // success: function (res) {
  363. // alert(res.longitude);
  364. // },
  365. // });
  366. // });
  367. proxy.$refs["oaWeatherRef"].getWeather("上海");
  368. //#endif
  369. //#ifdef APP-PLUS
  370. if (latitude && longitude) {
  371. proxy.$refs["oaWeatherRef"].getWeather(latitude + ":" + longitude);
  372. } else {
  373. proxy.$refs["oaWeatherRef"].getWeather("上海");
  374. }
  375. //#endif
  376. }
  377. /**
  378. * @右侧按钮点击事件
  379. */
  380. function rightButtonClick() {
  381. dialogFlag.value = !dialogFlag.value;
  382. }
  383. /**
  384. * @轮播图
  385. * @api接口请求
  386. */
  387. function getMobileBannerApi() {
  388. getMobileBanner({
  389. tenantId: useStore.tenantId,
  390. }).then((res) => {
  391. if (res.data.length > 0) {
  392. state.swiperList = [];
  393. state.swiperBool = res.data[0].openNot == 1 ? true : false;
  394. state.swiperTime = res.data[0].carouselTime * 1000;
  395. for (let i = 1; i <= 5; i++) {
  396. if (res.data[0]["bannerPath" + i]) {
  397. state.swiperList.push({
  398. url: res.data[0]["bannerPath" + i],
  399. link: res.data[0]["linkUrl" + i],
  400. linkType: res.data[0]["linkType" + i],
  401. type: "image",
  402. });
  403. }
  404. }
  405. }
  406. });
  407. }
  408. /**
  409. * @获取路由信息
  410. * @api接口请求
  411. */
  412. function getAppRoutersData() {
  413. getAppRouters().then((res) => {
  414. state.cuIconList = res.data;
  415. storageSystem.set("homeList", state);
  416. });
  417. }
  418. onLoad((options) => {
  419. uni.hideTabBar(); //隐藏自带tabbar
  420. init(options);
  421. });
  422. onShow(() => {
  423. var storages = storageSystem.get("homeList");
  424. Object.keys(storages).forEach((key) => {
  425. state[key] = storages[key];
  426. });
  427. });
  428. </script>
  429. <style lang="scss" scoped>
  430. .home-container {
  431. .transition {
  432. position: fixed;
  433. top: 0;
  434. left: 0;
  435. right: 0;
  436. bottom: 0;
  437. z-index: 1100;
  438. &-section {
  439. position: absolute;
  440. top: 10px;
  441. right: 15px;
  442. background-color: #fff;
  443. border-radius: 10px;
  444. box-shadow: 0px 0px 15px 0 rgba(0, 0, 0, 0.2);
  445. &-divider {
  446. border-bottom: 0.5px rgba(0, 0, 0, 0.1) solid;
  447. margin: 0 20px;
  448. }
  449. &-content {
  450. display: flex;
  451. padding: 15px 20px;
  452. &-icon {
  453. font-size: 18px;
  454. color: #000;
  455. }
  456. &-text {
  457. margin: 0 20px;
  458. }
  459. }
  460. &-content:first-child {
  461. padding-top: 15px;
  462. border-radius: 10px 10px 0 0;
  463. }
  464. &-content:last-child {
  465. padding-bottom: 15px;
  466. border-radius: 0 0 10px 10px;
  467. }
  468. &-content:hover {
  469. // transform: 3s;
  470. // transition: all 600ms cubic-bezier(0.3, 1, 0.2, 1);
  471. transition: all 3s cubic-bezier(0.7, -0.5, 0.2, 2);
  472. background-color: rgba(0, 0, 0, 0.1);
  473. }
  474. }
  475. }
  476. .grid-area {
  477. margin-bottom: 10px;
  478. &_title {
  479. padding: 10px 10px 5px 10px;
  480. color: #000000;
  481. font-size: $uni-font-size-base;
  482. }
  483. &_center {
  484. &_item {
  485. &_image {
  486. width: 40px;
  487. height: 40px;
  488. }
  489. &_title {
  490. font-size: $uni-font-size-sm;
  491. }
  492. }
  493. }
  494. }
  495. }
  496. .unit-change {
  497. width: 18px;
  498. height: 18px;
  499. position: fixed;
  500. top: 12px;
  501. left: 12px;
  502. }
  503. .unit {
  504. width: 100vw !important;
  505. height: 100%;
  506. background: #0d2e59;
  507. position: fixed;
  508. top: 0px;
  509. left: 0%;
  510. &-title {
  511. margin: 15px 0 10px 10px;
  512. color: #fff;
  513. }
  514. .list {
  515. margin-top: 10px;
  516. padding: 10px;
  517. position: relative;
  518. width: 90%;
  519. &-image {
  520. width: 29px;
  521. height: 29px;
  522. vertical-align: middle;
  523. margin-right: 10px;
  524. }
  525. &-name {
  526. vertical-align: middle;
  527. color: #fff;
  528. width: 60%;
  529. display: inline-block;
  530. white-space: nowrap; /* 防止文本换行 */
  531. overflow: hidden; /* 隐藏超出容器的文本 */
  532. text-overflow: ellipsis; /* 显示省略号以代表被隐藏的文本 */
  533. }
  534. &-right {
  535. position: absolute;
  536. top: 38%;
  537. right: 30%;
  538. width: 16px;
  539. height: 11px;
  540. vertical-align: middle;
  541. }
  542. &-state {
  543. position: absolute;
  544. right: 20px;
  545. top: 16px;
  546. font-size: 12px;
  547. color: #2a98ff;
  548. }
  549. &-state.active {
  550. color: #999;
  551. }
  552. }
  553. .list.active {
  554. background: #193b61;
  555. }
  556. }
  557. </style>