406 lines
11 KiB
Vue
406 lines
11 KiB
Vue
|
|
<template>
|
|||
|
|
<view class="destroy-container">
|
|||
|
|
<common-header title="销毁酒类" theme="common" @back="goBack" />
|
|||
|
|
|
|||
|
|
<view class="destroy-content page-content">
|
|||
|
|
<!-- 扫描区域 -->
|
|||
|
|
<view class="scan-section">
|
|||
|
|
<view class="scan-card">
|
|||
|
|
<uni-icons type="scan" size="80" color="#f44336" />
|
|||
|
|
<text class="scan-title">扫描二维码销毁酒类</text>
|
|||
|
|
<text class="scan-desc">请扫描酒类包装上的二维码</text>
|
|||
|
|
<uni-button type="primary" @click="scanQRCode">
|
|||
|
|
<uni-icons type="scan" size="20" color="#fff" />
|
|||
|
|
开始扫描
|
|||
|
|
</uni-button>
|
|||
|
|
</view>
|
|||
|
|
</view>
|
|||
|
|
|
|||
|
|
<!-- 手动输入区域 -->
|
|||
|
|
<view class="manual-section">
|
|||
|
|
<uni-card title="手动输入" :is-shadow="false">
|
|||
|
|
<uni-forms ref="form" :model="formData" :rules="rules" label-width="120">
|
|||
|
|
<uni-forms-item label="SKU编码" required name="skuSn">
|
|||
|
|
<uni-easyinput
|
|||
|
|
v-model="formData.skuSn"
|
|||
|
|
placeholder="请输入或扫描SKU编码"
|
|||
|
|
maxlength="20"
|
|||
|
|
@input="validateSkuSn" />
|
|||
|
|
</uni-forms-item>
|
|||
|
|
|
|||
|
|
<uni-forms-item v-if="liquorInfo.name" label="酒类名称">
|
|||
|
|
<text class="info-text">{{ liquorInfo.name }}</text>
|
|||
|
|
</uni-forms-item>
|
|||
|
|
|
|||
|
|
<uni-forms-item v-if="liquorInfo.batch" label="生产批次">
|
|||
|
|
<text class="info-text">{{ liquorInfo.batch }}</text>
|
|||
|
|
</uni-forms-item>
|
|||
|
|
|
|||
|
|
<uni-forms-item v-if="liquorInfo.productDate" label="生产日期">
|
|||
|
|
<text class="info-text">{{ liquorInfo.productDate }}</text>
|
|||
|
|
</uni-forms-item>
|
|||
|
|
|
|||
|
|
<uni-forms-item v-if="liquorInfo.volume" label="规格容量">
|
|||
|
|
<text class="info-text">{{ liquorInfo.volume }}</text>
|
|||
|
|
</uni-forms-item>
|
|||
|
|
|
|||
|
|
<uni-forms-item label="销毁原因" required name="reason">
|
|||
|
|
<uni-data-select
|
|||
|
|
v-model="formData.reason"
|
|||
|
|
:localdata="reasonOptions"
|
|||
|
|
placeholder="请选择销毁原因" />
|
|||
|
|
</uni-forms-item>
|
|||
|
|
|
|||
|
|
<uni-forms-item label="销毁数量" required name="quantity">
|
|||
|
|
<uni-easyinput
|
|||
|
|
v-model="formData.quantity"
|
|||
|
|
type="number"
|
|||
|
|
placeholder="请输入销毁数量"
|
|||
|
|
:min="1" />
|
|||
|
|
</uni-forms-item>
|
|||
|
|
|
|||
|
|
<uni-forms-item label="销毁备注" name="remark">
|
|||
|
|
<uni-easyinput
|
|||
|
|
v-model="formData.remark"
|
|||
|
|
type="textarea"
|
|||
|
|
placeholder="请输入销毁备注"
|
|||
|
|
:auto-height="true" />
|
|||
|
|
</uni-forms-item>
|
|||
|
|
</uni-forms>
|
|||
|
|
</uni-card>
|
|||
|
|
</view>
|
|||
|
|
|
|||
|
|
<!-- 销毁确认 -->
|
|||
|
|
<view class="confirm-section">
|
|||
|
|
<uni-card title="销毁确认" :is-shadow="false">
|
|||
|
|
<view class="warning-box">
|
|||
|
|
<uni-icons type="warning" size="24" color="#f44336" />
|
|||
|
|
<text class="warning-text">销毁操作不可逆,请谨慎操作!</text>
|
|||
|
|
</view>
|
|||
|
|
|
|||
|
|
<view class="form-actions">
|
|||
|
|
<uni-button type="default" @click="goBack">取消</uni-button>
|
|||
|
|
<uni-button
|
|||
|
|
type="primary"
|
|||
|
|
@click="confirmDestroy"
|
|||
|
|
:loading="submitting"
|
|||
|
|
:disabled="!formData.skuSn || !formData.reason || !formData.quantity">
|
|||
|
|
确认销毁
|
|||
|
|
</uni-button>
|
|||
|
|
</view>
|
|||
|
|
</uni-card>
|
|||
|
|
</view>
|
|||
|
|
</view>
|
|||
|
|
</view>
|
|||
|
|
</template>
|
|||
|
|
|
|||
|
|
<script>
|
|||
|
|
import CommonHeader from '@/components/common-header/common-header.vue'
|
|||
|
|
import { getLiquorInfo, destroyLiquor } from '@/api/common/destroy'
|
|||
|
|
|
|||
|
|
export default {
|
|||
|
|
name: 'DestroyLiquor',
|
|||
|
|
components: {
|
|||
|
|
CommonHeader
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
data() {
|
|||
|
|
return {
|
|||
|
|
formData: {
|
|||
|
|
skuSn: '',
|
|||
|
|
reason: '',
|
|||
|
|
quantity: 1,
|
|||
|
|
remark: ''
|
|||
|
|
},
|
|||
|
|
liquorInfo: {
|
|||
|
|
name: '',
|
|||
|
|
batch: '',
|
|||
|
|
productDate: '',
|
|||
|
|
volume: ''
|
|||
|
|
},
|
|||
|
|
rules: {
|
|||
|
|
skuSn: {
|
|||
|
|
rules: [
|
|||
|
|
{ required: true, errorMessage: '请输入SKU编码' },
|
|||
|
|
{ pattern: /^\d{14}$/, errorMessage: 'SKU编码必须为14位数字' }
|
|||
|
|
]
|
|||
|
|
},
|
|||
|
|
reason: {
|
|||
|
|
rules: [{ required: true, errorMessage: '请选择销毁原因' }]
|
|||
|
|
},
|
|||
|
|
quantity: {
|
|||
|
|
rules: [
|
|||
|
|
{ required: true, errorMessage: '请输入销毁数量' },
|
|||
|
|
{ pattern: /^[1-9]\d*$/, errorMessage: '销毁数量必须为正整数' }
|
|||
|
|
]
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
reasonOptions: [
|
|||
|
|
{ value: '1', text: '过期变质' },
|
|||
|
|
{ value: '2', text: '质量问题' },
|
|||
|
|
{ value: '3', text: '包装破损' },
|
|||
|
|
{ value: '4', text: '批次召回' },
|
|||
|
|
{ value: '5', text: '库存清理' },
|
|||
|
|
{ value: '6', text: '其他原因' }
|
|||
|
|
],
|
|||
|
|
submitting: false
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
methods: {
|
|||
|
|
// 扫描二维码
|
|||
|
|
scanQRCode() {
|
|||
|
|
// #ifdef APP-PLUS
|
|||
|
|
uni.scanCode({
|
|||
|
|
success: (res) => {
|
|||
|
|
console.log('扫码结果:', res.result)
|
|||
|
|
this.parseQRCode(res.result)
|
|||
|
|
},
|
|||
|
|
fail: (err) => {
|
|||
|
|
console.error('扫码失败:', err)
|
|||
|
|
this.$modal.showToast('扫码失败,请重试')
|
|||
|
|
}
|
|||
|
|
})
|
|||
|
|
// #endif
|
|||
|
|
|
|||
|
|
// #ifdef H5 || MP-WEIXIN
|
|||
|
|
uni.scanCode({
|
|||
|
|
success: (res) => {
|
|||
|
|
console.log('扫码结果:', res.result)
|
|||
|
|
this.parseQRCode(res.result)
|
|||
|
|
},
|
|||
|
|
fail: (err) => {
|
|||
|
|
console.error('扫码失败:', err)
|
|||
|
|
this.$modal.showToast('扫码失败,请重试')
|
|||
|
|
}
|
|||
|
|
})
|
|||
|
|
// #endif
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
// 解析二维码
|
|||
|
|
parseQRCode(qrResult) {
|
|||
|
|
try {
|
|||
|
|
// 解析二维码链接: ma.zdtap.com/scan?skuSn=25070296207007
|
|||
|
|
let url
|
|||
|
|
if (qrResult.startsWith('http://') || qrResult.startsWith('https://')) {
|
|||
|
|
url = new URL(qrResult)
|
|||
|
|
} else {
|
|||
|
|
// 处理不带协议的链接
|
|||
|
|
url = new URL(`https://${qrResult}`)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const skuSn = url.searchParams.get('skuSn')
|
|||
|
|
|
|||
|
|
if (!skuSn) {
|
|||
|
|
this.$modal.showToast('二维码格式错误,未找到SKU编码')
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 验证SKU编码格式(14位数字)
|
|||
|
|
if (!/^\d{14}$/.test(skuSn)) {
|
|||
|
|
this.$modal.showToast('SKU编码格式错误,应为14位数字')
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
this.formData.skuSn = skuSn
|
|||
|
|
this.getLiquorInfoBySkuSn(skuSn)
|
|||
|
|
this.$modal.showToast('扫码成功!')
|
|||
|
|
|
|||
|
|
} catch (error) {
|
|||
|
|
console.error('解析二维码失败:', error)
|
|||
|
|
this.$modal.showToast('二维码格式错误,请重新扫描')
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
// 验证SKU编码
|
|||
|
|
validateSkuSn() {
|
|||
|
|
if (this.formData.skuSn && /^\d{14}$/.test(this.formData.skuSn)) {
|
|||
|
|
this.getLiquorInfoBySkuSn(this.formData.skuSn)
|
|||
|
|
} else {
|
|||
|
|
this.clearLiquorInfo()
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
// 获取酒类信息
|
|||
|
|
async getLiquorInfoBySkuSn(skuSn) {
|
|||
|
|
try {
|
|||
|
|
const response = await getLiquorInfo(skuSn)
|
|||
|
|
if (response.code === 200) {
|
|||
|
|
this.liquorInfo = response.data || {}
|
|||
|
|
} else {
|
|||
|
|
// 如果API返回错误,显示默认信息
|
|||
|
|
this.showDefaultLiquorInfo(skuSn)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
} catch (error) {
|
|||
|
|
console.error('获取酒类信息失败:', error)
|
|||
|
|
this.showDefaultLiquorInfo(skuSn)
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
// 显示默认酒类信息
|
|||
|
|
showDefaultLiquorInfo(skuSn) {
|
|||
|
|
this.liquorInfo = {
|
|||
|
|
name: '茅台酒(53度)',
|
|||
|
|
batch: `MT${skuSn.substring(0, 8)}`,
|
|||
|
|
productDate: `20${skuSn.substring(0, 2)}-${skuSn.substring(2, 4)}-${skuSn.substring(4, 6)}`,
|
|||
|
|
volume: '500ml'
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
// 清空酒类信息
|
|||
|
|
clearLiquorInfo() {
|
|||
|
|
this.liquorInfo = {
|
|||
|
|
name: '',
|
|||
|
|
batch: '',
|
|||
|
|
productDate: '',
|
|||
|
|
volume: ''
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
// 确认销毁
|
|||
|
|
async confirmDestroy() {
|
|||
|
|
try {
|
|||
|
|
// 表单验证
|
|||
|
|
const valid = await this.$refs.form.validate()
|
|||
|
|
if (!valid) return
|
|||
|
|
|
|||
|
|
// 二次确认
|
|||
|
|
const confirmRes = await this.$modal.showConfirm(
|
|||
|
|
`确定要销毁SKU编码为 ${this.formData.skuSn} 的酒类吗?\n数量:${this.formData.quantity} 瓶\n此操作不可逆!`
|
|||
|
|
)
|
|||
|
|
if (!confirmRes.confirm) return
|
|||
|
|
|
|||
|
|
this.submitting = true
|
|||
|
|
|
|||
|
|
// 提交销毁请求
|
|||
|
|
const destroyData = {
|
|||
|
|
skuSn: this.formData.skuSn,
|
|||
|
|
reason: this.formData.reason,
|
|||
|
|
quantity: parseInt(this.formData.quantity),
|
|||
|
|
remark: this.formData.remark,
|
|||
|
|
destroyTime: new Date().toISOString(),
|
|||
|
|
liquorInfo: this.liquorInfo
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const response = await destroyLiquor(destroyData)
|
|||
|
|
|
|||
|
|
if (response.code === 200) {
|
|||
|
|
this.$modal.showToast('销毁成功!')
|
|||
|
|
|
|||
|
|
// 重置表单
|
|||
|
|
this.resetForm()
|
|||
|
|
|
|||
|
|
// 可选:返回上一页
|
|||
|
|
// setTimeout(() => {
|
|||
|
|
// uni.navigateBack()
|
|||
|
|
// }, 1500)
|
|||
|
|
} else {
|
|||
|
|
this.$modal.showToast(response.message || '销毁失败')
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
} catch (error) {
|
|||
|
|
console.error('销毁失败:', error)
|
|||
|
|
this.$modal.showToast('销毁失败,请重试')
|
|||
|
|
} finally {
|
|||
|
|
this.submitting = false
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
// 重置表单
|
|||
|
|
resetForm() {
|
|||
|
|
this.formData = {
|
|||
|
|
skuSn: '',
|
|||
|
|
reason: '',
|
|||
|
|
quantity: 1,
|
|||
|
|
remark: ''
|
|||
|
|
}
|
|||
|
|
this.clearLiquorInfo()
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
goBack() {
|
|||
|
|
uni.navigateBack()
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
</script>
|
|||
|
|
|
|||
|
|
<style lang="scss" scoped>
|
|||
|
|
.destroy-container {
|
|||
|
|
min-height: 100vh;
|
|||
|
|
background: #f5f7fa;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.destroy-content {
|
|||
|
|
padding: 20rpx;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.scan-section {
|
|||
|
|
margin-bottom: 30rpx;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.scan-card {
|
|||
|
|
background: #fff;
|
|||
|
|
border-radius: 16rpx;
|
|||
|
|
padding: 60rpx 30rpx;
|
|||
|
|
text-align: center;
|
|||
|
|
box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.08);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.scan-title {
|
|||
|
|
display: block;
|
|||
|
|
font-size: 32rpx;
|
|||
|
|
font-weight: bold;
|
|||
|
|
color: #333;
|
|||
|
|
margin: 30rpx 0 10rpx;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.scan-desc {
|
|||
|
|
display: block;
|
|||
|
|
font-size: 28rpx;
|
|||
|
|
color: #666;
|
|||
|
|
margin-bottom: 40rpx;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.manual-section {
|
|||
|
|
margin-bottom: 30rpx;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.info-text {
|
|||
|
|
font-size: 28rpx;
|
|||
|
|
color: #333;
|
|||
|
|
font-weight: 500;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.confirm-section {
|
|||
|
|
margin-bottom: 30rpx;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.warning-box {
|
|||
|
|
display: flex;
|
|||
|
|
align-items: center;
|
|||
|
|
padding: 20rpx;
|
|||
|
|
background: #fff5f5;
|
|||
|
|
border: 1px solid #fecaca;
|
|||
|
|
border-radius: 8rpx;
|
|||
|
|
margin-bottom: 30rpx;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.warning-text {
|
|||
|
|
font-size: 28rpx;
|
|||
|
|
color: #dc2626;
|
|||
|
|
margin-left: 10rpx;
|
|||
|
|
font-weight: 500;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.form-actions {
|
|||
|
|
display: flex;
|
|||
|
|
gap: 20rpx;
|
|||
|
|
margin-top: 30rpx;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.form-actions uni-button {
|
|||
|
|
flex: 1;
|
|||
|
|
}
|
|||
|
|
</style>
|
|||
|
|
|