index.vue 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600
  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.sort++;
  256. }
  257. });
  258. state.recentlyUsed = proxy.$common.sortEvent(state.recentlyUsed, 1);
  259. storageSystem.set("homeList", state);
  260. if (item.path.indexOf("http") != -1) {
  261. uni.navigateTo({
  262. url: "/pages/common/webview/index?url=" + item.path,
  263. });
  264. } else {
  265. uni.navigateTo({
  266. url: item.path,
  267. });
  268. }
  269. } else {
  270. uni.showModal({
  271. title: "Tips",
  272. content: "此模块开发中~",
  273. showCancel: false,
  274. success: function (res) {
  275. if (res.confirm) {
  276. } else if (res.cancel) {
  277. }
  278. },
  279. });
  280. }
  281. }
  282. // function connected() {
  283. // refresh();
  284. // uni.setNavigationBarColor({
  285. // frontColor: "#FFFFFF", //字体颜色
  286. // });
  287. // }
  288. // function disconnected() {
  289. // uni.setNavigationBarColor({
  290. // frontColor: "#000000", //字体颜色
  291. // });
  292. // }
  293. /**
  294. * @scrollView刷新数据
  295. */
  296. function refresh() {
  297. getAppRoutersData(); //调用路由信息接口
  298. getMobileBannerApi(); //调用banner图接口
  299. getLocation(); //调用获取地理位置方法
  300. }
  301. /**
  302. * @扫码功能
  303. */
  304. function scanCode() {
  305. //#ifdef H5 || MP-WEIXIN
  306. jwx.configWeiXin((jweixin) => {
  307. jweixin.scanQRCode({
  308. needResult: 1, // 默认为0,扫描结果由微信处理,1则直接返回扫描结果,
  309. scanType: ["qrCode", "barCode"], // 可以指定扫二维码还是一维码,默认二者都有
  310. success: function (res) {
  311. setTimeout(function () {
  312. scan_push({ ercode: res.resultStr }).then((res) => {
  313. if (res.data.flag) {
  314. uni.showToast({
  315. title: "扫码成功",
  316. icon: "none",
  317. });
  318. }
  319. });
  320. }, 1000);
  321. },
  322. });
  323. });
  324. //#endif
  325. //#ifdef APP-PLUS
  326. uni.scanCode({
  327. autoZoom: false,
  328. scanType: ["qrCode"],
  329. success: (res) => {
  330. let list = JSON.parse(res.result);
  331. uni.showToast({
  332. title: "扫码成功",
  333. icon: "none",
  334. });
  335. qrCodeSend({
  336. qrCode: list.uid,
  337. tenantId: useStore.tenantId,
  338. userName: useStore.name,
  339. }).then((res) => {});
  340. },
  341. fail: (err) => {
  342. console.log("扫码失败", err);
  343. },
  344. complete: () => {
  345. console.log("扫码结束");
  346. },
  347. });
  348. //#endif
  349. }
  350. /**
  351. * @获取地理位置
  352. */
  353. function getLocation() {
  354. var latitude = proxy.$settingStore.deviceList.latitude;
  355. var longitude = proxy.$settingStore.deviceList.longitude;
  356. //#ifdef H5 || MP-WEIXIN
  357. // jwx.configWeiXin((jweixin) => {
  358. // // 微信公众号获取位置
  359. // jweixin.getLocation({
  360. // type: "gcj02", // 默认为wgs84的gps坐标,如果要返回直接给openLocation用的火星坐标,可传入'gcj02'
  361. // success: function (res) {
  362. // alert(res.longitude);
  363. // },
  364. // });
  365. // });
  366. proxy.$refs["oaWeatherRef"].getWeather("上海");
  367. //#endif
  368. //#ifdef APP-PLUS
  369. if (latitude && longitude) {
  370. proxy.$refs["oaWeatherRef"].getWeather(latitude + ":" + longitude);
  371. } else {
  372. proxy.$refs["oaWeatherRef"].getWeather("上海");
  373. }
  374. //#endif
  375. }
  376. /**
  377. * @右侧按钮点击事件
  378. */
  379. function rightButtonClick() {
  380. dialogFlag.value = !dialogFlag.value;
  381. }
  382. /**
  383. * @轮播图
  384. * @api接口请求
  385. */
  386. function getMobileBannerApi() {
  387. getMobileBanner({
  388. tenantId: useStore.tenantId,
  389. }).then((res) => {
  390. if (res.data.length > 0) {
  391. state.swiperList = [];
  392. state.swiperBool = res.data[0].openNot == 1 ? true : false;
  393. state.swiperTime = res.data[0].carouselTime * 1000;
  394. for (let i = 1; i <= 5; i++) {
  395. if (res.data[0]["bannerPath" + i]) {
  396. state.swiperList.push({
  397. url: res.data[0]["bannerPath" + i],
  398. link: res.data[0]["linkUrl" + i],
  399. linkType: res.data[0]["linkType" + i],
  400. type: "image",
  401. });
  402. }
  403. }
  404. }
  405. });
  406. }
  407. /**
  408. * @获取路由信息
  409. * @api接口请求
  410. */
  411. function getAppRoutersData() {
  412. getAppRouters().then((res) => {
  413. state.cuIconList = res.data;
  414. storageSystem.set("homeList", state);
  415. });
  416. }
  417. onLoad((options) => {
  418. uni.hideTabBar(); //隐藏自带tabbar
  419. init(options);
  420. });
  421. onShow(() => {
  422. var storages = storageSystem.get("homeList");
  423. Object.keys(storages).forEach((key) => {
  424. state[key] = storages[key];
  425. });
  426. });
  427. </script>
  428. <style lang="scss" scoped>
  429. .home-container {
  430. .transition {
  431. position: fixed;
  432. top: 0;
  433. left: 0;
  434. right: 0;
  435. bottom: 0;
  436. z-index: 1100;
  437. &-section {
  438. position: absolute;
  439. top: 10px;
  440. right: 15px;
  441. background-color: #fff;
  442. border-radius: 10px;
  443. box-shadow: 0px 0px 15px 0 rgba(0, 0, 0, 0.2);
  444. &-divider {
  445. border-bottom: 0.5px rgba(0, 0, 0, 0.1) solid;
  446. margin: 0 20px;
  447. }
  448. &-content {
  449. display: flex;
  450. padding: 15px 20px;
  451. &-icon {
  452. font-size: 18px;
  453. color: #000;
  454. }
  455. &-text {
  456. margin: 0 20px;
  457. }
  458. }
  459. &-content:first-child {
  460. padding-top: 15px;
  461. border-radius: 10px 10px 0 0;
  462. }
  463. &-content:last-child {
  464. padding-bottom: 15px;
  465. border-radius: 0 0 10px 10px;
  466. }
  467. &-content:hover {
  468. // transform: 3s;
  469. // transition: all 600ms cubic-bezier(0.3, 1, 0.2, 1);
  470. transition: all 3s cubic-bezier(0.7, -0.5, 0.2, 2);
  471. background-color: rgba(0, 0, 0, 0.1);
  472. }
  473. }
  474. }
  475. .grid-area {
  476. margin-bottom: 10px;
  477. &_title {
  478. padding: 10px 10px 5px 10px;
  479. color: #000000;
  480. font-size: $uni-font-size-base;
  481. }
  482. &_center {
  483. &_item {
  484. &_image {
  485. width: 40px;
  486. height: 40px;
  487. }
  488. &_title {
  489. font-size: $uni-font-size-sm;
  490. }
  491. }
  492. }
  493. }
  494. }
  495. .unit-change {
  496. width: 18px;
  497. height: 18px;
  498. position: fixed;
  499. top: 12px;
  500. left: 12px;
  501. }
  502. .unit {
  503. width: 100vw !important;
  504. height: 100%;
  505. background: #0d2e59;
  506. position: fixed;
  507. top: 0px;
  508. left: 0%;
  509. &-title {
  510. margin: 15px 0 10px 10px;
  511. color: #fff;
  512. }
  513. .list {
  514. margin-top: 10px;
  515. padding: 10px;
  516. position: relative;
  517. width: 90%;
  518. &-image {
  519. width: 29px;
  520. height: 29px;
  521. vertical-align: middle;
  522. margin-right: 10px;
  523. }
  524. &-name {
  525. vertical-align: middle;
  526. color: #fff;
  527. width: 60%;
  528. display: inline-block;
  529. white-space: nowrap; /* 防止文本换行 */
  530. overflow: hidden; /* 隐藏超出容器的文本 */
  531. text-overflow: ellipsis; /* 显示省略号以代表被隐藏的文本 */
  532. }
  533. &-right {
  534. position: absolute;
  535. top: 38%;
  536. right: 30%;
  537. width: 16px;
  538. height: 11px;
  539. vertical-align: middle;
  540. }
  541. &-state {
  542. position: absolute;
  543. right: 20px;
  544. top: 16px;
  545. font-size: 12px;
  546. color: #2a98ff;
  547. }
  548. &-state.active {
  549. color: #999;
  550. }
  551. }
  552. .list.active {
  553. background: #193b61;
  554. }
  555. }
  556. </style>