This commit is contained in:
dzc committed 2025-08-26 19:40:22 +08:00
commit 361de88372
6 files changed
+105 -138

No files matched your search

@@ -54,6 +54,11 @@
>
<el-table-column type="selection" width="40" align="center" />
<el-table-column type="index" label="#" width="40" />
<el-table-column prop="merchantId" label="商户" show-overflow-tooltip min-width="100">
<template #default="{ row }">
{{ merchantOptions.find((item: any) => item.id === row.merchantId)?.name }}
</template>
</el-table-column>
<el-table-column prop="name" label="分类名称" show-overflow-tooltip />
<el-table-column prop="categoryType" label="餐段类型" show-overflow-tooltip width="180">
<template #default="scope">
@@ -98,6 +103,7 @@ import { BasicTableProps, useTable } from "/@/hooks/table"
import { fetchList, delObjs } from "/@/api/canteen/canteenOnlineCategory"
import { useMessage, useMessageBox } from "/@/hooks/message"
import { useDict } from "/@/hooks/dict"
import { select } from "/@/api/wallet/mch-manage"
// 引入组件
const FormDialog = defineAsyncComponent(() => import("./form.vue"))
@@ -112,12 +118,26 @@ const showSearch = ref(true)
// 多选变量
const selectObjs = ref([]) as any
const multiple = ref(true)
const merchantOptions = ref<any>([]) // 商户
const state: BasicTableProps = reactive<BasicTableProps>({
queryForm: {},
pageList: fetchList,
})
onMounted(async () => {
await getCanteenMerchant()
})
const getCanteenMerchant = async () => {
try {
const res = await select({ current: 1, size: 9999, types: 1 })
merchantOptions.value = res.data.records
} catch (error) {
merchantOptions.value = []
}
}
// table hook
const { getDataList, currentChangeHandle, sizeChangeHandle, sortChangeHandle, downBlobFile, tableStyle } = useTable(state)
@@ -128,6 +128,7 @@ const openDialog = async () => {
dialogVisible.value = true
merchantId.value = ""
getDataList(false)
tableRef.value.clearSelection()
}
// 获取商品数据并且勾选
@@ -166,10 +167,11 @@ const resetQuery = () => {
// 商品选择对话框确认
const dialogConfirm = async () => {
if (!merchantId.value) return useMessage().error("请选择商户")
const $table = tableRef.value
if ($table) {
const currentSelectedRows = $table.getSelectionRows()
if (!currentSelectedRows.length) return useMessage().error("请勾选菜品")
if (!merchantId.value) return useMessage().error("请选择商户")
const items = currentSelectedRows.map((item: any) => {
return {
+30 -18
View File
@@ -66,6 +66,11 @@
>
<el-table-column type="selection" width="40" align="center" />
<el-table-column type="index" label="#" width="50" />
<el-table-column prop="merchantId" label="商户" show-overflow-tooltip min-width="100">
<template #default="{ row }">
{{ merchantOptions.find((item: any) => item.id === row.merchantId)?.name }}
</template>
</el-table-column>
<el-table-column prop="name" label="商品名称" show-overflow-tooltip min-width="100" />
<el-table-column prop="categoryId" label="商品分类" show-overflow-tooltip min-width="100">
<template #default="{ row }">
@@ -77,30 +82,25 @@
<preview-image :src="scope.row.picUrl" />
</template>
</el-table-column>
<el-table-column prop="sort" label="排序字段" show-overflow-tooltip min-width="100" />
<el-table-column prop="status" label="商品上下架" show-overflow-tooltip min-width="100">
<template #default="scope">
<dict-tag :options="spu_status" :value="scope.row.status" />
</template>
</el-table-column>
<el-table-column prop="dishTypeName" label="上架类型" show-overflow-tooltip min-width="100">
<template #default="scope">
<el-tag v-show="scope.row.dishType == 1" type="success">{{ scope.row.dishTypeName}}</el-tag>
<el-tag v-show="scope.row.dishType == 2" type="primary">{{ scope.row.dishTypeName}}</el-tag>
</template>
</el-table-column>
<el-table-column prop="price" label="商品价格" show-overflow-tooltip min-width="100">
<template #default="scope">
{{ displayPrice(scope.row.price) }}
</template>
</el-table-column>
<!-- <el-table-column prop="marketPrice" label="市场价" show-overflow-tooltip min-width="100">-->
<!-- <template #default="scope">-->
<!-- {{ displayPrice(scope.row.marketPrice) }}-->
<!-- </template>-->
<!-- </el-table-column>-->
<el-table-column prop="stock" label="库存" show-overflow-tooltip min-width="100" />
<el-table-column prop="salesCount" label="商品销量" show-overflow-tooltip min-width="100" />
<el-table-column prop="dishTypeName" label="上架类型" show-overflow-tooltip min-width="100">
<template #default="scope">
<el-tag v-show="scope.row.dishType == 1" type="success">{{ scope.row.dishTypeName }}</el-tag>
<el-tag v-show="scope.row.dishType == 2" type="primary">{{ scope.row.dishTypeName }}</el-tag>
</template>
</el-table-column>
<el-table-column prop="salesCount" label="销量" show-overflow-tooltip min-width="100" />
<el-table-column prop="status" label="商品上下架" show-overflow-tooltip min-width="100">
<template #default="scope">
<dict-tag :options="spu_status" :value="scope.row.status" />
</template>
</el-table-column>
<el-table-column prop="sort" label="排序字段" show-overflow-tooltip min-width="100" />
<el-table-column prop="createTime" label="创建时间" show-overflow-tooltip min-width="160" />
<el-table-column label="操作" width="150" fixed="right">
<template #default="scope">
@@ -136,6 +136,7 @@ import { useMessage, useMessageBox } from "/@/hooks/message"
import { useDict } from "/@/hooks/dict"
import { displayPrice } from "/@/utils/formatMoney"
import { fetchList as getCanteenOnlineCategory } from "/@/api/canteen/canteenOnlineCategory"
import { select } from "/@/api/wallet/mch-manage"
const FormDialog = defineAsyncComponent(() => import("./form.vue"))
const ExportFormDialog = defineAsyncComponent(() => import("./export-form.vue"))
@@ -151,12 +152,14 @@ const showSearch = ref(true)
const selectObjs = ref([]) as any
const multiple = ref(true)
const categoryOptions = ref<any>([]) // 商品分类选项
const merchantOptions = ref<any>([]) // 商户
const state: BasicTableProps = reactive<BasicTableProps>({
queryForm: {},
pageList: fetchList,
})
onMounted(async () => {
await getCanteenMerchant()
await getCanteenOnlineCategoryAll()
})
@@ -169,6 +172,15 @@ const getCanteenOnlineCategoryAll = async () => {
}
}
const getCanteenMerchant = async () => {
try {
const res = await select({ current: 1, size: 9999, types: 1 })
merchantOptions.value = res.data.records
} catch (error) {
merchantOptions.value = []
}
}
const { getDataList, currentChangeHandle, sizeChangeHandle, sortChangeHandle, downBlobFile, tableStyle } = useTable(state)
// 清空搜索条件
+15 -113
View File
@@ -39,17 +39,14 @@
<div class="w-full">
<div class="w-full flex flex-wrap items-center justify-center" v-for="(hourType, index) in foodData" :key="index">
<div v-for="dish in hourType" :key="dish.id" class="w-60 p-2">
<div class="h-32 overflow-hidden">
<!-- <div class="absolute inset-0 bg-gradient-to-b from-transparent"></div> -->
<div class="relative h-32 overflow-hidden">
<img :src="imageBaseUrl + dish.picUrl" :alt="dish.name" class="h-full w-full object-cover" />
<!-- <div class="absolute left-2 top-2 rounded-lg">
<el-tag type="primary">午餐</el-tag>
</div> -->
<!-- <div class="absolute right-1 top-2 rounded-lg px-2 py-0.5 text-sm">
<el-tag type="primary">
{{ canteenCategoryOption?.find((v: any) => v.id == dish.categoryId)?.name }}
</el-tag>
</div> -->
<div class="absolute left-1 top-1">
<star-medal text="午餐" />
</div>
<div class="absolute left-1 top-1">
<star-medal :text="canteenCategoryOption?.find((v: any) => v.id == dish.categoryId)?.name" />
</div>
</div>
<div
class="w-full flex items-center justify-between bg-[#AEBBF9]/40 px-2 pb-4 backdrop-blur-sm rounded-bl-[50%] rounded-br-[50%]"
@@ -68,8 +65,14 @@
</template>
<script setup lang="ts">
import { ref, onMounted, onUnmounted } from "vue"
import { selectTimeFoodApi } from "/@/api/canteen/canteenDailyMenu"
import { getAllSimple as getCanteenCategory } from "/@/api/canteen/canteenCategory"
import { displayPrice } from "/@/utils/formatMoney"
import { useMessage } from "/@/hooks/message"
import { ElTooltip } from "element-plus"
import dayjs from "dayjs"
import StarMedal from "./star-medal.vue"
const containerRef = ref<HTMLElement | null>(null)
const currentDate = ref(dayjs().format("YYYY/MM/DD"))
@@ -96,7 +99,7 @@ const foodData = reactive<{
dinner: [],
})
const canteenCategoryOption = ref<any>()
let timer: number
let timer: number | null = null
onMounted(async () => {
timer = setInterval(() => (currentTime.value = dayjs().format("HH:mm:ss")), 1000)
@@ -182,6 +185,7 @@ const getDishByType = async () => {
}
})
}
// 获取食堂菜品分类
const getCanteenDishesCategory = async () => {
try {
@@ -193,108 +197,6 @@ const getCanteenDishesCategory = async () => {
canteenCategoryOption.value = []
}
}
// =====================================
import { ref, onMounted, onUnmounted, computed, watch, nextTick } from "vue"
import { selectTimeFoodApi } from "/@/api/canteen/canteenDailyMenu"
import { getAllSimple as getCanteenCategory } from "/@/api/canteen/canteenCategory"
import { displayPrice } from "/@/utils/formatMoney"
import { useMessage } from "/@/hooks/message"
const scrollContainerRef = ref<HTMLElement | null>(null)
let scrollOffset = ref(0)
let isScrolling = ref(true)
let lastTimestamp = 0
const SCROLL_SPEED = 0.5
let animationFrame: number | null = null
// 添加一个计算属性来判断是否需要滚动
const needScroll = ref(false)
// 优化后的滚动处理函数
const handleScroll = (timestamp: number) => {
if (!isScrolling.value) return
if (!lastTimestamp) {
lastTimestamp = timestamp
}
const deltaTime = timestamp - lastTimestamp
lastTimestamp = timestamp
const container = scrollContainerRef.value
if (!container) return
// 计算新的滚动偏移量
scrollOffset.value += SCROLL_SPEED * (deltaTime / 16)
const contentHeight = container.scrollHeight / 2 // 单个内容的高度
// 当滚动超过一个内容高度时,减去一个内容高度,造成无缝衔接的效果
if (scrollOffset.value >= contentHeight) {
scrollOffset.value -= contentHeight
}
animationFrame = requestAnimationFrame(handleScroll)
}
// 开始滚动
const startScroll = () => {
if (!isScrolling.value || !needScroll.value) return
lastTimestamp = 0
animationFrame = requestAnimationFrame(handleScroll)
}
// 停止滚动
const stopScroll = () => {
if (animationFrame) {
cancelAnimationFrame(animationFrame)
animationFrame = null
}
}
// 切换滚动状态
const toggleScroll = () => {
isScrolling.value = !isScrolling.value
if (isScrolling.value) {
startScroll()
} else {
stopScroll()
}
}
// 修改检查是否需要滚动的函数
const checkNeedScroll = () => {
const container = scrollContainerRef.value
if (!container) return false
// 获取内容的实际高度(不包括克隆的内容)
const contentHeight = container.querySelector(".grid")?.getBoundingClientRect().height || 0
// 获取容器的可视高度
const containerHeight = container.clientHeight
// 更新是否需要滚动的状态
needScroll.value = contentHeight > containerHeight
// 如果不需要滚动,确保停止滚动并重置位置
if (!needScroll.value) {
stopScroll()
isScrolling.value = false
scrollOffset.value = 0
}
return needScroll.value
}
// 防抖函数
function debounce(fn: Function, delay: number) {
let timer: number | null = null
return function (this: any, ...args: any[]) {
if (timer) clearTimeout(timer)
timer = setTimeout(() => {
fn.apply(this, args)
}, delay)
}
}
</script>
<style scoped lang="scss">
@@ -0,0 +1,29 @@
<template>
<div class="star-medal">{{ text }}</div>
</template>
<script setup lang="ts">
defineProps({
text: {
type: String,
default: "未知",
},
})
</script>
<style scoped>
.star-medal {
width: 30px;
height: 30px;
z-index: 100;
text-align: center;
line-height: 20px;
font-size: 12px;
border-radius: 4px;
background-color: #436df7;
color: #fff;
font-weight: bold;
-webkit-clip-path: polygon(0% 0%, 100% 0%, 100% 75%, 75% 75%, 75% 100%, 50% 75%, 0% 75%);
clip-path: polygon(0% 0%, 100% 0%, 100% 75%, 75% 75%, 75% 100%, 50% 75%, 0% 75%);
}
</style>
+8 -6
View File
@@ -66,7 +66,7 @@
</el-descriptions>
<el-descriptions :column="3" title="货柜信息" border>
<template #extra>
<template v-if="state.deviceDetail" #extra>
<el-space>
<el-button icon="RefreshRight" type="primary" @click="refreshCabinetQrCode">刷新货柜二维码</el-button>
<el-button icon="CircleCheck" type="primary" @click="checkOpenAccess" :disabled="checkCloseLoading" :loading="checkOpenLoading">
@@ -84,7 +84,7 @@
</el-space>
</template>
</el-descriptions>
<el-tabs type="border-card" @tab-click="doorTabClick">
<el-tabs v-if="state.deviceDetail" type="border-card" @tab-click="doorTabClick">
<el-tab-pane
v-if="state.deviceDetail.cabinetList?.length"
:label="state.deviceDetail.deviceCode + '-' + item.cabinetNo"
@@ -130,6 +130,7 @@
</el-descriptions>
</el-tab-pane>
</el-tabs>
<el-empty v-else description="无货柜信息" />
<el-descriptions :column="0" title="货柜商品" border>
<!-- <template #extra>
@@ -137,7 +138,7 @@
</template> -->
</el-descriptions>
<el-tabs type="border-card" @tab-click="tabClick">
<el-tabs v-if="state.deviceDetail" type="border-card" @tab-click="tabClick">
<el-tab-pane
v-if="state.deviceDetail.cabinetList?.length"
:label="state.deviceDetail.deviceCode + '-' + item.cabinetNo"
@@ -150,12 +151,12 @@
<div class="text-center w-24 text-lg font-bold">第 {{ floorIndex + 1 }} 层:</div>
<div class="flex flex-wrap">
<div class="flex flex-col items-center justify-start" v-for="(v, indexNo) in floorItem[floorIndex + 1]" :key="indexNo">
<div v-if="v.spuId && v.spuDetail" class="w-20 mx-4 my-1 flex flex-col items-center">
<div v-if="v.spuId && v.spuDetail" class="w-24 mx-4 my-1 flex flex-col items-center">
<div class="relative">
<el-icon @click.stop="deleteGoods(v)" class="absolute right-[-8px] top-[-8px] text-xl text-blue-600 z-50">
<CircleClose />
</el-icon>
<preview-image width="86px" height="86px" :src="v.spuDetail.pic" @click.stop />
<preview-image width="96px" height="86px" :src="v.spuDetail.pic" @click.stop />
</div>
<el-tooltip effect="dark" :content="v.spuDetail?.name">
<div class="line-clamp-1">{{ v.spuDetail?.name }}</div>
@@ -179,7 +180,7 @@
</div>
<div
v-else
class="bg-blue-50 w-20 h-20 border border-black mx-4 my-1 flex items-center justify-center cursor-pointer rounded-lg"
class="bg-blue-50 w-24 h-20 border border-black mx-4 my-1 flex items-center justify-center cursor-pointer rounded-lg"
@click="clickPutaway(v.id)"
>
点击上架
@@ -190,6 +191,7 @@
</div>
</el-tab-pane>
</el-tabs>
<el-empty v-else description="无货柜商品" />
</div>
<!-- 柜子设置 -->