2025-05-22 10:38:36 +08:00

343 lines
10 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="usage-monitor">
<!-- 顶部 TabPane居中显示 -->
<el-tabs v-model="activeTab" class="tabs-wrapper">
<el-tab-pane label="在售中" name="onSale" />
<el-tab-pane label="未上架" name="offShelf" />
<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="商品图" />
<!-- 名称 + 月售/库存 -->
<div class="item-info">
<div class="item-name">{{ p.name }}</div>
<div class="item-stats">月售 {{ p.monthlySales }} · 库存 {{ p.stock }}</div>
<div class="item-price">¥ {{ p.price }} /kg</div>
</div>
<div class="item-buttom">
<div class="item-status" :class="statusClass(activeTab)">
{{ tabLabels[activeTab] }}
</div>
<div class="item-actions">
<el-button size="large" class="button" @click="onInspect(p.id)">抽查</el-button>
<el-button size="large" class="button" type="danger" @click="onRevoke(p)">取消授权</el-button>
</div>
</div>
</div>
</div>
<!-- 抽查弹窗 -->
<el-dialog v-model="dialogVisible" width="720px" top="20px" modal="false" :before-close="() => (dialogVisible = false)" title="追溯记录">
<div v-if="traceData" class="trace-record">
<!-- 基本信息 -->
<section class="section">
<h3>基本信息</h3>
<el-row :gutter="12">
<el-col :span="6">产品名称:</el-col><el-col :span="18">{{ traceData.productName }}</el-col> <el-col :span="6">产品数量:</el-col
><el-col :span="18">{{ traceData.quantity }}</el-col> <el-col :span="6">生产经营主体:</el-col
><el-col :span="18">{{ traceData.producer }}</el-col> <el-col :span="6">原产地:</el-col
><el-col :span="18">{{ traceData.origin }}</el-col> <el-col :span="6">生产日期:</el-col
><el-col :span="18">{{ traceData.productionDate }}</el-col> <el-col :span="6">追溯码:</el-col
><el-col :span="18">{{ traceData.traceCode }}</el-col> <el-col :span="6">追溯次数:</el-col
><el-col :span="18">{{ traceData.traceCount }} 次</el-col>
</el-row>
</section>
<!-- 基地信息 -->
<section class="section">
<h3>基地信息</h3>
<el-row :gutter="12">
<el-col :span="6">基地地址:</el-col><el-col :span="18">{{ traceData.base.address }}</el-col> <el-col :span="6">地理位置:</el-col
><el-col :span="18">{{ traceData.base.location }}</el-col> <el-col :span="6">面积:</el-col
><el-col :span="18">{{ traceData.base.area }} 亩</el-col> <el-col :span="6">气候条件:</el-col
><el-col :span="18">{{ traceData.base.climate }}</el-col> <el-col :span="6">土壤类型:</el-col
><el-col :span="18">{{ traceData.base.soil }}</el-col>
</el-row>
</section>
<!-- 农事信息 -->
<section class="section">
<h3>农事信息</h3>
<el-table :data="traceData.farmingRecords" stripe border style="width: 100%">
<el-table-column prop="date" label="日期" width="120" />
<el-table-column prop="operation" label="操作" />
<el-table-column prop="operator" label="作业人" width="120" />
</el-table>
</section>
<!-- 包装信息 -->
<section class="section">
<h3>分拣包装</h3>
<el-row :gutter="12">
<el-col :span="6">包装企业:</el-col><el-col :span="18">{{ traceData.packaging.company }}</el-col> <el-col :span="6">包装类型:</el-col
><el-col :span="18">{{ traceData.packaging.type }}</el-col> <el-col :span="6">包装人:</el-col
><el-col :span="18">{{ traceData.packaging.person }}</el-col> <el-col :span="6">包装时间:</el-col
><el-col :span="18">{{ traceData.packaging.time }}</el-col>
</el-row>
</section>
<!-- 仓储物流 -->
<section class="section">
<h3>仓储物流信息</h3>
<el-row :gutter="12">
<el-col :span="6">存储类型:</el-col><el-col :span="18">{{ traceData.logistics.storageType }}</el-col>
<el-col :span="6">存储温度:</el-col><el-col :span="18">{{ traceData.logistics.temperature }}</el-col>
<el-col :span="6">发货地址:</el-col><el-col :span="18">{{ traceData.logistics.shipFrom }}</el-col> <el-col :span="6">收货地址:</el-col
><el-col :span="18">{{ traceData.logistics.shipTo }}</el-col>
</el-row>
</section>
<!-- 交易信息 -->
<section class="section">
<h3>交易信息</h3>
<el-row :gutter="12">
<el-col :span="6">交易时间:</el-col><el-col :span="18">{{ traceData.trade.time }}</el-col> <el-col :span="6">买家:</el-col
><el-col :span="18">{{ traceData.trade.buyer }}</el-col>
</el-row>
</section>
<!-- 右侧图片 -->
<div class="trace-img">
<img :src="getAssetsFile(traceData.img)" alt="产品图" />
</div>
</div>
</el-dialog>
</div>
</template>
<script setup>
import { ref, computed } from 'vue';
import { getAssetsFile } from '@/utils/index.js';
import { getMonitorList } from '@/apis/brand';
const activeTab = ref('onSale');
const dialogVisible = ref(false);
const traceData = ref(null);
const tabLabels = {
onSale: '在售中',
offShelf: '未上架',
expired: '已失效',
};
// 示例数据,替换为真实接口数据
const products = ref([
{
id: 1,
name: '耿马镇沙疆西红柿',
img: getAssetsFile('images/brand/product4.png'),
monthlySales: 999,
stock: 10000,
price: 3.0,
status: 'onSale',
},
{
id: 2,
name: '耿马镇沙疆土豆',
img: getAssetsFile('images/brand/product6.png'),
monthlySales: 123,
stock: 5000,
price: 2.5,
status: 'onSale',
},
{
id: 3,
name: '彩椒南瓜混合',
img: getAssetsFile('images/brand/product1.png'),
monthlySales: 456,
stock: 8000,
price: 4.2,
status: 'offShelf',
},
// … 更多数据
]);
// 根据当前 Tab 过滤
const filteredProducts = computed(() => products.value.filter((p) => p.status === activeTab.value));
// 点击抽查后,根据 id 单独拉取或赋值 traceData
function onInspect(id) {
console.log('查看产品:', id);
// 这里用硬编码模拟请求实际中可换成接口调用getTraceById(id).then(res=> traceData.value = res)
const mock = {
productName: '无土栽培土豆',
quantity: '200KG',
producer: '北大荒技术有限公司',
origin: '耿马县孟定镇下坝村',
productionDate: '2025-1-2',
traceCode: '10.5487542154785XSE254.1040201',
traceCount: 30,
base: {
address: '耿马县孟定镇下坝村',
location: '东经102° · 北纬24°',
area: 12000,
climate: '亚热带高原季风型,温和多雨',
soil: '红壤',
},
farmingRecords: [
{ date: '2024/1/2', operation: '播种 20250102批土豆种', operator: '张小东' },
{ date: '2024/2/2', operation: '施肥 氮肥', operator: '张小东' },
{ date: '2024/3/2', operation: '浇水', operator: '张小东' },
{ date: '2024/4/2', operation: '采摘', operator: '张小东' },
],
packaging: {
company: '瑞禾农产品包装公司',
type: '纸箱',
person: '王大福',
time: '2025-1-2 14:00:47',
},
logistics: {
storageType: '冷藏',
temperature: '2°C',
shipFrom: '北京市朝阳区解放路24号',
shipTo: '上海市黄浦区南京路36号',
},
trade: {
time: '2025-1-2 14:00:47',
buyer: '刘小花',
},
img: 'images/brand/product6.png',
};
traceData.value = mock;
dialogVisible.value = true;
}
const onRevoke = (p) => {
console.log('取消授权', p);
};
// 状态文字的颜色
const statusClass = (tab) => {
if (tab === 'offShelf') return 'text-warning';
if (tab === 'expired') return 'text-danger';
return 'text-success';
};
</script>
<style scoped lang="scss">
.usage-monitor {
padding: 20px;
background: #fff;
border-radius: 16px;
height: 100%;
.tabs-wrapper {
width: 100%;
display: flex;
align-items: center;
background-color: #fff;
:deep(.el-tabs__item) {
font-size: 24px;
font-weight: 700;
// border: 1 solid #f000;
}
}
.list-wrapper {
.list-item {
display: flex;
justify-content: start;
align-items: center;
padding: 20px 0;
.item-img {
width: 120px;
height: 120px;
object-fit: cover;
border-radius: 8px;
}
.item-info {
padding-left: 16px;
// background-color: #909399;
.item-name {
font-size: 20px;
font-weight: 700;
margin-bottom: 8px;
}
.item-stats {
color: #909399;
font-size: 14px;
}
}
.item-price {
font-size: 28px;
font-weight: 700;
color: #67c23a;
text-align: left;
padding-top: 8px;
}
.item-buttom {
display: flex;
flex-direction: column;
justify-content: space-between;
height: 110px;
flex: 1;
}
.item-actions {
display: flex;
justify-content: flex-end;
gap: 8px;
.button {
font-size: 20px;
font-weight: 400;
border-radius: 8px;
}
}
.item-status {
text-align: right;
font-size: 20px;
font-weight: 700;
&.text-success {
color: #67c23a;
}
&.text-warning {
color: #e6a23c;
}
&.text-danger {
color: #f56c6c;
}
}
}
}
.trace-record {
position: relative;
padding-right: 160px; /* 给图片预留空间 */
}
.trace-record .section {
margin-bottom: 16px;
}
.trace-record h3 {
margin-bottom: 8px;
font-size: 18px;
color: #409eff;
border-left: 4px solid #409eff;
padding-left: 8px;
}
.trace-img {
position: absolute;
top: 16px;
right: 16px;
width: 128px;
text-align: center;
}
.trace-img img {
width: 100%;
border-radius: 4px;
}
}
</style>