feat: 添加物供菜单入口

property-only-app
wx-jincw 3 months ago
parent 300d75bc42
commit 7a272e550e

@ -172,8 +172,71 @@
"path": "pages/index/components/b_combination",
"style": {}
}
],
"subPackages": [{
"root": "pages/supply_chain",
"name": "supply_chain",
"pages": [
{
"path": "traceability/index",
"style": {
"navigationBarTitleText": "溯源信息查看",
"navigationBarBackgroundColor": "#409EFF",
"navigationBarTextStyle": "white"
}
},
{
"path": "evaluation/index",
"style": {
"navigationBarTitleText": "食材满意度评价",
"navigationBarBackgroundColor": "#409EFF",
"navigationBarTextStyle": "white"
}
},
{
"path": "supply_query/index",
"style": {
"navigationBarTitleText": "物供相关查询",
"navigationBarBackgroundColor": "#409EFF",
"navigationBarTextStyle": "white"
}
},
{
"path": "purchase/index",
"style": {
"navigationBarTitleText": "采购相关操作",
"navigationBarBackgroundColor": "#409EFF",
"navigationBarTextStyle": "white"
}
},
{
"path": "stock/index",
"style": {
"navigationBarTitleText": "库存查询",
"navigationBarBackgroundColor": "#409EFF",
"navigationBarTextStyle": "white"
}
},
{
"path": "approval/index",
"style": {
"navigationBarTitleText": "审批处理",
"navigationBarBackgroundColor": "#409EFF",
"navigationBarTextStyle": "white"
}
},
{
"path": "material_receipt/index",
"style": {
"navigationBarTitleText": "物资领用",
"navigationBarBackgroundColor": "#409EFF",
"navigationBarTextStyle": "white"
}
}
]
},
{
"root": "pages/users",
"name": "users",
"pages": [

@ -0,0 +1,321 @@
<template>
<view class="approval-page">
<view class="header">
<view class="back" @click="goBack">
<text class="iconfont icon-xiangzuo"></text>
</view>
<view class="title">审批处理</view>
<view class="right"></view>
</view>
<view class="content">
<!-- 审批状态筛选 -->
<view class="filter-section">
<view class="filter-tab" :class="activeStatus === 'all' ? 'active' : ''" @click="activeStatus = 'all'">全部</view>
<view class="filter-tab" :class="activeStatus === 'pending' ? 'active' : ''" @click="activeStatus = 'pending'">待处理</view>
<view class="filter-tab" :class="activeStatus === 'processed' ? 'active' : ''" @click="activeStatus = 'processed'">已处理</view>
</view>
<!-- 审批列表 -->
<view class="approval-list">
<view class="approval-item" v-for="(item, index) in filteredApprovals" :key="index">
<view class="item-header">
<view class="header-left">
<text class="approval-type">{{ item.type }}</text>
<text class="approval-status" :class="getStatusClass(item.status)">{{ item.status }}</text>
</view>
<text class="approval-time">{{ item.time }}</text>
</view>
<view class="item-body">
<view class="info-item">
<text class="label">申请人</text>
<text class="value">{{ item.applicant }}</text>
</view>
<view class="info-item">
<text class="label">申请内容</text>
<text class="value">{{ item.content }}</text>
</view>
<view class="info-item" v-if="item.amount">
<text class="label">申请数量</text>
<text class="value">{{ item.amount }}</text>
</view>
</view>
<view class="item-footer" v-if="item.status === '待处理'">
<view class="reject-btn" @click="rejectApproval(item.id)"></view>
<view class="approve-btn" @click="approveApproval(item.id)"></view>
</view>
<view class="item-footer" v-else>
<text class="process-result">{{ item.result || '' }}</text>
</view>
</view>
</view>
<!-- 空状态 -->
<view class="empty-state" v-if="filteredApprovals.length === 0">
<text class="iconfont icon-wushuju"></text>
<text class="empty-text">暂无审批单据</text>
</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
activeStatus: 'all',
approvals: [
{ id: 1, type: '采购申请', status: '待处理', time: '2026-03-07 10:00', applicant: '张三', content: '采购有机蔬菜100斤', amount: 100 },
{ id: 2, type: '领用申请', status: '待处理', time: '2026-03-07 09:30', applicant: '李四', content: '领用维修耗材', amount: 50 },
{ id: 3, type: '采购申请', status: '已处理', time: '2026-03-06 16:00', applicant: '王五', content: '采购新鲜水果50斤', amount: 50, result: '已同意' },
{ id: 4, type: '领用申请', status: '已处理', time: '2026-03-06 14:00', applicant: '赵六', content: '领用办公用品', amount: 30, result: '已拒绝' }
]
};
},
computed: {
filteredApprovals() {
if (this.activeStatus === 'all') {
return this.approvals;
} else if (this.activeStatus === 'pending') {
return this.approvals.filter(item => item.status === '待处理');
} else if (this.activeStatus === 'processed') {
return this.approvals.filter(item => item.status === '已处理');
}
}
},
methods: {
goBack() {
uni.navigateBack();
},
getStatusClass(status) {
if (status === '待处理') {
return 'status-pending';
} else if (status === '已处理') {
return 'status-processed';
}
return '';
},
approveApproval(id) {
//
uni.showToast({
title: '审批已同意',
icon: 'success'
});
//
const approval = this.approvals.find(item => item.id === id);
if (approval) {
approval.status = '已处理';
approval.result = '已同意';
}
},
rejectApproval(id) {
//
uni.showToast({
title: '审批已拒绝',
icon: 'none'
});
//
const approval = this.approvals.find(item => item.id === id);
if (approval) {
approval.status = '已处理';
approval.result = '已拒绝';
}
}
}
};
</script>
<style lang="scss">
.approval-page {
.header {
display: flex;
align-items: center;
justify-content: space-between;
height: 88rpx;
padding: 0 30rpx;
background-color: #409EFF;
color: #fff;
.back {
width: 60rpx;
height: 100%;
display: flex;
align-items: center;
.iconfont {
font-size: 32rpx;
color: #fff;
}
}
.title {
font-size: 32rpx;
font-weight: 600;
}
.right {
width: 60rpx;
}
}
.content {
padding: 30rpx;
.filter-section {
display: flex;
margin-bottom: 30rpx;
background-color: #fff;
border-radius: 10rpx;
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.1);
.filter-tab {
flex: 1;
height: 80rpx;
display: flex;
align-items: center;
justify-content: center;
font-size: 26rpx;
color: #666;
position: relative;
&.active {
color: #409EFF;
&::after {
content: '';
position: absolute;
bottom: 0;
left: 50%;
transform: translateX(-50%);
width: 60rpx;
height: 4rpx;
background-color: #409EFF;
border-radius: 2rpx;
}
}
}
}
.approval-list {
.approval-item {
background-color: #fff;
border-radius: 10rpx;
padding: 20rpx;
margin-bottom: 20rpx;
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.1);
.item-header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 15rpx;
.header-left {
display: flex;
align-items: center;
.approval-type {
font-size: 26rpx;
font-weight: 600;
color: #333;
margin-right: 20rpx;
}
.approval-status {
padding: 5rpx 15rpx;
border-radius: 15rpx;
font-size: 20rpx;
}
.status-pending {
background-color: #E6F7FF;
color: #409EFF;
}
.status-processed {
background-color: #F6FFED;
color: #52C41A;
}
}
.approval-time {
font-size: 22rpx;
color: #999;
}
}
.item-body {
margin-bottom: 15rpx;
.info-item {
display: flex;
margin-bottom: 10rpx;
.label {
width: 100rpx;
font-size: 24rpx;
color: #666;
}
.value {
flex: 1;
font-size: 24rpx;
color: #333;
}
}
}
.item-footer {
display: flex;
align-items: center;
justify-content: flex-end;
.reject-btn,
.approve-btn {
padding: 8rpx 24rpx;
border-radius: 16rpx;
font-size: 22rpx;
margin-left: 20rpx;
}
.reject-btn {
background-color: #f5f5f5;
color: #666;
}
.approve-btn {
background-color: #409EFF;
color: #fff;
}
.process-result {
font-size: 22rpx;
color: #999;
}
}
}
}
.empty-state {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 400rpx;
.iconfont {
font-size: 80rpx;
color: #ddd;
margin-bottom: 20rpx;
}
.empty-text {
font-size: 24rpx;
color: #999;
}
}
}
}
</style>

@ -0,0 +1,285 @@
<template>
<view class="evaluation-page">
<view class="header">
<view class="back" @click="goBack">
<text class="iconfont icon-xiangzuo"></text>
</view>
<view class="title">食材满意度评价</view>
<view class="right"></view>
</view>
<view class="content">
<!-- 食材选择 -->
<view class="food-section">
<view class="section-title">选择食材</view>
<view class="food-list">
<view class="food-item" v-for="(item, index) in foodList" :key="index" @click="selectFood(item)">
<text class="food-name">{{ item.name }}</text>
<text class="food-date">{{ item.date }}</text>
<text class="iconfont" :class="selectedFood && selectedFood.id === item.id ? 'icon-duihao' : ''"></text>
</view>
</view>
</view>
<!-- 评分区域 -->
<view class="rating-section" v-if="selectedFood">
<view class="section-title">评分</view>
<view class="rating-box">
<view class="rating-item">
<text class="rating-label">质量评分</text>
<view class="stars">
<text class="iconfont" v-for="i in 5" :key="i" :class="i <= qualityRating ? 'icon-xingxing1' : 'icon-xingxing'" @click="qualityRating = i"></text>
</view>
</view>
<view class="rating-item">
<text class="rating-label">口感评分</text>
<view class="stars">
<text class="iconfont" v-for="i in 5" :key="i" :class="i <= tasteRating ? 'icon-xingxing1' : 'icon-xingxing'" @click="tasteRating = i"></text>
</view>
</view>
</view>
</view>
<!-- 评价意见 -->
<view class="comment-section" v-if="selectedFood">
<view class="section-title">评价意见</view>
<textarea v-model="comment" placeholder="请输入您的评价意见..." maxlength="200"></textarea>
<text class="count">{{ comment.length }}/200</text>
</view>
<!-- 提交按钮 -->
<view class="submit-section" v-if="selectedFood">
<view class="submit-btn" @click="submitEvaluation"></view>
</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
selectedFood: null,
qualityRating: 0,
tasteRating: 0,
comment: '',
foodList: [
{ id: 1, name: '有机蔬菜', date: '2026-03-07' },
{ id: 2, name: '新鲜水果', date: '2026-03-07' },
{ id: 3, name: '肉类食材', date: '2026-03-06' },
{ id: 4, name: '海鲜产品', date: '2026-03-06' }
]
};
},
methods: {
goBack() {
uni.navigateBack();
},
selectFood(food) {
this.selectedFood = food;
this.qualityRating = 0;
this.tasteRating = 0;
this.comment = '';
},
submitEvaluation() {
if (this.qualityRating === 0 || this.tasteRating === 0) {
uni.showToast({
title: '请完成评分',
icon: 'none'
});
return;
}
//
uni.showToast({
title: '评价提交成功',
icon: 'success'
});
//
setTimeout(() => {
this.selectedFood = null;
this.qualityRating = 0;
this.tasteRating = 0;
this.comment = '';
}, 1500);
}
}
};
</script>
<style lang="scss">
.evaluation-page {
.header {
display: flex;
align-items: center;
justify-content: space-between;
height: 88rpx;
padding: 0 30rpx;
background-color: #409EFF;
color: #fff;
.back {
width: 60rpx;
height: 100%;
display: flex;
align-items: center;
.iconfont {
font-size: 32rpx;
color: #fff;
}
}
.title {
font-size: 32rpx;
font-weight: 600;
}
.right {
width: 60rpx;
}
}
.content {
padding: 30rpx;
.food-section {
margin-bottom: 40rpx;
.section-title {
font-size: 28rpx;
font-weight: 600;
margin-bottom: 20rpx;
color: #333;
}
.food-list {
.food-item {
display: flex;
align-items: center;
background-color: #fff;
border-radius: 10rpx;
padding: 20rpx;
margin-bottom: 15rpx;
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
.food-name {
flex: 1;
font-size: 26rpx;
color: #333;
}
.food-date {
font-size: 22rpx;
color: #999;
margin-right: 20rpx;
}
.iconfont {
font-size: 28rpx;
color: #ddd;
}
.icon-duihao {
color: #409EFF;
}
}
}
}
.rating-section {
margin-bottom: 40rpx;
.section-title {
font-size: 28rpx;
font-weight: 600;
margin-bottom: 20rpx;
color: #333;
}
.rating-box {
background-color: #fff;
border-radius: 10rpx;
padding: 30rpx;
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.1);
.rating-item {
display: flex;
align-items: center;
margin-bottom: 30rpx;
&:last-child {
margin-bottom: 0;
}
.rating-label {
width: 160rpx;
font-size: 26rpx;
color: #666;
}
.stars {
flex: 1;
.iconfont {
font-size: 36rpx;
margin-right: 10rpx;
color: #ddd;
}
.icon-xingxing1 {
color: #FFD700;
}
}
}
}
}
.comment-section {
margin-bottom: 40rpx;
.section-title {
font-size: 28rpx;
font-weight: 600;
margin-bottom: 20rpx;
color: #333;
}
textarea {
width: 100%;
height: 200rpx;
border: 1rpx solid #ddd;
border-radius: 10rpx;
padding: 20rpx;
font-size: 24rpx;
background-color: #fff;
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.1);
}
.count {
display: block;
text-align: right;
font-size: 20rpx;
color: #999;
margin-top: 10rpx;
}
}
.submit-section {
.submit-btn {
height: 80rpx;
background-color: #409EFF;
color: #fff;
border-radius: 40rpx;
display: flex;
align-items: center;
justify-content: center;
font-size: 28rpx;
font-weight: 600;
box-shadow: 0 4rpx 12rpx rgba(64, 158, 255, 0.3);
}
}
}
}
</style>

@ -0,0 +1,337 @@
<template>
<view class="material-receipt-page">
<view class="header">
<view class="back" @click="goBack">
<text class="iconfont icon-xiangzuo"></text>
</view>
<view class="title">物资领用</view>
<view class="right"></view>
</view>
<view class="content">
<!-- 发起领用申请 -->
<view class="form-section">
<view class="form-title">发起领用申请</view>
<view class="form-content">
<view class="form-item">
<text class="label">物资名称</text>
<select v-model="receiptForm.materialName">
<option v-for="material in materials" :key="material.id" :value="material.name">{{ material.name }}</option>
</select>
</view>
<view class="form-item">
<text class="label">领用数量</text>
<input type="number" v-model="receiptForm.quantity" placeholder="请输入领用数量" />
</view>
<view class="form-item">
<text class="label">领用用途</text>
<textarea v-model="receiptForm.purpose" placeholder="请输入领用用途" maxlength="200"></textarea>
</view>
<view class="form-item">
<text class="label">领用人</text>
<input type="text" v-model="receiptForm.applicant" placeholder="请输入领用人姓名" />
</view>
<view class="submit-btn" @click="submitReceipt"></view>
</view>
</view>
<!-- 领用记录 -->
<view class="record-section">
<view class="record-title">领用记录</view>
<view class="record-list">
<view class="record-item" v-for="(item, index) in receiptRecords" :key="index">
<view class="item-header">
<text class="material-name">{{ item.materialName }}</text>
<text class="receipt-status" :class="getStatusClass(item.status)">{{ item.status }}</text>
</view>
<view class="item-body">
<view class="info-item">
<text class="label">领用数量</text>
<text class="value">{{ item.quantity }}</text>
</view>
<view class="info-item">
<text class="label">领用用途</text>
<text class="value">{{ item.purpose }}</text>
</view>
<view class="info-item">
<text class="label">领用人</text>
<text class="value">{{ item.applicant }}</text>
</view>
<view class="info-item">
<text class="label">申请时间</text>
<text class="value">{{ item.applyTime }}</text>
</view>
</view>
<view class="item-footer" v-if="item.status === '已审批'">
<view class="voucher-btn" @click="viewVoucher(item.id)"></view>
</view>
</view>
</view>
</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
receiptForm: {
materialName: '',
quantity: '',
purpose: '',
applicant: ''
},
materials: [
{ id: 1, name: '维修耗材' },
{ id: 2, name: '办公用品' },
{ id: 3, name: '清洁用品' },
{ id: 4, name: '食材' }
],
receiptRecords: [
{ id: 1, materialName: '维修耗材', quantity: 10, purpose: '设备维修', applicant: '张三', status: '已审批', applyTime: '2026-03-07 10:00' },
{ id: 2, materialName: '办公用品', quantity: 5, purpose: '日常办公', applicant: '李四', status: '待审批', applyTime: '2026-03-07 09:30' },
{ id: 3, materialName: '清洁用品', quantity: 20, purpose: '公共区域清洁', applicant: '王五', status: '已拒绝', applyTime: '2026-03-06 16:00' }
]
};
},
methods: {
goBack() {
uni.navigateBack();
},
submitReceipt() {
if (!this.receiptForm.materialName || !this.receiptForm.quantity || !this.receiptForm.purpose || !this.receiptForm.applicant) {
uni.showToast({
title: '请填写完整信息',
icon: 'none'
});
return;
}
//
uni.showToast({
title: '领用申请提交成功',
icon: 'success'
});
//
setTimeout(() => {
this.receiptForm = {
materialName: '',
quantity: '',
purpose: '',
applicant: ''
};
},
1500);
},
viewVoucher(id) {
//
uni.showModal({
title: '领用凭证',
content: '凭证编号LP20260307001\n领用人张三\n领用物资维修耗材\n领用数量10件\n审批状态已审批',
showCancel: false
});
},
getStatusClass(status) {
if (status === '待审批') {
return 'status-pending';
} else if (status === '已审批') {
return 'status-approved';
} else if (status === '已拒绝') {
return 'status-rejected';
}
return '';
}
}
};
</script>
<style lang="scss">
.material-receipt-page {
.header {
display: flex;
align-items: center;
justify-content: space-between;
height: 88rpx;
padding: 0 30rpx;
background-color: #409EFF;
color: #fff;
.back {
width: 60rpx;
height: 100%;
display: flex;
align-items: center;
.iconfont {
font-size: 32rpx;
color: #fff;
}
}
.title {
font-size: 32rpx;
font-weight: 600;
}
.right {
width: 60rpx;
}
}
.content {
padding: 30rpx;
.form-section {
background-color: #fff;
border-radius: 10rpx;
padding: 30rpx;
margin-bottom: 30rpx;
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.1);
.form-title {
font-size: 28rpx;
font-weight: 600;
color: #333;
margin-bottom: 30rpx;
text-align: center;
}
.form-content {
.form-item {
margin-bottom: 30rpx;
.label {
display: block;
font-size: 26rpx;
color: #333;
margin-bottom: 10rpx;
font-weight: 600;
}
input,
select,
textarea {
width: 100%;
border: 1rpx solid #ddd;
border-radius: 10rpx;
padding: 20rpx;
font-size: 24rpx;
}
textarea {
height: 150rpx;
}
}
.submit-btn {
height: 80rpx;
background-color: #409EFF;
color: #fff;
border-radius: 40rpx;
display: flex;
align-items: center;
justify-content: center;
font-size: 28rpx;
font-weight: 600;
box-shadow: 0 4rpx 12rpx rgba(64, 158, 255, 0.3);
}
}
}
.record-section {
background-color: #fff;
border-radius: 10rpx;
padding: 30rpx;
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.1);
.record-title {
font-size: 28rpx;
font-weight: 600;
color: #333;
margin-bottom: 30rpx;
text-align: center;
}
.record-list {
.record-item {
background-color: #f9f9f9;
border-radius: 10rpx;
padding: 20rpx;
margin-bottom: 20rpx;
.item-header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 15rpx;
.material-name {
font-size: 26rpx;
font-weight: 600;
color: #333;
}
.receipt-status {
padding: 5rpx 15rpx;
border-radius: 15rpx;
font-size: 20rpx;
}
.status-pending {
background-color: #E6F7FF;
color: #409EFF;
}
.status-approved {
background-color: #F6FFED;
color: #52C41A;
}
.status-rejected {
background-color: #FFF1F0;
color: #FF4D4F;
}
}
.item-body {
margin-bottom: 15rpx;
.info-item {
display: flex;
margin-bottom: 10rpx;
.label {
width: 120rpx;
font-size: 24rpx;
color: #666;
}
.value {
flex: 1;
font-size: 24rpx;
color: #333;
}
}
}
.item-footer {
display: flex;
align-items: center;
justify-content: flex-end;
.voucher-btn {
padding: 8rpx 24rpx;
background-color: #409EFF;
color: #fff;
border-radius: 16rpx;
font-size: 22rpx;
}
}
}
}
}
}
}
</style>

@ -0,0 +1,581 @@
<template>
<view class="purchase-page">
<view class="header">
<view class="back" @click="goBack">
<text class="iconfont icon-xiangzuo"></text>
</view>
<view class="title">采购相关操作</view>
<view class="right"></view>
</view>
<view class="content">
<!-- 操作菜单 -->
<view class="menu-grid">
<view class="menu-item" @click="openPurchaseRequest">
<view class="menu-icon">
<text class="iconfont icon-fapiaoshenqing"></text>
</view>
<text class="menu-text">发起采购需求</text>
</view>
<view class="menu-item" @click="openPurchasePlan">
<view class="menu-icon">
<text class="iconfont icon-jihua"></text>
</view>
<text class="menu-text">查看采购计划</text>
</view>
<view class="menu-item" @click="openOrderTracking">
<view class="menu-icon">
<text class="iconfont icon-dingdan"></text>
</view>
<text class="menu-text">跟踪订单进度</text>
</view>
<view class="menu-item" @click="openQualityFeedback">
<view class="menu-icon">
<text class="iconfont icon-tousu"></text>
</view>
<text class="menu-text">质量问题反馈</text>
</view>
</view>
<!-- 采购需求表单 -->
<view class="form-section" v-if="activeForm === 'request'">
<view class="form-title">发起采购需求</view>
<view class="form-content">
<view class="form-item">
<text class="label">采购物品</text>
<input type="text" v-model="purchaseRequest.name" placeholder="请输入采购物品名称" />
</view>
<view class="form-item">
<text class="label">采购数量</text>
<input type="number" v-model="purchaseRequest.quantity" placeholder="请输入采购数量" />
</view>
<view class="form-item">
<text class="label">采购原因</text>
<textarea v-model="purchaseRequest.reason" placeholder="请输入采购原因" maxlength="200"></textarea>
</view>
<view class="form-item">
<text class="label">期望到货时间</text>
<input type="date" v-model="purchaseRequest.expectedTime" />
</view>
<view class="submit-btn" @click="submitPurchaseRequest"></view>
</view>
</view>
<!-- 订单跟踪 -->
<view class="tracking-section" v-if="activeForm === 'tracking'">
<view class="form-title">跟踪订单进度</view>
<view class="search-box">
<input type="text" v-model="orderKeyword" placeholder="输入订单号搜索" />
<view class="search-btn" @click="searchOrder"></view>
</view>
<view class="order-list">
<view class="order-item" v-for="(item, index) in orders" :key="index">
<view class="item-header">
<text class="order-no">订单号{{ item.orderNo }}</text>
<text class="order-status" :class="getStatusClass(item.status)">{{ item.status }}</text>
</view>
<view class="item-body">
<view class="info-item">
<text class="label">采购物品</text>
<text class="value">{{ item.name }}</text>
</view>
<view class="info-item">
<text class="label">采购数量</text>
<text class="value">{{ item.quantity }}</text>
</view>
<view class="info-item">
<text class="label">下单时间</text>
<text class="value">{{ item.orderTime }}</text>
</view>
<view class="info-item">
<text class="label">预计到货</text>
<text class="value">{{ item.expectedTime }}</text>
</view>
</view>
<view class="item-footer">
<view class="detail-btn" @click="viewOrderDetail(item.id)"></view>
</view>
</view>
</view>
</view>
<!-- 质量问题反馈 -->
<view class="feedback-section" v-if="activeForm === 'feedback'">
<view class="form-title">质量问题反馈</view>
<view class="form-content">
<view class="form-item">
<text class="label">订单号</text>
<input type="text" v-model="qualityFeedback.orderNo" placeholder="请输入订单号" />
</view>
<view class="form-item">
<text class="label">问题描述</text>
<textarea v-model="qualityFeedback.description" placeholder="请详细描述质量问题" maxlength="200"></textarea>
</view>
<view class="form-item">
<text class="label">上传照片</text>
<view class="upload-box">
<view class="upload-btn" @click="uploadQualityImage">
<text class="iconfont icon-tianjia"></text>
<text>添加图片</text>
</view>
<view class="image-list">
<view class="image-item" v-for="(img, index) in qualityFeedback.images" :key="index">
<image :src="img" mode="aspectFill"></image>
<text class="delete-btn" @click="deleteQualityImage(index)">×</text>
</view>
</view>
</view>
</view>
<view class="submit-btn" @click="submitQualityFeedback"></view>
</view>
</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
activeForm: '',
orderKeyword: '',
purchaseRequest: {
name: '',
quantity: '',
reason: '',
expectedTime: ''
},
qualityFeedback: {
orderNo: '',
description: '',
images: []
},
orders: [
{ id: 1, orderNo: 'CG20260307001', name: '有机蔬菜', quantity: 100, status: '已下单', orderTime: '2026-03-07', expectedTime: '2026-03-09' },
{ id: 2, orderNo: 'CG20260307002', name: '新鲜水果', quantity: 50, status: '配送中', orderTime: '2026-03-06', expectedTime: '2026-03-08' },
{ id: 3, orderNo: 'CG20260307003', name: '肉类食材', quantity: 80, status: '已完成', orderTime: '2026-03-05', expectedTime: '2026-03-07' }
]
};
},
methods: {
goBack() {
uni.navigateBack();
},
openPurchaseRequest() {
this.activeForm = 'request';
this.purchaseRequest = {
name: '',
quantity: '',
reason: '',
expectedTime: ''
};
},
openPurchasePlan() {
uni.showToast({
title: '查看采购计划功能开发中',
icon: 'none'
});
},
openOrderTracking() {
this.activeForm = 'tracking';
this.orderKeyword = '';
},
openQualityFeedback() {
this.activeForm = 'feedback';
this.qualityFeedback = {
orderNo: '',
description: '',
images: []
};
},
submitPurchaseRequest() {
if (!this.purchaseRequest.name || !this.purchaseRequest.quantity || !this.purchaseRequest.reason) {
uni.showToast({
title: '请填写完整信息',
icon: 'none'
});
return;
}
//
uni.showToast({
title: '采购需求提交成功',
icon: 'success'
});
//
setTimeout(() => {
this.activeForm = '';
this.purchaseRequest = {
name: '',
quantity: '',
reason: '',
expectedTime: ''
};
}, 1500);
},
searchOrder() {
uni.showToast({
title: '搜索功能开发中',
icon: 'none'
});
},
viewOrderDetail(id) {
uni.showToast({
title: '查看订单详情',
icon: 'none'
});
},
uploadQualityImage() {
//
this.qualityFeedback.images.push('https://via.placeholder.com/100x100');
uni.showToast({
title: '图片上传成功',
icon: 'success'
});
},
deleteQualityImage(index) {
this.qualityFeedback.images.splice(index, 1);
},
submitQualityFeedback() {
if (!this.qualityFeedback.orderNo || !this.qualityFeedback.description) {
uni.showToast({
title: '请填写完整信息',
icon: 'none'
});
return;
}
//
uni.showToast({
title: '质量反馈提交成功',
icon: 'success'
});
//
setTimeout(() => {
this.activeForm = '';
this.qualityFeedback = {
orderNo: '',
description: '',
images: []
};
}, 1500);
},
getStatusClass(status) {
switch (status) {
case '已下单':
return 'status-ordered';
case '配送中':
return 'status-delivering';
case '已完成':
return 'status-completed';
default:
return '';
}
}
}
};
</script>
<style lang="scss">
.purchase-page {
.header {
display: flex;
align-items: center;
justify-content: space-between;
height: 88rpx;
padding: 0 30rpx;
background-color: #409EFF;
color: #fff;
.back {
width: 60rpx;
height: 100%;
display: flex;
align-items: center;
.iconfont {
font-size: 32rpx;
color: #fff;
}
}
.title {
font-size: 32rpx;
font-weight: 600;
}
.right {
width: 60rpx;
}
}
.content {
padding: 30rpx;
.menu-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 20rpx;
margin-bottom: 40rpx;
.menu-item {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
background-color: #fff;
border-radius: 10rpx;
padding: 40rpx 20rpx;
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.1);
.menu-icon {
width: 80rpx;
height: 80rpx;
background-color: #E6F7FF;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 20rpx;
.iconfont {
font-size: 40rpx;
color: #409EFF;
}
}
.menu-text {
font-size: 24rpx;
color: #333;
}
}
}
.form-section,
.tracking-section,
.feedback-section {
background-color: #fff;
border-radius: 10rpx;
padding: 30rpx;
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.1);
.form-title {
font-size: 28rpx;
font-weight: 600;
color: #333;
margin-bottom: 30rpx;
text-align: center;
}
.form-content {
.form-item {
margin-bottom: 30rpx;
.label {
display: block;
font-size: 26rpx;
color: #333;
margin-bottom: 10rpx;
font-weight: 600;
}
input,
textarea {
width: 100%;
border: 1rpx solid #ddd;
border-radius: 10rpx;
padding: 20rpx;
font-size: 24rpx;
}
textarea {
height: 150rpx;
}
.upload-box {
.display: flex;
flex-wrap: wrap;
.upload-btn {
width: 120rpx;
height: 120rpx;
border: 1rpx dashed #ddd;
border-radius: 10rpx;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
margin-right: 20rpx;
.iconfont {
font-size: 40rpx;
color: #ddd;
margin-bottom: 10rpx;
}
text {
font-size: 20rpx;
color: #999;
}
}
.image-list {
display: flex;
flex-wrap: wrap;
.image-item {
position: relative;
width: 120rpx;
height: 120rpx;
margin-right: 20rpx;
margin-bottom: 20rpx;
image {
width: 100%;
height: 100%;
border-radius: 10rpx;
}
.delete-btn {
position: absolute;
top: -10rpx;
right: -10rpx;
width: 30rpx;
height: 30rpx;
background-color: #ff4d4f;
color: #fff;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-size: 24rpx;
font-weight: bold;
}
}
}
}
}
.submit-btn {
height: 80rpx;
background-color: #409EFF;
color: #fff;
border-radius: 40rpx;
display: flex;
align-items: center;
justify-content: center;
font-size: 28rpx;
font-weight: 600;
box-shadow: 0 4rpx 12rpx rgba(64, 158, 255, 0.3);
}
}
.search-box {
display: flex;
margin-bottom: 20rpx;
input {
flex: 1;
height: 60rpx;
border: 1rpx solid #ddd;
border-radius: 30rpx;
padding: 0 30rpx;
font-size: 24rpx;
}
.search-btn {
width: 120rpx;
height: 60rpx;
background-color: #409EFF;
color: #fff;
border-radius: 30rpx;
display: flex;
align-items: center;
justify-content: center;
margin-left: 20rpx;
font-size: 24rpx;
}
}
.order-list {
.order-item {
background-color: #f9f9f9;
border-radius: 10rpx;
padding: 20rpx;
margin-bottom: 20rpx;
.item-header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 15rpx;
.order-no {
font-size: 24rpx;
color: #333;
font-weight: 600;
}
.order-status {
padding: 5rpx 15rpx;
border-radius: 15rpx;
font-size: 20rpx;
}
.status-ordered {
background-color: #E6F7FF;
color: #409EFF;
}
.status-delivering {
background-color: #FFF7E6;
color: #FA8C16;
}
.status-completed {
background-color: #F6FFED;
color: #52C41A;
}
}
.item-body {
margin-bottom: 15rpx;
.info-item {
display: flex;
margin-bottom: 10rpx;
.label {
width: 120rpx;
font-size: 24rpx;
color: #666;
}
.value {
flex: 1;
font-size: 24rpx;
color: #333;
}
}
}
.item-footer {
.display: flex;
justify-content: flex-end;
.detail-btn {
padding: 8rpx 16rpx;
background-color: #409EFF;
color: #fff;
border-radius: 16rpx;
font-size: 20rpx;
}
}
}
}
}
}
}
</style>

@ -0,0 +1,365 @@
<template>
<view class="stock-page">
<view class="header">
<view class="back" @click="goBack">
<text class="iconfont icon-xiangzuo"></text>
</view>
<view class="title">库存查询</view>
<view class="right"></view>
</view>
<view class="content">
<!-- 搜索和筛选 -->
<view class="search-section">
<view class="search-box">
<input type="text" v-model="searchKeyword" placeholder="搜索物资名称" />
<view class="search-btn" @click="searchStock"></view>
</view>
<view class="filter-box">
<view class="filter-item" @click="toggleFilter('category')">
<text>{{ selectedCategory || '全部类别' }}</text>
<text class="iconfont icon-xiangxia"></text>
</view>
<view class="filter-item" @click="toggleFilter('location')">
<text>{{ selectedLocation || '全部位置' }}</text>
<text class="iconfont icon-xiangxia"></text>
</view>
</view>
</view>
<!-- 库存预警 -->
<view class="alert-section" v-if="alertItems.length > 0">
<view class="alert-title">
<text class="iconfont icon-jinggao"></text>
<text>库存预警</text>
</view>
<view class="alert-list">
<view class="alert-item" v-for="(item, index) in alertItems" :key="index">
<text class="item-name">{{ item.name }}</text>
<text class="item-stock">当前库存{{ item.stock }}</text>
<text class="item-min">最低库存{{ item.minStock }}</text>
</view>
</view>
</view>
<!-- 库存列表 -->
<view class="stock-section">
<view class="stock-title">库存列表</view>
<view class="stock-list">
<view class="stock-item" v-for="(item, index) in stockItems" :key="index">
<view class="item-header">
<text class="item-name">{{ item.name }}</text>
<text class="item-status" :class="item.stock <= item.minStock ? 'status-warning' : 'status-normal'">
{{ item.stock <= item.minStock ? '库存不足' : '库存正常' }}
</text>
</view>
<view class="item-body">
<view class="info-item">
<text class="label">当前库存</text>
<text class="value">{{ item.stock }}</text>
</view>
<view class="info-item">
<text class="label">最低库存</text>
<text class="value">{{ item.minStock }}</text>
</view>
<view class="info-item">
<text class="label">库存位置</text>
<text class="value">{{ item.location }}</text>
</view>
<view class="info-item">
<text class="label">物资类别</text>
<text class="value">{{ item.category }}</text>
</view>
<view class="info-item">
<text class="label">最后更新</text>
<text class="value">{{ item.updateTime }}</text>
</view>
</view>
<view class="item-footer">
<view class="detail-btn" @click="viewStockDetail(item.id)"></view>
</view>
</view>
</view>
</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
searchKeyword: '',
selectedCategory: '',
selectedLocation: '',
alertItems: [
{ id: 1, name: '有机蔬菜', stock: 20, minStock: 30, location: '仓库A区', category: '食材' },
{ id: 3, name: '肉类食材', stock: 15, minStock: 20, location: '冷库C区', category: '食材' }
],
stockItems: [
{ id: 1, name: '有机蔬菜', stock: 20, minStock: 30, location: '仓库A区', category: '食材', updateTime: '2026-03-07 10:00' },
{ id: 2, name: '新鲜水果', stock: 40, minStock: 25, location: '仓库B区', category: '食材', updateTime: '2026-03-07 09:30' },
{ id: 3, name: '肉类食材', stock: 15, minStock: 20, location: '冷库C区', category: '食材', updateTime: '2026-03-06 18:00' },
{ id: 4, name: '海鲜产品', stock: 25, minStock: 15, location: '冷库D区', category: '食材', updateTime: '2026-03-06 17:30' },
{ id: 5, name: '维修耗材', stock: 50, minStock: 20, location: '仓库E区', category: '耗材', updateTime: '2026-03-05 14:00' },
{ id: 6, name: '办公用品', stock: 30, minStock: 15, location: '仓库F区', category: '办公', updateTime: '2026-03-05 13:30' }
]
};
},
methods: {
goBack() {
uni.navigateBack();
},
searchStock() {
uni.showToast({
title: '搜索功能开发中',
icon: 'none'
});
},
toggleFilter(type) {
uni.showToast({
title: '筛选功能开发中',
icon: 'none'
});
},
viewStockDetail(id) {
uni.showToast({
title: '查看库存详情',
icon: 'none'
});
}
}
};
</script>
<style lang="scss">
.stock-page {
.header {
display: flex;
align-items: center;
justify-content: space-between;
height: 88rpx;
padding: 0 30rpx;
background-color: #409EFF;
color: #fff;
.back {
width: 60rpx;
height: 100%;
display: flex;
align-items: center;
.iconfont {
font-size: 32rpx;
color: #fff;
}
}
.title {
font-size: 32rpx;
font-weight: 600;
}
.right {
width: 60rpx;
}
}
.content {
padding: 30rpx;
.search-section {
margin-bottom: 30rpx;
.search-box {
display: flex;
margin-bottom: 20rpx;
input {
flex: 1;
height: 60rpx;
border: 1rpx solid #ddd;
border-radius: 30rpx;
padding: 0 30rpx;
font-size: 24rpx;
}
.search-btn {
width: 120rpx;
height: 60rpx;
background-color: #409EFF;
color: #fff;
border-radius: 30rpx;
display: flex;
align-items: center;
justify-content: center;
margin-left: 20rpx;
font-size: 24rpx;
}
}
.filter-box {
display: flex;
.filter-item {
display: flex;
align-items: center;
padding: 10rpx 20rpx;
background-color: #fff;
border-radius: 20rpx;
margin-right: 20rpx;
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
text {
font-size: 24rpx;
color: #333;
margin-right: 10rpx;
}
.iconfont {
font-size: 20rpx;
color: #666;
}
}
}
}
.alert-section {
background-color: #FFF7E6;
border-radius: 10rpx;
padding: 20rpx;
margin-bottom: 30rpx;
border-left: 4rpx solid #FA8C16;
.alert-title {
display: flex;
align-items: center;
margin-bottom: 15rpx;
.iconfont {
font-size: 28rpx;
color: #FA8C16;
margin-right: 10rpx;
}
text {
font-size: 26rpx;
font-weight: 600;
color: #333;
}
}
.alert-list {
.alert-item {
display: flex;
align-items: center;
background-color: #fff;
border-radius: 8rpx;
padding: 15rpx;
margin-bottom: 10rpx;
.item-name {
flex: 1;
font-size: 24rpx;
color: #333;
font-weight: 600;
}
.item-stock {
font-size: 22rpx;
color: #FA8C16;
margin-right: 20rpx;
}
.item-min {
font-size: 22rpx;
color: #666;
}
}
}
}
.stock-section {
.stock-title {
font-size: 28rpx;
font-weight: 600;
color: #333;
margin-bottom: 20rpx;
}
.stock-list {
.stock-item {
background-color: #fff;
border-radius: 10rpx;
padding: 20rpx;
margin-bottom: 20rpx;
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.1);
.item-header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 15rpx;
.item-name {
font-size: 26rpx;
font-weight: 600;
color: #333;
}
.item-status {
padding: 5rpx 15rpx;
border-radius: 15rpx;
font-size: 20rpx;
}
.status-warning {
background-color: #FFF7E6;
color: #FA8C16;
}
.status-normal {
background-color: #F6FFED;
color: #52C41A;
}
}
.item-body {
margin-bottom: 15rpx;
.info-item {
display: flex;
margin-bottom: 10rpx;
.label {
width: 120rpx;
font-size: 24rpx;
color: #666;
}
.value {
flex: 1;
font-size: 24rpx;
color: #333;
}
}
}
.item-footer {
.display: flex;
justify-content: flex-end;
.detail-btn {
padding: 8rpx 16rpx;
background-color: #409EFF;
color: #fff;
border-radius: 16rpx;
font-size: 20rpx;
}
}
}
}
}
}
}
</style>

@ -0,0 +1,520 @@
<template>
<view class="supply-query-page">
<view class="header">
<view class="back" @click="goBack">
<text class="iconfont icon-xiangzuo"></text>
</view>
<view class="title">物供相关查询</view>
<view class="right"></view>
</view>
<view class="content">
<!-- 标签页 -->
<view class="tabs">
<view class="tab" :class="activeTab === 'purchase' ? 'active' : ''" @click="activeTab = 'purchase'">采购计划</view>
<view class="tab" :class="activeTab === 'stock' ? 'active' : ''" @click="activeTab = 'stock'">库存状态</view>
<view class="tab" :class="activeTab === 'quality' ? 'active' : ''" @click="activeTab = 'quality'">质量反馈</view>
</view>
<!-- 采购计划 -->
<view class="tab-content" v-show="activeTab === 'purchase'">
<view class="search-box">
<input type="text" v-model="searchKeyword" placeholder="搜索采购计划" />
<view class="search-btn" @click="searchPurchase"></view>
</view>
<view class="purchase-list">
<view class="purchase-item" v-for="(item, index) in purchasePlans" :key="index">
<view class="item-header">
<text class="plan-name">{{ item.name }}</text>
<text class="plan-status" :class="item.status === '进行中' ? 'status-active' : 'status-completed'">
{{ item.status }}
</text>
</view>
<view class="item-body">
<view class="info-item">
<text class="label">计划时间</text>
<text class="value">{{ item.time }}</text>
</view>
<view class="info-item">
<text class="label">采购数量</text>
<text class="value">{{ item.quantity }}</text>
</view>
<view class="info-item">
<text class="label">负责人</text>
<text class="value">{{ item.manager }}</text>
</view>
</view>
<view class="item-footer">
<view class="detail-btn" @click="viewPurchaseDetail(item.id)"></view>
</view>
</view>
</view>
</view>
<!-- 库存状态 -->
<view class="tab-content" v-show="activeTab === 'stock'">
<view class="search-box">
<input type="text" v-model="stockKeyword" placeholder="搜索库存物资" />
<view class="search-btn" @click="searchStock"></view>
</view>
<view class="stock-list">
<view class="stock-item" v-for="(item, index) in stockItems" :key="index">
<view class="item-header">
<text class="item-name">{{ item.name }}</text>
<text class="stock-status" :class="item.stock <= item.minStock ? 'status-warning' : 'status-normal'">
{{ item.stock <= item.minStock ? '库存不足' : '库存正常' }}
</text>
</view>
<view class="item-body">
<view class="info-item">
<text class="label">当前库存</text>
<text class="value">{{ item.stock }}</text>
</view>
<view class="info-item">
<text class="label">最低库存</text>
<text class="value">{{ item.minStock }}</text>
</view>
<view class="info-item">
<text class="label">库存位置</text>
<text class="value">{{ item.location }}</text>
</view>
</view>
</view>
</view>
</view>
<!-- 质量反馈 -->
<view class="tab-content" v-show="activeTab === 'quality'">
<view class="feedback-form">
<view class="form-item">
<text class="label">食材名称</text>
<select v-model="feedbackFood">
<option v-for="food in foodList" :key="food.id" :value="food.name">{{ food.name }}</option>
</select>
</view>
<view class="form-item">
<text class="label">问题类型</text>
<select v-model="feedbackType">
<option value="质量问题">质量问题</option>
<option value="数量问题">数量问题</option>
<option value="其他问题">其他问题</option>
</select>
</view>
<view class="form-item">
<text class="label">问题描述</text>
<textarea v-model="feedbackDesc" placeholder="请详细描述问题..." maxlength="200"></textarea>
</view>
<view class="form-item">
<text class="label">上传图片</text>
<view class="upload-box">
<view class="upload-btn" @click="uploadImage">
<text class="iconfont icon-tianjia"></text>
<text>添加图片</text>
</view>
<view class="image-list">
<view class="image-item" v-for="(img, index) in feedbackImages" :key="index">
<image :src="img" mode="aspectFill"></image>
<text class="delete-btn" @click="deleteImage(index)">×</text>
</view>
</view>
</view>
</view>
<view class="submit-btn" @click="submitFeedback"></view>
</view>
</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
activeTab: 'purchase',
searchKeyword: '',
stockKeyword: '',
feedbackFood: '',
feedbackType: '质量问题',
feedbackDesc: '',
feedbackImages: [],
purchasePlans: [
{ id: 1, name: '蔬菜采购计划', status: '进行中', time: '2026-03-07', quantity: 100, manager: '张三' },
{ id: 2, name: '水果采购计划', status: '进行中', time: '2026-03-08', quantity: 50, manager: '李四' },
{ id: 3, name: '肉类采购计划', status: '已完成', time: '2026-03-05', quantity: 80, manager: '王五' }
],
stockItems: [
{ id: 1, name: '有机蔬菜', stock: 20, minStock: 30, location: '仓库A区' },
{ id: 2, name: '新鲜水果', stock: 40, minStock: 25, location: '仓库B区' },
{ id: 3, name: '肉类食材', stock: 15, minStock: 20, location: '冷库C区' },
{ id: 4, name: '海鲜产品', stock: 25, minStock: 15, location: '冷库D区' }
],
foodList: [
{ id: 1, name: '有机蔬菜' },
{ id: 2, name: '新鲜水果' },
{ id: 3, name: '肉类食材' },
{ id: 4, name: '海鲜产品' }
]
};
},
methods: {
goBack() {
uni.navigateBack();
},
searchPurchase() {
uni.showToast({
title: '搜索功能开发中',
icon: 'none'
});
},
searchStock() {
uni.showToast({
title: '搜索功能开发中',
icon: 'none'
});
},
viewPurchaseDetail(id) {
uni.showToast({
title: '查看采购详情',
icon: 'none'
});
},
uploadImage() {
//
this.feedbackImages.push('https://via.placeholder.com/100x100');
uni.showToast({
title: '图片上传成功',
icon: 'success'
});
},
deleteImage(index) {
this.feedbackImages.splice(index, 1);
},
submitFeedback() {
if (!this.feedbackFood || !this.feedbackDesc) {
uni.showToast({
title: '请填写完整信息',
icon: 'none'
});
return;
}
//
uni.showToast({
title: '反馈提交成功',
icon: 'success'
});
//
setTimeout(() => {
this.feedbackFood = '';
this.feedbackType = '质量问题';
this.feedbackDesc = '';
this.feedbackImages = [];
}, 1500);
}
}
};
</script>
<style lang="scss">
.supply-query-page {
.header {
display: flex;
align-items: center;
justify-content: space-between;
height: 88rpx;
padding: 0 30rpx;
background-color: #409EFF;
color: #fff;
.back {
width: 60rpx;
height: 100%;
display: flex;
align-items: center;
.iconfont {
font-size: 32rpx;
color: #fff;
}
}
.title {
font-size: 32rpx;
font-weight: 600;
}
.right {
width: 60rpx;
}
}
.content {
padding: 30rpx;
.tabs {
display: flex;
margin-bottom: 30rpx;
background-color: #fff;
border-radius: 10rpx;
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.1);
.tab {
flex: 1;
height: 80rpx;
display: flex;
align-items: center;
justify-content: center;
font-size: 26rpx;
color: #666;
position: relative;
&.active {
color: #409EFF;
&::after {
content: '';
position: absolute;
bottom: 0;
left: 50%;
transform: translateX(-50%);
width: 60rpx;
height: 4rpx;
background-color: #409EFF;
border-radius: 2rpx;
}
}
}
}
.tab-content {
.search-box {
display: flex;
margin-bottom: 20rpx;
input {
flex: 1;
height: 60rpx;
border: 1rpx solid #ddd;
border-radius: 30rpx;
padding: 0 30rpx;
font-size: 24rpx;
}
.search-btn {
width: 120rpx;
height: 60rpx;
background-color: #409EFF;
color: #fff;
border-radius: 30rpx;
display: flex;
align-items: center;
justify-content: center;
margin-left: 20rpx;
font-size: 24rpx;
}
}
.purchase-list,
.stock-list {
.purchase-item,
.stock-item {
background-color: #fff;
border-radius: 10rpx;
padding: 20rpx;
margin-bottom: 20rpx;
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.1);
.item-header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 15rpx;
.plan-name,
.item-name {
font-size: 26rpx;
font-weight: 600;
color: #333;
}
.plan-status,
.stock-status {
padding: 5rpx 15rpx;
border-radius: 15rpx;
font-size: 20rpx;
}
.status-active {
background-color: #E6F7FF;
color: #409EFF;
}
.status-completed {
background-color: #F6FFED;
color: #52C41A;
}
.status-warning {
background-color: #FFF7E6;
color: #FA8C16;
}
.status-normal {
background-color: #F6FFED;
color: #52C41A;
}
}
.item-body {
margin-bottom: 15rpx;
.info-item {
display: flex;
margin-bottom: 10rpx;
.label {
width: 120rpx;
font-size: 24rpx;
color: #666;
}
.value {
flex: 1;
font-size: 24rpx;
color: #333;
}
}
}
.item-footer {
.display: flex;
justify-content: flex-end;
.detail-btn {
padding: 8rpx 16rpx;
background-color: #409EFF;
color: #fff;
border-radius: 16rpx;
font-size: 20rpx;
}
}
}
}
.feedback-form {
background-color: #fff;
border-radius: 10rpx;
padding: 30rpx;
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.1);
.form-item {
margin-bottom: 30rpx;
.label {
display: block;
font-size: 26rpx;
color: #333;
margin-bottom: 10rpx;
font-weight: 600;
}
select {
width: 100%;
height: 60rpx;
border: 1rpx solid #ddd;
border-radius: 10rpx;
padding: 0 20rpx;
font-size: 24rpx;
}
textarea {
width: 100%;
height: 150rpx;
border: 1rpx solid #ddd;
border-radius: 10rpx;
padding: 20rpx;
font-size: 24rpx;
}
.upload-box {
.display: flex;
flex-wrap: wrap;
.upload-btn {
width: 120rpx;
height: 120rpx;
border: 1rpx dashed #ddd;
border-radius: 10rpx;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
margin-right: 20rpx;
.iconfont {
font-size: 40rpx;
color: #ddd;
margin-bottom: 10rpx;
}
text {
font-size: 20rpx;
color: #999;
}
}
.image-list {
display: flex;
flex-wrap: wrap;
.image-item {
position: relative;
width: 120rpx;
height: 120rpx;
margin-right: 20rpx;
margin-bottom: 20rpx;
image {
width: 100%;
height: 100%;
border-radius: 10rpx;
}
.delete-btn {
position: absolute;
top: -10rpx;
right: -10rpx;
width: 30rpx;
height: 30rpx;
background-color: #ff4d4f;
color: #fff;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-size: 24rpx;
font-weight: bold;
}
}
}
}
}
.submit-btn {
height: 80rpx;
background-color: #409EFF;
color: #fff;
border-radius: 40rpx;
display: flex;
align-items: center;
justify-content: center;
font-size: 28rpx;
font-weight: 600;
box-shadow: 0 4rpx 12rpx rgba(64, 158, 255, 0.3);
}
}
}
}
}
</style>

@ -0,0 +1,307 @@
<template>
<view class="traceability-page">
<view class="header">
<view class="back" @click="goBack">
<text class="iconfont icon-xiangzuo"></text>
</view>
<view class="title">溯源信息查看</view>
<view class="right"></view>
</view>
<view class="content">
<!-- 扫码按钮 -->
<view class="scan-section">
<view class="scan-btn" @click="scanCode">
<text class="iconfont icon-saoma"></text>
<text class="btn-text">扫描溯源码</text>
</view>
<text class="hint">扫描食材上的追溯码查看详细信息</text>
</view>
<!-- 溯源信息展示 -->
<view class="info-section" v-if="traceInfo">
<view class="info-card">
<view class="info-item">
<text class="label">产品名称</text>
<text class="value">{{ traceInfo.productName }}</text>
</view>
<view class="info-item">
<text class="label">原料来源</text>
<text class="value">{{ traceInfo.source }}</text>
</view>
<view class="info-item">
<text class="label">检测报告</text>
<view class="report-btn" @click="viewReport"></view>
</view>
<view class="info-item">
<text class="label">物流轨迹</text>
<view class="track-btn" @click="viewTrack"></view>
</view>
<view class="info-item">
<text class="label">生产时间</text>
<text class="value">{{ traceInfo.productionTime }}</text>
</view>
<view class="info-item">
<text class="label">保质期</text>
<text class="value">{{ traceInfo.shelfLife }}</text>
</view>
</view>
</view>
<!-- 公共区域物资查询 -->
<view class="public-section">
<view class="section-title">公共区域物资查询</view>
<view class="search-box">
<input type="text" v-model="searchKeyword" placeholder="输入物资名称" />
<view class="search-btn" @click="searchPublicSupply"></view>
</view>
<view class="public-list">
<view class="public-item" v-for="(item, index) in publicSupplies" :key="index">
<text class="item-name">{{ item.name }}</text>
<text class="item-code">{{ item.code }}</text>
<view class="item-btn" @click="viewPublicTrace(item.id)"></view>
</view>
</view>
</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
traceInfo: null,
searchKeyword: '',
publicSupplies: [
{ id: 1, name: '维修耗材', code: 'WH-20260307-001' },
{ id: 2, name: '清洁用品', code: 'WH-20260307-002' },
{ id: 3, name: '办公用品', code: 'WH-20260307-003' }
]
};
},
methods: {
goBack() {
uni.navigateBack();
},
scanCode() {
//
uni.showToast({
title: '模拟扫码成功',
icon: 'success'
});
//
this.traceInfo = {
productName: '有机蔬菜',
source: '绿色农场',
productionTime: '2026-03-01',
shelfLife: '7天'
};
},
viewReport() {
uni.showToast({
title: '查看检测报告',
icon: 'none'
});
},
viewTrack() {
uni.showToast({
title: '查看物流轨迹',
icon: 'none'
});
},
searchPublicSupply() {
uni.showToast({
title: '搜索功能开发中',
icon: 'none'
});
},
viewPublicTrace(id) {
uni.showToast({
title: '查看公共物资溯源',
icon: 'none'
});
}
}
};
</script>
<style lang="scss">
.traceability-page {
.header {
display: flex;
align-items: center;
justify-content: space-between;
height: 88rpx;
padding: 0 30rpx;
background-color: #409EFF;
color: #fff;
.back {
width: 60rpx;
height: 100%;
display: flex;
align-items: center;
.iconfont {
font-size: 32rpx;
color: #fff;
}
}
.title {
font-size: 32rpx;
font-weight: 600;
}
.right {
width: 60rpx;
}
}
.content {
padding: 30rpx;
.scan-section {
display: flex;
flex-direction: column;
align-items: center;
margin-bottom: 40rpx;
.scan-btn {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
width: 200rpx;
height: 200rpx;
background-color: #409EFF;
border-radius: 20rpx;
margin-bottom: 20rpx;
.iconfont {
font-size: 80rpx;
color: #fff;
margin-bottom: 10rpx;
}
.btn-text {
color: #fff;
font-size: 24rpx;
}
}
.hint {
font-size: 24rpx;
color: #999;
}
}
.info-section {
margin-bottom: 40rpx;
.info-card {
background-color: #fff;
border-radius: 10rpx;
padding: 30rpx;
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.1);
.info-item {
display: flex;
align-items: center;
margin-bottom: 20rpx;
.label {
width: 160rpx;
font-size: 26rpx;
color: #666;
}
.value {
flex: 1;
font-size: 26rpx;
color: #333;
}
.report-btn,
.track-btn {
padding: 10rpx 20rpx;
background-color: #409EFF;
color: #fff;
border-radius: 20rpx;
font-size: 22rpx;
}
}
}
}
.public-section {
.section-title {
font-size: 28rpx;
font-weight: 600;
margin-bottom: 20rpx;
color: #333;
}
.search-box {
display: flex;
margin-bottom: 20rpx;
input {
flex: 1;
height: 60rpx;
border: 1rpx solid #ddd;
border-radius: 30rpx;
padding: 0 30rpx;
font-size: 24rpx;
}
.search-btn {
width: 120rpx;
height: 60rpx;
background-color: #409EFF;
color: #fff;
border-radius: 30rpx;
display: flex;
align-items: center;
justify-content: center;
margin-left: 20rpx;
font-size: 24rpx;
}
}
.public-list {
.public-item {
display: flex;
align-items: center;
background-color: #fff;
border-radius: 10rpx;
padding: 20rpx;
margin-bottom: 15rpx;
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
.item-name {
flex: 1;
font-size: 26rpx;
color: #333;
}
.item-code {
font-size: 22rpx;
color: #999;
margin-right: 20rpx;
}
.item-btn {
padding: 8rpx 16rpx;
background-color: #409EFF;
color: #fff;
border-radius: 16rpx;
font-size: 20rpx;
}
}
}
}
}
}
</style>
Loading…
Cancel
Save