Browse Source

product:优化商品列表的样式、实现代码

YunaiV 1 year ago
parent
commit
3a9668d632

+ 7 - 9
src/router/modules/remaining.ts

@@ -331,9 +331,8 @@ const remainingRouter: AppRouteRecordRaw[] = [
     ]
   },
   {
-    path: '/product',
+    path: '/mall/product', // 商品中心
     component: Layout,
-    name: 'Product',
     meta: {
       hidden: true
     },
@@ -348,11 +347,11 @@ const remainingRouter: AppRouteRecordRaw[] = [
           canTo: true,
           icon: 'ep:edit',
           title: '添加商品',
-          activeMenu: '/product/product-spu'
+          activeMenu: '/mall/product/spu'
         }
       },
       {
-        path: 'spu/edit/:spuId(\\d+)',
+        path: 'spu/edit/:id(\\d+)',
         component: () => import('@/views/mall/product/spu/form/index.vue'),
         name: 'ProductSpuEdit',
         meta: {
@@ -361,11 +360,11 @@ const remainingRouter: AppRouteRecordRaw[] = [
           canTo: true,
           icon: 'ep:edit',
           title: '编辑商品',
-          activeMenu: '/product/product-spu'
+          activeMenu: '/mall/product/spu'
         }
       },
       {
-        path: 'spu/detail/:spuId(\\d+)',
+        path: 'spu/detail/:id(\\d+)',
         component: () => import('@/views/mall/product/spu/form/index.vue'),
         name: 'ProductSpuDetail',
         meta: {
@@ -374,7 +373,7 @@ const remainingRouter: AppRouteRecordRaw[] = [
           canTo: true,
           icon: 'ep:view',
           title: '商品详情',
-          activeMenu: '/product/product-spu'
+          activeMenu: '/mall/product/spu'
         }
       },
       {
@@ -393,9 +392,8 @@ const remainingRouter: AppRouteRecordRaw[] = [
     ]
   },
   {
-    path: '/trade',
+    path: '/trade', // 交易中心
     component: Layout,
-    name: 'Order',
     meta: {
       hidden: true
     },

+ 3 - 2
src/utils/index.ts

@@ -230,6 +230,7 @@ export const yuanToFen = (amount: string | number): number => {
 /**
  * 分转元
  */
-export const fenToYuan = (amount: string | number): number => {
-  return Number((Number(amount) / 100).toFixed(2))
+export const fenToYuan = (price: string | number): number => {
+  price = Number(price)
+  return (price / 100.0).toFixed(2)
 }

+ 4 - 3
src/utils/tree.ts

@@ -13,7 +13,8 @@ export const defaultProps = {
   children: 'children',
   label: 'name',
   value: 'id',
-  isLeaf: 'leaf'
+  isLeaf: 'leaf',
+  emitPath: false // 用于 cascader 组件:在选中节点改变时,是否返回由该节点所在的各级菜单的值所组成的数组,若设置 false,则只返回该节点的值
 }
 
 const getConfig = (config: Partial<TreeHelperConfig>) => Object.assign({}, DEFAULT_CONFIG, config)
@@ -377,10 +378,10 @@ export const treeToString = (tree: any[], nodeId) => {
   function performAThoroughValidation(arr) {
     for (const item of arr) {
       if (item.id === nodeId) {
-        str += `/${item.name}`
+        str += ` / ${item.name}`
         return true
       } else if (typeof item.children !== 'undefined' && item.children.length !== 0) {
-        str += `/${item.name}`
+        str += ` / ${item.name}`
         if (performAThoroughValidation(item.children)) {
           return true
         }

+ 1 - 1
src/views/mall/product/spu/form/index.vue

@@ -102,7 +102,7 @@ const getDetail = async () => {
   if ('ProductSpuDetail' === name) {
     isDetail.value = true
   }
-  const id = params.spuId as unknown as number
+  const id = params.id as unknown as number
   if (id) {
     formLoading.value = true
     try {

+ 53 - 81
src/views/mall/product/spu/index.vue

@@ -18,15 +18,14 @@
         />
       </el-form-item>
       <el-form-item label="商品分类" prop="categoryId">
-        <el-tree-select
+        <el-cascader
           v-model="queryParams.categoryId"
-          :data="categoryList"
+          :options="categoryList"
           :props="defaultProps"
-          check-strictly
           class="w-1/1"
-          node-key="id"
+          clearable
           placeholder="请选择商品分类"
-          @change="nodeClick"
+          filterable
         />
       </el-form-item>
       <el-form-item label="创建时间" prop="createTime">
@@ -78,7 +77,7 @@
       />
     </el-tabs>
     <el-table v-loading="loading" :data="list">
-      <el-table-column type="expand" width="30">
+      <el-table-column type="expand">
         <template #default="{ row }">
           <el-form class="spu-table-expand" label-position="left">
             <el-row>
@@ -86,17 +85,17 @@
                 <el-row>
                   <el-col :span="8">
                     <el-form-item label="商品分类:">
-                      <span>{{ categoryString(row.categoryId) }}</span>
+                      <span>{{ formatCategoryName(row.categoryId) }}</span>
                     </el-form-item>
                   </el-col>
                   <el-col :span="8">
                     <el-form-item label="市场价:">
-                      <span>{{ floatToFixed2(row.marketPrice) }}元</span>
+                      <span>{{ fenToYuan(row.marketPrice) }}</span>
                     </el-form-item>
                   </el-col>
                   <el-col :span="8">
                     <el-form-item label="成本价:">
-                      <span>{{ floatToFixed2(row.costPrice) }}元</span>
+                      <span>{{ fenToYuan(row.costPrice) }}</span>
                     </el-form-item>
                   </el-col>
                 </el-row>
@@ -106,9 +105,8 @@
               <el-col :span="24">
                 <el-row>
                   <el-col :span="8">
-                    <el-form-item label="收藏:">
-                      <!-- TODO 没有这个属性,暂时写死 5 个 -->
-                      <span>5</span>
+                    <el-form-item label="浏览量:">
+                      <span>{{ row.browseCount }}</span>
                     </el-form-item>
                   </el-col>
                   <el-col :span="8">
@@ -122,7 +120,7 @@
           </el-form>
         </template>
       </el-table-column>
-      <el-table-column key="id" align="center" label="商品编号" prop="id" />
+      <el-table-column align="center" label="商品编号" min-width="60" prop="id" />
       <el-table-column label="商品图" min-width="80">
         <template #default="{ row }">
           <el-image :src="row.picUrl" class="h-30px w-30px" @click="imagePreview(row.picUrl)" />
@@ -130,7 +128,7 @@
       </el-table-column>
       <el-table-column :show-overflow-tooltip="true" label="商品名称" min-width="300" prop="name" />
       <el-table-column align="center" label="商品售价" min-width="90" prop="price">
-        <template #default="{ row }"> {{ floatToFixed2(row.price) }}元</template>
+        <template #default="{ row }"> {{ fenToYuan(row.price) }}元</template>
       </el-table-column>
       <el-table-column align="center" label="销量" min-width="90" prop="salesCount" />
       <el-table-column align="center" label="库存" min-width="90" prop="stock" />
@@ -152,7 +150,7 @@
               active-text="上架"
               inactive-text="下架"
               inline-prompt
-              @change="changeStatus(row)"
+              @change="handleStatusChange(row)"
             />
           </template>
           <template v-else>
@@ -191,7 +189,7 @@
               v-hasPermi="['product:spu:update']"
               link
               type="primary"
-              @click="changeStatus(row, ProductSpuStatusEnum.DISABLE.status)"
+              @click="handleStatus02Change(row, ProductSpuStatusEnum.DISABLE.status)"
             >
               恢复到仓库
             </el-button>
@@ -201,7 +199,7 @@
               v-hasPermi="['product:spu:update']"
               link
               type="primary"
-              @click="changeStatus(row, ProductSpuStatusEnum.RECYCLE.status)"
+              @click="handleStatus02Change(row, ProductSpuStatusEnum.RECYCLE.status)"
             >
               加入回收站
             </el-button>
@@ -220,12 +218,11 @@
 </template>
 <script lang="ts" setup>
 import { TabsPaneContext } from 'element-plus'
-import { cloneDeep } from 'lodash-es'
 import { createImageViewer } from '@/components/ImageViewer'
 import { dateFormatter } from '@/utils/formatTime'
-import { checkSelectedNode, defaultProps, handleTree, treeToString } from '@/utils/tree'
+import { defaultProps, handleTree, treeToString } from '@/utils/tree'
 import { ProductSpuStatusEnum } from '@/utils/constants'
-import { floatToFixed2 } from '@/utils'
+import { fenToYuan } from '@/utils'
 import download from '@/utils/download'
 import * as ProductSpuApi from '@/api/mall/product/spu'
 import * as ProductCategoryApi from '@/api/mall/product/category'
@@ -254,7 +251,7 @@ const tabsData = ref([
   },
   {
     count: 0,
-    name: '已经售空商品',
+    name: '已售罄商品',
     type: 2
   },
   {
@@ -303,43 +300,37 @@ const getList = async () => {
   }
 }
 
-/**
- * 更改 SPU 状态
- *
- * @param row
- * @param status 更改前的值
- */
-const changeStatus = async (row, status?: number) => {
-  const deepCopyValue = cloneDeep(unref(row))
-  if (typeof status !== 'undefined') deepCopyValue.status = status
+/** 添加到仓库 / 回收站的状态 */
+const handleStatus02Change = async (row, newStatus: number) => {
+  try {
+    // 二次确认
+    const text = newStatus === ProductSpuStatusEnum.RECYCLE.status ? '加入到回收站' : '恢复到仓库'
+    await message.confirm(`确认要"${row.name}"${text}吗?`)
+    // 发起修改
+    await ProductSpuApi.updateStatus({ id: row.id, status: newStatus })
+    message.success(text + '成功')
+    // 刷新 tabs 数据
+    await getTabsCount()
+    // 刷新列表
+    await getList()
+  } catch {}
+}
+
+/** 更新上架/下架状态 */
+const handleStatusChange = async (row) => {
   try {
-    let text = ''
-    switch (deepCopyValue.status) {
-      case ProductSpuStatusEnum.DISABLE.status:
-        text = ProductSpuStatusEnum.DISABLE.name
-        break
-      case ProductSpuStatusEnum.ENABLE.status:
-        text = ProductSpuStatusEnum.ENABLE.name
-        break
-      case ProductSpuStatusEnum.RECYCLE.status:
-        text = `加入${ProductSpuStatusEnum.RECYCLE.name}`
-        break
-    }
-    await message.confirm(
-      deepCopyValue.status === -1
-        ? `确认要将[${row.name}]${text}吗?`
-        : row.status === -1 // 再判断一次原对象是否等于-1,例: 把回收站中的商品恢复到仓库中,事件触发时原对象status为-1 深拷贝对象status被赋值为0
-        ? `确认要将[${row.name}]恢复到仓库吗?`
-        : `确认要${text}[${row.name}]吗?`
-    )
-    await ProductSpuApi.updateStatus({ id: deepCopyValue.id, status: deepCopyValue.status })
-    message.success('更新状态成功')
+    // 二次确认
+    const text = row.status ? '上架' : '下架'
+    await message.confirm(`确认要${text}"${row.name}"吗?`)
+    // 发起修改
+    await ProductSpuApi.updateStatus({ id: row.id, status: row.status })
+    message.success(text + '成功')
     // 刷新 tabs 数据
     await getTabsCount()
     // 刷新列表
     await getList()
   } catch {
-    // 取消更改状态时回显数据
+    // 异常时,需要重置回之前的值
     row.status =
       row.status === ProductSpuStatusEnum.DISABLE.status
         ? ProductSpuStatusEnum.ENABLE.status
@@ -380,26 +371,20 @@ const resetQuery = () => {
   handleQuery()
 }
 
-/**
- * 新增或修改
- *
- * @param id 商品 SPU 编号
- */
+/** 新增或修改 */
 const openForm = (id?: number) => {
   // 修改
   if (typeof id === 'number') {
-    push({ name: 'ProductSpuEdit', params: { spuId: id } })
+    push({ name: 'ProductSpuEdit', params: { id } })
     return
   }
   // 新增
   push({ name: 'ProductSpuAdd' })
 }
 
-/**
- * 查看商品详情
- */
+/** 查看商品详情 */
 const openDetail = (id: number) => {
-  push({ name: 'ProductSpuDetail', params: { spuId: id } })
+  push({ name: 'ProductSpuDetail', params: { id } })
 }
 
 /** 导出按钮操作 */
@@ -417,6 +402,12 @@ const handleExport = async () => {
   }
 }
 
+const categoryList = ref() // 分类树
+/** 获取分类的节点的完整结构 */
+const formatCategoryName = (categoryId) => {
+  return treeToString(categoryList.value, categoryId)
+}
+
 // 监听路由变化更新列表,解决商品保存后,列表不刷新的问题。
 watch(
   () => currentRoute.value,
@@ -425,25 +416,6 @@ watch(
   }
 )
 
-const categoryList = ref() // 分类树
-/**
- * 获取分类的节点的完整结构
- * @param categoryId 分类id
- */
-const categoryString = (categoryId) => {
-  return treeToString(categoryList.value, categoryId)
-}
-
-/**
- * 校验所选是否为二级及以下节点
- */
-const nodeClick = () => {
-  if (!checkSelectedNode(categoryList.value, queryParams.value.categoryId)) {
-    queryParams.value.categoryId = null
-    message.warning('必须选择二级及以下节点!!')
-  }
-}
-
 /** 初始化 **/
 onMounted(async () => {
   await getTabsCount()