2025-6-10

This commit is contained in:
姚俊旭 2025-06-10 18:19:58 +08:00
parent 9482747e01
commit 7198451dac
10 changed files with 393 additions and 37 deletions

View File

@ -43,7 +43,7 @@ export function addToCart(params) {
// 立即购买商品按钮
export function quicklyBuy(data = {}) {
return request('goods/goodInfoManage/contentPage', {
return request('user-center/orderInfo/genQuickBuyOrder', {
method: 'POST',
data,
});

View File

@ -86,6 +86,10 @@ const meuns = ref([
label: '智慧种植',
path: '/sub-operation-service/smartFarm',
},
{
label: '农事服务',
path: '/sub-operation-service/farmService',
},
{
label: '电商交易',
path: '/sub-operation-service/ecommerce',

View File

@ -71,17 +71,21 @@
<el-tag v-if="product.status == 2" size="large" class="text-warning status-tag" type="warning">审批中</el-tag>
<el-tag v-if="product.status == 3" size="large" class="text-danger status-tag" type="danger">被驳回</el-tag>
<el-tag v-if="product.status == 4" size="large" class="text-info status-tag" type="info">已失效</el-tag>
<el-button
v-if="product.status == 1"
type="primary"
plain
:icon="Edit"
size="large"
style="border-radius: 8px"
@click="handleCertificate(product)"
>
授权证书
</el-button>
<div style="display: flex">
<el-button
v-if="product.status == 1"
type="primary"
plain
:icon="Edit"
size="large"
style="border-radius: 8px"
@click="handleCertificate(product)"
>
授权证书
</el-button>
<el-button size="large" class="button" @click="onInspect(product)">溯源报告</el-button>
<el-button v-if="product.status == 1" size="large" class="button" type="danger" @click="onRevoke(product)">取消授权</el-button>
</div>
</div>
</div>
</div>
@ -98,6 +102,82 @@
/>
</div>
</el-dialog>
<!-- 抽查弹窗 -->
<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="traceData.img" alt="产品图" />
</div>
</div>
</el-dialog>
</div>
</template>
@ -107,6 +187,9 @@ import { getAssetsFile } from '@/utils/index.js';
import { authList, getProducts } from '@/apis/brand';
import { Edit } from '@element-plus/icons-vue';
const dialogVisible = ref(false);
const traceData = ref(null);
const activeStatus = ref('1');
const products = ref([
@ -172,6 +255,60 @@ const products = ref([
},
]);
const onRevoke = (p) => {
console.log('取消授权', p);
};
function onInspect(item) {
// getTraceById(id).then(res=> traceData.value = res)
const mocks = [
{
productName: '耿马镇沙疆西红柿',
quantity: '300KG',
producer: '北大荒技术有限公司',
origin: '耿马县孟定镇下坝村',
productionDate: '2025-6-3',
traceCode: '10.5487542154785XSE254.1040201',
traceCount: 30,
base: {
address: '耿马县孟定镇下坝村',
location: '东经102° · 北纬24°',
area: 9000,
climate: '亚热带高原季风型,温和多雨',
soil: '红壤',
},
farmingRecords: [
{ date: '2025/3/14', operation: '播种西红柿种', operator: '李强' },
{ date: '2025/4/2', operation: '施肥 氮肥', operator: '李强' },
{ date: '2025/5/17', operation: '浇水', operator: '李强' },
{ date: '2025/6/14', operation: '采摘', operator: '李强' },
],
packaging: {
company: '瑞禾农产品包装公司',
type: '纸箱',
person: '李明瑞',
time: '2025-1-20 16:27:41',
},
logistics: {
storageType: '冷藏',
temperature: '2°C',
shipFrom: '北京市朝阳区解放路24号',
shipTo: '上海市黄浦区南京路36号',
},
trade: {
time: '2025-4-2 08:13:52',
buyer: '李楠',
},
img: 'images/brand/product4.png',
},
];
traceData.value = mocks[0];
traceData.value.img = item.goodsUrl;
traceData.value.productName = item.productName;
console.log(item);
dialogVisible.value = true;
}
// const filteredProducts = computed(() => products.value.filter((p) => p.status === activeStatus.value));
const certificateDialogVisible = ref(false);
const currentCertificateImg = ref('');
@ -316,7 +453,7 @@ onMounted(() => {
:deep(.el-tabs__item) {
font-size: 24px;
font-weight: 700;
border: 1 solid #f000;
border: 0;
}
}
.flex {

View File

@ -15,13 +15,13 @@
<span>授权管理</span>
</template>
<el-menu-item index="auth/record"> 授权记录 </el-menu-item>
<el-menu-item index="auth/system"> 品牌制度 </el-menu-item>
<el-menu-item index="auth/system"> 品牌使用管理 </el-menu-item>
</el-sub-menu>
<el-menu-item index="monitor">
<img :src="getAssetsFile('images/brand/supervision.png')" class="menu-icon" alt="" />
<span>使用监管</span>
</el-menu-item>
<!-- <el-menu-item index="monitor">-->
<!-- <img :src="getAssetsFile('images/brand/supervision.png')" class="menu-icon" alt="" />-->
<!-- <span>使用监管</span>-->
<!-- </el-menu-item>-->
</el-menu>
</el-aside>

View File

@ -143,7 +143,7 @@ import { useRoute, useRouter } from 'vue-router';
import { getGoodDetail } from '@/apis/agricultural.js';
import { addToCart, quicklyBuy } from '../../apis/agricultural.js';
import { useMethodsStore } from '@/store/modules/methods';
import { ElMessage } from 'element-plus';
import { ElMessage, ElMessageBox } from 'element-plus';
const methodsStore = useMethodsStore();
@ -406,12 +406,25 @@ const toBack = (level) => {
};
const buyGood = () => {
const obj = {
goodsId: goodId,
weightId: currentGood.value.netWeight[currentWeight.value].id, // ID
quantity: saveInfo.num,
};
// quicklyBuy(obj).then((res) => {});
ElMessageBox.confirm('是否确认直接购买该商品?', '请确认', {
distinguishCancelAndClose: true,
confirmButtonText: '确认',
cancelButtonText: '取消',
}).then(() => {
const obj = {
goodsId: goodId,
weightId: currentGood.value.netWeight[currentWeight.value].id, // ID
quantity: saveInfo.num,
};
quicklyBuy(obj).then((res) => {
if (res.code === 200) {
router.push({
path: '/sub-operation-service/sureOrder',
query: { id: res.data.id },
});
}
});
});
};
const addGoodToCart = () => {

View File

@ -3,8 +3,8 @@
<div style="width: 40%; margin-left: 10px">
<div class="search-container">
<div class="search-box">
<input type="text" placeholder="请输入农资商品名称" class="search-input" />
<button class="search-button">
<input v-model="searchName" type="text" placeholder="请输入农资商品名称" class="search-input" />
<button class="search-button" @click.stop="search()">
<svg
xmlns="http://www.w3.org/2000/svg"
width="16"
@ -53,6 +53,12 @@ const props = defineProps({
},
});
const searchName = ref('');
const search = () => {
emit('search', { searchName: searchName.value });
};
watch(
() => props.list,
() => {
@ -147,7 +153,7 @@ const selectAll = (key) => {
emit('select', select);
};
const emit = defineEmits(['select']);
const emit = defineEmits(['select', 'search']);
</script>
<style lang="scss" scoped>
.el-input-group--append > .el-input__wrapper {

View File

@ -7,17 +7,58 @@
<div class="goods-name txt-ellipsis clamp2">{{ data.goodName }}</div>
<div class="goods-do">
<div class="price txt-ellipsis clamp">{{ data.goodPrice }}</div>
<div class="do">
<div class="do" @click.stop="openDialog(data)">
<div class="iconfont icon-cart"></div>
</div>
</div>
</div>
<el-dialog v-model="centerDialogVisible" title="Warning" width="80%" align-center :show-close="false" style="border-radius: 16px">
<template #header>
<div style="text-align: right" @click="centerDialogVisible = false">
<el-icon size="25" style="cursor: pointer"><Close /></el-icon>
</div>
</template>
<template #default>
<div style="padding: 20px; text-align: left">
<div style="text-align: left; display: flex">
<img :src="currentGood.goodUrl" style="width: 120px" alt="" />
<div style="margin-left: 15px; display: flex; flex-direction: column; justify-content: space-around">
<div style="font-size: 20px; color: #25bf82">{{ currentGood.netWeight ? currentGood.netWeight[0].goodPrice : 0 }}</div>
<div style="font-size: 18px; color: black">{{ currentGood.goodName }}</div>
</div>
</div>
<div class="dialogSubTitle">选择规格</div>
<div class="weight">
<div
v-for="(item, index) in currentGood.netWeight"
:key="item.id"
:class="{ weightActive: currentWeight === index }"
@click="currentWeight = index"
>
{{ item.goodSpecs }}{{ item.unit }}
</div>
</div>
<div class="dialogSubTitle">购买数量</div>
<el-input-number v-model="buyCount" :min="1" :max="10" style="margin-top: 20px" />
</div>
</template>
<template #footer>
<div class="dialog-footer" style="text-align: center">
<el-button class="btnBottom" style="background-color: #25bf82" @click="buyGood">立即购买</el-button>
<el-button class="btnBottom" style="background-color: #ffbe4d" @click="addGoodToCart">加入购物车</el-button>
</div>
</template>
</el-dialog>
</template>
<script setup>
import { ref, onMounted, computed } from 'vue';
import { isEmpty, getAssetsFile } from '@/utils';
import { useRoute, useRouter } from 'vue-router';
import { encodeURL } from 'js-base64';
import { getGoodDetail } from '@/apis/agricultural.js';
import { addToCart, quicklyBuy } from '@/apis/agricultural.js';
import { useMethodsStore } from '@/store/modules/methods';
import { ElMessage, ElMessageBox } from 'element-plus';
const route = useRoute();
const router = useRouter();
@ -32,10 +73,66 @@ const props = defineProps({
},
});
const centerDialogVisible = ref(false);
const currentWeight = ref(0);
const handleImageError = (e) => {
console.error('图片加载失败:', e);
};
const currentGood = ref({});
const buyCount = ref(1);
const methodsStore = useMethodsStore();
const buyGood = () => {
ElMessageBox.confirm('是否确认直接购买该商品?', '请确认', {
distinguishCancelAndClose: true,
confirmButtonText: '确认',
cancelButtonText: '取消',
}).then(() => {
const obj = {
goodsId: currentGood.value.id,
weightId: currentGood.value.netWeight[currentWeight.value].id, // ID
quantity: buyCount.value,
};
quicklyBuy(obj).then((res) => {
if (res.code === 200) {
router.push({
path: '/sub-operation-service/sureOrder',
query: { id: res.data.id },
});
}
});
});
};
const addGoodToCart = () => {
const obj = {
goodsId: currentGood.value.id,
weightId: currentGood.value.netWeight[currentWeight.value].id, // ID
quantity: buyCount.value,
};
addToCart(obj).then((res) => {
if (res.code === 200) {
centerDialogVisible.value = false;
methodsStore.callOuterMethod();
ElMessage.success('添加成功');
}
});
};
const openDialog = (data) => {
centerDialogVisible.value = true;
getGoodDetail(data.id).then(async (res) => {
if (res.code === 200) {
currentGood.value = res.data;
currentGood.value.id = data.id;
console.log(currentGood.value);
}
});
};
const toDetail = (id, pid) => {
if (props.type === 2) {
router.push('/sub-operation-service/ecommerce-supplier/detail?id=' + id + '&pid=' + pid);
@ -45,6 +142,43 @@ const toDetail = (id, pid) => {
};
</script>
<style lang="scss" scoped>
.dialog-footer {
.btnBottom {
height: 60px;
width: 200px;
border-radius: 16px;
font-size: 20px;
font-weight: bold;
color: #ffffff;
}
}
.weight {
display: flex;
justify-content: flex-start;
margin-top: 20px;
text-align: center;
div {
width: 22%;
margin: 0 1%;
font-size: 18px;
padding: 10px 0;
color: #dadada;
border-radius: 8px;
border: 1px solid #dadada;
cursor: pointer;
}
}
.weightActive {
border: 1px solid #25bf82 !important;
color: #25bf82 !important;
}
.dialogSubTitle {
font-size: 20px;
font-weight: bold;
text-align: left;
color: black;
margin-top: 20px;
}
.c-goods-item-warp {
padding: 8px;
width: 100%;

View File

@ -3,7 +3,7 @@
<common current-name="agricultural">
<template #main>
<banner :imglist="bannerList"></banner>
<filtertop :list="treeList" @select="selected"></filtertop>
<filtertop :list="treeList" @select="selected" @search="search"></filtertop>
<div class="goods-list-warp">
<div class="goods-list">
<template v-for="(n, index) in list" :key="n.id">
@ -104,7 +104,10 @@ const handleCurrentChange = (val) => {
pagination.current = val;
getList();
};
const getList = () => {
const getList = (data) => {
if (data) {
params.goodName = data.searchName;
}
params.current = pagination.current;
params.size = pagination.size;
agriculturalList(params).then((res) => {
@ -117,10 +120,13 @@ const getList = () => {
let bannerList = reactive(['images/ecommerce/' + 'banner.png', 'images/ecommerce/' + 'banner1.png']);
const search = (data) => {
getList(data);
};
const selected = (data) => {
//
// const val = Object.values(data);
console.log(data);
params.categoryId = data.id;
// if (val.length === 1) {
// params.parentId = val[0].id;

View File

@ -3,7 +3,7 @@
<common current-name="supplier">
<template #main>
<banner name="supplier" :imglist="bannerList"></banner>
<filtertop :list="treeList" @select="selected"></filtertop>
<filtertop :list="treeList" @select="selected" @search="search"></filtertop>
<div class="goods-list-warp">
<div class="goods-list">
<template v-for="(n, index) in list" :key="n.id">
@ -65,7 +65,10 @@ let pagination = reactive({
total: 4,
});
let bannerList = reactive(['images/ecommerce/' + 'banner1.png', 'images/ecommerce/' + 'banner1.png']);
const getList = () => {
const getList = (data) => {
if (data) {
params.goodName = data.searchName;
}
params.current = pagination.current;
params.size = pagination.size;
agriculturalList(params).then((res) => {
@ -81,6 +84,10 @@ onMounted(() => {
getTree();
});
const search = (data) => {
getList(data);
};
const handleSizeChange = (val) => {
pagination.size = val;
getList();

View File

@ -57,10 +57,10 @@
</div>
</div>
<div class="top-btn">
<div class="item-btn sign">
<div class="item-btn sign" @click="buyGood">
<span>立即购买</span>
</div>
<div class="item-btn reservation">
<div class="item-btn reservation" @click="addGoodToCart">
<span>加入购物车</span>
</div>
</div>
@ -141,6 +141,11 @@ import { qrImg } from '@/layouts/component/Header/base64img.js';
import evaluate from './components/evaluate.vue';
import { useRoute, useRouter } from 'vue-router';
import { getGoodDetail } from '@/apis/agricultural.js';
import { addToCart, quicklyBuy } from '../../apis/agricultural.js';
import { useMethodsStore } from '@/store/modules/methods';
import { ElMessage, ElMessageBox } from 'element-plus';
const methodsStore = useMethodsStore();
const route = useRoute();
const router = useRouter();
@ -393,13 +398,49 @@ const formattedData = (data) => {
};
const toCodeDetail = () => {
router.push('/sub-operation-service/ecommerce-supplier/detail/source?id=' + goodId);
router.push('/sub-operation-service/ecommerce-agricultural/ecommerce-agriculturalDetail/source?id=' + goodId);
};
const toBack = (level) => {
router.go(level);
};
const buyGood = () => {
ElMessageBox.confirm('是否确认直接购买该商品?', '请确认', {
distinguishCancelAndClose: true,
confirmButtonText: '确认',
cancelButtonText: '取消',
}).then(() => {
const obj = {
goodsId: goodId,
weightId: currentGood.value.netWeight[currentWeight.value].id, // ID
quantity: saveInfo.num,
};
quicklyBuy(obj).then((res) => {
if (res.code === 200) {
router.push({
path: '/sub-operation-service/sureOrder',
query: { id: res.data.id },
});
}
});
});
};
const addGoodToCart = () => {
const obj = {
goodsId: goodId, // ID
weightId: currentGood.value.netWeight[currentWeight.value].id, // ID
quantity: saveInfo.num, // 1
};
addToCart(obj).then((res) => {
if (res.code === 200) {
methodsStore.callOuterMethod();
ElMessage.success('添加成功');
}
});
};
const toCopy = () => {};
</script>
<style lang="scss" scoped>
@ -583,9 +624,17 @@ const toCopy = () => {};
line-height: 42px;
&.sign {
background: $color-main;
cursor: pointer;
}
&.sign:hover {
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15); /* 添加阴影效果 */
}
&.reservation {
background: $color-warning;
cursor: pointer;
}
&.reservation:hover {
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15); /* 添加阴影效果 */
}
}
}