706 lines
15 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>
<view class="winelist">
<!-- 页面标题 -->
<view class="page-title">3步快速生成酒单</view>
<!-- 顶部酒款信息 -->
<view class="beer-info">
<view class="info-card" v-if="beerInfo.name">
<image :src="beerInfo.cover" mode="aspectFill" class="cover"></image>
<view class="info">
<view class="title">{{ beerInfo.name }}</view>
<view class="brewery">{{ beerInfo.brewery }}</view>
<view class="style">{{ beerInfo.style }}</view>
</view>
</view>
<view class="info-card empty-state" v-if="!beerInfo.name">
<view class="info">
<view class="title">请先选择酒款</view>
<view class="search-btn" @click="toSearch">
<text class="cuIcon-search"></text>
<text>搜索酒款</text>
</view>
</view>
</view>
</view>
<!-- 步骤引导 -->
<view class="steps">
<view class="step-item" :class="{'active': currentStep >= 1}">
<view class="step-number">1</view>
<view class="step-content">
<view class="step-title">输入酒枪编号</view>
<view class="step-desc">下方输入酒款对应的酒枪编号</view>
</view>
</view>
<view class="step-line" :class="{'active': currentStep >= 2}"></view>
<view class="step-item" :class="{'active': currentStep >= 2}">
<view class="step-number">2</view>
<view class="step-content">
<view class="step-title">编辑售卖规格</view>
<view class="step-desc">设置酒款的售卖规格和价格</view>
</view>
</view>
<view class="step-line" :class="{'active': currentStep >= 3}"></view>
<view class="step-item" :class="{'active': currentStep >= 3}">
<view class="step-number">3</view>
<view class="step-content">
<view class="step-title">选择导出方式</view>
<view class="step-desc">选择图片或文件格式导出</view>
</view>
</view>
</view>
<!-- 步骤内容区 -->
<view class="step-content-area">
<!-- 步骤1输入酒枪编号 -->
<view class="step-panel" v-if="currentStep === 1">
<view class="input-group">
<text class="label">酒枪编号</text>
<input type="number" v-model="tapNumber" placeholder="请输入整数" class="input" />
</view>
<view class="btn-group">
<button class="btn next" @click="nextStep">下一步</button>
</view>
</view>
<!-- 步骤2编辑售卖规格 -->
<view class="step-panel" v-if="currentStep === 2">
<view class="specs-list">
<view class="spec-item" v-for="(spec, index) in specs" :key="index">
<view class="spec-header">
<text class="spec-name">{{ spec.name }}</text>
<text class="delete" @click="deleteSpec(index)">删除</text>
</view>
<view class="spec-content">
<view class="input-group">
<text class="label">规格</text>
<view class="input-wrapper">
<input type="number" v-model="spec.unit" placeholder="请输入数字" class="input" @focus="handleUnitFocus(index)" @blur="handleUnitBlur(index)" />
<text class="unit" v-if="!spec.unitFocused">ML</text>
</view>
</view>
<view class="input-group">
<text class="label">价格</text>
<view class="input-wrapper">
<input type="number" v-model="spec.price" placeholder="请输入数字" class="input" @focus="handlePriceFocus(index)" @blur="handlePriceBlur(index)" />
<text class="unit" v-if="!spec.priceFocused"></text>
</view>
</view>
</view>
</view>
</view>
<view class="add-spec" @click="addSpec" v-if="specs.length < 2">
<text class="cuIcon-add"></text>
<text>添加规格</text>
</view>
<view class="btn-group">
<button class="btn prev" @click="prevStep">
<text class="cuIcon-back"></text>
<text>上一步</text>
</button>
<button class="btn next" @click="nextStep">下一步</button>
</view>
</view>
<!-- 步骤3选择导出方式 -->
<view class="step-panel" v-if="currentStep === 3">
<view class="export-options">
<view class="option-item" @click="toPerview(1)">
<text class="cuIcon-pic"></text>
<text>导出图片</text>
<text class="desc">以图片形式分享</text>
</view>
<view class="option-item" @click="toPerview(2)">
<text class="cuIcon-file"></text>
<text>导出文件</text>
<text class="desc">PDF文件适合打印460mm*230mm</text>
</view>
</view>
<view class="btn-group">
<button class="btn prev" @click="prevStep">
<text class="cuIcon-back"></text>
<text>上一步</text>
</button>
</view>
</view>
</view>
</view>
</template>
<script>
import {
getBeerInfo
} from "@/api/bar.js"
// 常量定义
const MAX_SPECS = 2
const DEFAULT_SPEC = {
name: '标准杯',
price: '',
unit: '',
unitFocused: false,
priceFocused: false
}
export default {
data() {
return {
currentStep: 1,
beerId: '',
beerInfo: {
cover: '',
name: '',
brewery: '',
style: ''
},
tapNumber: '',
specs: [DEFAULT_SPEC]
}
},
computed: {
canProceed() {
if (!this.beerInfo.name) return false
switch(this.currentStep) {
case 1: return this.tapNumber.length > 0
case 2: return this.specs.every(spec => spec.price && spec.unit)
default: return true
}
},
stepErrorMessage() {
if (!this.beerInfo.name) return '请先选择酒款'
switch(this.currentStep) {
case 1: return '请输入酒枪编号'
case 2: return '请完善规格信息'
default: return '请完成当前步骤'
}
}
},
onLoad(options) {
if(options.beerId) {
this.beerId = options.beerId
this.getBeerInfo()
}
},
methods: {
// 数据获取
async getBeerInfo() {
try {
const res = await getBeerInfo(this.beerId)
this.beerInfo = {
cover: res.data.cover,
name: res.data.beerName,
brewery: res.data.brandName,
style: res.data.beerStyles
}
} catch (error) {
uni.showToast({
title: '获取酒款信息失败',
icon: 'none'
})
console.error('获取酒款信息失败:', error)
}
},
// 步骤控制
nextStep() {
if (!this.beerInfo.name) {
this.showToast('请先选择酒款')
return
}
if (!this.canProceed) {
this.showToast(this.stepErrorMessage)
return
}
// 检查登录和认证状态
const token = uni.getStorageSync('token')
const isAuth = uni.getStorageSync('isAuth')
if (!token) {
this.$refs.loginRef.open()
return
}
if (!isAuth) {
uni.showModal({
title: '提示',
content: '您还未认证门店,请先完成认证',
confirmText: '去认证',
success: (res) => {
if (res.confirm) {
uni.navigateTo({
url: '/pagesActivity/barAuth'
})
}
}
})
return
}
if (this.currentStep < 3) {
this.currentStep++
}
},
prevStep() {
if (this.currentStep > 1) {
this.currentStep--
}
},
// 规格管理
addSpec() {
if (this.specs.length >= MAX_SPECS) {
this.showToast('最多添加2个规格')
return
}
this.specs.push({
...DEFAULT_SPEC,
name: `规格${this.specs.length + 1}`
})
},
deleteSpec(index) {
if (this.specs.length <= 1) {
this.showToast('至少保留一个规格')
return
}
this.specs.splice(index, 1)
},
// 输入处理
handleUnitFocus(index) {
this.specs[index].unitFocused = true
},
handleUnitBlur(index) {
this.specs[index].unitFocused = false
if (this.specs[index].unit) {
this.specs[index].unit = `${this.specs[index].unit}ML`
}
},
handlePriceFocus(index) {
this.specs[index].priceFocused = true
},
handlePriceBlur(index) {
this.specs[index].priceFocused = false
if (this.specs[index].price) {
this.specs[index].price = `${this.specs[index].price}`
}
},
// 导出处理
toPerview(type) {
if (!this.beerInfo.name) {
this.showToast('请先选择酒款')
return
}
if (!this.canProceed) {
this.showToast(this.stepErrorMessage)
return
}
const specs = this.specs.map(spec => ({
amount: spec.price,
specs: spec.unit
}))
const params = {
type,
beerId: this.beerId,
no: this.tapNumber,
amount: specs[0].amount,
amount1: specs[1]?.amount || '',
specs: specs[0].specs,
specs1: specs[1]?.specs || ''
}
uni.navigateTo({
url: `/pagesActivity/bgSelect?${this.buildQueryString(params)}`
})
},
// 工具方法
showToast(title) {
uni.showToast({
title,
icon: 'none'
})
},
buildQueryString(params) {
return Object.entries(params)
.map(([key, value]) => `${key}=${encodeURIComponent(value)}`)
.join('&')
},
// 页面跳转
toSearch() {
uni.navigateTo({
url: '/pagesActivity/homeSearch'
})
}
}
}
</script>
<style lang="scss" scoped>
// 通用样式
.input {
width: 100%;
height: 88rpx;
background: #F7F7F7;
border-radius: 12rpx;
padding: 0 24rpx;
font-size: 28rpx;
color: #0B0E26;
}
.btn {
width: 45%;
height: 88rpx;
border-radius: 44rpx;
font-size: 32rpx;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.3s ease;
&.prev {
background: #F7F7F7;
color: #606060;
border: 2rpx solid #E5E5E5;
.cuIcon-back {
font-size: 32rpx;
margin-right: 8rpx;
}
&:active {
background: #EEEEEE;
border-color: #D8D8D8;
transform: scale(0.98);
}
}
&.next {
background: #19367A;
color: #FFFFFF;
box-shadow: 0rpx 4rpx 12rpx rgba(25, 54, 122, 0.2);
&:active {
background: #152B5C;
transform: scale(0.98);
}
}
}
.winelist {
min-height: 100vh;
background: #F7F7F7;
padding: 32rpx;
.page-title {
font-size: 36rpx;
color: #0B0E26;
font-weight: 600;
margin-bottom: 32rpx;
text-align: center;
}
.beer-info {
margin-bottom: 48rpx;
.info-card {
background: #FFFFFF;
border-radius: 24rpx;
padding: 32rpx;
display: flex;
box-shadow: 0rpx 4rpx 12rpx rgba(0, 0, 0, 0.08);
height: 277rpx;
.cover {
width: 120rpx;
height: 213rpx;
border-radius: 16rpx;
margin-right: 24rpx;
overflow: hidden;
}
.info {
flex: 1;
display: flex;
flex-direction: column;
justify-content: space-between;
.title {
font-size: 32rpx;
color: #0B0E26;
font-weight: 600;
margin-bottom: 12rpx;
}
.brewery {
font-size: 28rpx;
color: #606060;
margin-bottom: 8rpx;
}
.style {
font-size: 24rpx;
color: #979797;
}
.search-btn {
height: 72rpx;
background: #D42E78;
border-radius: 36rpx;
display: flex;
align-items: center;
justify-content: center;
color: #FFFFFF;
font-size: 26rpx;
transition: all 0.3s ease;
width: 200rpx;
.cuIcon-search {
font-size: 28rpx;
margin-right: 8rpx;
}
&:active {
transform: scale(0.98);
background: #B81F5F;
}
}
}
&.empty-state {
.info {
justify-content: center;
align-items: center;
.title {
color: #606060;
text-align: center;
margin-bottom: 24rpx;
}
}
}
}
}
.steps {
background: #FFFFFF;
border-radius: 24rpx;
padding: 32rpx;
margin-bottom: 48rpx;
box-shadow: 0rpx 4rpx 12rpx rgba(0, 0, 0, 0.08);
.step-item {
display: flex;
align-items: flex-start;
margin-bottom: 32rpx;
&:last-child {
margin-bottom: 0;
}
&.active {
.step-number {
background: #19367A;
color: #FFFFFF;
}
.step-title {
color: #19367A;
}
}
.step-number {
width: 48rpx;
height: 48rpx;
border-radius: 50%;
background: #F5F5F5;
color: #979797;
display: flex;
align-items: center;
justify-content: center;
font-size: 24rpx;
margin-right: 24rpx;
transition: all 0.3s ease;
}
.step-content {
flex: 1;
.step-title {
font-size: 28rpx;
color: #606060;
margin-bottom: 8rpx;
transition: all 0.3s ease;
}
.step-desc {
font-size: 24rpx;
color: #979797;
}
}
}
.step-line {
height: 32rpx;
width: 2rpx;
background: #F5F5F5;
margin-left: 24rpx;
margin-bottom: 32rpx;
&.active {
background: #19367A;
}
}
}
.step-content-area {
background: #FFFFFF;
border-radius: 24rpx;
padding: 32rpx;
box-shadow: 0rpx 4rpx 12rpx rgba(0, 0, 0, 0.08);
.input-group {
margin-bottom: 24rpx;
.label {
font-size: 28rpx;
color: #606060;
margin-bottom: 12rpx;
display: block;
}
}
.input-wrapper {
position: relative;
width: 100%;
.unit {
position: absolute;
right: 24rpx;
top: 50%;
transform: translateY(-50%);
font-size: 28rpx;
color: #979797;
}
}
.specs-list {
margin-bottom: 32rpx;
.spec-item {
background: #F7F7F7;
border-radius: 16rpx;
padding: 24rpx;
margin-bottom: 24rpx;
&:last-child {
margin-bottom: 0;
}
.spec-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 24rpx;
.spec-name {
font-size: 28rpx;
color: #0B0E26;
font-weight: 500;
}
.delete {
font-size: 24rpx;
color: #FF4D4F;
}
}
}
}
.add-spec {
height: 88rpx;
background: #F7F7F7;
border-radius: 12rpx;
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 32rpx;
.cuIcon-add {
font-size: 32rpx;
color: #19367A;
margin-right: 8rpx;
}
text {
font-size: 28rpx;
color: #19367A;
}
}
.export-options {
display: flex;
justify-content: space-around;
margin-bottom: 48rpx;
.option-item {
width: 240rpx;
height: 240rpx;
background: #F7F7F7;
border-radius: 24rpx;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
transition: all 0.3s ease;
&:active {
transform: scale(0.98);
}
.cuIcon-pic,
.cuIcon-file {
font-size: 64rpx;
color: #19367A;
margin-bottom: 16rpx;
}
text {
font-size: 28rpx;
color: #606060;
&.desc {
font-size: 24rpx;
color: #979797;
margin-top: 8rpx;
text-align: center;
padding: 0 16rpx;
}
}
}
}
.btn-group {
display: flex;
justify-content: space-between;
margin-top: 48rpx;
}
}
}
</style>