fix:修复bug

This commit is contained in:
2026-03-09 09:06:33 +08:00
parent 40665dda67
commit e855ecde78
8 changed files with 267 additions and 136 deletions
+2 -2
View File
@@ -5,7 +5,7 @@ VITE_DELETE_CONSOLE=false
#本地环境 #本地环境
#VITE_SERVER_BASEURL=http://liuyao.nat100.top/meiguowaimai #VITE_SERVER_BASEURL=http://liuyao.nat100.top/meiguowaimai
VITE_SERVER_BASEURL=http://192.168.5.23:8889 #VITE_SERVER_BASEURL=http://192.168.5.64:8080
#VITE_SERVER_BASEURL=https://howhowfresh.com/prod-api VITE_SERVER_BASEURL=https://howhowfresh.com/prod-api
#VITE_SERVER_BASEURL=http://192.168.1.8:8811 #VITE_SERVER_BASEURL=http://192.168.1.8:8811
#VITE_SERVER_BASEURL=http://mifengchuantou.natapp1.cc/meiguowaimai #VITE_SERVER_BASEURL=http://mifengchuantou.natapp1.cc/meiguowaimai
+3 -1
View File
@@ -428,7 +428,9 @@
"name": "name:", "name": "name:",
"nameRequired": "Name is required", "nameRequired": "Name is required",
"setDefaultDays": "Set the default days and times this menu will be available", "setDefaultDays": "Set the default days and times this menu will be available",
"submit": "submit" "submit": "submit",
"sort": "Sort position",
"sortPlaceholder": "Please enter sort number"
}, },
"message": { "message": {
"readAll": "One-click read", "readAll": "One-click read",
+3 -1
View File
@@ -428,7 +428,9 @@
"name": "名称:", "name": "名称:",
"nameRequired": "名称不能为空", "nameRequired": "名称不能为空",
"setDefaultDays": "设置此菜单可用的默认天数和时间", "setDefaultDays": "设置此菜单可用的默认天数和时间",
"submit": "提交" "submit": "提交",
"sort": "排序位置",
"sortPlaceholder": "请输入排序数字"
}, },
"message": { "message": {
"readAll": "一键已读", "readAll": "一键已读",
+2 -2
View File
@@ -2,8 +2,8 @@
"name" : "CHEFLINK Merchant", "name" : "CHEFLINK Merchant",
"appid" : "__UNI__BB8E3C9", "appid" : "__UNI__BB8E3C9",
"description" : "美国外卖商户端", "description" : "美国外卖商户端",
"versionName" : "1.0.13", "versionName" : "1.0.16",
"versionCode" : 113, "versionCode" : 116,
"transformPx" : false, "transformPx" : false,
/* 5+App */ /* 5+App */
"app-plus" : { "app-plus" : {
+33 -12
View File
@@ -130,29 +130,50 @@ onLoad((options) => {
getMenuListByMerchant() getMenuListByMerchant()
}) })
const menuList = ref([]) // 默认分页配置(避免一次请求 1000 条)
const DEFAULT_PAGE_SIZE = 10;
const DEFAULT_PAGE_NUM = 1;
function getMenuListByMerchant() { const menuList = ref<any[]>([])
appMerchantMenuMenuListByMerchantPost({
async function getMenuListByMerchant() {
const allRows: any[] = []
let pageNum = DEFAULT_PAGE_NUM
while (true) {
const res = await appMerchantMenuMenuListByMerchantPost({
params: { params: {
pageSize: 1000, pageSize: DEFAULT_PAGE_SIZE,
pageNum: 1 pageNum
} }
}).then(res => { })
menuList.value = res.rows
selectedMenu.value = menuList.value[0].id
if (res.rows.length === 0) { const rows = res.rows || []
allRows.push(...rows)
if ((typeof res.total === 'number' && allRows.length >= res.total) || rows.length < DEFAULT_PAGE_SIZE) {
break
}
pageNum += 1
if (pageNum > 200) break
}
menuList.value = allRows
if (menuList.value.length === 0) {
uni.showToast({ uni.showToast({
title: t('pages-user.food.add-food.tips'), title: t('pages-user.food.add-food.tips'),
icon: 'none' icon: 'none'
}) })
} else { return
}
selectedMenu.value = menuList.value[0]?.id
// 回显 menu // 回显 menu
formData.value.menu = menuList.value.find(item => item.id === formData.value.menuId)?.menuName formData.value.menu = menuList.value.find(item => item.id === formData.value.menuId)?.menuName
} }
})
}
// 获取菜品详情 // 获取菜品详情
function getDishDetail() { function getDishDetail() {
+26
View File
@@ -17,6 +17,8 @@ const formData = reactive({
id: '', id: '',
menuName: '', menuName: '',
scheduleTimes: '', scheduleTimes: '',
// 排序
sort: 0,
isActive: true isActive: true
}) })
// 提交表单 // 提交表单
@@ -94,6 +96,8 @@ function getMenuDetail() {
formData.menuName = res.data.menuName formData.menuName = res.data.menuName
formData.scheduleTimes = res.data.scheduleTimes formData.scheduleTimes = res.data.scheduleTimes
formData.isActive = +res.data.delFlag === 1 formData.isActive = +res.data.delFlag === 1
// 排序
formData.sort = res.data.sort ?? 0
}) })
} }
@@ -152,6 +156,28 @@ function deleteMenu() {
</view> </view>
</view> </view>
<!-- 排序 -->
<view class="mb-44rpx">
<text class="text-36rpx text-#333 font-500 mb-20rpx block">
{{ t('pages-user.menu.sort') }}
</text>
<view class="bg-#F6F6F6 rounded-16rpx h-98rpx px-24rpx flex items-center">
<wd-input
type="number"
:focus-when-clear="false"
:modelValue="formData.sort"
:placeholder="t('pages-user.menu.sortPlaceholder')"
clearable
confirm-type="done"
custom-class="!text-30rpx !bg-transparent flex-1"
no-border
placeholderStyle="font-size: 30rpx;color: #999;"
@update:modelValue="formData.sort = Number($event || 0)"
>
</wd-input>
</view>
</view>
<!-- 菜单激活状态 --> <!-- 菜单激活状态 -->
<view class="form-section mb-60rpx"> <view class="form-section mb-60rpx">
<view class="flex items-center justify-between mb-20rpx"> <view class="flex items-center justify-between mb-20rpx">
@@ -15,6 +15,10 @@ const {t} = useI18n()
const message = useMessage(); const message = useMessage();
// 默认分页配置(菜单相关接口仍然依赖)
const DEFAULT_PAGE_SIZE = 10;
const DEFAULT_PAGE_NUM = 1;
const props = defineProps<{ const props = defineProps<{
tabIndex: number | string tabIndex: number | string
currentIndex: number | string currentIndex: number | string
@@ -25,46 +29,76 @@ function changeMenu() {
emits('changeMenu') emits('changeMenu')
} }
watch(() => props.currentIndex, (newVal) => { const tabIndexNum = computed(() => +props.tabIndex)
console.log('111', newVal, props.tabIndex)
if (+newVal === props.tabIndex && +props.tabIndex === 1) {
getMenuListByMerchant()
}
if (+newVal === props.tabIndex && +props.tabIndex === 2) {
getMenuListByMerchant()
} else if (+newVal === props.tabIndex && +props.tabIndex === 3) {
// 获取菜品列表
console.log('获取菜品列表')
getDishList()
}
}, {immediate: true})
const paging = ref(null) watch(
const dataList = ref([]) () => props.currentIndex,
const queryList = (pageNo, pageSize) => { (newVal) => {
return new Promise((resolve, reject) => { console.log('111', newVal, props.tabIndex)
paging.value.complete([ if (+newVal === props.tabIndex) {
{ // 切换到当前tab,触发分页加载(pageNum会由z-paging自动递增)
title: '订单1' paging.value?.reload()
}
}, },
{ {immediate: true},
title: '订单2' )
},
{ // 分页数据源:tab1=菜单详情内dishList(本地分页)tab2=菜单列表(后端分页),tab3=菜品列表(后端分页)
title: '订单3' function queryByTab(pageNum: number, pageSize: number) {
}, // tab1:菜单概览-菜单下菜品(本地分页)
]); if (tabIndexNum.value === 1) {
return new Promise<IResData<any>>(async (resolve) => {
await ensureMenuListLoaded()
await ensureMenuDetailLoaded()
const all = menuDishListData.value || []
const start = (pageNum - 1) * pageSize
resolve({
rows: all.slice(start, start + pageSize),
total: all.length,
} as any)
}) })
} }
// 加载状态
const loading = ref(true) // tab2:周菜单管理-菜单列表(后端分页)
// 模拟数据加载 if (tabIndexNum.value === 2) {
onMounted(() => { return new Promise<IResData<any>>((resolve) => {
loading.value = true if (!userStore.isLogin) return resolve({rows: [], total: 0} as any)
setTimeout(() => { appMerchantMenuMenuListByMerchantPost({
loading.value = false params: {
}, 300) pageNum,
pageSize,
},
}).then((res: any) => {
resolve({
...(res as any),
rows: (res as any).rows || [],
total: (res as any).total || 0,
}) })
})
})
}
// tab3:菜品列表(后端分页)
return new Promise<IResData<any>>((resolve) => {
if (!userStore.isLogin) return resolve({rows: [], total: 0} as any)
appMerchantDishListPost({
params: {
pageNum,
pageSize,
},
// @ts-ignore 后端 body 暂无筛选条件,这里传空对象
body: {},
}).then((res: any) => {
resolve({
...(res as any),
rows: (res as any).rows || [],
total: (res as any).total || 0,
})
})
})
}
const {paging, dataList, loading, queryList} = usePage<any>(queryByTab)
function navigateTo(url: string) { function navigateTo(url: string) {
uni.navigateTo({url}) uni.navigateTo({url})
@@ -72,76 +106,85 @@ function navigateTo(url: string) {
// 获取当前商户的菜单列表 // 获取当前商户的菜单列表
const menuList = ref([]) const menuList = ref<any[]>([])
// 当前选中的菜单索引 // 当前选中的菜单索引
const currentMenuIndex = ref(0) const currentMenuIndex = ref(0)
// 当前选中的菜单数据 // 当前选中的菜单数据
const currentMenu = computed(() => { const currentMenu = computed(() => {
return menuList.value[currentMenuIndex.value] return menuList.value[currentMenuIndex.value] || {}
}) })
function getMenuListByMerchant() { async function ensureMenuListLoaded() {
// 仅tab1需要完整menuList用于头部展示 & indexChangeMenu定位
if (tabIndexNum.value !== 1) return
if (!userStore.isLogin) return if (!userStore.isLogin) return
appMerchantMenuMenuListByMerchantPost({ if (menuList.value.length > 0) return
const allRows: any[] = []
let pageNum = DEFAULT_PAGE_NUM
while (true) {
const res: any = await appMerchantMenuMenuListByMerchantPost({
params: { params: {
pageSize: 1000, pageSize: DEFAULT_PAGE_SIZE,
pageNum: 1 pageNum,
} },
}).then(res => {
menuList.value = res.rows || []
if (res.rows && res.rows.length > 0) {
// 设置当前选中的菜单索引
currentMenuIndex.value = 0
if (+props.currentIndex === 1) {
// 获取菜单详情
getMenuDetail()
}
}
}) })
const rows = res.rows || []
allRows.push(...rows)
if ((typeof res.total === 'number' && allRows.length >= res.total) || rows.length < DEFAULT_PAGE_SIZE) {
break
} }
const findIndexById = (array, targetId) => pageNum += 1
array.findIndex(item => item.id === targetId); if (pageNum > 200) break
}
menuList.value = allRows
if (menuList.value.length > 0) {
currentMenuIndex.value = 0
}
}
const findIndexById = (array: any[], targetId: string | number) =>
array.findIndex((item) => item.id === targetId);
function indexChangeMenu(id: string) { function indexChangeMenu(id: string) {
// 最新的菜单ID // 最新的菜单ID
console.log('indexChangeMenu', id) console.log('indexChangeMenu', id)
currentMenuIndex.value = findIndexById(menuList.value, id) currentMenuIndex.value = findIndexById(menuList.value, id)
console.log('当前选中的菜单索引', currentMenuIndex.value) console.log('当前选中的菜单索引', currentMenuIndex.value)
getMenuDetail() getMenuDetail().then(() => {
paging.value?.reload()
})
} }
// 菜单下面的菜品数据 // 菜单下面的菜品数据(完整数据,用于tab1本地分页与搜索)
const menuDishListData = ref<MerchantDishVo[]>([]) const menuDishListData = ref<MerchantDishVo[]>([])
function getMenuDetail() { async function getMenuDetail() {
appMerchantMenuMenuDetailPost({ return appMerchantMenuMenuDetailPost({
params: { params: {
recipeId: currentMenu.value.id || '' recipeId: currentMenu.value.id || ''
} }
}).then(res => { }).then((res: any) => {
console.log('获取菜单详情', res) console.log('获取菜单详情', res)
if (res.data && res.data.dishList) { if (res.data && (res.data as any).dishList) {
menuDishListData.value = res.data.dishList || [] menuDishListData.value = (res.data as any).dishList || []
} }
}).catch(err => { }).catch(err => {
console.error('获取菜单详情失败', err) console.error('获取菜单详情失败', err)
}) })
} }
const dishList = ref<MerchantDishVo[]>([]) async function ensureMenuDetailLoaded() {
if (tabIndexNum.value !== 1) return
function getDishList() { if (!currentMenu.value?.id) return
appMerchantDishListPost({ // 没有数据时才请求,避免每次上拉都重复打接口
params: { if (menuDishListData.value.length > 0) return
pageSize: 1000, await getMenuDetail()
pageNum: 1
}
}).then(res => {
console.log('res', res)
dishList.value = res.rows
console.log('dishList', dishList.value)
})
} }
function handleClickMenu(item: any) { function handleClickMenu(item: any) {
@@ -157,12 +200,21 @@ function handleClickDish(item: MerchantDishVo) {
}) })
} }
// 库存文案相关辅助方法
function hasStock(item: any) {
return !!(item as any)?.stock
}
function getStock(item: any) {
const stock = (item as any)?.stock
if (stock === undefined || stock === null) return ''
return Number(stock).toFixed(0)
}
function initData() { function initData() {
console.log('页面回来的时候获取最新的数据', props.currentIndex) console.log('页面回来的时候获取最新的数据', props.currentIndex)
if (+props.currentIndex === 2 || +props.currentIndex === 1) { if (+props.currentIndex === +props.tabIndex) {
getMenuListByMerchant() paging.value?.reload()
} else if (+props.currentIndex === 3) {
getDishList()
} }
} }
@@ -182,11 +234,14 @@ function handleSearch() {
isShowSearch.value = true isShowSearch.value = true
} }
const searchResult = ref([]); type DishSearchResult = {
item: MerchantDishVo
}
const searchResult = ref<DishSearchResult[]>([]);
function handleConfirmSearch() { function handleConfirmSearch() {
console.log('handleConfirmSearch', keyword.value) console.log('handleConfirmSearch', keyword.value)
const fuse = new Fuse(menuDishListData.value, { const fuse = new Fuse<MerchantDishVo>(menuDishListData.value, {
threshold: 0.2, threshold: 0.2,
keys: ["dishName", "dishDescription"], keys: ["dishName", "dishDescription"],
}); });
@@ -199,7 +254,7 @@ function inputClear() {
} }
// 删除菜品 // 删除菜品
function deleteRecipe(item) { function deleteRecipe(item: MerchantDishVo) {
message message
.confirm({ .confirm({
title: t("common.prompt.system-prompt"), title: t("common.prompt.system-prompt"),
@@ -217,7 +272,7 @@ function deleteRecipe(item) {
}) })
.then(async () => { .then(async () => {
appMerchantDishRemovePost({ appMerchantDishRemovePost({
body: [item.id] body: [item.id as number],
}).then((res) => { }).then((res) => {
uni.showToast({ uni.showToast({
title: t('toast.deleteSuccess'), title: t('toast.deleteSuccess'),
@@ -324,7 +379,7 @@ const isMerchant = computed(() => {
<!--搜索结果数据--> <!--搜索结果数据-->
<template v-if="isShowSearch"> <template v-if="isShowSearch">
<template v-if="searchResult.length>0"> <template v-if="searchResult.length>0">
<template v-for="(item, index) in searchResult"> <template v-for="(item, index) in searchResult" :key="item.item.id || index">
<view :class="[index === 0 ? '' : 'mt-46rpx']" @click="handleClickDish(item.item)"> <view :class="[index === 0 ? '' : 'mt-46rpx']" @click="handleClickDish(item.item)">
<view class="flex-center-sb"> <view class="flex-center-sb">
<image <image
@@ -354,12 +409,13 @@ const isMerchant = computed(() => {
</template> </template>
</template> </template>
<template v-else> <template v-else>
<template v-for="(item, index) in menuDishListData"> <!-- tab1 使用本地分页后的 dataList 渲染menuDishListData 仅用于搜索与总数据缓存 -->
<template v-for="(item, index) in dataList" :key="item.id || index">
<view :class="[index === 0 ? '' : 'mt-46rpx']"> <view :class="[index === 0 ? '' : 'mt-46rpx']">
<wd-swipe-action v-model="swipeActionValue"> <wd-swipe-action v-model="swipeActionValue">
<view class="flex-center-sb" @click="handleClickDish(item)"> <view class="flex-center-sb" @click="handleClickDish(item)">
<image <image
:src="item.dishImage.split(',')[0]" :src="item.dishImage ? item.dishImage.split(',')[0] : ''"
class="w-176rpx h-176rpx mr-28rpx shrink-0 rounded-24rpx" class="w-176rpx h-176rpx mr-28rpx shrink-0 rounded-24rpx"
mode="aspectFill" mode="aspectFill"
></image> ></image>
@@ -411,7 +467,7 @@ const isMerchant = computed(() => {
<!-- 菜单列表 --> <!-- 菜单列表 -->
<view class=""> <view class="">
<!-- Monday Menu Item --> <!-- Monday Menu Item -->
<template v-for="item in menuList"> <template v-for="item in dataList" :key="item.id">
<view class="flex-center-sb border-b-1rpx border-b-solid border-b-#F6F6F6 h-170rpx" <view class="flex-center-sb border-b-1rpx border-b-solid border-b-#F6F6F6 h-170rpx"
@click="handleClickMenu(item)"> @click="handleClickMenu(item)">
<view class="flex-1"> <view class="flex-1">
@@ -421,7 +477,7 @@ const isMerchant = computed(() => {
<image class="w-32rpx h-32rpx shrink-0 rotate-0" src="@img/chef/115.png"></image> <image class="w-32rpx h-32rpx shrink-0 rotate-0" src="@img/chef/115.png"></image>
</view> </view>
</template> </template>
<template v-if="menuList.length === 0"> <template v-if="dataList.length === 0">
<view class="py-100rpx center"> <view class="py-100rpx center">
<image class="w-250rpx h-250rpx" src="@img/chef/16033@2x.png"></image> <image class="w-250rpx h-250rpx" src="@img/chef/16033@2x.png"></image>
</view> </view>
@@ -437,10 +493,10 @@ const isMerchant = computed(() => {
<image class="w-28rpx h-28rpx shrink-0 mr-10rpx" src="@img/chef/107.png"></image> <image class="w-28rpx h-28rpx shrink-0 mr-10rpx" src="@img/chef/107.png"></image>
<text class="text-26rpx text-#333 font-500">{{ t('pages.menu.add') }}</text> <text class="text-26rpx text-#333 font-500">{{ t('pages.menu.add') }}</text>
</view> </view>
<template v-for="(item, index) in dishList"> <template v-for="(item, index) in dataList" :key="item.id || index">
<view :class="[index === 0 ? '' : 'mt-46rpx']" class="flex-center-sb" @click="handleClickDish(item)"> <view :class="[index === 0 ? '' : 'mt-46rpx']" class="flex-center-sb" @click="handleClickDish(item)">
<image <image
:src="item.dishImage.split(',')[0]" :src="item.dishImage ? item.dishImage.split(',')[0] : ''"
class="w-176rpx h-176rpx mr-28rpx shrink-0 rounded-24rpx bg-common" class="w-176rpx h-176rpx mr-28rpx shrink-0 rounded-24rpx bg-common"
mode="aspectFill" mode="aspectFill"
></image> ></image>
@@ -456,8 +512,8 @@ const isMerchant = computed(() => {
${{ item.originalPrice }} ${{ item.originalPrice }}
</view> </view>
<view class="mt-63rpx text-#333 text-30rpx font-500"> <view class="mt-63rpx text-#333 text-30rpx font-500">
<template v-if="item.stock"> <template v-if="hasStock(item)">
{{ t('common.stock') }}: {{ Number(item.stock).toFixed(0) }} {{ t('common.stock') }}: {{ getStock(item) }}
</template> </template>
</view> </view>
</view> </view>
@@ -465,7 +521,7 @@ const isMerchant = computed(() => {
</view> </view>
</template> </template>
<template v-if="dishList.length === 0"> <template v-if="dataList.length === 0">
<view class="py-100rpx center"> <view class="py-100rpx center">
<image class="w-250rpx h-250rpx" src="@img/chef/16033@2x.png"></image> <image class="w-250rpx h-250rpx" src="@img/chef/16033@2x.png"></image>
</view> </view>
@@ -8,27 +8,53 @@ const show = ref(false);
const pickerValue = ref(0) const pickerValue = ref(0)
const emits = defineEmits(['confirm']) const emits = defineEmits(['confirm'])
// 默认分页配置(避免一次请求 1000 条)
const DEFAULT_PAGE_SIZE = 10;
const DEFAULT_PAGE_NUM = 1;
type MenuColumnItem = {
value: string | number
label: string
}
function onOpen(value: number) { function onOpen(value: number) {
getMenuListByMerchant() getMenuListByMerchant()
show.value = true; show.value = true;
} }
function getMenuListByMerchant() { const columns = ref<MenuColumnItem[]>([])
appMerchantMenuMenuListByMerchantPost({
async function getMenuListByMerchant() {
if (!userStore.isLogin) return
const allRows: any[] = []
let pageNum = DEFAULT_PAGE_NUM
while (true) {
const res = await appMerchantMenuMenuListByMerchantPost({
params: { params: {
pageSize: 1000, pageSize: DEFAULT_PAGE_SIZE,
pageNum: 1 pageNum
} }
}).then(res => { })
if (res.rows && res.rows.length > 0) {
columns.value = res.rows.map((item) => { const rows = res.rows || []
return { allRows.push(...rows)
// 按 total 或 “本页不足 pageSize” 判断结束,保证符合分页语义
if ((typeof res.total === 'number' && allRows.length >= res.total) || rows.length < DEFAULT_PAGE_SIZE) {
break
}
pageNum += 1
// 安全阈值,避免后端异常导致死循环
if (pageNum > 200) break
}
columns.value = allRows.map((item) => ({
value: item.id, value: item.id,
label: item.menuName, label: item.menuName,
} }))
})
}
})
} }
@@ -42,8 +68,6 @@ function handleSubmit() {
handleClose() handleClose()
} }
const columns = ref([])
defineExpose({ defineExpose({
onOpen, onOpen,
}); });