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

View File

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

View File

@ -6,7 +6,7 @@
<el-menu v-model:default-active="activeMenu" class="aside-menu" @select="handleMenuSelect">
<el-menu-item index="1">
<el-icon><Document /></el-icon>
<span>使用申请</span>
<span>申请</span>
</el-menu-item>
<el-menu-item index="2">