tabbar.vue 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436
  1. <template>
  2. <Theme>
  3. <view class="cu-bar tabbar foot ZIndex tabbars">
  4. <view
  5. class="action"
  6. @click="NavChange(item, index)"
  7. v-for="(item, index) in currentNavList"
  8. :key="index"
  9. :data-cur="item.name"
  10. >
  11. <!-- 图标和数量显示 -->
  12. <view class="cuIcon-cu-image _item">
  13. <view>
  14. <i
  15. class="icon-font"
  16. :class="item.icon"
  17. :style="
  18. pageCur == item.name
  19. ? { color: 'var(--primary)' }
  20. : { color: '#c3cad9' }
  21. "
  22. v-if="item.icon"
  23. ></i>
  24. <image
  25. class="img"
  26. :src="pageCur == item.name ? item.img_active : item.img"
  27. mode="heightFix"
  28. v-else
  29. ></image>
  30. </view>
  31. <!-- 数量徽章 -->
  32. <view class="entry_num" v-if="item.num > 0">{{ item.num }}</view>
  33. </view>
  34. <view :class="pageCur == item.name ? 'tabbar_active' : 'tabbar_item'">
  35. {{ t(item.title) }}
  36. </view>
  37. </view>
  38. </view>
  39. </Theme>
  40. </template>
  41. <script setup>
  42. import { onMounted, computed, watch, ref, nextTick } from "vue";
  43. import {
  44. useTabbarStore,
  45. useMessageStore,
  46. useShopStore,
  47. useUserStore,
  48. } from "@/store";
  49. // 导入图片资源(保持不变)
  50. import channel from "@/static/tabbar/channel.png";
  51. import home from "@/static/tabbar/home.png";
  52. import home_active from "@/static/tabbar/home_active.png";
  53. import cart from "@/static/tabbar/cart.png";
  54. import cart_active from "@/static/tabbar/cart_active.png";
  55. import ship from "@/static/tabbar/ship.png";
  56. import ship_active from "@/static/tabbar/ship_active.png";
  57. import chat from "@/static/tabbar/chat.png";
  58. import chat_active from "@/static/tabbar/chat_active.png";
  59. import user from "@/static/tabbar/user.png";
  60. import user_active from "@/static/tabbar/user_active.png";
  61. import shop from "@/static/tabbar/shop.png";
  62. import shop_active from "@/static/tabbar/shop_active.png";
  63. import index from "@/static/tabbar/index.png";
  64. import index_active from "@/static/tabbar/index_active.png";
  65. import { t } from "@/locale";
  66. import { storeToRefs } from "pinia";
  67. import { query } from "@/utils";
  68. import { onShow } from "@dcloudio/uni-app";
  69. const useTabbar = useTabbarStore();
  70. const useShop = useShopStore();
  71. const useMessage = useMessageStore();
  72. const useUser = useUserStore();
  73. const { globalMap } = storeToRefs(useMessage);
  74. const unreadCount = ref(0);
  75. // 1. 定义购物车数量计算属性(响应式)
  76. const cartNum = computed(() => useShop.getCartNum);
  77. const sellerNum = computed(() => useShop.getSellerNum);
  78. // 获取用户信息
  79. const userInfo = computed(() => useUser.getuserInfo);
  80. const isBuyer = computed(() => {
  81. console.log(useUser.getUserType, "123");
  82. return useUser.getUserType == 0;
  83. });
  84. const props = defineProps({
  85. page: {
  86. type: String,
  87. default: "index",
  88. },
  89. });
  90. const emit = defineEmits(["getTabbarHeight"]);
  91. // 2. 将navList定义为ref响应式数组(关键修改)
  92. const navList = ref([
  93. {
  94. name: "index",
  95. title: "tabbar.首页",
  96. img: home,
  97. img_active: home_active,
  98. num: 0,
  99. },
  100. {
  101. name: "shop",
  102. title: "tabbar.购物车",
  103. img: cart,
  104. img_active: cart_active,
  105. num: cartNum.value, // 初始值
  106. },
  107. {
  108. name: "chat",
  109. title: "tabbar.咨询",
  110. img: chat,
  111. img_active: chat_active,
  112. num: unreadCount.value,
  113. },
  114. {
  115. name: "order",
  116. title: "tabbar.订单",
  117. img: ship,
  118. img_active: ship_active,
  119. num: 0,
  120. },
  121. {
  122. name: "user",
  123. title: "tabbar.我的",
  124. img: user,
  125. img_active: user_active,
  126. num: 0,
  127. },
  128. ]);
  129. // 买家端导航列表
  130. const buyerNavList = ref([
  131. {
  132. name: "index",
  133. title: "tabbar.首页",
  134. img: index,
  135. img_active: index_active,
  136. num: 0,
  137. },
  138. {
  139. name: "store",
  140. title: "tabbar.店铺街",
  141. img: shop,
  142. img_active: shop_active,
  143. num: 0,
  144. },
  145. {
  146. name: "cart",
  147. title: "tabbar.购物车",
  148. img: cart,
  149. img_active: cart_active,
  150. num: sellerNum.value,
  151. },
  152. {
  153. name: "user",
  154. title: "tabbar.我的",
  155. img: user,
  156. img_active: user_active,
  157. num: 0,
  158. },
  159. ]);
  160. // 3. 监听cartNum变化,实时更新navList中购物车项的num(关键修改)
  161. watch(
  162. cartNum,
  163. (newNum) => {
  164. // 更新卖家端购物车数量
  165. const cartItem = navList.value.find((item) => item.name === "shop");
  166. if (cartItem) {
  167. cartItem.num = newNum;
  168. }
  169. // 更新买家端购物车数量
  170. const buyerCartItem = buyerNavList.value.find(
  171. (item) => item.name === "cart"
  172. );
  173. if (buyerCartItem) {
  174. buyerCartItem.num = newNum;
  175. }
  176. },
  177. { immediate: true } // 初始化时立即执行一次
  178. );
  179. // 监听咨询消息数量(保持不变)
  180. watch(
  181. () => globalMap.value.serviceChannel,
  182. (newVal) => {
  183. if (newVal) {
  184. unreadCount.value = newVal.unreadCount;
  185. const chatItem = navList.value.find((item) => item.name === "chat");
  186. if (chatItem) {
  187. chatItem.num = unreadCount.value;
  188. }
  189. }
  190. },
  191. { deep: true, immediate: true }
  192. );
  193. const pageCur = computed(() => useTabbar.setPageCur);
  194. // 根据用户类型返回相应的导航列表
  195. const currentNavList = computed(() => {
  196. // 如果用户已登录,根据用户类型显示导航
  197. if (userInfo.value && Object.keys(userInfo.value).length > 0) {
  198. return isBuyer.value ? buyerNavList.value : navList.value;
  199. }
  200. // 如果用户未登录,根据当前页面路径判断
  201. const currentPath = getCurrentPages()[getCurrentPages().length - 1].route;
  202. const isBuyerPage = currentPath.includes("pagesBuyer");
  203. return isBuyerPage ? buyerNavList.value : navList.value;
  204. });
  205. const NavChange = (item, index) => {
  206. if (item.name == pageCur.value) return;
  207. let targetUrl = "";
  208. // 根据用户类型决定跳转路径
  209. if (userInfo.value && Object.keys(userInfo.value).length > 0) {
  210. // 用户已登录,根据用户类型跳转
  211. if (isBuyer.value) {
  212. // 买家端页面跳转
  213. if (item.name === "cart") {
  214. targetUrl = "/pagesBuyer/cart/index";
  215. } else if (item.name === "index") {
  216. targetUrl = "/pagesBuyer/home/index";
  217. } else if (item.name === "store") {
  218. targetUrl = "/pagesBuyer/store/index";
  219. } else if (item.name === "user") {
  220. targetUrl = "/pagesBuyer/profile/index";
  221. } else {
  222. targetUrl = `/pagesBuyer/${item.name}/index`;
  223. }
  224. } else {
  225. // 卖家端页面跳转
  226. if (item.name === "shop") {
  227. targetUrl = "/pages/shop/cart";
  228. } else {
  229. targetUrl = `/pages/${item.name}/index`;
  230. }
  231. }
  232. } else {
  233. // 用户未登录,根据当前页面路径判断
  234. const currentPath = getCurrentPages()[getCurrentPages().length - 1].route;
  235. const isBuyerPage = currentPath.includes("pagesBuyer");
  236. if (isBuyerPage) {
  237. // 买家端页面跳转
  238. if (item.name === "cart") {
  239. targetUrl = "/pagesBuyer/cart/index";
  240. } else if (item.name === "index") {
  241. targetUrl = "/pagesBuyer/home/index";
  242. } else if (item.name === "store") {
  243. targetUrl = "/pagesBuyer/store/index";
  244. } else if (item.name === "user") {
  245. targetUrl = "/pagesBuyer/profile/index";
  246. } else {
  247. targetUrl = `/pagesBuyer/${item.name}/index`;
  248. }
  249. } else {
  250. // 卖家端页面跳转
  251. if (item.name === "shop") {
  252. targetUrl = "/pages/shop/cart";
  253. } else {
  254. targetUrl = `/pages/${item.name}/index`;
  255. }
  256. }
  257. }
  258. useTabbar.getPageIndex(index);
  259. // 判断是否为买家端页面
  260. const isBuyerPage = targetUrl.includes("pagesBuyer");
  261. if (isBuyerPage) {
  262. // 买家端页面使用 navigateTo
  263. uni.navigateTo({
  264. url: targetUrl,
  265. success: () => {
  266. useTabbar.getPageCur(item.name);
  267. useTabbar.getPageIndex(index);
  268. },
  269. fail: (err) => {
  270. console.error("买家端页面跳转失败:", err);
  271. // 如果 navigateTo 失败,尝试使用 reLaunch
  272. uni.reLaunch({
  273. url: targetUrl,
  274. success: () => {
  275. useTabbar.getPageCur(item.name);
  276. useTabbar.getPageIndex(index);
  277. },
  278. });
  279. },
  280. });
  281. } else {
  282. // 卖家端页面使用 switchTab
  283. uni.switchTab({
  284. url: targetUrl,
  285. success: () => {
  286. useTabbar.getPageCur(item.name);
  287. useTabbar.getPageIndex(index);
  288. },
  289. fail: (err) => {
  290. console.error("卖家端页面跳转失败:", err);
  291. },
  292. });
  293. }
  294. };
  295. const getHeight = async () => {
  296. try {
  297. const res = await query(".tabbar");
  298. nextTick(() => {
  299. emit("getTabbarHeight", res.height);
  300. });
  301. } catch (error) {}
  302. };
  303. onMounted(() => {
  304. let num = navList.value.findIndex((item) => item.name == props.page);
  305. if (num >= 0) {
  306. useTabbar.getPageCur(props.page);
  307. }
  308. });
  309. onShow(() => {
  310. setTimeout(() => {
  311. getHeight();
  312. }, 200);
  313. });
  314. </script>
  315. <!-- 样式部分保持不变 -->
  316. <style>
  317. .ZIndex {
  318. z-index: 2000;
  319. bottom: 0;
  320. }
  321. :deep(.cu-bar .content) {
  322. cursor: pointer;
  323. pointer-events: unset;
  324. }
  325. .cu-tag.badge:not([class*="bg-"]) {
  326. background-color: var(--red) !important;
  327. color: var(--black);
  328. position: absolute;
  329. top: -10rpx;
  330. right: 32%;
  331. }
  332. </style>
  333. <style lang="less" scoped>
  334. @import "@/static/css/theme.less";
  335. @import url("@/style.less");
  336. .tabbar {
  337. background-color: var(--light);
  338. bottom: 0;
  339. }
  340. .action {
  341. display: flex !important;
  342. justify-content: center;
  343. align-items: center;
  344. flex-direction: column;
  345. }
  346. ._item {
  347. width: max-content !important;
  348. position: relative;
  349. .icon-font {
  350. font-size: 24px;
  351. }
  352. ._item {
  353. height: 24px;
  354. vertical-align: top;
  355. }
  356. .entry_num {
  357. position: absolute;
  358. top: -12rpx;
  359. right: -14rpx;
  360. background-color: var(--danger);
  361. border: 1px solid var(--light);
  362. color: var(--light);
  363. width: 36rpx;
  364. height: 36rpx;
  365. border-radius: 50%;
  366. .size(18rpx);
  367. .flex_center();
  368. }
  369. }
  370. .tabbar_item {
  371. color: var(--text-01);
  372. font-size: 10px;
  373. line-height: 12px;
  374. margin: 2px auto 0;
  375. }
  376. .tabbar_active {
  377. font-size: 10px;
  378. line-height: 12px;
  379. margin: 2px auto 0;
  380. color: var(--text-02);
  381. }
  382. .foot {
  383. box-shadow: 0 -4px 6px #0000000d;
  384. }
  385. .cont_num {
  386. position: absolute;
  387. @width: 32rpx;
  388. width: @width;
  389. height: @width;
  390. border-radius: 50%;
  391. display: flex;
  392. align-items: center;
  393. justify-content: center;
  394. color: var(--light);
  395. background-color: var(--red);
  396. font-size: 24rpx;
  397. z-index: 2;
  398. right: -18rpx;
  399. top: -6rpx;
  400. }
  401. </style>