Compare commits

..

No commits in common. "d485768e8fd016b8ebcdbfa4fae0bc554044f2d6" and "71abc7497e18d2023f129bcaa26c0d948215708c" have entirely different histories.

21 changed files with 291 additions and 233 deletions

File diff suppressed because one or more lines are too long

View File

@ -1,23 +0,0 @@
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); // 模拟网络延迟
});
},
};

View File

Before

Width:  |  Height:  |  Size: 61 KiB

After

Width:  |  Height:  |  Size: 61 KiB

View File

Before

Width:  |  Height:  |  Size: 55 KiB

After

Width:  |  Height:  |  Size: 55 KiB

View File

Before

Width:  |  Height:  |  Size: 59 KiB

After

Width:  |  Height:  |  Size: 59 KiB

View File

Before

Width:  |  Height:  |  Size: 53 KiB

After

Width:  |  Height:  |  Size: 53 KiB

View File

Before

Width:  |  Height:  |  Size: 46 KiB

After

Width:  |  Height:  |  Size: 46 KiB

View File

Before

Width:  |  Height:  |  Size: 62 KiB

After

Width:  |  Height:  |  Size: 62 KiB

View File

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 18 KiB

View File

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 18 KiB

View File

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 22 KiB

View File

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

View File

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

View File

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

View File

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

View File

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

@ -1,100 +1,67 @@
<template> <template>
<el-row :gutter="20" class="content-box"> <el-page-header>
<el-col v-for="product in products" :key="product.id" :span="6"> <template #breadcrumb>
<el-card class="box-card" :body-style="{ padding: '8px', height: '100%' }"> <el-breadcrumb separator="·">
<div class="flex-column"> <el-breadcrumb-item :to="{ path: './page-header.html' }"> 使用申请 </el-breadcrumb-item>
<img :src="product.img" alt="商品图" class="img" /> <el-breadcrumb-item>我要申请</el-breadcrumb-item>
<div class="flex-1 flex-around"> </el-breadcrumb>
<p>{{ product.name }}</p> </template>
<el-button type="success" class="button">我要申请</el-button> </el-page-header>
</div> <el-space class="content-box" wrap>
</div> <el-card v-for="o in 12" :key="o" class="box-card">
</el-card> <div style="height: 100%" class="flex-clomn">
</el-col> <img :src="url" alt="" class="img" />
</el-row> <p>耿马绿色蔬菜</p>
<el-button class="button">我要申请</el-button>
</div>
</el-card>
</el-space>
</template> </template>
<script setup> <script setup>
import { ref, onMounted } from 'vue'; const goBack = () => {
import productsApi from '@/apis/products'; console.log('go back');
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;
row-gap: 20px; box-sizing: border-box;
}
.box-card { .box-card {
width: 100%; box-shadow: none;
height: 334px; width: 224px;
border-radius: 16px; height: 334px;
padding: 0; background: #ffffff;
box-shadow: none; border-radius: 16px;
padding: 8;
.flex-column { .flex-clomn {
height: 100%; display: flex;
display: flex; flex-direction: column;
flex-direction: column; gap: 8;
justify-content: space-between; }
align-items: center; p {
padding: 0; text-align: center;
} font-size: 20px;
font-weight: 700;
.flex-around { }
display: flex;
flex-direction: column; .img {
justify-content: space-around; width: 182px;
align-items: center; height: 182px;
} }
.button {
.flex-1 { width: 96px;
flex: 1; height: 40px;
} background: #25bf82;
border-radius: 8px;
.flex-column p { align-self: center;
margin: 0; color: #fff;
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>

View File

@ -1,180 +1,179 @@
<template> <template>
<div class="usage-monitor"> <div class="usage-monitor">
<!-- 顶部 TabPane居中显示 --> <!-- 状态筛选 -->
<div class="tabs-wrapper"> <el-tabs v-model="activeStatus" class="mb-24">
<el-tabs v-model="activeTab" type="card" class="centered-tabs"> <el-tab-pane label="在售中" name="onSale" />
<el-tab-pane label="在售中" name="onSale" /> <el-tab-pane label="未上架" name="notListed" />
<el-tab-pane label="未上架" name="offShelf" /> <el-tab-pane label="已失效" name="expired" />
<el-tab-pane label="已失效" name="expired" /> </el-tabs>
</el-tabs>
</div>
<!-- 列表内容 --> <!-- 商品列表 -->
<div class="list-wrapper"> <el-row :gutter="16">
<div v-for="(p, idx) in filteredProducts" :key="p.id" class="list-item" :class="{ 'has-border': idx > 0 }"> <el-col v-for="product in filteredProducts" :key="product.id" :xs="24" :sm="12" :md="8" :lg="6" class="mb-16">
<!-- 商品图 --> <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="item-info"> <div class="product-content">
<div class="item-name">{{ p.name }}</div> <h4 class="product-name">{{ product.name }}</h4>
<div class="item-stats">月售 {{ p.monthlySales }} · 库存 {{ p.stock }}</div>
</div>
<!-- 价格 --> <div class="sales-info">
<div class="item-price">¥ {{ p.price }} /kg</div> <div class="data-item">
<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">
<div class="item-actions"> {{ product.price }}
<el-button size="small" @click="onInspect(p)">抽查</el-button> </div>
<el-button size="small" type="danger" @click="onRevoke(p)">取消授权</el-button> </div>
</div>
<!-- 右侧状态 --> <!-- 操作按钮 -->
<div class="item-status" :class="statusClass(activeTab)"> <div class="product-actions">
{{ tabLabels[activeTab] }} <el-button v-if="product.status !== 'expired'" size="small" @click="handleInspect(product)">抽查</el-button>
</div> <el-button v-if="product.status === 'onSale'" size="small" type="danger" plain @click="handleRevoke(product)">取消授权</el-button>
</div> </div>
</div> </el-card>
</el-col>
</el-row>
</div> </div>
</template> </template>
<script setup> <script setup>
import { ref, computed } from 'vue'; import { ref, computed } from 'vue';
const activeTab = ref('onSale'); const activeStatus = ref('onSale');
const tabLabels = { // el-tag
onSale: '在售中', const statusMap = {
offShelf: '未上架', onSale: 'success',
expired: '已失效', notListed: 'info',
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, price: '¥3.0/kg',
status: 'onSale', status: 'onSale',
statusLabel: '在售中',
}, },
{ {
id: 2, id: 2,
name: '耿马镇沙疆土豆', name: '昭通乡土黄瓜',
img: 'https://via.placeholder.com/80', monthlySales: 750,
monthlySales: 123, stock: 8500,
stock: 5000, price: '¥2.5/kg',
price: 2.5,
status: 'onSale', status: 'onSale',
statusLabel: '在售中',
}, },
{ {
id: 3, id: 3,
name: '彩椒南瓜混合', name: '昆明有机苹果',
img: 'https://via.placeholder.com/80', monthlySales: 450,
monthlySales: 456, stock: 5000,
stock: 8000, price: '¥6.0/kg',
price: 4.2, status: 'notListed', // notListed
status: 'offShelf', statusLabel: '未上架',
},
{
id: 4,
name: '楚雄散养鸡蛋',
monthlySales: 1200,
stock: 20000,
price: '¥8.0/斤',
status: 'onSale',
statusLabel: '在售中',
}, },
//
]); ]);
// Tab //
const filteredProducts = computed(() => products.value.filter((p) => p.status === activeTab.value)); const filteredProducts = computed(() => {
return products.value.filter((item) => item.status === activeStatus.value);
});
// //
const onInspect = (p) => { const handleInspect = (product) => {
console.log('抽查商品', p); console.log('抽查商品:', product);
};
const onRevoke = (p) => {
console.log('取消授权', p);
}; };
// const handleRevoke = (product) => {
const statusClass = (tab) => { console.log('取消授权:', product);
if (tab === 'offShelf') return 'text-warning';
if (tab === 'expired') return 'text-danger';
return 'text-success';
}; };
</script> </script>
<style scoped lang="scss"> <style lang="scss" scoped>
.usage-monitor { .usage-monitor {
padding: 20px; padding: 20px;
background: #fff;
.tabs-wrapper { .mb-24 {
display: flex;
justify-content: center;
margin-bottom: 24px; margin-bottom: 24px;
.centered-tabs {
width: 600px; /* 根据实际需要调整宽度 */
.el-tabs__header {
justify-content: center;
}
}
} }
.list-wrapper { .product-card {
.list-item { position: relative;
display: grid; margin-bottom: 16px;
grid-template-columns: 80px 1fr auto auto 80px; transition: box-shadow 0.3s;
align-items: center;
padding: 16px 0; &:hover {
&.has-border { box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
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;
} }
.item-img { .sales-info {
width: 80px; display: flex;
height: 80px; gap: 20px;
object-fit: cover; margin-bottom: 12px;
border-radius: 8px;
}
.item-info { .data-item {
padding-left: 16px; .label {
.item-name { color: #909399;
font-size: 16px; margin-right: 4px;
font-weight: 500; }
margin-bottom: 8px; .value {
} font-weight: 500;
.item-stats { }
color: #909399;
font-size: 14px;
} }
} }
.item-price { .price {
color: #f56c6c;
font-size: 18px; font-size: 18px;
font-weight: 600; font-weight: 600;
color: #67c23a;
text-align: right;
padding: 0 16px;
} }
}
.item-actions { .product-actions {
display: flex; margin-top: 16px;
gap: 8px; display: flex;
} 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;
}
}
} }
} }
} }

View File

@ -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">