tabbar.vue 10 KB

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