소스 검색

Merge branch 'dev' of https://git.citupro.com/zhengnaiwen_citu/menduner into dev

Xiao_123 4 달 전
부모
커밋
cbe517f319

+ 8 - 0
src/api/mall/index.js

@@ -14,6 +14,14 @@ export const getProductByIds = async (ids) => {
   })
 }
 
+// 获取商品列表
+export const getGoodsList = async (params) => {
+  return request.get({
+    url: '/app-api/product/spu/page',
+    params
+  })
+}
+
 // 提交积分商品兑换
 export const redeemSubmit = async (data) => {
   return await request.post({

+ 8 - 0
src/router/modules/recruit.js

@@ -43,6 +43,14 @@ const recruit = [
           title: '门墩儿商城'
         }
       },
+      {
+        path: '/mall/goodsList',
+        component: () => import('@/views/mall/goodsList/index'),
+        name: 'goodsList',
+        meta: {
+          title: '商品列表'
+        }
+      },
       {
         path: '/mall/goodsDetail/:id',
         component: () => import('@/views/mall/components/details.vue'),

+ 1 - 1
src/views/mall/components/details.vue

@@ -1,6 +1,6 @@
 <!-- 商品详情 -->
 <template>
-  <Navbar class="mb-3" hideSearch />
+  <Navbar class="mb-3" />
   <div class="default-width pb-5" v-if="state.goodsInfo && Object.keys(state.goodsInfo).length">
     <v-card class="carousel border-radius-8 white-bgc pa-5" style="width: 100%;">
       <div class=" d-flex">

+ 68 - 44
src/views/mall/components/navbar.vue

@@ -1,53 +1,60 @@
 <template>
-  <div class="stickyBox py-5">
-    <div class="default-width d-flex align-center justify-space-between">
-      <div class="header-link d-flex">
-        <span class="cursor-pointer d-flex align-center ml-8" :class="{'active-route' : isActive('/mall')}" @click="router.push('/mall')">
-          <v-icon size="24" class="mr-2">mdi-shopping-outline</v-icon>
-          首页
-        </span>
-        <span class="cursor-pointer d-flex align-center ml-8" :class="{'active-route' : isActive('/mall/user', true)}" @click="handleTo('/mall/user')">
-          <v-icon size="24" class="mr-2">mdi-account-circle-outline</v-icon>
-          我的
-        </span>
-        <!-- <span class="cursor-pointer d-flex align-center ml-8" @click="emit('pointExchange')">
-          <v-icon>mdi-octagram-outline</v-icon>
-          积分兑换
-        </span> -->
-        <!-- <span class="cursor-pointer d-flex align-center ml-8" :class="{'active-route' : isActive('/mall/order')}" @click="handleTo('/mall/user/order')">
-          <v-icon size="20" class="mr-2">mdi-order-bool-ascending</v-icon>
-          我的订单
-        </span> -->
-        <span class="cursor-pointer d-flex align-center ml-8" :class="{'active-route' : isActive('/mall/cart')}" @click="handleTo('/mall/cart')">
-          <v-icon size="20" class="mr-2">mdi-cart-outline</v-icon>
-          购物车
-        </span>
-      </div>
-      <div v-if="!props.hideSearch" class="search d-flex align-center">
-        <v-text-field
-          v-model="inputVal"
-          placeholder="请输入关键词"
-          color="primary"
-          variant="plain"
-          density="compact"
-          clearable
-          :hide-details="true"
-          class="ml-3 px-2"
-          style="height: 100%; line-height: 100%;"
-          @keyup.enter="handleSearch"
-        ></v-text-field>
-        <v-btn class="searchBtn" prepend-icon="mdi-shopping-search-outline" @click="handleSearch">搜索</v-btn>
+  <div>
+    <div class="stickyBox py-5">
+      <div class="default-width d-flex align-center justify-space-between">
+        <div class="header-link d-flex">
+          <span class="cursor-pointer d-flex align-center ml-8" :class="{'active-route' : isActive('/mall')}" @click="router.push('/mall')">
+            <v-icon size="24" class="mr-2">mdi-shopping-outline</v-icon>
+            首页
+          </span>
+          <span class="cursor-pointer d-flex align-center ml-8" :class="{'active-route' : isActive('/mall/user', true)}" @click="handleTo('/mall/user')">
+            <v-icon size="24" class="mr-2">mdi-account-circle-outline</v-icon>
+            我的
+          </span>
+          <!-- <span class="cursor-pointer d-flex align-center ml-8" @click="emit('pointExchange')">
+            <v-icon>mdi-octagram-outline</v-icon>
+            积分兑换
+          </span> -->
+          <!-- <span class="cursor-pointer d-flex align-center ml-8" :class="{'active-route' : isActive('/mall/order')}" @click="handleTo('/mall/user/order')">
+            <v-icon size="20" class="mr-2">mdi-order-bool-ascending</v-icon>
+            我的订单
+          </span> -->
+          <span class="cursor-pointer d-flex align-center ml-8" :class="{'active-route' : isActive('/mall/cart')}" @click="handleTo('/mall/cart')">
+            <v-icon size="20" class="mr-2">mdi-cart-outline</v-icon>
+            购物车
+          </span>
+        </div>
+        <div v-if="!props.hideSearch" class="search d-flex align-center">
+          <v-text-field
+            v-model="inputVal"
+            placeholder="请输入商品关键词"
+            color="primary"
+            variant="plain"
+            density="compact"
+            clearable
+            :hide-details="true"
+            class="ml-3 px-2"
+            style="height: 100%; line-height: 100%;"
+            @keyup.enter="handleSearch"
+          ></v-text-field>
+          <v-btn class="searchBtn" prepend-icon="mdi-shopping-search-outline" @click="handleSearch">搜索</v-btn>
+        </div>
       </div>
     </div>
+    <!-- 快速登录 -->
+    <loginPage v-if="showLogin" @loginSuccess="loginSuccess" @close="loginClose"></loginPage>
   </div>
 </template>
 
 <script setup>
 defineOptions({ name: 'formPage'})
 import { computed, ref } from 'vue'
-import { useRouter } from 'vue-router'
+import { useRoute } from 'vue-router'; const route = useRoute()
+import { useRouter } from 'vue-router'; const router = useRouter()
 import { getToken } from '@/utils/auth'
 import Snackbar from '@/plugins/snackbar'
+import loginPage from '@/views/common/loginDialog.vue'
+const emit = defineEmits(['login', 'pointExchange', 'search'])
 const props = defineProps({
   hideSearch: {
     type: Boolean,
@@ -55,24 +62,41 @@ const props = defineProps({
   },
 })
 
-const emit = defineEmits(['login', 'pointExchange'])
-const router = useRouter()
 const isActive = computed(() => (path, hasChild) => {
   const currentPath = router.currentRoute.value.path
   return hasChild ? currentPath.includes(path) : currentPath === path
 })
 
+const showLogin = ref(false)
 const handleTo = (path) => {
   if (!getToken()) {
     Snackbar.warning('请先登录')
-    emit('login', path)
+    showLogin.value = true // 打开快速登录弹窗
     return
   }
   router.push(path)
 }
 
-const inputVal = ref('')
-const handleSearch = () => {}
+const open = false
+// 更新路由进行搜素
+const inputVal = ref(route?.query?.keyWord || '')
+const handleSearch = () => {
+  if (!open) return
+  const path = '/mall/goodsList'
+  router.push({ path, query: { keyWord: inputVal.value } })
+  emit('search', inputVal.value)
+}
+
+// 快速登录
+const loginSuccess = () => {
+  showLogin.value = false
+  Snackbar.success('登录成功')
+}
+
+const loginClose = () => {
+  showLogin.value = false
+  Snackbar.warning('您已取消登录')
+}
 </script>
 
 <style scoped lang="scss">

+ 92 - 0
src/views/mall/goodsList/index.vue

@@ -0,0 +1,92 @@
+<!--  -->
+<template>
+  <div>
+    <Navbar style="min-width: 1184px;" @search="keyword=> getData(keyword)" />
+    <div class="white-bgc py-3" style="border-top: 1px solid #eee;">
+      <div class="default-width my-3" :loading="loading">
+        <div v-if="goodList.length">
+          <div class="goods-box mt-5">
+            <v-card v-for="val in goodList" :key="val.id" class="goods-box-item" hover elevation="2" @click="handleClickGood(val)">
+              <v-img :src="val.picUrl" width="100%" height="68%" cover></v-img>
+              <div class="px-3 pt-3">
+                <p class="ellipsis color-333">{{ val.name }}</p>
+                <p class="color-999 ellipsis font-size-14 mt-1">{{ val.introduction }}</p>
+                <div class="mt-1 d-flex justify-space-between">
+                  <div class="goods-box-item-price">¥{{ isArray(val.price) ? fen2yuan(val.price[0]) : fen2yuan(val.price) }}</div>
+                  <div class="font-size-15 mt-1" style="color: #c4c4c4">{{ salesAndStock(val) }}</div>
+                </div>
+              </div>
+            </v-card>
+          </div>
+          <CtPagination :total="total" :page="page.pageNo" :limit="page.pageSize" @handleChange="handleChangePage"></CtPagination>
+        </div>
+        <Empty v-else :elevation="false" message="没有找到相关商品~"></Empty>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script setup>
+defineOptions({name: 'mall-goodsList-index'})
+import Navbar from '@/views/mall/components/navbar.vue'
+import { useRoute } from 'vue-router'; const route = useRoute()
+import { getGoodsList } from '@/api/mall/index'
+import { isArray } from 'lodash-es'
+import { formatSales, fen2yuan } from '@/hooks/web/useGoods'
+import { ref, computed } from 'vue'
+
+const page = ref({
+  pageNo: 1,
+  pageSize: 10
+})
+
+// 根据id获取商品列表
+const loading = ref(false)
+const total = ref(0)
+const goodList = ref([])
+const getData = async (keyword) => {
+  const params = {
+    ...page.value
+  }
+  console.log('keyword:', keyword)
+  console.log('route.query.keyWord:', route.query.keyWord)
+  if (route?.query?.keyWord || keyword) params.keyword = keyword || route.query.keyWord
+  const { list, total: number } = await getGoodsList(params)
+  goodList.value = list
+  total.value = number || 0
+}
+getData()
+
+// 分页
+const handleChangePage = (e) => {
+  page.value.pageNo = e
+  getData()
+}
+
+// 格式化销量、库存信息
+const salesAndStock = computed(() => (data) => {
+  let text = []
+  text.push(formatSales(undefined, data.salesCount))
+  return text.join(' | ')
+})
+
+</script>
+<style lang="scss" scoped>
+.goods-box {
+  width: 100%;
+  display: flex;
+  flex-wrap: wrap;
+  &-item {
+    height: 330px;
+    width: calc((100% - 48px) / 5);
+    margin: 0 12px 12px 0;
+    &:nth-child(5n) {
+      margin-right: 0;
+    }
+    &-price {
+      color: #ff3000;
+      font-size: 20px;
+    }
+  }
+}
+</style>

+ 1 - 1
src/views/mall/home/components/hotGoods.vue

@@ -2,7 +2,7 @@
   <div>
     <div class="d-flex justify-space-between color-666">
       <div class="color-primary" style="font-size: 25px;">热门商品</div>
-      <div class="cursor-pointer">查看更多</div>
+      <div class="cursor-pointer" @click="router.push('/mall/goodsList')">查看更多</div>
     </div>
     <div v-if="goodList.length" class="goods-box mt-5">
       <v-card v-for="val in goodList" :key="val.id" class="goods-box-item" hover elevation="2" @click="handleClickGood(val)">

+ 5 - 1
src/views/mall/home/index.vue

@@ -1,7 +1,7 @@
 <template>
   <div style="min-width: 1184px;" class="white-bgc">
     <!-- 导航栏 -->
-    <Navbar @login="handleLogin" />
+    <Navbar />
 
     <div id="contentBox" ref="scrollBox">
       <!-- 轮播图 -->
@@ -76,6 +76,10 @@ const loginClose = () => {
   showLogin.value = false
   Snackbar.warning('您已取消登录')
 }
+
+const handleSearch = (val) => {
+  
+}
 </script>
 
 <style scoped lang="scss">