更多新增存酒功能

This commit is contained in:
gyq
2026-05-08 15:05:48 +08:00
parent 1ed8fa8c8e
commit 4e1484d4bb
13 changed files with 1096 additions and 62 deletions

View File

@@ -5,10 +5,10 @@ ENV = development
# VITE_API_WSS = 'wss://sockets.sxczgkj.com/wss'
# 正式ws
VITE_API_WSS = 'wss://czgeatws.sxczgkj.com/wss'
# VITE_API_WSS = 'wss://czgeatws.sxczgkj.com/wss'
# 本地ws
# VITE_API_WSS = 'ws://192.168.1.42:2348'
VITE_API_WSS = 'ws://192.168.1.42:2348'
# 正式 php
VITE_API_PHP_URL = 'https://newblockwlx.sxczgkj.cn/index.php/api'
@@ -23,7 +23,7 @@ VITE_API_PHP_URL = 'https://newblockwlx.sxczgkj.cn/index.php/api'
# VITE_API_URL = 'https://tapi.cashier.sxczgkj.cn'
# 线上正式
VITE_API_URL = 'https://cashier.sxczgkj.com'
# VITE_API_URL = 'https://cashier.sxczgkj.com'
# 本地调试连接
# VITE_API_URL = 'http://192.168.1.42/'
VITE_API_URL = 'http://192.168.1.42/'

File diff suppressed because one or more lines are too long

View File

@@ -49,7 +49,7 @@ watch(route, (to) => {
includeList.push(to.name);
}
// 需要全屏的路由
let arr = ["/login", "/device_list", "/add_device", "/add_label", "/webview", '/workrecord'];
let arr = ["/login", "/device_list", "/add_device", "/add_label", "/webview", '/workrecord', '/store_wine'];
if (arr.includes(to.path)) {
hideLeftMenu.value = true;
} else {

View File

@@ -65,6 +65,44 @@ export function storageGoodGet(params) {
});
}
/**
* 添加酒品
* @param {*} params
* @returns
*/
export function storageGoodPost(data) {
return request({
method: "post",
url: "/product/admin/storageGood",
data,
});
}
/**
* 编辑酒品
* @param {*} params
* @returns
*/
export function storageGoodPut(data) {
return request({
method: "put",
url: "/product/admin/storageGood/edit",
data,
});
}
/**
* 删除酒品
* @param {*} params
* @returns
*/
export function storageGoodDelete(id) {
return request({
method: "DELETE",
url: `/product/admin/storageGood?id=${id}`,
});
}
/**
* 存酒记录添加
* @param {*} data
@@ -117,6 +155,18 @@ export function shopStorageRecord(params) {
});
}
/**
* 存酒统计
* @param {*} data
* @returns
*/
export function shopStorageCount() {
return request({
method: "get",
url: "/product/admin/shopStorage/count"
});
}
/**
* 耗材库存列表接口
* @param {*} data

View File

@@ -45,11 +45,19 @@
<div class="drawerbox_bo_box_itembox" @click="router.push({ name: 'device_list' })">
<div class="drawerbox_bo_box_icon">
<el-icon size="40">
<TurnOff />
<Printer />
</el-icon>
</div>
<div class="drawerbox_bo_box_icontext">设备管理</div>
</div>
<div class="drawerbox_bo_box_itembox" @click="router.push({ name: 'store_wine' })">
<div class="drawerbox_bo_box_icon">
<el-icon size="40">
<Goblet />
</el-icon>
</div>
<div class="drawerbox_bo_box_icontext">存酒管理</div>
</div>
<!-- <div class="drawerbox_bo_box_itembox" @click="openCallHandle">
<div class="drawerbox_bo_box_icon">
<el-icon size="40">

View File

@@ -17,7 +17,6 @@ import { ref } from 'vue';
import userStore from '@/utils/useStorage.js'
import { ElUpload, ElMessage } from 'element-plus';
const fileList = ref([])
// 定义接收的外部属性

View File

@@ -101,6 +101,11 @@ const routes = [
name: "webview",
component: () => import("@/views/webview/index.vue"),
},
{
path: "/store_wine",
name: "store_wine",
component: () => import("@/views/store_wine/index.vue"),
},
];
const router = createRouter({

View File

@@ -1,3 +0,0 @@
<template>
收银
</template>

View File

@@ -38,7 +38,7 @@
@click="takeWineDialogVisible = true; maxTakeNum = row.num; takeWineForm.id = row.id;">
<span v-if="isExpired(row.expTime) || row.status == 2">已过期</span>
<span v-else-if="row.num <= 0">已取完</span>
<span v-else>取酒</span>
<span v-else>取酒</span>
</el-button>
</template>
</el-table-column>
@@ -48,18 +48,18 @@
</div>
</el-drawer>
<el-dialog v-model="dialogVisible" title="新增存酒" width="350px" :close-on-click-modal="false" destroy-on-close>
<el-form :model="form" :rules="rules" label-width="100px" label-position="left">
<el-form-item label="选择酒品">
<el-form ref="formRef" :model="form" :rules="rules" label-width="100px" label-position="left">
<el-form-item label="选择酒品" prop="shopStorageGoodId">
<el-select v-model="form.shopStorageGoodId" placeholder="请选择存酒商品" style="width: 180px;">
<el-option v-for="item in storageGoodList" :key="item.id" :label="item.name" :value="item.id">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="存酒数量">
<el-input-number v-model="form.num" :min="1"></el-input-number>
<el-input-number v-model="form.num" :min="1" :step="1" step-strictly></el-input-number>
</el-form-item>
<el-form-item label="存酒有效期">
<el-input-number v-model="form.expDay" :min="1"></el-input-number>
<el-input-number v-model="form.expDay" :min="1" :step="1" step-strictly></el-input-number>
<span style="margin-left: 8px;"></span>
</el-form-item>
</el-form>
@@ -77,7 +77,8 @@
<el-dialog v-model="takeWineDialogVisible" title="取酒" width="350px" :close-on-click-modal="false" destroy-on-close>
<el-form :model="takeWineForm" :rules="takeWineRules" label-width="100px" label-position="left">
<el-form-item label="取酒数量">
<el-input-number v-model="takeWineForm.num" :min="1" :max="maxTakeNum"></el-input-number>
<el-input-number v-model="takeWineForm.num" :min="1" :step="1" step-strictly
:max="maxTakeNum"></el-input-number>
</el-form-item>
</el-form>
<div class="dialog-footer">
@@ -131,6 +132,8 @@ async function shopStorageGetAjax() {
}
}
const formRef = ref(null)
const form = ref({
userId: '',
shopStorageGoodId: '', // 存酒商品ID
@@ -146,19 +149,23 @@ const rules = {
// 确认存酒
const confirmLoading = ref(false);
async function confirmHandle() {
try {
confirmLoading.value = true;
form.value.userId = props.userInfo.userId;
await shopStoragePost(form.value);
ElMessage.success('存酒成功');
dialogVisible.value = false;
shopStorageGetAjax(); // 刷新存酒商品列表
} catch (error) {
console.error('存酒失败:', error);
} finally {
confirmLoading.value = false;
}
function confirmHandle() {
formRef.value.validate(async vaild => {
try {
if (vaild) {
confirmLoading.value = true;
form.value.userId = props.userInfo.userId;
await shopStoragePost(form.value);
ElMessage.success('存酒成功');
dialogVisible.value = false;
shopStorageGetAjax(); // 刷新存酒商品列表
}
} catch (error) {
console.error('存酒失败:', error);
} finally {
confirmLoading.value = false;
}
})
}
// 获取存酒商品列表

View File

@@ -0,0 +1,55 @@
<template>
<div class="wrap">
<el-table :data="list" stripe border v-loading="loading" height="100%">
<el-table-column label="商品信息">
<template v-slot="scope">
<div class="center">
<el-avatar :size="40" shape="square" :src="scope.row.imgUrl" style="flex-shrink: 0;">
{{ scope.row.name.charAt(0) }}
</el-avatar>
<el-text>{{ scope.row.name }}</el-text>
</div>
</template>
</el-table-column>
<el-table-column label="有效存酒" prop="savNum"></el-table-column>
<el-table-column label="已过期存酒" prop="savNum"></el-table-column>
</el-table>
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import { shopStorageCount } from '@/api/product_new'
const loading = ref(false)
const list = ref([])
async function shopStorageCountAjax() {
try {
loading.value = true
list.value = await shopStorageCount()
} catch (error) {
console.log(error);
} finally {
setTimeout(() => {
loading.value = false
}, 300);
}
}
onMounted(() => {
shopStorageCountAjax()
})
</script>
<style scoped lang="scss">
.wrap {
width: 100%;
height: 100%;
}
.center {
display: flex;
align-items: center;
gap: 10px;
}
</style>

View File

@@ -0,0 +1,416 @@
<!-- 存酒记录 -->
<template>
<div class="wrap">
<div class="top_wrap">
<el-form :model="queryForm" inline>
<el-form-item label="酒名">
<el-input v-model="queryForm.name" placeholder="请输入酒名"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" :loading="tableData.loading"
@click="storageGoodGetAjax">搜索</el-button>
<el-button icon="Refresh" :loading="tableData.loading" @click="reset">重置</el-button>
</el-form-item>
</el-form>
<el-button type="primary" @click="addFormDialogShow = true">新增</el-button>
</div>
<div class="tab">
<div class="tab_wrap">
<el-table :data="tableData.list" v-loading="tableData.loading" border stripe height="100%">
<el-table-column label="酒品名">
<template v-slot="scope">
<div class="center">
<el-avatar :size="40" shape="square" :src="scope.row.imgUrl" style="flex-shrink: 0;">
{{ scope.row.name.charAt(0) }}
</el-avatar>
<el-text>{{ scope.row.name }}</el-text>
</div>
</template>
</el-table-column>
<el-table-column label="单位" prop="unit"></el-table-column>
<el-table-column label="有效期(天)" prop="period"></el-table-column>
<el-table-column label="来源" prop="source" width="100">
<template v-slot="scope">
<el-text v-if="scope.row.source === 1">商品</el-text>
<el-text v-if="scope.row.source === 0">手动</el-text>
</template>
</el-table-column>
<el-table-column label="操作" width="300">
<template #default="{ row }">
<el-button type="primary" @click="storeHandle(row)">存酒</el-button>
<el-button @click="editorHandle(row)">编辑</el-button>
<el-button type="danger" @click="deleteHandle(row)">删除</el-button>
</template>
</el-table-column>
</el-table>
</div>
</div>
<div class="pagination">
<el-pagination background v-model:current-page="tableData.page" v-model:page-size="tableData.size"
:page-sizes="[10, 30, 50, 100]" layout="sizes, pager, jumper, total" :total="tableData.total"
@size-change="storageGoodGetAjax" @current-change="storageGoodGetAjax"></el-pagination>
</div>
<!-- 添加/编辑存酒 -->
<el-dialog :title="addForm.id ? '编辑酒品' : '添加酒品'" width="600px" v-model="addFormDialogShow"
@close="addFormDialogClsoe">
<el-form ref="addFormRef" :model="addForm" :rules="addFormRules" label-width="120" label-position="right">
<el-form-item label="类型">
<el-radio-group v-model="addForm.source">
<el-radio-button label="手动添加" :value="0"></el-radio-button>
<el-radio-button label="从商品添加" :value="1"></el-radio-button>
</el-radio-group>
</el-form-item>
<div v-if="addForm.source === 0">
<el-form-item label="酒品名" prop="name">
<el-input placeholder="请输入酒品名称" v-model="addForm.name" style="width: 80%;"></el-input>
</el-form-item>
<el-form-item label="酒品图片">
<UploadImg ref="UploadImgRef" @success="e => addForm.imgUrl = e" />
</el-form-item>
<el-form-item label="单位">
<el-input placeholder="请输入单位" v-model="addForm.unit" style="width: 50%;"></el-input>
</el-form-item>
</div>
<div v-else>
<el-form-item label="选择商品">
<el-select v-model="addForm.prodId" style="width: 80%;">
<el-option v-for="item in goodsStore.originGoodsList" :label="item.name" :value="item.id"
:key="item.id" @click="selectGoods(item)"></el-option>
</el-select>
</el-form-item>
<el-form-item label="商品名称">
<el-text v-if="addForm.name">{{ addForm.name }}</el-text>
<el-text type="info" v-else>请选择商品</el-text>
</el-form-item>
<el-form-item label="商品图片">
<el-image :src="addForm.imgUrl" style="width: 140px;height: 140px;"></el-image>
</el-form-item>
</div>
<el-form-item label="有效期">
<el-input-number v-model="addForm.period" :min="1" :step="1" step-strictly></el-input-number>
</el-form-item>
</el-form>
<div class="dialog-footer">
<div class="btn">
<el-button style="width: 100%;" @click="addFormDialogShow = false">
取消
</el-button>
</div>
<div class="btn">
<el-button style="width: 100%;" type="primary" :loading="addFormConfirmLoading"
@click="addFormConfirm">
确定
</el-button>
</div>
</div>
</el-dialog>
<!-- 存酒 -->
<el-dialog v-model="dialogVisible" :title="`${form.name} - 新增存酒`" width="400px" :close-on-click-modal="false"
destroy-on-close @close="storeInClose">
<el-form ref="formRef" :model="form" :rules="rules" label-width="100px" label-position="left">
<el-form-item label="选择用户" prop="userId">
<el-select v-model="form.userId" placeholder="请选择用户(可搜索)" clearable filterable remote
remote-show-suffix :remote-method="remoteMethod" :loading="userListLoading"
@clear="getUserList">
<el-option :label="`${item.nickName}/${item.phone}`" :value="item.userId"
v-for="item in userList" :key="item.id"></el-option>
</el-select>
</el-form-item>
<!-- <el-form-item label="选择酒品">
<el-select v-model="form.shopStorageGoodId" placeholder="请选择存酒商品">
<el-option v-for="item in storageGoodList" :key="item.id" :label="item.name" :value="item.id">
</el-option>
</el-select>
</el-form-item> -->
<el-form-item label="存酒数量">
<el-input-number v-model="form.num" :min="1" :step="1" step-strictly></el-input-number>
</el-form-item>
<el-form-item label="存酒有效期">
<el-input-number v-model="form.expDay" :min="1" :step="1" step-strictly></el-input-number>
<span style="margin-left: 8px;"></span>
</el-form-item>
</el-form>
<div class="dialog-footer">
<div class="btn">
<el-button style="width: 100%;" @click="dialogVisible = false"> </el-button>
</div>
<div class="btn">
<el-button style="width: 100%;" type="primary" :loading="confirmLoading" @click="confirmHandle">
</el-button>
</div>
</div>
</el-dialog>
</div>
</template>
<script setup>
import _ from 'lodash'
import { ref, onMounted, nextTick } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import { shopStoragePost, storageGoodGet, storageGoodPost, storageGoodPut, storageGoodDelete } from '@/api/product_new'
import { shopUserList } from '@/api/account.js'
import UploadImg from '@/components/uploadImg.vue'
import { useGoods } from '@/store/goods.js'
const goodsStore = useGoods()
const UploadImgRef = ref(null)
const queryForm = ref({
name: ''
})
const tableData = ref({
loading: false,
page: 1,
size: 10,
total: 0,
list: []
});
function isExpired(expTime) {
if (!expTime) return false;
const now = new Date();
const expDate = new Date(expTime);
return expDate < now;
}
function reset() {
queryForm.value.name = ''
tableData.page = 1
storageGoodGetAjax()
}
const userList = ref([])
// 获取用户列表
const userListLoading = ref(false)
function remoteMethod(query) {
if (query) {
getUserList(query)
}
}
// 获取用户列表
async function getUserList(name = '') {
try {
userListLoading.value = true
const res = await shopUserList({ page: 1, key: name, size: 20 })
userList.value = res.records
} catch (error) {
console.log(error);
} finally {
setTimeout(() => {
userListLoading.value = false
}, 100);
}
}
// 获取存酒商品列表
const storageGoodList = ref([]);
async function storageGoodGetAjax() {
try {
tableData.value.loading = true
const res = await storageGoodGet({
name: queryForm.value.name,
page: tableData.value.page,
size: tableData.value.size,
});
tableData.value.list = res.records || [];
tableData.value.total = +res.totalRow || 0
} catch (error) {
console.error('获取存酒商品列表失败:', error);
} finally {
setTimeout(() => {
tableData.value.loading = false
}, 300);
}
}
const dialogVisible = ref(false);
const formObj = {
name: '',
userId: '',
shopStorageGoodId: '', // 存酒商品ID
num: 1, // 存酒数量
expDay: 1, // 存酒有效期单位天默认1天
}
const formRef = ref(null)
const form = ref(formObj)
const rules = {
userId: [{ required: true, message: '请选择用户', trigger: 'change' }],
shopStorageGoodId: [{ required: true, message: '请选择存酒商品', trigger: 'change' }],
num: [{ required: true, message: '请输入存酒数量', trigger: 'change' }],
expDay: [{ required: true, message: '请输入存酒有效期', trigger: 'change' }],
}
function storeInClose() {
formRef.value.resetFields()
form.value = _.cloneDeep(formObj)
}
// 确认存酒
const confirmLoading = ref(false);
function confirmHandle() {
formRef.value.validate(async vaild => {
try {
if (vaild) {
confirmLoading.value = true;
await shopStoragePost(form.value);
ElMessage.success('存酒成功');
dialogVisible.value = false;
}
} catch (error) {
console.error('存酒失败:', error);
} finally {
confirmLoading.value = false;
}
})
}
// 添加酒品
const addFormDialogShow = ref(false)
const addFormRef = ref(null)
const addFormObj = {
id: '',
name: '', // 酒品名称
imgUrl: '', // 商品图片
unit: '瓶', // 单位
period: 365, // 过期时间
prodId: '', // 商品id
source: 0, // 0手动 1商品
}
const addForm = ref(_.cloneDeep(addFormObj))
const addFormRules = ref({
name: [
{
required: true,
message: '请输入酒品名称',
trigger: 'blur'
}
]
})
// 显示存酒
async function storeHandle(row) {
form.value.name = row.name
form.value.shopStorageGoodId = row.id
await nextTick()
dialogVisible.value = true
}
// 编辑
async function editorHandle(row) {
addForm.value = _.cloneDeep(row)
addFormDialogShow.value = true
if (row.source == 0) {
await nextTick()
UploadImgRef.value.init([{ url: row.imgUrl }])
}
}
// 删除
function deleteHandle(row) {
ElMessageBox.confirm(`确认要删除酒品「${row.name}」吗?`).then(async () => {
try {
tableData.value.loading = true
await storageGoodDelete(row.id)
reset()
} catch (error) {
tableData.value.loading = false
}
}).catch(() => { })
}
// 选择商品
function selectGoods(item) {
addForm.value.name = item.name
addForm.value.imgUrl = item.coverImg
}
function addFormDialogClsoe() {
addFormRef.value.resetFields()
addForm.value = _.cloneDeep(addFormObj)
if (form.value.source == 0) {
UploadImgRef.value.init([])
}
}
const addFormConfirmLoading = ref(false)
function addFormConfirm() {
addFormRef.value.validate(async vaild => {
try {
if (vaild) {
addFormConfirmLoading.value = true
if (addForm.value.id) {
await storageGoodPut(addForm.value)
} else {
await storageGoodPost(addForm.value)
}
ElMessage.success(addForm.value.id ? '编辑成功' : '添加成功')
addFormDialogShow.value = false
reset()
}
} catch (error) {
console.log(error);
} finally {
setTimeout(() => {
addFormConfirmLoading.value = false
}, 300);
}
})
}
onMounted(() => {
storageGoodGetAjax()
getUserList()
})
</script>
<style scoped lang="scss">
.wrap {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
}
.tab {
flex: 1;
position: relative;
.tab_wrap {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
}
}
.center {
display: flex;
align-items: center;
gap: 10px;
}
.top_wrap {
display: flex;
justify-content: space-between;
}
.pagination {
padding-top: var(--el-font-size-base);
}
.dialog-footer {
display: flex;
justify-content: flex-end;
gap: var(--el-font-size-base);
.btn {
flex: 1;
}
}
</style>

View File

@@ -0,0 +1,393 @@
<!-- 存酒记录 -->
<template>
<div class="wrap">
<div class="top_wrap">
<el-form :model="queryForm" inline>
<el-form-item label="酒名/用户昵称">
<el-input v-model="queryForm.key" placeholder="请输入酒名/用户昵称"></el-input>
</el-form-item>
<el-form-item label="状态">
<el-select v-model="queryForm.status" placeholder="请选择状态" clearable style="width: 150px;">
<el-option label="全部" value="" />
<el-option label="已取完" value="0" />
<el-option label="储存中" value="1" />
<el-option label="已过期" value="2" />
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" :loading="tableData.loading"
@click="shopStorageGetAjax">搜索</el-button>
<el-button icon="Refresh" :loading="tableData.loading" @click="reset">重置</el-button>
</el-form-item>
</el-form>
<el-button type="primary" @click="dialogVisible = true">新增存酒</el-button>
</div>
<div class="tab">
<div class="tab_wrap">
<el-table :data="tableData.list" v-loading="tableData.loading" border stripe height="100%">
<el-table-column label="用户">
<template v-slot="scope">
<div class="center">
<el-avatar :size="40" :src="scope.row.headImg" style="flex-shrink: 0;">
{{ scope.row.nickName.charAt(0) }}
</el-avatar>
<el-text>{{ scope.row.nickName }}</el-text>
</div>
</template>
</el-table-column>
<el-table-column label="酒品名">
<template v-slot="scope">
<div class="center">
<el-avatar :size="40" shape="square" :src="scope.row.imgUrl" style="flex-shrink: 0;">
{{ scope.row.name.charAt(0) }}
</el-avatar>
<el-text>{{ scope.row.name }}</el-text>
</div>
</template>
</el-table-column>
<el-table-column label="数量" prop="num" width="80">
<template v-slot="scope">
<el-text>{{ scope.row.num }}{{ scope.row.unit }}</el-text>
</template>
</el-table-column>
<el-table-column label="存酒时间" prop="savTime"></el-table-column>
<el-table-column label="到期时间" prop="expTime"></el-table-column>
<el-table-column label="状态" prop="status" width="100">
<template v-slot="scope">
<el-tag disable-transitions type="info"
v-if="isExpired(scope.row.expTime) || scope.row.status == 2">已过期</el-tag>
<el-tag disable-transitions type="info" v-else-if="scope.row.num <= 0">已取完</el-tag>
<el-tag disable-transitions type="primary" v-else>未取完</el-tag>
</template>
</el-table-column>
<el-table-column label="操作" width="240">
<template #default="{ row }">
<el-button type="primary" @click="viewRecord(row)">查看记录</el-button>
<el-button type="danger" :disabled="isExpired(row.expTime) || row.num <= 0"
@click="takeWineDialogVisible = true; maxTakeNum = row.num; takeWineForm.id = row.id;">
<span v-if="isExpired(row.expTime) || row.status == 2">已过期</span>
<span v-else-if="row.num <= 0">已取完</span>
<span v-else>待取酒</span>
</el-button>
</template>
</el-table-column>
</el-table>
</div>
</div>
<div class="pagination">
<el-pagination background v-model:current-page="tableData.page" v-model:page-size="tableData.size"
:page-sizes="[10, 30, 50, 100]" layout="sizes, pager, jumper, total" :total="tableData.total"
@size-change="shopStorageGetAjax" @current-change="shopStorageGetAjax"></el-pagination>
</div>
<!-- 存酒 -->
<el-dialog v-model="dialogVisible" title="新增存酒" width="400px" :close-on-click-modal="false" destroy-on-close
@open="storeInOpen">
<el-form ref="formRef" :model="form" :rules="rules" label-width="100px" label-position="left">
<el-form-item label="选择用户" prop="userId">
<el-select v-model="form.userId" placeholder="请选择用户(可搜索)" clearable filterable remote
remote-show-suffix :remote-method="remoteMethod" :loading="userListLoading"
@clear="getUserList">
<el-option :label="`${item.nickName}/${item.phone}`" :value="item.userId"
v-for="item in userList" :key="item.id"></el-option>
</el-select>
</el-form-item>
<el-form-item label="选择酒品" prop="shopStorageGoodId">
<el-select v-model="form.shopStorageGoodId" placeholder="请选择存酒商品">
<el-option v-for="item in storageGoodList" :key="item.id" :label="item.name" :value="item.id">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="存酒数量">
<el-input-number v-model="form.num" :min="1" :step="1" step-strictly></el-input-number>
</el-form-item>
<el-form-item label="存酒有效期">
<el-input-number v-model="form.expDay" :min="1" :step="1" step-strictly></el-input-number>
<span style="margin-left: 8px;"></span>
</el-form-item>
</el-form>
<div class="dialog-footer">
<div class="btn">
<el-button style="width: 100%;" @click="dialogVisible = false"> </el-button>
</div>
<div class="btn">
<el-button style="width: 100%;" type="primary" :loading="confirmLoading" @click="confirmHandle">
</el-button>
</div>
</div>
</el-dialog>
<!-- 存取酒记录弹窗 -->
<el-dialog title="记录" width="600px" v-model="showRecordDialogVisible">
<el-table :data="recordList" border stripe>
<el-table-column label="记录" prop="content"></el-table-column>
<el-table-column label="操作时间" prop="time"></el-table-column>
</el-table>
</el-dialog>
<!-- 取酒对话框,只选择数量即可不可超过存酒的数量 -->
<el-dialog v-model="takeWineDialogVisible" title="取酒" width="350px" :close-on-click-modal="false"
destroy-on-close>
<el-form :model="takeWineForm" :rules="takeWineRules" label-width="100px" label-position="left">
<el-form-item label="取酒数量">
<el-input-number v-model="takeWineForm.num" :min="1" :step="1" step-strictly
:max="maxTakeNum"></el-input-number>
</el-form-item>
</el-form>
<div class="dialog-footer">
<div class="btn">
<el-button style="width: 100%;" @click="takeWineDialogVisible = false"> </el-button>
</div>
<div class="btn">
<el-button style="width: 100%;" type="primary" :loading="takeWineConfirmLoading"
@click="confirmTakeWineHandle"> </el-button>
</div>
</div>
</el-dialog>
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import { ElMessage } from 'element-plus'
import { shopStoragePost, storageGoodGet, shopStorageGet, shopStoragePut, shopStorageRecord } from '@/api/product_new'
import { shopUserList } from '@/api/account.js'
const queryForm = ref({
key: '',
status: ''
})
const tableData = ref({
loading: false,
page: 1,
size: 10,
total: 0,
list: []
});
function isExpired(expTime) {
if (!expTime) return false;
const now = new Date();
const expDate = new Date(expTime);
return expDate < now;
}
function reset() {
queryForm.value.name = ''
queryForm.value.status = ''
tableData.page = 1
shopStorageGetAjax()
}
// 获取存酒记录
async function shopStorageGetAjax() {
try {
tableData.value.loading = true
const res = await shopStorageGet({
key: queryForm.value.key,
phone: '',
status: queryForm.value.status,
page: tableData.value.page,
size: tableData.value.size,
});
tableData.value.list = res.records || [];
tableData.value.total = +res.totalRow || 0
} catch (error) {
console.error('获取存酒列表失败:', error);
} finally {
setTimeout(() => {
tableData.value.loading = false
}, 300);
}
}
function storeInOpen() {
init()
getUserList()
storageGoodGetAjax()
}
function init() {
form.value = {
userId: '',
shopStorageGoodId: '',
num: 1,
expDay: 1,
};
}
const userList = ref([])
// 获取用户列表
const userListLoading = ref(false)
function remoteMethod(query) {
if (query) {
getUserList(query)
}
}
async function getUserList(name = '') {
try {
userListLoading.value = true
const res = await shopUserList({ page: 1, key: name, size: 20 })
userList.value = res.records
} catch (error) {
console.log(error);
} finally {
setTimeout(() => {
userListLoading.value = false
}, 100);
}
}
// 获取存酒商品列表
const storageGoodList = ref([]);
async function storageGoodGetAjax() {
try {
const res = await storageGoodGet({
page: 1,
size: 999,
});
storageGoodList.value = res.records || [];
} catch (error) {
console.error('获取存酒商品列表失败:', error);
}
}
const dialogVisible = ref(false);
const formRef = ref(null)
const form = ref({
userId: '',
shopStorageGoodId: '', // 存酒商品ID
num: 1, // 存酒数量
expDay: 1, // 存酒有效期单位天默认1天
})
const rules = {
userId: [{ required: true, message: '请选择用户', trigger: 'change' }],
shopStorageGoodId: [{ required: true, message: '请选择存酒商品', trigger: 'change' }],
num: [{ required: true, message: '请输入存酒数量', trigger: 'change' }],
expDay: [{ required: true, message: '请输入存酒有效期', trigger: 'change' }],
}
// 确认存酒
const confirmLoading = ref(false);
function confirmHandle() {
formRef.value.validate(async vaild => {
try {
if (vaild) {
confirmLoading.value = true;
await shopStoragePost(form.value);
ElMessage.success('存酒成功');
dialogVisible.value = false;
shopStorageGetAjax(); // 刷新存酒商品列表
}
} catch (error) {
console.error('存酒失败:', error);
} finally {
confirmLoading.value = false;
}
})
}
// 查看记录
const showRecordDialogVisible = ref(false);
const recordList = ref([]);
async function viewRecord(row) {
try {
showRecordDialogVisible.value = true;
const res = await shopStorageRecord({
id: row.id,
page: 1,
size: 999,
});
recordList.value = res || [];
} catch (error) {
console.error('获取存取酒记录失败:', error);
}
}
const takeWineDialogVisible = ref(false);
const takeWineForm = ref({
id: '', // 存酒记录ID
num: 1,
})
const takeWineRules = {
num: [{ required: true, message: '请输入取酒数量', trigger: 'change' }],
}
const maxTakeNum = ref(1);
const takeWineConfirmLoading = ref(false);
function confirmTakeWineHandle() {
shopStoragePutAjax();
}
// 存酒取酒 num 必需 正数为存酒反之为取酒
async function shopStoragePutAjax() {
try {
takeWineConfirmLoading.value = true;
await shopStoragePut({
id: takeWineForm.value.id,
num: -takeWineForm.value.num, // 取酒数量为负数
});
ElMessage.success('取酒成功');
takeWineDialogVisible.value = false;
shopStorageGetAjax(); // 刷新存酒记录列表
} catch (error) {
console.error('取酒失败:', error);
} finally {
takeWineConfirmLoading.value = false;
}
}
onMounted(() => {
shopStorageGetAjax()
})
</script>
<style scoped lang="scss">
.wrap {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
}
.tab {
flex: 1;
position: relative;
.tab_wrap {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
}
}
.center {
display: flex;
align-items: center;
gap: 10px;
}
.top_wrap {
display: flex;
justify-content: space-between;
}
.pagination {
padding-top: var(--el-font-size-base);
}
.dialog-footer {
display: flex;
justify-content: flex-end;
gap: var(--el-font-size-base);
.btn {
flex: 1;
}
}
</style>

View File

@@ -0,0 +1,104 @@
<template>
<div class="container">
<div class="drawer_wrap">
<div class="header">
<div class="left">
<div class="return" @click="router.back()">
<el-icon size="26" color="#555">
<Back />
</el-icon>
</div>
<div class="menu_wrap">
<el-radio-group v-model="pageType">
<el-radio-button label="存酒记录" :value="1"></el-radio-button>
<el-radio-button label="可存酒管理" :value="2"></el-radio-button>
<el-radio-button label="存酒统计" :value="3"></el-radio-button>
</el-radio-group>
</div>
</div>
</div>
<div class="pay_wrap">
<!-- 存酒记录 -->
<record name="record" key="record" v-if="pageType == 1" />
<!-- 存酒管理 -->
<managePage name="managePage" key="managePage" v-if="pageType == 2" />
<!-- 存酒统计 -->
<countPage name="countPage" key="countPage" v-if="pageType == 3" />
</div>
</div>
</div>
</template>
<script setup>
import { ref, onMounted } from "vue";
import { useRouter } from 'vue-router'
import record from "./components/record.vue";
import countPage from "./components/countPage.vue";
import managePage from "./components/managePage.vue";
const router = useRouter()
const pageType = ref(1)
</script>
<style scoped lang="scss">
.container {
width: 100vw;
height: 100vh;
padding: var(--el-font-size-base);
background-color: #efefef;
}
.drawer_wrap {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
gap: var(--el-font-size-base);
.header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 0 var(--el-font-size-base);
background-color: #fff;
padding: var(--el-font-size-base);
border-radius: var(--el-font-size-base);
.left {
display: flex;
align-items: center;
gap: var(--el-font-size-base);
.return {
cursor: pointer;
border-radius: 4px;
transition: background-color 0.3s;
padding: 10px 8px 4px;
&:hover {
background-color: rgba(0, 0, 0, 0.1);
}
}
.user_info {
display: flex;
align-items: center;
gap: var(--el-font-size-base);
}
.menu_wrap {
display: flex;
align-items: center;
}
}
}
.pay_wrap {
flex: 1;
background: #fff;
border-radius: var(--el-font-size-base);
padding: var(--el-font-size-base);
}
}
</style>