新增团餐管理
This commit is contained in:
@@ -172,4 +172,20 @@ export enum MessageTypeEnum {
|
||||
COMMENT_APPROVED = 13,
|
||||
/** 评论审核未通过 */
|
||||
COMMENT_REJECTED = 14,
|
||||
}
|
||||
|
||||
/** 团餐预定状态 */
|
||||
export enum GroupMealReservationStatus {
|
||||
/** 待处理 */
|
||||
PENDING = 1,
|
||||
/** 已联系 */
|
||||
CONTACTED = 2,
|
||||
/** 已确认 */
|
||||
CONFIRMED = 3,
|
||||
/** 已拒绝 */
|
||||
REJECTED = 4,
|
||||
/** 已完成 */
|
||||
COMPLETED = 5,
|
||||
/** 用户取消 */
|
||||
USER_CANCELLED = 6,
|
||||
}
|
||||
@@ -95,6 +95,7 @@
|
||||
"navbar-future-order": "Future Order",
|
||||
"navbar-month-order": "This Month's Order",
|
||||
"navbar-refund-order": "Refund order",
|
||||
"navbar-group-meal-reservation": "Group meal reservation",
|
||||
"navbar-reservation": "Today's ordered dishes",
|
||||
"navbar-set-payment-password": "Set a payment password",
|
||||
"navbar-settings": "Settings",
|
||||
@@ -108,6 +109,7 @@
|
||||
"card-title": "CHEFLINK stir fry machine",
|
||||
"commonTools": "Common tools",
|
||||
"coupons": "Coupons",
|
||||
"groupMealReservation": "Group meals",
|
||||
"createStore": "Create a store",
|
||||
"dataStatistics": "Data statistics",
|
||||
"futureOrders": "Booking order",
|
||||
@@ -371,6 +373,34 @@
|
||||
"value": "Value"
|
||||
}
|
||||
},
|
||||
"groupMealReservation": {
|
||||
"tabs": {
|
||||
"all": "All"
|
||||
},
|
||||
"status": {
|
||||
"pending": "Pending",
|
||||
"contacted": "Contacted",
|
||||
"confirmed": "Confirmed",
|
||||
"rejected": "Rejected",
|
||||
"completed": "Completed",
|
||||
"userCancelled": "Cancelled by user"
|
||||
},
|
||||
"contactPhone": "Contact phone",
|
||||
"peopleCount": "People count",
|
||||
"perCapitaPrice": "Price per person",
|
||||
"estimatedTotal": "Estimated total",
|
||||
"expectedTime": "Expected time",
|
||||
"scene": "Scene",
|
||||
"remark": "User remark",
|
||||
"handleRemark": "Handle remark",
|
||||
"cancelReason": "Cancel reason",
|
||||
"userNickName": "User nickname",
|
||||
"detailTitle": "Group meal details",
|
||||
"handleTitle": "Update status",
|
||||
"handleRemarkPlaceholder": "Handle remark (optional)",
|
||||
"confirmHandle": "Update status to \"{status}\"?",
|
||||
"userCancelledTip": "Cancelled by user. View only."
|
||||
},
|
||||
"income": {
|
||||
"index": {
|
||||
"accountToReceive": "Account to receive:",
|
||||
|
||||
@@ -95,6 +95,7 @@
|
||||
"navbar-future-order": "未来订单",
|
||||
"navbar-month-order": "本月订单",
|
||||
"navbar-refund-order": "退款订单",
|
||||
"navbar-group-meal-reservation": "团餐预定",
|
||||
"navbar-reservation": "今日预定菜品统计",
|
||||
"navbar-set-payment-password": "设置支付密码",
|
||||
"navbar-settings": "设置",
|
||||
@@ -106,6 +107,7 @@
|
||||
"bookDishesToday": "预订菜品",
|
||||
"commonTools": "常用工具",
|
||||
"coupons": "优惠券",
|
||||
"groupMealReservation": "团餐预定",
|
||||
"createStore": "创建店铺",
|
||||
"dataStatistics": "数据统计",
|
||||
"futureOrders": "预定单",
|
||||
@@ -371,6 +373,34 @@
|
||||
"value": "值"
|
||||
}
|
||||
},
|
||||
"groupMealReservation": {
|
||||
"tabs": {
|
||||
"all": "全部"
|
||||
},
|
||||
"status": {
|
||||
"pending": "待处理",
|
||||
"contacted": "已联系",
|
||||
"confirmed": "已确认",
|
||||
"rejected": "已拒绝",
|
||||
"completed": "已完成",
|
||||
"userCancelled": "用户取消"
|
||||
},
|
||||
"contactPhone": "联系电话",
|
||||
"peopleCount": "团餐人数",
|
||||
"perCapitaPrice": "人均单价",
|
||||
"estimatedTotal": "预计总价",
|
||||
"expectedTime": "期望时间",
|
||||
"scene": "场景",
|
||||
"remark": "用户备注",
|
||||
"handleRemark": "处理备注",
|
||||
"cancelReason": "取消原因",
|
||||
"userNickName": "用户昵称",
|
||||
"detailTitle": "团餐预定详情",
|
||||
"handleTitle": "处理状态",
|
||||
"handleRemarkPlaceholder": "请输入处理备注(选填)",
|
||||
"confirmHandle": "确认将状态更新为「{status}」?",
|
||||
"userCancelledTip": "用户已取消,仅可查看详情"
|
||||
},
|
||||
"income": {
|
||||
"index": {
|
||||
"accountToReceive": "到账账户:",
|
||||
|
||||
+2
-2
@@ -2,8 +2,8 @@
|
||||
"name" : "CHEFLINK Merchant",
|
||||
"appid" : "__UNI__BB8E3C9",
|
||||
"description" : "美国外卖商户端",
|
||||
"versionName" : "3.0.1",
|
||||
"versionCode" : 301,
|
||||
"versionName" : "3.0.2",
|
||||
"versionCode" : 302,
|
||||
"transformPx" : false,
|
||||
/* 5+App特有相关 */
|
||||
"app-plus" : {
|
||||
|
||||
@@ -0,0 +1,247 @@
|
||||
<script lang="ts" setup>
|
||||
import {
|
||||
appGroupMealReservationMerchantIdGet,
|
||||
appGroupMealReservationMerchantStatusPost,
|
||||
type GroupMealReservationVo,
|
||||
} from '@/service'
|
||||
import {GroupMealReservationStatus} from '@/constant/enums'
|
||||
import {
|
||||
calcGroupMealTotal,
|
||||
canMerchantHandleGroupMeal,
|
||||
getGroupMealContactPhone,
|
||||
} from '@/utils/groupMealReservation'
|
||||
import {callPhone, formatTimestampWithMonthName} from '@/utils/utils'
|
||||
import {useMessage} from 'wot-design-uni'
|
||||
|
||||
const message = useMessage()
|
||||
const {t} = useI18n()
|
||||
|
||||
const reservationId = ref('')
|
||||
const detail = ref<GroupMealReservationVo>()
|
||||
const loading = ref(false)
|
||||
const handleRemark = ref('')
|
||||
|
||||
const handleActions = computed(() => [
|
||||
{status: GroupMealReservationStatus.CONTACTED, label: t('pages-user.groupMealReservation.status.contacted')},
|
||||
{status: GroupMealReservationStatus.CONFIRMED, label: t('pages-user.groupMealReservation.status.confirmed')},
|
||||
{status: GroupMealReservationStatus.REJECTED, label: t('pages-user.groupMealReservation.status.rejected')},
|
||||
{status: GroupMealReservationStatus.COMPLETED, label: t('pages-user.groupMealReservation.status.completed')},
|
||||
])
|
||||
|
||||
const canHandle = computed(() => canMerchantHandleGroupMeal(detail.value?.status))
|
||||
|
||||
function statusLabel(status?: number) {
|
||||
const map: Record<number, string> = {
|
||||
[GroupMealReservationStatus.PENDING]: t('pages-user.groupMealReservation.status.pending'),
|
||||
[GroupMealReservationStatus.CONTACTED]: t('pages-user.groupMealReservation.status.contacted'),
|
||||
[GroupMealReservationStatus.CONFIRMED]: t('pages-user.groupMealReservation.status.confirmed'),
|
||||
[GroupMealReservationStatus.REJECTED]: t('pages-user.groupMealReservation.status.rejected'),
|
||||
[GroupMealReservationStatus.COMPLETED]: t('pages-user.groupMealReservation.status.completed'),
|
||||
[GroupMealReservationStatus.USER_CANCELLED]: t('pages-user.groupMealReservation.status.userCancelled'),
|
||||
}
|
||||
return status != null ? (map[status] || String(status)) : '-'
|
||||
}
|
||||
|
||||
function loadDetail() {
|
||||
if (!reservationId.value) return
|
||||
loading.value = true
|
||||
appGroupMealReservationMerchantIdGet({
|
||||
params: {id: reservationId.value},
|
||||
}).then((res: any) => {
|
||||
detail.value = res.data
|
||||
handleRemark.value = res.data?.handleRemark || ''
|
||||
}).catch((err: any) => {
|
||||
uni.showToast({
|
||||
title: err?.msg || err?.message || t('common.prompt.request-failed-please-try-again-later'),
|
||||
icon: 'none',
|
||||
})
|
||||
}).finally(() => {
|
||||
loading.value = false
|
||||
})
|
||||
}
|
||||
|
||||
function makeCall() {
|
||||
callPhone(getGroupMealContactPhone(detail.value))
|
||||
}
|
||||
|
||||
function submitStatus(status: 2 | 3 | 4 | 5) {
|
||||
if (!detail.value?.id) return
|
||||
message.confirm({
|
||||
title: t('common.prompt.system-prompt'),
|
||||
msg: t('pages-user.groupMealReservation.confirmHandle', {status: statusLabel(status)}),
|
||||
confirmButtonText: t('common.yes'),
|
||||
cancelButtonText: t('common.no'),
|
||||
}).then(() => {
|
||||
appGroupMealReservationMerchantStatusPost({
|
||||
body: {
|
||||
id: detail.value!.id!,
|
||||
status,
|
||||
handleRemark: handleRemark.value.trim() || undefined,
|
||||
},
|
||||
}).then((res: any) => {
|
||||
uni.showToast({
|
||||
title: res?.msg || t('common.operation-success'),
|
||||
icon: 'none',
|
||||
})
|
||||
loadDetail()
|
||||
}).catch((err: any) => {
|
||||
uni.showToast({
|
||||
title: err?.msg || err?.message || t('common.prompt.request-incorrect'),
|
||||
icon: 'none',
|
||||
})
|
||||
})
|
||||
}).catch(() => {
|
||||
})
|
||||
}
|
||||
|
||||
function handleActionClick(status: number) {
|
||||
submitStatus(status as 2 | 3 | 4 | 5)
|
||||
}
|
||||
|
||||
onLoad((options) => {
|
||||
if (options?.id) {
|
||||
reservationId.value = options.id
|
||||
}
|
||||
})
|
||||
|
||||
onShow(() => {
|
||||
if (reservationId.value) {
|
||||
loadDetail()
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<view class="min-h-100vh bg-#F6F6F6 pb-200rpx">
|
||||
<navbar :title="t('pages-user.groupMealReservation.detailTitle')"/>
|
||||
|
||||
<view v-if="loading" class="px-30rpx pt-30rpx">
|
||||
<view class="bg-white rounded-16rpx p-30rpx">
|
||||
<view v-for="n in 6" :key="n" class="w-full h-28rpx skeleton-item mb-24rpx"/>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view v-else-if="detail" class="px-30rpx pt-30rpx">
|
||||
<view class="bg-white rounded-16rpx p-30rpx mb-24rpx">
|
||||
<view class="flex-center-sb mb-28rpx">
|
||||
<text class="text-36rpx text-#333 font-500">{{ detail.contactName || '-' }}</text>
|
||||
<text class="text-26rpx text-#FF6106">{{ statusLabel(detail.status) }}</text>
|
||||
</view>
|
||||
|
||||
<view class="info-row">
|
||||
<text class="label">{{ t('pages-user.groupMealReservation.contactPhone') }}</text>
|
||||
<view class="flex items-center" @click="makeCall">
|
||||
<text class="value text-#007AFF mr-12rpx">{{ getGroupMealContactPhone(detail) || '-' }}</text>
|
||||
<image class="w-48rpx h-48rpx shrink-0" src="@img/chef/206.png"/>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="info-row">
|
||||
<text class="label">{{ t('pages-user.groupMealReservation.scene') }}</text>
|
||||
<text class="value">{{ detail.scene || '-' }}</text>
|
||||
</view>
|
||||
|
||||
<view class="info-row">
|
||||
<text class="label">{{ t('pages-user.groupMealReservation.peopleCount') }}</text>
|
||||
<text class="value">{{ detail.peopleCount || 0 }}</text>
|
||||
</view>
|
||||
|
||||
<view class="info-row">
|
||||
<text class="label">{{ t('pages-user.groupMealReservation.perCapitaPrice') }}</text>
|
||||
<text class="value">${{ detail.perCapitaPrice ?? 0 }}</text>
|
||||
</view>
|
||||
|
||||
<view class="info-row">
|
||||
<text class="label">{{ t('pages-user.groupMealReservation.estimatedTotal') }}</text>
|
||||
<text class="value font-500">${{ calcGroupMealTotal(detail.peopleCount, detail.perCapitaPrice) }}</text>
|
||||
</view>
|
||||
|
||||
<view class="info-row">
|
||||
<text class="label">{{ t('pages-user.groupMealReservation.expectedTime') }}</text>
|
||||
<text class="value">
|
||||
{{ detail.expectedTime ? formatTimestampWithMonthName(detail.expectedTime) : '-' }}
|
||||
</text>
|
||||
</view>
|
||||
|
||||
<view v-if="detail.remark" class="info-row items-start">
|
||||
<text class="label">{{ t('pages-user.groupMealReservation.remark') }}</text>
|
||||
<text class="value flex-1 text-right">{{ detail.remark }}</text>
|
||||
</view>
|
||||
|
||||
<view v-if="detail.handleRemark" class="info-row items-start">
|
||||
<text class="label">{{ t('pages-user.groupMealReservation.handleRemark') }}</text>
|
||||
<text class="value flex-1 text-right">{{ detail.handleRemark }}</text>
|
||||
</view>
|
||||
|
||||
<view v-if="detail.cancelReason" class="info-row items-start">
|
||||
<text class="label">{{ t('pages-user.groupMealReservation.cancelReason') }}</text>
|
||||
<text class="value flex-1 text-right">{{ detail.cancelReason }}</text>
|
||||
</view>
|
||||
|
||||
<view v-if="detail.user?.nickName" class="info-row">
|
||||
<text class="label">{{ t('pages-user.groupMealReservation.userNickName') }}</text>
|
||||
<text class="value">{{ detail.user.nickName }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view v-if="canHandle" class="bg-white rounded-16rpx p-30rpx">
|
||||
<text class="text-32rpx text-#333 font-500 mb-24rpx block">
|
||||
{{ t('pages-user.groupMealReservation.handleTitle') }}
|
||||
</text>
|
||||
|
||||
<view class="bg-#F6F6F6 rounded-16rpx px-24rpx py-20rpx mb-30rpx">
|
||||
<wd-textarea
|
||||
v-model="handleRemark"
|
||||
:placeholder="t('pages-user.groupMealReservation.handleRemarkPlaceholder')"
|
||||
auto-height
|
||||
custom-class="!bg-#F6F6F6"
|
||||
custom-textarea-container-class="!bg-#F6F6F6"
|
||||
no-border
|
||||
/>
|
||||
</view>
|
||||
|
||||
<view class="grid grid-cols-2 gap-20rpx">
|
||||
<view
|
||||
v-for="action in handleActions"
|
||||
:key="action.status"
|
||||
class="h-88rpx center rounded-16rpx bg-#F2F2F2 text-28rpx text-#333 font-500"
|
||||
@click="handleActionClick(action.status)"
|
||||
>
|
||||
{{ action.label }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view v-else-if="detail.status === GroupMealReservationStatus.USER_CANCELLED"
|
||||
class="bg-white rounded-16rpx p-30rpx text-28rpx text-#999 center">
|
||||
{{ t('pages-user.groupMealReservation.userCancelledTip') }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.info-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 24rpx;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.label {
|
||||
font-size: 28rpx;
|
||||
color: #666;
|
||||
margin-right: 20rpx;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.value {
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,149 @@
|
||||
<script lang="ts" setup>
|
||||
import {
|
||||
appGroupMealReservationMerchantListPost,
|
||||
type GroupMealReservationVo,
|
||||
} from '@/service'
|
||||
import {GroupMealReservationStatus} from '@/constant/enums'
|
||||
import {calcGroupMealTotal, getGroupMealContactPhone} from '@/utils/groupMealReservation'
|
||||
import {callPhone, formatTimestampWithMonthName} from '@/utils/utils'
|
||||
import {useUserStore} from '@/store'
|
||||
|
||||
const {t} = useI18n()
|
||||
const userStore = useUserStore()
|
||||
|
||||
const currentTab = ref(0)
|
||||
const tabsList = computed(() => [
|
||||
{title: t('pages-user.groupMealReservation.tabs.all'), status: undefined},
|
||||
{title: t('pages-user.groupMealReservation.status.pending'), status: GroupMealReservationStatus.PENDING},
|
||||
{title: t('pages-user.groupMealReservation.status.contacted'), status: GroupMealReservationStatus.CONTACTED},
|
||||
{title: t('pages-user.groupMealReservation.status.confirmed'), status: GroupMealReservationStatus.CONFIRMED},
|
||||
{title: t('pages-user.groupMealReservation.status.rejected'), status: GroupMealReservationStatus.REJECTED},
|
||||
{title: t('pages-user.groupMealReservation.status.completed'), status: GroupMealReservationStatus.COMPLETED},
|
||||
{title: t('pages-user.groupMealReservation.status.userCancelled'), status: GroupMealReservationStatus.USER_CANCELLED},
|
||||
])
|
||||
|
||||
function statusLabel(status?: number) {
|
||||
const map: Record<number, string> = {
|
||||
[GroupMealReservationStatus.PENDING]: t('pages-user.groupMealReservation.status.pending'),
|
||||
[GroupMealReservationStatus.CONTACTED]: t('pages-user.groupMealReservation.status.contacted'),
|
||||
[GroupMealReservationStatus.CONFIRMED]: t('pages-user.groupMealReservation.status.confirmed'),
|
||||
[GroupMealReservationStatus.REJECTED]: t('pages-user.groupMealReservation.status.rejected'),
|
||||
[GroupMealReservationStatus.COMPLETED]: t('pages-user.groupMealReservation.status.completed'),
|
||||
[GroupMealReservationStatus.USER_CANCELLED]: t('pages-user.groupMealReservation.status.userCancelled'),
|
||||
}
|
||||
return status != null ? (map[status] || String(status)) : '-'
|
||||
}
|
||||
|
||||
function statusClass(status?: number) {
|
||||
if (status === GroupMealReservationStatus.PENDING) return 'text-#FF6106 bg-#FFF3EB'
|
||||
if (status === GroupMealReservationStatus.CONTACTED) return 'text-#007AFF bg-#EAF3FF'
|
||||
if (status === GroupMealReservationStatus.CONFIRMED) return 'text-#00A76D bg-#E8F8F2'
|
||||
if (status === GroupMealReservationStatus.REJECTED) return 'text-#FF2828 bg-#FFECEC'
|
||||
if (status === GroupMealReservationStatus.COMPLETED) return 'text-#333 bg-#F2F2F2'
|
||||
if (status === GroupMealReservationStatus.USER_CANCELLED) return 'text-#999 bg-#F6F6F6'
|
||||
return 'text-#666 bg-#F6F6F6'
|
||||
}
|
||||
|
||||
const {paging, dataList, loading, queryList} = usePage<GroupMealReservationVo>((pageNum, pageSize) => {
|
||||
const tab = tabsList.value[currentTab.value]
|
||||
return appGroupMealReservationMerchantListPost({
|
||||
params: {pageNum, pageSize},
|
||||
body: tab?.status != null ? {status: tab.status} : {},
|
||||
})
|
||||
})
|
||||
|
||||
function tabsChange(e: { index: number }) {
|
||||
currentTab.value = e.index
|
||||
paging.value?.reload()
|
||||
}
|
||||
|
||||
function goDetail(item: GroupMealReservationVo) {
|
||||
if (!item.id) return
|
||||
uni.navigateTo({
|
||||
url: `/pages-user/pages/group-meal-reservation/detail?id=${item.id}`,
|
||||
})
|
||||
}
|
||||
|
||||
function dialPhone(item: GroupMealReservationVo) {
|
||||
callPhone(getGroupMealContactPhone(item))
|
||||
}
|
||||
|
||||
onShow(() => {
|
||||
if (!userStore.isLogin) return
|
||||
nextTick(() => {
|
||||
paging.value?.reload()
|
||||
})
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<z-paging ref="paging" v-model="dataList" :auto="false" @query="queryList">
|
||||
<template #top>
|
||||
<navbar :title="t('navbar-group-meal-reservation')"/>
|
||||
<wd-tabs v-model="currentTab" :lineWidth="67" animated color="#14181B" inactiveColor="#666666" sticky
|
||||
@change="tabsChange">
|
||||
<wd-tab v-for="(item, index) in tabsList" :key="index" :title="item.title"/>
|
||||
</wd-tabs>
|
||||
</template>
|
||||
|
||||
<view v-show="loading" class="px-30rpx py-20rpx">
|
||||
<view v-for="n in 4" :key="n" class="bg-white rounded-16rpx p-24rpx mb-20rpx">
|
||||
<view class="w-200rpx h-28rpx skeleton-item mb-20rpx"/>
|
||||
<view class="w-full h-24rpx skeleton-item mb-16rpx"/>
|
||||
<view class="w-300rpx h-24rpx skeleton-item"/>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view v-show="!loading" class="px-30rpx py-20rpx">
|
||||
<view
|
||||
v-for="item in dataList"
|
||||
:key="item.id"
|
||||
class="bg-white rounded-16rpx p-24rpx mb-20rpx last:mb-0"
|
||||
@click="goDetail(item)"
|
||||
>
|
||||
<view class="flex-center-sb mb-20rpx">
|
||||
<text class="text-32rpx text-#333 font-500">{{ item.contactName || '-' }}</text>
|
||||
<text :class="statusClass(item.status)" class="text-24rpx px-16rpx py-6rpx rounded-8rpx">
|
||||
{{ statusLabel(item.status) }}
|
||||
</text>
|
||||
</view>
|
||||
|
||||
<view class="flex-center-sb mb-16rpx">
|
||||
<text class="text-28rpx text-#666">{{ t('pages-user.groupMealReservation.contactPhone') }}</text>
|
||||
<view class="flex items-center" @click.stop="dialPhone(item)">
|
||||
<text class="text-28rpx text-#007AFF mr-10rpx">{{ getGroupMealContactPhone(item) || '-' }}</text>
|
||||
<image class="w-36rpx h-36rpx shrink-0" src="@img/chef/206.png"/>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="flex-center-sb mb-16rpx">
|
||||
<text class="text-28rpx text-#666">{{ t('pages-user.groupMealReservation.peopleCount') }}</text>
|
||||
<text class="text-28rpx text-#333">{{ item.peopleCount || 0 }}</text>
|
||||
</view>
|
||||
|
||||
<view class="flex-center-sb mb-16rpx">
|
||||
<text class="text-28rpx text-#666">{{ t('pages-user.groupMealReservation.perCapitaPrice') }}</text>
|
||||
<text class="text-28rpx text-#333">${{ item.perCapitaPrice ?? 0 }}</text>
|
||||
</view>
|
||||
|
||||
<view class="flex-center-sb mb-16rpx">
|
||||
<text class="text-28rpx text-#666">{{ t('pages-user.groupMealReservation.estimatedTotal') }}</text>
|
||||
<text class="text-28rpx text-#333 font-500">${{ calcGroupMealTotal(item.peopleCount, item.perCapitaPrice) }}</text>
|
||||
</view>
|
||||
|
||||
<view class="flex-center-sb">
|
||||
<text class="text-28rpx text-#666">{{ t('pages-user.groupMealReservation.expectedTime') }}</text>
|
||||
<text class="text-28rpx text-#333">
|
||||
{{ item.expectedTime ? formatTimestampWithMonthName(item.expectedTime) : '-' }}
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</z-paging>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
:deep(.wd-tabs__nav-item) {
|
||||
font-size: 28rpx !important;
|
||||
}
|
||||
</style>
|
||||
@@ -99,6 +99,12 @@
|
||||
{
|
||||
"path": "pages/home-order/refund-order"
|
||||
},
|
||||
{
|
||||
"path": "pages/group-meal-reservation/index"
|
||||
},
|
||||
{
|
||||
"path": "pages/group-meal-reservation/detail"
|
||||
},
|
||||
{
|
||||
"path": "pages/store-management/index"
|
||||
},
|
||||
|
||||
@@ -21,6 +21,13 @@ function navigateTo(url: string) {
|
||||
})
|
||||
return
|
||||
}
|
||||
if (url === '/pages-user/pages/group-meal-reservation/index' && !userStore.currentMerchantToken) {
|
||||
uni.showToast({
|
||||
title: t('toast.pleaseSelectStore'),
|
||||
icon: 'none',
|
||||
})
|
||||
return
|
||||
}
|
||||
uni.navigateTo({
|
||||
url,
|
||||
})
|
||||
@@ -293,30 +300,40 @@ defineExpose({
|
||||
<view class="text-36rpx text-#333 font-bold lh-36rpx mb-48rpx tracking-[.04em]">
|
||||
{{ t('pages.home.commonTools') }}
|
||||
</view>
|
||||
<view class="grid grid-cols-4">
|
||||
<view class="flex flex-col items-center relative"
|
||||
<scroll-view :show-scrollbar="false" class="common-tools-scroll w-full" scroll-x>
|
||||
<view class="common-tools-row flex flex-nowrap">
|
||||
<view class="common-tools-item flex flex-col items-center relative shrink-0"
|
||||
@click="navigateTo('/pages-user/pages/home-order/refund-order')">
|
||||
<view
|
||||
v-if="storeInfo?.refundOrderNum && +storeInfo?.refundOrderNum > 0"
|
||||
class="absolute top--10rpx right-40rpx z-2 min-w-36rpx h-36rpx rounded-full bg-#FF1212 text-28rpx text-#fff center">
|
||||
class="absolute top--10rpx right-8rpx z-2 min-w-36rpx h-36rpx rounded-full bg-#FF1212 text-28rpx text-#fff center">
|
||||
{{ +storeInfo?.refundOrderNum > 99 ? '99+' : storeInfo?.refundOrderNum }}
|
||||
</view>
|
||||
<image class="w-52rpx h-52rpx mb-24rpx" src="@img/chef/101.png"></image>
|
||||
<view class="text-24rpx text-#333 lh-20rpx">{{ t('pages.home.refundOrders') }}</view>
|
||||
<view class="text-24rpx text-#333 lh-20rpx text-center px-8rpx">{{ t('pages.home.refundOrders') }}</view>
|
||||
</view>
|
||||
<view class="flex flex-col items-center" @click="navigateTo('/pages-user/pages/income/index')">
|
||||
<view class="common-tools-item flex flex-col items-center shrink-0"
|
||||
@click="navigateTo('/pages-user/pages/income/index')">
|
||||
<image class="w-52rpx h-52rpx mb-24rpx" src="@img/chef/102.png"></image>
|
||||
<view class="text-24rpx text-#333 lh-20rpx">{{ t('pages.home.myIncome') }}</view>
|
||||
<view class="text-24rpx text-#333 lh-20rpx text-center px-8rpx">{{ t('pages.home.myIncome') }}</view>
|
||||
</view>
|
||||
<view class="flex flex-col items-center" @click="navigateTo('/pages-user/pages/recipe/index')">
|
||||
<view class="common-tools-item flex flex-col items-center shrink-0"
|
||||
@click="navigateTo('/pages-user/pages/recipe/index')">
|
||||
<image class="w-52rpx h-52rpx mb-24rpx" src="@img/chef/103.png"></image>
|
||||
<view class="text-24rpx text-#333 lh-20rpx">{{ t('pages.home.recipes') }}</view>
|
||||
<view class="text-24rpx text-#333 lh-20rpx text-center px-8rpx">{{ t('pages.home.recipes') }}</view>
|
||||
</view>
|
||||
<view class="flex flex-col items-center" @click="navigateTo('/pages-user/pages/coupons/index')">
|
||||
<view class="common-tools-item flex flex-col items-center shrink-0"
|
||||
@click="navigateTo('/pages-user/pages/coupons/index')">
|
||||
<image class="w-52rpx h-52rpx mb-24rpx" src="@img/chef/104.png"></image>
|
||||
<view class="text-24rpx text-#333 lh-20rpx">{{ t('pages.home.coupons') }}</view>
|
||||
<view class="text-24rpx text-#333 lh-20rpx text-center px-8rpx">{{ t('pages.home.coupons') }}</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="common-tools-item flex flex-col items-center shrink-0"
|
||||
@click="navigateTo('/pages-user/pages/group-meal-reservation/index')">
|
||||
<image class="w-52rpx h-52rpx mb-24rpx" src="@img/chef/9191.png"></image>
|
||||
<view class="text-24rpx text-#333 lh-20rpx text-center px-8rpx">{{ t('pages.home.groupMealReservation') }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
|
||||
<!-- 订单列表 -->
|
||||
@@ -407,6 +424,21 @@ defineExpose({
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.common-tools-scroll {
|
||||
width: 100%;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.common-tools-row {
|
||||
min-width: 100%;
|
||||
}
|
||||
|
||||
.common-tools-item {
|
||||
width: 20%;
|
||||
min-width: 136rpx;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
:deep(.wd-tabs__nav-item) {
|
||||
font-size: 30rpx !important;
|
||||
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
/* eslint-disable */
|
||||
import request from '@/http/vue-query';
|
||||
import type { CustomRequestOptions } from '@/http/types';
|
||||
|
||||
export type GroupMealReservationVo = {
|
||||
id?: number;
|
||||
merchantId?: number;
|
||||
userId?: number;
|
||||
peopleCount?: number;
|
||||
perCapitaPrice?: number;
|
||||
scene?: string;
|
||||
contactName?: string;
|
||||
contactPhone?: string;
|
||||
expectedTime?: number;
|
||||
status?: number;
|
||||
handleRemark?: string;
|
||||
cancelReason?: string;
|
||||
remark?: string;
|
||||
createTime?: number;
|
||||
merchant?: {
|
||||
merchantName?: string;
|
||||
logo?: string;
|
||||
merchantAddress?: string;
|
||||
};
|
||||
user?: {
|
||||
nickName?: string;
|
||||
surname?: string;
|
||||
firstName?: string;
|
||||
phone?: string;
|
||||
};
|
||||
};
|
||||
|
||||
export type GroupMealReservationQueryBo = {
|
||||
status?: number;
|
||||
contactName?: string;
|
||||
contactPhone?: string;
|
||||
expectedBeginTime?: number;
|
||||
expectedEndTime?: number;
|
||||
createBeginTime?: number;
|
||||
createEndTime?: number;
|
||||
};
|
||||
|
||||
export type GroupMealReservationStatusBo = {
|
||||
id: number;
|
||||
status: 2 | 3 | 4 | 5;
|
||||
handleRemark?: string;
|
||||
};
|
||||
|
||||
/** 商户端团餐预定列表 POST /app/groupMealReservation/merchantList */
|
||||
export async function appGroupMealReservationMerchantListPost({
|
||||
params,
|
||||
body,
|
||||
options,
|
||||
}: {
|
||||
params: { pageNum: number; pageSize: number };
|
||||
body?: GroupMealReservationQueryBo;
|
||||
options?: CustomRequestOptions;
|
||||
}) {
|
||||
return request<any>('/app/groupMealReservation/merchantList', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
params: {
|
||||
...params,
|
||||
},
|
||||
data: body || {},
|
||||
...(options || {}),
|
||||
});
|
||||
}
|
||||
|
||||
/** 商户端团餐预定详情 GET /app/groupMealReservation/merchant/{id} */
|
||||
export async function appGroupMealReservationMerchantIdGet({
|
||||
params,
|
||||
options,
|
||||
}: {
|
||||
params: { id: number | string };
|
||||
options?: CustomRequestOptions;
|
||||
}) {
|
||||
return request<{ data?: GroupMealReservationVo }>(`/app/groupMealReservation/merchant/${params.id}`, {
|
||||
method: 'GET',
|
||||
...(options || {}),
|
||||
});
|
||||
}
|
||||
|
||||
/** 商户端处理团餐预定状态 POST /app/groupMealReservation/merchant/status */
|
||||
export async function appGroupMealReservationMerchantStatusPost({
|
||||
body,
|
||||
options,
|
||||
}: {
|
||||
body: GroupMealReservationStatusBo;
|
||||
options?: CustomRequestOptions;
|
||||
}) {
|
||||
return request<{ code?: number; msg?: string }>('/app/groupMealReservation/merchant/status', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
data: body,
|
||||
...(options || {}),
|
||||
});
|
||||
}
|
||||
@@ -28,6 +28,7 @@ export * from './merchantCart';
|
||||
export * from './coupon';
|
||||
export * from './search';
|
||||
export * from './merchantOrder';
|
||||
export * from './groupMealReservation';
|
||||
export * from './featuredMerchant';
|
||||
export * from './feedback';
|
||||
export * from './membershipConfig';
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 4.0 KiB |
@@ -0,0 +1,15 @@
|
||||
import {GroupMealReservationStatus} from '@/constant/enums'
|
||||
|
||||
export function calcGroupMealTotal(peopleCount?: number, perCapitaPrice?: number) {
|
||||
const count = Number(peopleCount) || 0
|
||||
const price = Number(perCapitaPrice) || 0
|
||||
return (count * price).toFixed(2)
|
||||
}
|
||||
|
||||
export function canMerchantHandleGroupMeal(status?: number) {
|
||||
return status === GroupMealReservationStatus.PENDING || status === GroupMealReservationStatus.CONTACTED
|
||||
}
|
||||
|
||||
export function getGroupMealContactPhone(item?: { contactPhone?: string; user?: { phone?: string } }) {
|
||||
return (item?.contactPhone || item?.user?.phone || '').trim()
|
||||
}
|
||||
Reference in New Issue
Block a user