整页导出功能上线

This commit is contained in:
davy 2025-08-05 14:38:36 +08:00
parent 40cfe0f9ff
commit 5557109499
5 changed files with 308 additions and 29 deletions

View File

@ -1,2 +1,3 @@
# 预发布环境接口地址 # 开发环境接口地址
VITE_API_URL=https://vue.ruoyi.vip/prod-api VITE_API_URL=http://dev.bar.beerape.com/prod-api
VITE_API_STORE_URL=http://dev.design.beerape.com

BIN
dist.zip Normal file

Binary file not shown.

View File

@ -97,8 +97,8 @@
<layout-tool> <layout-tool>
<header-user /> <header-user />
</layout-tool> </layout-tool>
<!-- 夜间模式 --> <!-- 夜间模式 - 已禁用使用固定默认主题配置 -->
<layout-tool <!-- <layout-tool
ref="darkSwitchRef" ref="darkSwitchRef"
:class="[ :class="[
'dark-switch', 'dark-switch',
@ -111,9 +111,9 @@
:model-value="darkMode" :model-value="darkMode"
@update:modelValue="updateDarkMode" @update:modelValue="updateDarkMode"
/> />
</layout-tool> </layout-tool> -->
<!-- 主题设置 --> <!-- 主题设置 - 已禁用使用固定默认主题配置 -->
<!-- <layout-tool @click="openSetting"> <!-- <layout-tool @click="openSetting"></layout-tool>
<el-icon> <el-icon>
<MoreOutlined /> <MoreOutlined />
</el-icon> </el-icon>
@ -162,7 +162,7 @@
</span> </span>
</template> </template>
</ele-pro-layout> </ele-pro-layout>
<!-- 主题设置抽屉 --> <!-- 主题设置抽屉 - 已禁用使用固定默认主题配置 -->
<!-- <setting-drawer v-model="settingVisible" /> --> <!-- <setting-drawer v-model="settingVisible" /> -->
</template> </template>
@ -184,24 +184,24 @@
ReloadOutlined, ReloadOutlined,
ExpandOutlined, ExpandOutlined,
CompressOutlined, CompressOutlined,
MoreOutlined, // MoreOutlined,
CloseOutlined, CloseOutlined,
ArrowLeftOutlined, ArrowLeftOutlined,
ArrowRightOutlined, ArrowRightOutlined,
MinusCircleOutlined, MinusCircleOutlined,
CloseCircleOutlined, CloseCircleOutlined
MoonOutlined, // MoonOutlined,
SunOutlined // SunOutlined
} from '@/components/icons'; } from '@/components/icons';
import { PROJECT_NAME, HOME_PATH, REDIRECT_PATH } from '@/config/setting'; import { PROJECT_NAME, HOME_PATH, REDIRECT_PATH } from '@/config/setting';
import { doWithTransition } from '@/utils/common'; // import { doWithTransition } from '@/utils/common';
import { useUserStore } from '@/store/modules/user'; import { useUserStore } from '@/store/modules/user';
import { useThemeStore } from '@/store/modules/theme'; import { useThemeStore } from '@/store/modules/theme';
import { useMobileDevice } from '@/utils/use-mobile'; import { useMobileDevice } from '@/utils/use-mobile';
import { usePageTab } from '@/utils/use-page-tab'; import { usePageTab } from '@/utils/use-page-tab';
import RouterLayout from '@/components/RouterLayout/index.vue'; import RouterLayout from '@/components/RouterLayout/index.vue';
import HeaderUser from './components/header-user.vue'; import HeaderUser from './components/header-user.vue';
import HeaderNotice from './components/header-notice.vue'; // import HeaderNotice from './components/header-notice.vue';
import PageFooter from './components/page-footer.vue'; import PageFooter from './components/page-footer.vue';
// import SettingDrawer from './components/setting-drawer.vue'; // import SettingDrawer from './components/setting-drawer.vue';
@ -266,7 +266,7 @@
/** 是否全屏 */ /** 是否全屏 */
const isFullscreen = ref(false); const isFullscreen = ref(false);
/** 是否显示主题设置抽屉 */ /** 是否显示主题设置抽屉 - 已禁用,使用固定默认主题配置 */
// const settingVisible = ref(false); // const settingVisible = ref(false);
/** 页签右键菜单 */ /** 页签右键菜单 */
@ -396,22 +396,22 @@
} }
}; };
/** 打开主题设置抽屉 */ /** 打开主题设置抽屉 - 已禁用,使用固定默认主题配置 */
// const openSetting = () => { // const openSetting = () => {
// settingVisible.value = true; // settingVisible.value = true;
// }; // };
/** 暗黑主题切换开关 */ /** 暗黑主题切换开关 - 已禁用,使用固定默认主题配置 */
const darkSwitchRef = ref(null); // const darkSwitchRef = ref(null);
/** 切换暗黑模式 */ /** 切换暗黑模式 - 已禁用,使用固定默认主题配置 */
const updateDarkMode = (isDark) => { // const updateDarkMode = (isDark) => {
doWithTransition( // doWithTransition(
() => themeStore.setValue('darkMode', isDark), // () => themeStore.setValue('darkMode', isDark),
darkSwitchRef.value?.$el?.querySelector?.('.el-switch__action'), // darkSwitchRef.value?.$el?.querySelector?.('.el-switch__action'),
!isDark // !isDark
); // );
}; // };
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@ -33,11 +33,11 @@ const DEFAULT_STATE = {
/** 是否需要页签栏 */ /** 是否需要页签栏 */
tabBar: true, tabBar: true,
/** 布局类型 */ /** 布局类型 */
layout: 'default', layout: 'top',
/** 侧栏布局类型 */ /** 侧栏布局类型 */
sidebarLayout: 'default', sidebarLayout: 'default',
/** 顶栏风格 */ /** 顶栏风格 */
headerStyle: 'light', headerStyle: 'dark',
/** 侧栏风格 */ /** 侧栏风格 */
sidebarStyle: 'dark', sidebarStyle: 'dark',
/** 双侧栏二级风格 */ /** 双侧栏二级风格 */
@ -51,7 +51,7 @@ const DEFAULT_STATE = {
/** 是否固定内容区 */ /** 是否固定内容区 */
fixedBody: true, fixedBody: true,
/** 内容区是否撑满 */ /** 内容区是否撑满 */
fluid: true, fluid: false,
/** 图标是否置于顶栏 */ /** 图标是否置于顶栏 */
logoInHeader: false, logoInHeader: false,
/** 侧栏菜单是否彩色图标 */ /** 侧栏菜单是否彩色图标 */

View File

@ -0,0 +1,278 @@
<template>
<div class="add-beer-form">
<el-form ref="formRef" :model="form" :rules="rules" label-width="120px">
<!-- 酒款信息展示 -->
<el-card shadow="never" class="beer-info-card">
<template #header>
<h4>选中酒款信息</h4>
</template>
<div class="beer-info" v-if="selectedBeer">
<div class="beer-basic">
<div class="beer-image">
<el-image
:src="selectedBeer.cover || '/images/default-beer.png'"
fit="cover"
style="width: 80px; height: 120px; border-radius: 8px;"
/>
</div>
<div class="beer-details">
<h3>{{ selectedBeer.beerName || selectedBeer.name }}</h3>
<p><strong>品牌:</strong> {{ selectedBeer.brandName || selectedBeer.brand || '未知品牌' }}</p>
<p><strong>风格:</strong> {{ selectedBeer.beerStyles || selectedBeer.style || '未知风格' }}</p>
<p><strong>酒精度:</strong> {{ selectedBeer.beerAbv || selectedBeer.abv }}%</p>
</div>
</div>
</div>
<el-empty v-else description="未选择酒款" />
</el-card>
<!-- 上枪配置 -->
<div class="form-section">
<h4>上枪配置</h4>
<el-form-item label="选择酒头" prop="tapNo" required>
<el-select v-model="form.tapNo" placeholder="请选择要使用的酒头" style="width: 100%">
<el-option
v-for="n in 20"
:key="n"
:label="`${n}号酒头`"
:value="n"
/>
</el-select>
</el-form-item>
<el-form-item label="上枪时间" prop="onTapTime">
<el-date-picker
v-model="form.onTapTime"
type="datetime"
placeholder="选择上枪时间"
format="YYYY-MM-DD HH:mm:ss"
value-format="YYYY-MM-DD HH:mm:ss"
style="width: 100%"
/>
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input
v-model="form.remark"
type="textarea"
:rows="3"
placeholder="请输入备注信息(可选)"
/>
</el-form-item>
</div>
<!-- 规格价格配置 -->
<div class="form-section">
<h4>规格价格配置</h4>
<el-table :data="form.specList" style="width: 100%">
<el-table-column label="规格名称" min-width="120">
<template #default="{ row, $index }">
<el-input v-model="row.specName" placeholder="如330ML" />
</template>
</el-table-column>
<el-table-column label="销售价格" min-width="120">
<template #default="{ row, $index }">
<el-input-number
v-model="row.price"
:precision="2"
:min="0"
placeholder="0.00"
style="width: 100%"
/>
</template>
</el-table-column>
<el-table-column label="操作" width="80">
<template #default="{ $index }">
<el-button
type="danger"
size="small"
@click="removeSpec($index)"
:disabled="form.specList.length <= 1"
>
删除
</el-button>
</template>
</el-table-column>
</el-table>
<div style="margin-top: 10px;">
<el-button type="primary" plain @click="addSpec">+ 添加规格</el-button>
</div>
</div>
</el-form>
<!-- 操作按钮 -->
<div class="form-actions">
<el-button @click="handleCancel">取消</el-button>
<el-button type="primary" @click="handleSubmit" :loading="submitting">
确认上枪
</el-button>
</div>
</div>
</template>
<script setup>
import { ref, reactive, watch } from 'vue'
import { ElMessage } from 'element-plus'
// Props
const props = defineProps({
selectedBeer: {
type: Object,
default: () => null
}
})
// Events
const emit = defineEmits(['submit', 'cancel'])
//
const formRef = ref()
const submitting = ref(false)
const form = reactive({
tapNo: null,
onTapTime: new Date().toISOString().slice(0, 19).replace('T', ' '),
remark: '',
specList: [
{ specName: '330ML', price: 0 },
{ specName: '500ML', price: 0 }
]
})
//
const rules = {
tapNo: [
{ required: true, message: '请选择酒头', trigger: 'change' }
]
}
//
watch(() => props.selectedBeer, (newBeer) => {
if (newBeer) {
//
if (newBeer.specs && newBeer.specs.length > 0) {
form.specList = newBeer.specs.map(spec => ({
specName: spec.name || spec.specName,
price: spec.price || 0
}))
}
}
}, { immediate: true })
//
const addSpec = () => {
form.specList.push({
specName: '',
price: 0
})
}
//
const removeSpec = (index) => {
if (form.specList.length > 1) {
form.specList.splice(index, 1)
}
}
//
const handleSubmit = async () => {
if (!formRef.value) return
try {
await formRef.value.validate()
//
const validSpecs = form.specList.filter(spec => spec.specName && spec.price > 0)
if (validSpecs.length === 0) {
ElMessage.warning('请至少添加一个有效的规格价格')
return
}
submitting.value = true
const submitData = {
...form,
specList: validSpecs,
beerId: props.selectedBeer?.id || props.selectedBeer?.beerId,
beerType: props.selectedBeer?.beerType || 'main' // main custom
}
emit('submit', submitData)
} catch (error) {
console.log('表单验证失败:', error)
} finally {
submitting.value = false
}
}
//
const handleCancel = () => {
emit('cancel')
}
</script>
<style scoped>
.add-beer-form {
padding: 20px 0;
}
.beer-info-card {
margin-bottom: 20px;
}
.beer-info {
padding: 10px;
}
.beer-basic {
display: flex;
gap: 15px;
align-items: flex-start;
}
.beer-image {
flex-shrink: 0;
}
.beer-details {
flex: 1;
}
.beer-details h3 {
margin: 0 0 10px 0;
color: #303133;
font-size: 18px;
}
.beer-details p {
margin: 5px 0;
color: #606266;
font-size: 14px;
}
.form-section {
margin-bottom: 20px;
padding: 15px;
background: #fafafa;
border-radius: 8px;
}
.form-section h4 {
margin: 0 0 15px 0;
color: #303133;
font-size: 16px;
font-weight: 600;
}
.form-actions {
text-align: right;
padding-top: 20px;
border-top: 1px solid #ebeef5;
}
.form-actions .el-button {
margin-left: 10px;
}
</style>