877 lines
24 KiB
Vue
Raw Normal View History

2025-08-04 09:59:12 +08:00
<template>
<div class="app-container">
<div class="content-wrapper">
<!-- 操作区域 -->
<div class="operation-header">
<h2>我的酒单</h2>
<div class="operation-buttons">
<el-button type="primary" :icon="Plus" @click="showAddBeerDialog">
新酒上枪
</el-button>
<el-button type="success" :icon="Download" @click="showExportMenuDialog">
2025-08-04 20:02:06 +08:00
整版酒单
2025-08-04 09:59:12 +08:00
</el-button>
<el-button type="info" :icon="Refresh" @click="refreshData">
刷新
</el-button>
</div>
</div>
<!-- 在售酒款列表 -->
<div class="tap-list" v-loading="loading">
<div v-if="tapList.length === 0" class="empty-state">
<el-empty description="暂无在售酒款" />
</div>
<div v-else class="tap-items">
<div v-for="item in tapList" :key="item.id" class="tap-item">
<!-- 酒头编号 -->
<div class="tap-number">
<span class="tap-badge">{{ item.tapNo }}</span>
</div>
<!-- 酒款信息 -->
<div class="beer-info">
<div class="beer-image">
<img
:src="item.beerCover || '/images/default-beer.png'"
:alt="item.beerName"
/>
</div>
<div class="beer-details">
<h3 class="beer-name">{{ item.beerName }}</h3>
<p class="beer-brand">{{ item.brandName }}</p>
<p class="beer-style">
{{ item.beerStyles || item.customStyle }}
</p>
<p class="beer-abv">ABV {{ item.beerAbv }}%</p>
</div>
</div>
<!-- 规格价格 -->
<div class="specs-info">
<div
v-for="spec in item.specList"
:key="spec.id"
class="spec-item"
>
<span class="spec-name">{{ spec.specName }}</span>
<span class="spec-price">{{ spec.specPrice }}</span>
</div>
</div>
<!-- 操作按钮 -->
<div class="actions">
<el-button size="small" type="primary" @click="editSpecs(item)" class="action-btn">
修改规格
</el-button>
2025-08-04 20:02:06 +08:00
<el-button size="small" type="success" @click="exportSingleBeer(item)" class="action-btn">
导出图片
2025-08-04 09:59:12 +08:00
</el-button>
<el-button size="small" type="warning" @click="offTap(item)" class="action-btn">
下架
</el-button>
</div>
</div>
</div>
</div>
</div>
<!-- 新酒上枪对话框 -->
<el-dialog
v-model="addBeerDialog.visible"
title="新酒上枪"
width="1000px"
:close-on-click-modal="false"
:close-on-press-escape="false"
>
<BeerSelectionWizard
2025-08-04 20:02:06 +08:00
ref="beerSelectionWizardRef"
2025-08-04 09:59:12 +08:00
@submit="handleAddBeer"
2025-08-04 20:02:06 +08:00
@cancel="handleAddBeerCancel"
2025-08-04 09:59:12 +08:00
/>
</el-dialog>
<!-- 导出酒单对话框 -->
2025-08-04 20:02:06 +08:00
<el-dialog v-model="exportMenuDialog.visible" title="整版导出" width="900px">
2025-08-04 09:59:12 +08:00
<MenuExportWizard
2025-08-04 20:02:06 +08:00
ref="menuExportWizardRef"
2025-08-04 09:59:12 +08:00
:tap-list="tapList"
@submit="handleExportMenu"
2025-08-04 20:02:06 +08:00
@cancel="handleExportMenuCancel"
2025-08-04 09:59:12 +08:00
/>
</el-dialog>
<!-- 编辑规格价格对话框 -->
2025-08-04 20:02:06 +08:00
<el-dialog v-model="editSpecDialog.visible" title="编辑规格价格" width="900px">
2025-08-04 09:59:12 +08:00
<EditSpecForm
:tap-beer="editSpecDialog.data"
@submit="handleUpdateSpecs"
@cancel="editSpecDialog.visible = false"
/>
</el-dialog>
2025-08-04 20:02:06 +08:00
<!-- 单酒款导出对话框 -->
<el-dialog v-model="singleExportDialog.visible" title="导出单酒款图片" width="900px">
<SingleBeerExportWizard
ref="singleExportWizardRef"
:beer-data="singleExportDialog.beerData"
@submit="handleSingleBeerExport"
@cancel="singleExportDialog.visible = false"
2025-08-04 09:59:12 +08:00
/>
</el-dialog>
</div>
</template>
<script setup>
import { ref, reactive, onMounted } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import { Plus, Download, Refresh } from '@element-plus/icons-vue'
import {
getTapList,
addBeerToTap,
offTapBeer,
updateTapBeerSpecs
} from '@/api/barmgr/tap'
import { formatTime } from '@/utils/date-util'
2025-08-04 20:02:06 +08:00
import { generateWineMenu, generateSingleBeerPoster } from '@/api/template'
2025-08-04 09:59:12 +08:00
import BeerSelectionWizard from './components/BeerSelectionWizard.vue'
import EditSpecForm from './components/EditSpecForm.vue'
import MenuExportWizard from './components/MenuExportWizard.vue'
2025-08-04 20:02:06 +08:00
import SingleBeerExportWizard from './components/SingleBeerExportWizard.vue'
2025-08-04 09:59:12 +08:00
// 响应式数据
const loading = ref(false)
const tapList = ref([])
2025-08-04 20:02:06 +08:00
const beerSelectionWizardRef = ref()
const menuExportWizardRef = ref()
const singleExportWizardRef = ref()
2025-08-04 09:59:12 +08:00
const addBeerDialog = reactive({
visible: false
})
const exportMenuDialog = reactive({
visible: false
})
const editSpecDialog = reactive({
visible: false,
data: null
})
2025-08-04 20:02:06 +08:00
const singleExportDialog = reactive({
2025-08-04 09:59:12 +08:00
visible: false,
2025-08-04 20:02:06 +08:00
beerData: null
2025-08-04 09:59:12 +08:00
})
// 获取在售酒款列表
const fetchTapList = async () => {
try {
loading.value = true
const response = await getTapList({ pageNum: 1, pageSize: 1000 })
// axios 返回的数据在 response.data 中
const responseData = response.data
if (responseData && responseData.code === 200) {
// TableDataInfo 结构:{code: 200, msg: "查询成功", rows: [...], total: 1}
tapList.value = responseData.rows || []
} else {
ElMessage.error('获取酒款列表失败: ' + (responseData?.msg || '未知错误'))
}
} catch (error) {
ElMessage.error('获取酒款列表失败: ' + error.message)
} finally {
loading.value = false
}
}
// 刷新数据
const refreshData = async () => {
await fetchTapList()
ElMessage.success('数据刷新成功')
}
// 显示新酒上枪对话框
const showAddBeerDialog = () => {
addBeerDialog.visible = true
}
2025-08-04 20:02:06 +08:00
// 处理新酒上枪取消
const handleAddBeerCancel = () => {
addBeerDialog.visible = false
// 重置表单(下次打开时状态会重置)
if (beerSelectionWizardRef.value) {
beerSelectionWizardRef.value.resetForm()
}
}
2025-08-04 09:59:12 +08:00
// 显示导出酒单对话框
const showExportMenuDialog = () => {
exportMenuDialog.visible = true
}
2025-08-04 20:02:06 +08:00
// 处理导出酒单取消
const handleExportMenuCancel = () => {
exportMenuDialog.visible = false
// 重置向导状态(下次打开时状态会重置)
if (menuExportWizardRef.value) {
menuExportWizardRef.value.resetWizard()
}
}
2025-08-04 09:59:12 +08:00
// 处理新酒上枪
const handleAddBeer = async (data) => {
try {
const response = await addBeerToTap(data)
// 检查不同的响应数据结构
if (response.data && response.data.code === 200) {
ElMessage.success('上枪成功')
addBeerDialog.visible = false
2025-08-04 20:02:06 +08:00
// 重置表单
if (beerSelectionWizardRef.value) {
beerSelectionWizardRef.value.resetForm()
}
2025-08-04 09:59:12 +08:00
await refreshData()
} else if (response.code === 200) {
ElMessage.success('上枪成功')
addBeerDialog.visible = false
2025-08-04 20:02:06 +08:00
// 重置表单
if (beerSelectionWizardRef.value) {
beerSelectionWizardRef.value.resetForm()
}
2025-08-04 09:59:12 +08:00
await refreshData()
} else {
const errorMsg = (response.data && response.data.msg) || response.msg || '上枪失败'
throw new Error(errorMsg)
}
} catch (error) {
ElMessage.error('上枪失败: ' + error.message)
}
}
// 处理导出酒单
const handleExportMenu = async (exportData) => {
try {
// 构建请求参数,按照整版酒单编辑器的数据结构要求
const params = {
uuid: exportData.template.uuid || exportData.template.posterId || String(exportData.template.id), // 优先使用uuid字段
format: exportData.format || 'PDF'
}
// 按照 beer{index}_{field} 格式传递酒款数据
exportData.generateParams.beerList.forEach((beer, index) => {
2025-08-04 20:02:06 +08:00
// 基础酒款信息
2025-08-04 09:59:12 +08:00
params[`beer${index}_name`] = beer.beerName || ''
2025-08-04 20:02:06 +08:00
params[`beer${index}_name_en`] = beer.beerNameEn || ''
// 风格优先级custom_style > beer_style
params[`beer${index}_style`] = beer.customStyle || beer.beerStyles || ''
params[`beer${index}_custom_style`] = beer.customStyle || ''
params[`beer${index}_beer_styles_en`] = beer.beerStylesEn || ''
params[`beer${index}_abv`] = beer.beerAbv ? `ABV: ${beer.beerAbv}%` : ''
params[`beer${index}_ibu`] = beer.beerIbus ? `IBU: ${beer.beerIbus}` : ''
params[`beer${index}_og`] = beer.beerOg ? `OG: ${beer.beerOg}` : ''
params[`beer${index}_intro`] = beer.beerDesc || ''
params[`beer${index}_juice_content`] = beer.juiceContent || ''
params[`beer${index}_score`] = beer.beerScore || ''
params[`beer${index}_img`] = beer.cover || beer.beerCover || ''
// 鱼眼标处理逗号分隔的图片URL取第一张
let fisheyeLogo = beer.fisheyeLogo || ''
if (fisheyeLogo) {
// 按逗号分隔,取第一张图片
const logoArray = fisheyeLogo.split(',').map(url => url.trim()).filter(url => url)
fisheyeLogo = logoArray.length > 0 ? logoArray[0] : fisheyeLogo
}
// 如果鱼眼标为空,使用酒款图片并标记为圆形处理
if (!fisheyeLogo && (beer.cover || beer.beerCover)) {
fisheyeLogo = beer.cover || beer.beerCover
// 添加圆形处理标识
params[`beer${index}_fisheye_logo_crop`] = 'circle'
}
params[`beer${index}_fisheye_logo`] = fisheyeLogo
// 厂牌信息
params[`beer${index}_brewery_name`] = beer.breweryName || beer.brandName || ''
params[`beer${index}_brewery_name_en`] = beer.breweryNameEn || ''
params[`beer${index}_brewery_logo`] = beer.brandLogo || beer.breweryLogo || ''
params[`beer${index}_country`] = beer.country || ''
params[`beer${index}_city`] = beer.city || ''
// 酒头信息
params[`beer${index}_tapno`] = beer.tapNo ? String(beer.tapNo) : ''
// 规格价格信息
2025-08-04 09:59:12 +08:00
params[`beer${index}_price`] = beer.specs && beer.specs[0] ? String(beer.specs[0].specPrice) : ''
params[`beer${index}_spec`] = beer.specs && beer.specs[0] ? beer.specs[0].specName : ''
// 如果有多个规格,添加第二个规格
if (beer.specs && beer.specs[1]) {
params[`beer${index}_spec1`] = beer.specs[1].specName
params[`beer${index}_price1`] = String(beer.specs[1].specPrice)
}
})
ElMessage({
message: '正在生成酒单,请稍候...',
type: 'info',
duration: 0
})
// 调用现有的整版酒单生成接口
const response = await generateWineMenu(params)
if (response.data && response.data.code === 200 && response.data.data && response.data.data.image) {
const result = response.data
// 现有接口返回base64图片需要转换为可下载的文件
const base64Image = result.data.image
// 将base64转换为blob
const byteCharacters = atob(base64Image)
const byteNumbers = new Array(byteCharacters.length)
for (let i = 0; i < byteCharacters.length; i++) {
byteNumbers[i] = byteCharacters.charCodeAt(i)
}
const byteArray = new Uint8Array(byteNumbers)
// 根据格式设置正确的MIME类型和文件扩展名
let mimeType = 'image/png'
let fileExtension = 'png'
if (result.data.format === 'base64_pdf') {
mimeType = 'application/pdf'
fileExtension = 'pdf'
}
const blob = new Blob([byteArray], { type: mimeType })
// 创建下载链接
const url = window.URL.createObjectURL(blob)
const a = document.createElement('a')
a.href = url
a.download = `酒单_${new Date().getTime()}.${fileExtension}`
document.body.appendChild(a)
a.click()
document.body.removeChild(a)
window.URL.revokeObjectURL(url)
ElMessage.closeAll() // 关闭loading消息
if (result.data.format === 'base64_pdf') {
ElMessage.success('PDF酒单导出成功')
} else {
ElMessage.success('PNG酒单导出成功')
}
exportMenuDialog.visible = false
2025-08-04 20:02:06 +08:00
// 重置向导状态
if (menuExportWizardRef.value) {
menuExportWizardRef.value.resetWizard()
}
2025-08-04 09:59:12 +08:00
} else {
// axios响应错误处理
const errorMsg = response.data?.msg || response.msg || '生成失败'
throw new Error(errorMsg)
}
} catch (error) {
ElMessage.closeAll() // 关闭loading消息
ElMessage.error('导出酒单失败: ' + error.message)
}
}
// 下架酒款
const offTap = async (row) => {
try {
await ElMessageBox.confirm(
`确定要下架酒头 ${row.tapNo} 上的"${row.beerName}"吗?`,
'下架确认',
{
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}
)
const response = await offTapBeer(row.tapId)
// axios 返回的数据在 response.data 中
const responseData = response.data || response
if (responseData && responseData.code === 200) {
ElMessage.success('下架成功')
await refreshData()
} else {
throw new Error(responseData?.msg || '下架失败')
}
} catch (error) {
if (error !== 'cancel') {
ElMessage.error('下架失败: ' + (error.message || error))
}
}
}
// 编辑规格价格
const editSpecs = (row) => {
2025-08-04 20:02:06 +08:00
// 安全地复制数据避免Vue内部属性
editSpecDialog.data = {
id: row.id,
tapBeerId: row.id, // 确保有tapBeerId
tapId: row.tapId,
tapNo: row.tapNo,
beerId: row.beerId,
beerName: row.beerName,
beerCover: row.beerCover,
brandName: row.brandName,
beerStyles: row.beerStyles,
customStyle: row.customStyle,
specList: row.specList || []
}
2025-08-04 09:59:12 +08:00
editSpecDialog.visible = true
}
2025-08-04 20:02:06 +08:00
// 导出单酒款图片
const exportSingleBeer = (row) => {
// 安全地复制数据避免Vue内部属性
singleExportDialog.beerData = {
id: row.id,
tapId: row.tapId,
tapNo: row.tapNo,
beerId: row.beerId,
beerName: row.beerName,
beerNameEn: row.beerNameEn,
beerCover: row.beerCover,
cover: row.cover,
brandName: row.brandName,
brandLogo: row.brandLogo,
beerStyles: row.beerStyles,
customStyle: row.customStyle,
beerStylesEn: row.beerStylesEn,
beerAbv: row.beerAbv,
beerIbus: row.beerIbus,
beerOg: row.beerOg,
beerDesc: row.beerDesc,
juiceContent: row.juiceContent,
fisheyeLogo: row.fisheyeLogo,
breweryName: row.breweryName,
breweryNameEn: row.breweryNameEn,
country: row.country,
city: row.city,
specList: row.specList || []
}
singleExportDialog.visible = true
2025-08-04 09:59:12 +08:00
}
2025-08-04 20:02:06 +08:00
// 处理单酒款导出
const handleSingleBeerExport = async (exportData) => {
2025-08-04 09:59:12 +08:00
try {
2025-08-04 20:02:06 +08:00
// //console.log('导出单酒款数据:', exportData)
// 构建请求参数,用于单酒款海报
const params = {
uuid: exportData.template.uuid || String(exportData.template.id),
format: exportData.format || 'PNG'
}
// 传递完整的酒款数据,确保兼容所有模板组件
const beerData = exportData.beerData
// 酒款信息组件
params[`beer_name`] = beerData.beerName || ''
2025-08-04 20:02:06 +08:00
params[`beer_name_en`] = beerData.beerNameEn || beerData.beerEnglishName || ''
params[`beer_image`] = beerData.beerCover || beerData.cover || ''
// 风格优先级custom_style > beer_style
params[`beer_style`] = beerData.customStyle || beerData.beerStyles || ''
params[`custom_style`] = beerData.customStyle || ''
params[`beer_styles_en`] = beerData.beerStylesEn || ''
params[`abv`] = beerData.beerAbv ? `ABV: ${beerData.beerAbv}%` : ''
params[`ibu`] = beerData.beerIbus ? `IBU: ${beerData.beerIbus}` : ''
params[`og`] = beerData.beerOg ? `OG: ${beerData.beerOg}` : ''
params[`intro`] = beerData.beerDesc || beerData.beerIntro || beerData.beerDescription || ''
params[`juice_content`] = beerData.juiceContent || ''
params[`score`] = beerData.beerScore || ''
// 鱼眼标处理逗号分隔的图片URL取第一张
let fisheyeLogo = beerData.fisheyeLogo || ''
if (fisheyeLogo) {
// 按逗号分隔,取第一张图片
const logoArray = fisheyeLogo.split(',').map(url => url.trim()).filter(url => url)
fisheyeLogo = logoArray.length > 0 ? logoArray[0] : fisheyeLogo
}
// 如果鱼眼标为空,使用酒款图片并标记为圆形处理
if (!fisheyeLogo && (beerData.beerCover || beerData.cover)) {
fisheyeLogo = beerData.beerCover || beerData.cover
// 添加圆形处理标识
params[`fisheye_logo_crop`] = 'circle'
}
params[`fisheye_logo`] = fisheyeLogo
// 厂牌信息组件
params[`brewery_name`] = beerData.breweryName || beerData.brandName || ''
params[`brewery_name_en`] = beerData.breweryNameEn || ''
params[`country`] = beerData.country || ''
params[`city`] = beerData.city || ''
params[`brewery_logo`] = beerData.breweryLogo || beerData.brandLogo || ''
// 市售规格组件
params[`tapno`] = beerData.tapNo || ''
if (beerData.specList && beerData.specList.length > 0) {
params[`spec1_name`] = beerData.specList[0].specName || ''
params[`spec1_price`] = beerData.specList[0].specPrice ? `${beerData.specList[0].specPrice}` : ''
if (beerData.specList.length > 1) {
params[`spec2_name`] = beerData.specList[1].specName || ''
params[`spec2_price`] = beerData.specList[1].specPrice ? `${beerData.specList[1].specPrice}` : ''
}
}
// 其他常用组件(预留)
params[`qtcy_text`] = ''
params[`qtcy_image`] = ''
params[`qtcy_avatar`] = ''
params[`qtcy_qrcode`] = ''
//console.log('单酒款图片生成参数:', params)
// 调用生成图片接口
const response = await generateSingleBeerPoster(params)
if (response.data?.code === 200) {
const { url } = response.data.data
if (url) {
// 生成下载文件名
const fileExtension = params.format.toLowerCase()
const fileName = `${beerData.beerName || '酒款'}_${beerData.tapNo}号酒头.${fileExtension}`
// 下载文件
try {
const downloadResponse = await fetch(url)
const blob = await downloadResponse.blob()
// 触发下载
const link = document.createElement('a')
link.href = URL.createObjectURL(blob)
link.download = fileName
document.body.appendChild(link)
link.click()
document.body.removeChild(link)
URL.revokeObjectURL(link.href)
ElMessage.success('单酒款图片导出成功')
singleExportDialog.visible = false
// 重置弹窗状态
if (singleExportWizardRef.value) {
singleExportWizardRef.value.resetState()
}
} catch (downloadError) {
// 如果下载失败,直接打开链接
window.open(url, '_blank')
ElMessage.success('图片已在新窗口打开,请右键保存')
singleExportDialog.visible = false
// 重置弹窗状态
if (singleExportWizardRef.value) {
singleExportWizardRef.value.resetState()
}
}
2025-08-04 09:59:12 +08:00
} else {
2025-08-04 20:02:06 +08:00
throw new Error('生成的图片URL为空')
2025-08-04 09:59:12 +08:00
}
} else {
2025-08-04 20:02:06 +08:00
throw new Error(response.data?.msg || response.msg || '生成图片失败')
2025-08-04 09:59:12 +08:00
}
} catch (error) {
2025-08-04 20:02:06 +08:00
console.error('导出单酒款图片失败:', error)
ElMessage.error('导出失败: ' + error.message)
2025-08-04 09:59:12 +08:00
}
}
// 处理更新规格价格
const handleUpdateSpecs = async (data) => {
try {
2025-08-04 20:02:06 +08:00
//console.log('Update specs data:', data)
2025-08-04 09:59:12 +08:00
const response = await updateTapBeerSpecs(data)
2025-08-04 20:02:06 +08:00
//console.log('Update specs response:', response)
2025-08-04 09:59:12 +08:00
// axios 返回的数据在 response.data 中
const responseData = response.data || response
if (responseData && responseData.code === 200) {
ElMessage.success('价格更新成功')
editSpecDialog.visible = false
await refreshData()
} else {
throw new Error(responseData?.msg || '价格更新失败')
}
} catch (error) {
console.error('Update specs error:', error)
ElMessage.error('价格更新失败: ' + error.message)
}
}
// 组件挂载时获取数据
onMounted(() => {
refreshData()
})
</script>
<style scoped>
.app-container {
min-height: 100vh;
height: auto; /* 允许高度自动扩展 */
2025-08-04 09:59:12 +08:00
background: #f5f7fa;
padding: 20px 0 80px 0; /* 增加底部padding为版权信息留出空间 */
position: relative; /* 确保背景能够包含所有内容 */
2025-08-04 09:59:12 +08:00
}
.content-wrapper {
max-width: 1200px;
margin: 0 auto 20px auto; /* 增加底部margin与背景分离 */
2025-08-04 09:59:12 +08:00
background: white;
border-radius: 12px;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
overflow: hidden;
position: relative; /* 确保相对定位 */
z-index: 1; /* 确保内容在背景之上 */
2025-08-04 09:59:12 +08:00
}
.operation-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 24px 32px;
border-bottom: 1px solid #f0f0f0;
background: #fafafa;
}
.operation-header h2 {
margin: 0;
color: #303133;
font-size: 20px;
font-weight: 600;
}
.operation-buttons {
display: flex;
gap: 12px;
}
.tap-list {
padding: 0;
min-height: 200px; /* 确保列表区域有最小高度 */
position: relative;
2025-08-04 09:59:12 +08:00
}
.empty-state {
padding: 60px 32px;
text-align: center;
}
.tap-items {
padding: 0;
}
.tap-item {
display: flex;
align-items: center;
padding: 24px 32px;
border-bottom: 1px solid #f0f0f0;
transition: background-color 0.2s;
}
.tap-item:hover {
background-color: #fafafa;
}
.tap-item:last-child {
border-bottom: none;
}
.tap-number {
margin-right: 24px;
}
.tap-badge {
display: inline-block;
width: 48px;
height: 48px;
line-height: 48px;
text-align: center;
background: #409eff;
color: white;
border-radius: 50%;
font-weight: bold;
font-size: 14px;
}
.beer-info {
display: flex;
align-items: center;
flex: 1;
margin-right: 24px;
}
.beer-image {
margin-right: 16px;
}
.beer-image img {
width: 60px;
height: 90px;
border-radius: 8px;
object-fit: cover;
border: 2px solid #f0f0f0;
}
.beer-details {
flex: 1;
}
.beer-name {
margin: 0 0 4px 0;
font-size: 16px;
font-weight: 600;
color: #303133;
line-height: 1.4;
}
.beer-brand {
margin: 0 0 2px 0;
font-size: 14px;
color: #606266;
line-height: 1.4;
}
.beer-style {
margin: 0 0 2px 0;
font-size: 12px;
color: #67c23a;
line-height: 1.4;
}
.beer-abv {
margin: 0;
font-size: 12px;
color: #909399;
line-height: 1.4;
}
.specs-info {
margin-right: 24px;
min-width: 120px;
}
.spec-item {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 8px;
padding: 8px 12px;
background: #f8f9fa;
border-radius: 6px;
font-size: 14px;
width: 200px;
margin-right: 100px;
}
.spec-item:last-child {
margin-bottom: 0;
}
.spec-name {
font-size: 14px;
color: #606266;
font-weight: 500;
}
.spec-price {
font-size: 16px;
font-weight: 600;
color: #e6a23c;
}
.actions {
display: flex;
flex-direction: column;
gap: 8px;
min-width: 80px;
}
.actions .el-button {
width: 100%;
height: 32px;
font-size: 12px;
}
.action-btn {
width: 100% !important;
height: 32px !important;
font-size: 12px !important;
margin: 0 !important;
}
/* 响应式设计 */
@media (max-width: 768px) {
.content-wrapper {
margin: 0 16px;
border-radius: 8px;
}
.operation-header {
padding: 16px 20px;
flex-direction: column;
gap: 16px;
align-items: stretch;
}
.operation-buttons {
justify-content: center;
}
.tap-item {
padding: 16px 20px;
flex-direction: column;
align-items: stretch;
gap: 16px;
}
.tap-number {
margin-right: 0;
text-align: center;
}
.beer-info {
margin-right: 0;
justify-content: center;
}
.specs-info {
margin-right: 0;
min-width: auto;
}
.actions {
flex-direction: row;
justify-content: center;
}
}
/* 确保页面整体布局正确 */
:deep(.ele-pro-body) {
min-height: auto !important;
height: auto !important;
}
/* 确保主内容区域能够正确扩展 */
:deep(.ele-pro-layout-body) {
min-height: auto !important;
display: flex;
flex-direction: column;
}
/* 确保路由视图容器能够正确扩展 */
:deep(.router-view-wrapper) {
flex: 1;
display: flex;
flex-direction: column;
}
2025-08-04 09:59:12 +08:00
</style>