使用申请
							
								
								
									
										23
									
								
								sub-operation-service/src/apis/products.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,23 @@ | |||||||
|  | export default { | ||||||
|  |   // 模拟获取商品列表
 | ||||||
|  |   getProducts: () => { | ||||||
|  |     return new Promise((resolve) => { | ||||||
|  |       setTimeout(() => { | ||||||
|  |         resolve([ | ||||||
|  |           { id: 1, name: '耿马绿色蔬菜', imageUrl: 'images/brand/11.png' }, | ||||||
|  |           { id: 2, name: '云南高山茶', imageUrl: 'images/brand/12.png' }, | ||||||
|  |           { id: 3, name: '新疆大枣', imageUrl: 'images/brand/13.png' }, | ||||||
|  |           { id: 4, name: '东北大米', imageUrl: 'images/brand/14.png' }, | ||||||
|  |           { id: 5, name: '山东苹果', imageUrl: 'images/brand/15.png' }, | ||||||
|  |           { id: 6, name: '四川泡菜', imageUrl: 'images/brand/16.png' }, | ||||||
|  |           { id: 7, name: '江苏阳澄湖大闸蟹', imageUrl: 'images/brand/11.png' }, | ||||||
|  |           { id: 8, name: '海南椰子', imageUrl: 'images/brand/12.png' }, | ||||||
|  |           { id: 9, name: '广东早茶', imageUrl: 'images/brand/13.png' }, | ||||||
|  |           { id: 10, name: '北京烤鸭', imageUrl: 'images/brand/14.png' }, | ||||||
|  |           { id: 11, name: '西藏青稞酒', imageUrl: 'images/brand/15.png' }, | ||||||
|  |           { id: 12, name: '青海牦牛肉', imageUrl: 'images/brand/16.png' }, | ||||||
|  |         ]); | ||||||
|  |       }, 500); // 模拟网络延迟
 | ||||||
|  |     }); | ||||||
|  |   }, | ||||||
|  | }; | ||||||
| Before Width: | Height: | Size: 61 KiB After Width: | Height: | Size: 61 KiB | 
| Before Width: | Height: | Size: 55 KiB After Width: | Height: | Size: 55 KiB | 
| Before Width: | Height: | Size: 46 KiB After Width: | Height: | Size: 46 KiB | 
| Before Width: | Height: | Size: 53 KiB After Width: | Height: | Size: 53 KiB | 
| Before Width: | Height: | Size: 59 KiB After Width: | Height: | Size: 59 KiB | 
| Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB | 
| Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB | 
| Before Width: | Height: | Size: 62 KiB After Width: | Height: | Size: 62 KiB | 
| Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.2 KiB | 
| Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.3 KiB | 
| Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB | 
| Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 18 KiB | 
| Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 22 KiB | 
| Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB | 
| Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 18 KiB | 
| Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.3 KiB | 
| @ -1,67 +1,100 @@ | |||||||
| <template> | <template> | ||||||
|   <el-page-header> |   <el-row :gutter="20" class="content-box"> | ||||||
|     <template #breadcrumb> |     <el-col v-for="product in products" :key="product.id" :span="6"> | ||||||
|       <el-breadcrumb separator="·"> |       <el-card class="box-card" :body-style="{ padding: '8px', height: '100%' }"> | ||||||
|         <el-breadcrumb-item :to="{ path: './page-header.html' }"> 使用申请 </el-breadcrumb-item> |         <div class="flex-column"> | ||||||
|         <el-breadcrumb-item>我要申请</el-breadcrumb-item> |           <img :src="product.img" alt="商品图" class="img" /> | ||||||
|       </el-breadcrumb> |           <div class="flex-1 flex-around"> | ||||||
|     </template> |             <p>{{ product.name }}</p> | ||||||
|   </el-page-header> |             <el-button type="success" class="button">我要申请</el-button> | ||||||
|   <el-space class="content-box" wrap> |           </div> | ||||||
|     <el-card v-for="o in 12" :key="o" class="box-card"> |         </div> | ||||||
|       <div style="height: 100%" class="flex-clomn"> |       </el-card> | ||||||
|         <img :src="url" alt="" class="img" /> |     </el-col> | ||||||
|         <p>耿马绿色蔬菜</p> |   </el-row> | ||||||
|         <el-button class="button">我要申请</el-button> |  | ||||||
|       </div> |  | ||||||
|     </el-card> |  | ||||||
|   </el-space> |  | ||||||
| </template> | </template> | ||||||
|  | 
 | ||||||
| <script setup> | <script setup> | ||||||
| const goBack = () => { | import { ref, onMounted } from 'vue'; | ||||||
|   console.log('go back'); | import productsApi from '@/apis/products'; | ||||||
|  | import { getAssetsFile } from '@/utils/index.js'; | ||||||
|  | 
 | ||||||
|  | const url = 'https://via.placeholder.com/182'; | ||||||
|  | const products = ref([]); | ||||||
|  | 
 | ||||||
|  | // 获取商品数据 | ||||||
|  | const fetchProducts = async () => { | ||||||
|  |   try { | ||||||
|  |     const data = await productsApi.getProducts(); | ||||||
|  |     const processedData = data.map((item) => { | ||||||
|  |       return { | ||||||
|  |         ...item, | ||||||
|  |         img: getAssetsFile(item.imageUrl), // 确保图片路径正确 | ||||||
|  |       }; | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     products.value = processedData; | ||||||
|  |   } catch (error) { | ||||||
|  |     console.error('获取商品数据失败:', error); | ||||||
|  |   } | ||||||
| }; | }; | ||||||
|  | 
 | ||||||
|  | // 组件挂载时获取数据 | ||||||
|  | onMounted(() => { | ||||||
|  |   fetchProducts(); | ||||||
|  | }); | ||||||
| </script> | </script> | ||||||
|  | 
 | ||||||
| <style scoped lang="scss"> | <style scoped lang="scss"> | ||||||
| .content-box { | .content-box { | ||||||
|   margin: 0; |   margin: 0; | ||||||
|   padding: 0; |   padding: 0; | ||||||
|   box-sizing: border-box; |   row-gap: 20px; | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
|   .box-card { | .box-card { | ||||||
|     box-shadow: none; |   width: 100%; | ||||||
|     width: 224px; |   height: 334px; | ||||||
|     height: 334px; |   border-radius: 16px; | ||||||
|     background: #ffffff; |   padding: 0; | ||||||
|     border-radius: 16px; |   box-shadow: none; | ||||||
|     padding: 8; |  | ||||||
| 
 | 
 | ||||||
|     .flex-clomn { |   .flex-column { | ||||||
|       display: flex; |     height: 100%; | ||||||
|       flex-direction: column; |     display: flex; | ||||||
|       gap: 8; |     flex-direction: column; | ||||||
|     } |     justify-content: space-between; | ||||||
|     p { |     align-items: center; | ||||||
|       text-align: center; |     padding: 0; | ||||||
|       font-size: 20px; |   } | ||||||
|       font-weight: 700; | 
 | ||||||
|     } |   .flex-around { | ||||||
| 
 |     display: flex; | ||||||
|     .img { |     flex-direction: column; | ||||||
|       width: 182px; |     justify-content: space-around; | ||||||
|       height: 182px; |     align-items: center; | ||||||
|     } |   } | ||||||
|     .button { | 
 | ||||||
|       width: 96px; |   .flex-1 { | ||||||
|       height: 40px; |     flex: 1; | ||||||
|       background: #25bf82; |   } | ||||||
|       border-radius: 8px; | 
 | ||||||
|       align-self: center; |   .flex-column p { | ||||||
|       color: #fff; |     margin: 0; | ||||||
|     } |     font-size: 20px; | ||||||
|  |     font-weight: 700; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   .img { | ||||||
|  |     width: 100%; | ||||||
|  |     aspect-ratio: 1 / 1; | ||||||
|  |     object-fit: cover; | ||||||
|  |     border-radius: 8px; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   .button { | ||||||
|  |     width: 96px; | ||||||
|  |     height: 40px; | ||||||
|   } |   } | ||||||
|   // .content-box::-webkit-scrollbar { |  | ||||||
|   //   display: none; /* 隐藏滚动条 */ |  | ||||||
|   // } |  | ||||||
| } | } | ||||||
| </style> | </style> | ||||||
|  | |||||||
| @ -1,179 +1,180 @@ | |||||||
| <template> | <template> | ||||||
|   <div class="usage-monitor"> |   <div class="usage-monitor"> | ||||||
|     <!-- 状态筛选 --> |     <!-- 顶部 TabPane,居中显示 --> | ||||||
|     <el-tabs v-model="activeStatus" class="mb-24"> |     <div class="tabs-wrapper"> | ||||||
|       <el-tab-pane label="在售中" name="onSale" /> |       <el-tabs v-model="activeTab" type="card" class="centered-tabs"> | ||||||
|       <el-tab-pane label="未上架" name="notListed" /> |         <el-tab-pane label="在售中" name="onSale" /> | ||||||
|       <el-tab-pane label="已失效" name="expired" /> |         <el-tab-pane label="未上架" name="offShelf" /> | ||||||
|     </el-tabs> |         <el-tab-pane label="已失效" name="expired" /> | ||||||
|  |       </el-tabs> | ||||||
|  |     </div> | ||||||
| 
 | 
 | ||||||
|     <!-- 商品列表 --> |     <!-- 列表内容 --> | ||||||
|     <el-row :gutter="16"> |     <div class="list-wrapper"> | ||||||
|       <el-col v-for="product in filteredProducts" :key="product.id" :xs="24" :sm="12" :md="8" :lg="6" class="mb-16"> |       <div v-for="(p, idx) in filteredProducts" :key="p.id" class="list-item" :class="{ 'has-border': idx > 0 }"> | ||||||
|         <el-card class="product-card"> |         <!-- 商品图 --> | ||||||
|           <!-- 商品状态 --> |         <img class="item-img" :src="p.img" alt="商品图" /> | ||||||
|           <div class="status-tag"> |  | ||||||
|             <el-tag :type="statusMap[product.status]" size="small"> |  | ||||||
|               {{ product.statusLabel }} |  | ||||||
|             </el-tag> |  | ||||||
|           </div> |  | ||||||
| 
 | 
 | ||||||
|           <!-- 商品信息 --> |         <!-- 名称 + 月售/库存 --> | ||||||
|           <div class="product-content"> |         <div class="item-info"> | ||||||
|             <h4 class="product-name">{{ product.name }}</h4> |           <div class="item-name">{{ p.name }}</div> | ||||||
|  |           <div class="item-stats">月售 {{ p.monthlySales }} · 库存 {{ p.stock }}</div> | ||||||
|  |         </div> | ||||||
| 
 | 
 | ||||||
|             <div class="sales-info"> |         <!-- 价格 --> | ||||||
|               <div class="data-item"> |         <div class="item-price">¥ {{ p.price }} /kg</div> | ||||||
|                 <span class="label">月售</span> |  | ||||||
|                 <span class="value">{{ product.monthlySales }}</span> |  | ||||||
|               </div> |  | ||||||
|               <div class="data-item"> |  | ||||||
|                 <span class="label">库存</span> |  | ||||||
|                 <span class="value">{{ product.stock }}</span> |  | ||||||
|               </div> |  | ||||||
|             </div> |  | ||||||
| 
 | 
 | ||||||
|             <div class="price"> |         <!-- 操作按钮 --> | ||||||
|               {{ product.price }} |         <div class="item-actions"> | ||||||
|             </div> |           <el-button size="small" @click="onInspect(p)">抽查</el-button> | ||||||
|           </div> |           <el-button size="small" type="danger" @click="onRevoke(p)">取消授权</el-button> | ||||||
|  |         </div> | ||||||
| 
 | 
 | ||||||
|           <!-- 操作按钮 --> |         <!-- 右侧状态 --> | ||||||
|           <div class="product-actions"> |         <div class="item-status" :class="statusClass(activeTab)"> | ||||||
|             <el-button v-if="product.status !== 'expired'" size="small" @click="handleInspect(product)">抽查</el-button> |           {{ tabLabels[activeTab] }} | ||||||
|             <el-button v-if="product.status === 'onSale'" size="small" type="danger" plain @click="handleRevoke(product)">取消授权</el-button> |         </div> | ||||||
|           </div> |       </div> | ||||||
|         </el-card> |     </div> | ||||||
|       </el-col> |  | ||||||
|     </el-row> |  | ||||||
|   </div> |   </div> | ||||||
| </template> | </template> | ||||||
| 
 | 
 | ||||||
| <script setup> | <script setup> | ||||||
| import { ref, computed } from 'vue'; | import { ref, computed } from 'vue'; | ||||||
| 
 | 
 | ||||||
| const activeStatus = ref('onSale'); | const activeTab = ref('onSale'); | ||||||
| 
 | 
 | ||||||
| // 状态映射配置,用于 el-tag 的样式 | const tabLabels = { | ||||||
| const statusMap = { |   onSale: '在售中', | ||||||
|   onSale: 'success', |   offShelf: '未上架', | ||||||
|   notListed: 'info', |   expired: '已失效', | ||||||
|   expired: 'danger', |  | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| // 商品数据,这里保持与原型图中的展示一致 | // 示例数据,替换为真实接口数据 | ||||||
| const products = ref([ | const products = ref([ | ||||||
|   { |   { | ||||||
|     id: 1, |     id: 1, | ||||||
|     name: '耿马镇沙瓢西红柿', |     name: '耿马镇沙疆西红柿', | ||||||
|  |     img: 'https://via.placeholder.com/80', | ||||||
|     monthlySales: 999, |     monthlySales: 999, | ||||||
|     stock: 10000, |     stock: 10000, | ||||||
|     price: '¥3.0/kg', |     price: 3.0, | ||||||
|     status: 'onSale', |     status: 'onSale', | ||||||
|     statusLabel: '在售中', |  | ||||||
|   }, |   }, | ||||||
|   { |   { | ||||||
|     id: 2, |     id: 2, | ||||||
|     name: '昭通乡土黄瓜', |     name: '耿马镇沙疆土豆', | ||||||
|     monthlySales: 750, |     img: 'https://via.placeholder.com/80', | ||||||
|     stock: 8500, |     monthlySales: 123, | ||||||
|     price: '¥2.5/kg', |     stock: 5000, | ||||||
|  |     price: 2.5, | ||||||
|     status: 'onSale', |     status: 'onSale', | ||||||
|     statusLabel: '在售中', |  | ||||||
|   }, |   }, | ||||||
|   { |   { | ||||||
|     id: 3, |     id: 3, | ||||||
|     name: '昆明有机苹果', |     name: '彩椒南瓜混合', | ||||||
|     monthlySales: 450, |     img: 'https://via.placeholder.com/80', | ||||||
|     stock: 5000, |     monthlySales: 456, | ||||||
|     price: '¥6.0/kg', |     stock: 8000, | ||||||
|     status: 'notListed', // 修改为 notListed,对应“未上架” |     price: 4.2, | ||||||
|     statusLabel: '未上架', |     status: 'offShelf', | ||||||
|   }, |  | ||||||
|   { |  | ||||||
|     id: 4, |  | ||||||
|     name: '楚雄散养鸡蛋', |  | ||||||
|     monthlySales: 1200, |  | ||||||
|     stock: 20000, |  | ||||||
|     price: '¥8.0/斤', |  | ||||||
|     status: 'onSale', |  | ||||||
|     statusLabel: '在售中', |  | ||||||
|   }, |   }, | ||||||
|  |   // … 更多数据 | ||||||
| ]); | ]); | ||||||
| 
 | 
 | ||||||
| // 根据当前选择状态过滤商品列表 | // 根据当前 Tab 过滤 | ||||||
| const filteredProducts = computed(() => { | const filteredProducts = computed(() => products.value.filter((p) => p.status === activeTab.value)); | ||||||
|   return products.value.filter((item) => item.status === activeStatus.value); |  | ||||||
| }); |  | ||||||
| 
 | 
 | ||||||
| // 操作处理逻辑 | // 操作回调 | ||||||
| const handleInspect = (product) => { | const onInspect = (p) => { | ||||||
|   console.log('抽查商品:', product); |   console.log('抽查商品', p); | ||||||
|  | }; | ||||||
|  | const onRevoke = (p) => { | ||||||
|  |   console.log('取消授权', p); | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| const handleRevoke = (product) => { | // 状态文字的颜色 | ||||||
|   console.log('取消授权:', product); | const statusClass = (tab) => { | ||||||
|  |   if (tab === 'offShelf') return 'text-warning'; | ||||||
|  |   if (tab === 'expired') return 'text-danger'; | ||||||
|  |   return 'text-success'; | ||||||
| }; | }; | ||||||
| </script> | </script> | ||||||
| 
 | 
 | ||||||
| <style lang="scss" scoped> | <style scoped lang="scss"> | ||||||
| .usage-monitor { | .usage-monitor { | ||||||
|   padding: 20px; |   padding: 20px; | ||||||
|  |   background: #fff; | ||||||
| 
 | 
 | ||||||
|   .mb-24 { |   .tabs-wrapper { | ||||||
|  |     display: flex; | ||||||
|  |     justify-content: center; | ||||||
|     margin-bottom: 24px; |     margin-bottom: 24px; | ||||||
|  | 
 | ||||||
|  |     .centered-tabs { | ||||||
|  |       width: 600px; /* 根据实际需要调整宽度 */ | ||||||
|  |       .el-tabs__header { | ||||||
|  |         justify-content: center; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   .product-card { |   .list-wrapper { | ||||||
|     position: relative; |     .list-item { | ||||||
|     margin-bottom: 16px; |       display: grid; | ||||||
|     transition: box-shadow 0.3s; |       grid-template-columns: 80px 1fr auto auto 80px; | ||||||
| 
 |       align-items: center; | ||||||
|     &:hover { |       padding: 16px 0; | ||||||
|       box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1); |       &.has-border { | ||||||
|     } |         border-top: 1px solid #ebeef5; | ||||||
| 
 |  | ||||||
|     .status-tag { |  | ||||||
|       position: absolute; |  | ||||||
|       top: 12px; |  | ||||||
|       right: 12px; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     .product-content { |  | ||||||
|       .product-name { |  | ||||||
|         margin: 0 0 12px; |  | ||||||
|         font-size: 16px; |  | ||||||
|         color: #303133; |  | ||||||
|       } |       } | ||||||
| 
 | 
 | ||||||
|       .sales-info { |       .item-img { | ||||||
|         display: flex; |         width: 80px; | ||||||
|         gap: 20px; |         height: 80px; | ||||||
|         margin-bottom: 12px; |         object-fit: cover; | ||||||
|  |         border-radius: 8px; | ||||||
|  |       } | ||||||
| 
 | 
 | ||||||
|         .data-item { |       .item-info { | ||||||
|           .label { |         padding-left: 16px; | ||||||
|             color: #909399; |         .item-name { | ||||||
|             margin-right: 4px; |           font-size: 16px; | ||||||
|           } |           font-weight: 500; | ||||||
|           .value { |           margin-bottom: 8px; | ||||||
|             font-weight: 500; |         } | ||||||
|           } |         .item-stats { | ||||||
|  |           color: #909399; | ||||||
|  |           font-size: 14px; | ||||||
|         } |         } | ||||||
|       } |       } | ||||||
| 
 | 
 | ||||||
|       .price { |       .item-price { | ||||||
|         color: #f56c6c; |  | ||||||
|         font-size: 18px; |         font-size: 18px; | ||||||
|         font-weight: 600; |         font-weight: 600; | ||||||
|  |         color: #67c23a; | ||||||
|  |         text-align: right; | ||||||
|  |         padding: 0 16px; | ||||||
|       } |       } | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|     .product-actions { |       .item-actions { | ||||||
|       margin-top: 16px; |         display: flex; | ||||||
|       display: flex; |         gap: 8px; | ||||||
|       gap: 8px; |       } | ||||||
|       justify-content: flex-end; | 
 | ||||||
|  |       .item-status { | ||||||
|  |         text-align: right; | ||||||
|  |         font-size: 14px; | ||||||
|  |         &.text-success { | ||||||
|  |           color: #67c23a; | ||||||
|  |         } | ||||||
|  |         &.text-warning { | ||||||
|  |           color: #e6a23c; | ||||||
|  |         } | ||||||
|  |         &.text-danger { | ||||||
|  |           color: #f56c6c; | ||||||
|  |         } | ||||||
|  |       } | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  | |||||||
| @ -6,7 +6,7 @@ | |||||||
|         <el-menu v-model:default-active="activeMenu" class="aside-menu" @select="handleMenuSelect"> |         <el-menu v-model:default-active="activeMenu" class="aside-menu" @select="handleMenuSelect"> | ||||||
|           <el-menu-item index="1"> |           <el-menu-item index="1"> | ||||||
|             <el-icon><Document /></el-icon> |             <el-icon><Document /></el-icon> | ||||||
|             <span>申请</span> |             <span>使用申请</span> | ||||||
|           </el-menu-item> |           </el-menu-item> | ||||||
| 
 | 
 | ||||||
|           <el-menu-item index="2"> |           <el-menu-item index="2"> | ||||||
|  | |||||||