Explorar o código

新建菜品,菜品管理页面

付晓文。 hai 1 mes
pai
achega
cff88f18ae

+ 12 - 13
pages/merchantDish/dish/components/SpecModeSwitch.vue

@@ -4,10 +4,7 @@
 			<view class="radio-dot"></view>
 			<text>单规格</text>
 		</view>
-		<view
-			:class="['spec-mode-item', mode === 'multi' ? 'on' : '', locked && mode !== 'multi' ? 'disabled' : '']"
-			@click="onPick('multi')"
-		>
+		<view :class="['spec-mode-item', mode === 'multi' ? 'on' : '', locked && mode !== 'multi' ? 'disabled' : '']" @click="onPick('multi')">
 			<view class="radio-dot"></view>
 			<text>多规格</text>
 		</view>
@@ -60,7 +57,7 @@ export default {
 	display: flex;
 	justify-content: flex-end;
 	align-items: center;
-	gap: 32rpx;
+	gap: 40rpx;
 }
 .spec-mode-item {
 	display: flex;
@@ -77,19 +74,21 @@ export default {
 		position: relative;
 	}
 	&.on {
-		color: #449aff;
+		color: #333;
 		.radio-dot {
 			border-color: #449aff;
+			background: #449aff;
 			&::after {
 				content: '';
 				position: absolute;
-				left: 50%;
-				top: 50%;
-				width: 16rpx;
-				height: 16rpx;
-				margin: -8rpx 0 0 -8rpx;
-				border-radius: 50%;
-				background: #449aff;
+				left: 10rpx;
+				top: 5rpx;
+				width: 8rpx;
+				height: 14rpx;
+				border: 2rpx solid #fff;
+				border-top: 0;
+				border-left: 0;
+				transform: rotate(45deg);
 			}
 		}
 	}

+ 101 - 39
pages/merchantDish/dish/form.vue

@@ -3,31 +3,31 @@
 		<u-navbar :title="isEdit ? '编辑菜品' : '新建菜品'" :autoBack="true" :placeholder="true"></u-navbar>
 
 		<view class="card">
-			<view class="section-title">基信息</view>
+			<view class="section-title">基信息</view>
 			<view class="row">
-				<text class="label required">品归属</text>
+				<text class="label required">品归属</text>
 				<u-radio-group v-model="form.belong" :disabled="isEdit" @change="onBelongChange">
 					<u-radio name="store" active-color="#449AFF">门店</u-radio>
 					<u-radio v-if="showGroupBelong" name="group" active-color="#449AFF">团餐</u-radio>
 				</u-radio-group>
 			</view>
 			<view class="row" @click="pickCategory">
-				<text class="label required">品分类</text>
+				<text class="label required">品分类</text>
 				<text class="value">{{ categoryName || '请选择' }}</text>
-				<u-icon name="arrow-right" color="#C7C6CA"></u-icon>
+				<image class="arrow-down" src="/static/merchantDish/selete.png" mode="aspectFit"></image>
 			</view>
 			<view class="row">
-				<text class="label required">品名称</text>
-				<input class="input" v-model="form.name" placeholder="请输入" />
+				<text class="label required">品名称</text>
+				<input class="input" v-model="form.name" placeholder="请输入" placeholder-class="ph" />
 			</view>
 			<view class="row" @click="pickProductType">
-				<text class="label required">商品类型</text>
+				<text class="label required">菜品分类</text>
 				<text class="value">{{ productTypeName || '请选择' }}</text>
-				<u-icon name="arrow-right" color="#C7C6CA"></u-icon>
+				<image class="arrow-down" src="/static/merchantDish/selete.png" mode="aspectFit"></image>
 			</view>
 			<view class="upload-row">
-				<text class="label required">品封面图</text>
-				<view class="tip">支持jpg、png格式,建议尺寸为750px*750px,上传1-4张</view>
+				<text class="label required">品封面图</text>
+				<view class="tip">支持jpg、png格式,尺寸为750px * 750px</view>
 				<u-upload
 					:action="uploadAction"
 					:file-list="fileList.cover"
@@ -35,18 +35,23 @@
 					:max-count="4"
 					:multiple="true"
 					:deletable="true"
+					:custom-btn="true"
 					del-bg-color="#fa3534"
-					upload-text="选择图片"
 					width="140"
 					height="140"
 					preview-full-image
 					@on-success="onCoverSuccess"
 					@on-remove="onCoverRemove"
-				/>
+				>
+					<view slot="addBtn" class="upload-btn">
+						<image class="upload-icon" src="/static/merchantDish/photo.png" mode="aspectFit"></image>
+						<text>上传</text>
+					</view>
+				</u-upload>
 			</view>
-			<view class="upload-row">
-				<text class="label required">商品详情图</text>
-				<view class="tip">支持jpg、png格式,最多20张</view>
+			<view class="upload-row last">
+				<text class="label required">菜品图片详情</text>
+				<view class="tip">支持jpg、png格式,尺寸为750px * 750px</view>
 				<u-upload
 					:action="uploadAction"
 					:file-list="fileList.detail"
@@ -54,18 +59,24 @@
 					:max-count="20"
 					:multiple="true"
 					:deletable="true"
+					:custom-btn="true"
 					del-bg-color="#fa3534"
-					upload-text="选择图片"
 					width="140"
 					height="140"
 					preview-full-image
 					@on-success="onDetailSuccess"
 					@on-remove="onDetailRemove"
-				/>
+				>
+					<view slot="addBtn" class="upload-btn">
+						<image class="upload-icon" src="/static/merchantDish/photo.png" mode="aspectFit"></image>
+						<text>上传</text>
+					</view>
+				</u-upload>
 			</view>
 		</view>
 
 		<view class="card">
+			<view class="section-title">其他信息</view>
 			<view class="row">
 				<text class="label required">是否为套餐</text>
 				<u-radio-group v-model="form.isCombo" @change="onComboChange">
@@ -78,10 +89,6 @@
 				<text class="value link">{{ comboCount ? `共${comboCount}项` : '去添加' }}</text>
 				<u-icon name="arrow-right" color="#C7C6CA"></u-icon>
 			</view>
-		</view>
-
-		<view class="card">
-			<view class="section-title">销售规格</view>
 			<view class="row">
 				<text class="label required">销售规格</text>
 				<SpecModeSwitch
@@ -99,19 +106,19 @@
 				<view class="panel panel-single">
 					<view class="row">
 						<text class="label required">售价 (元)</text>
-						<input class="input" type="digit" :value="form.price" @input="onPriceInput('price', $event)" placeholder="请输入" />
+						<input class="input" type="digit" :value="form.price" @input="onPriceInput('price', $event)" placeholder="请输入" placeholder-class="ph" />
 					</view>
 					<view class="row">
 						<text class="label required">原价 (元)</text>
-						<input class="input" type="digit" :value="form.sellingPrice" @input="onPriceInput('sellingPrice', $event)" placeholder="请输入" />
+						<input class="input" type="digit" :value="form.sellingPrice" @input="onPriceInput('sellingPrice', $event)" placeholder="请输入" placeholder-class="ph" />
 					</view>
 					<view class="row">
 						<text class="label required">可售库存</text>
-						<input class="input" type="number" :value="form.stock" @input="onPriceInput('stock', $event)" placeholder="请输入" />
+						<input class="input" type="number" :value="form.stock" @input="onPriceInput('stock', $event)" placeholder="请输入" placeholder-class="ph" />
 					</view>
 					<view class="row">
 						<text class="label">成本价 (元)</text>
-						<input class="input" type="digit" :value="form.costPrice" @input="onPriceInput('costPrice', $event)" placeholder="请输入 (选填)" />
+						<input class="input" type="digit" :value="form.costPrice" @input="onPriceInput('costPrice', $event)" placeholder="请输入 (选填)" placeholder-class="ph" />
 					</view>
 				</view>
 				<view class="panel panel-multi">
@@ -126,7 +133,10 @@
 								:key="v.id"
 								:class="['tag', v.selected ? 'on' : '']"
 								@click="toggleSpecValue(v)"
-							>{{ v.name }}</view>
+							>
+								{{ v.name }}
+								<image v-if="v.selected" class="tag-check" src="/static/merchantDish/selete-true.png" mode="aspectFit"></image>
+							</view>
 						</view>
 					</view>
 					<view class="add-spec" @click="addSpec">+ 添加规格</view>
@@ -207,9 +217,9 @@ import SpecModeSwitch from './components/SpecModeSwitch.vue';
 import FormNextBtn from './components/FormNextBtn.vue';
 
 const PRODUCT_TYPES = [
-	{ label: '早', value: 'breakfast' },
-	{ label: '午', value: 'lunch' },
-	{ label: '晚', value: 'dinner' }
+	{ label: '早', value: 'breakfast' },
+	{ label: '午', value: 'lunch' },
+	{ label: '晚', value: 'dinner' }
 ];
 
 const DEFAULT_SPECS = [
@@ -790,7 +800,7 @@ export default {
 <style lang="scss" scoped>
 .page {
 	min-height: 100vh;
-	background: #f7f8fc;
+	background: #f7f8fa;
 	padding-bottom: 160rpx;
 }
 .card {
@@ -800,10 +810,22 @@ export default {
 	padding: 8rpx 24rpx 16rpx;
 }
 .section-title {
+	position: relative;
+	display: inline-block;
 	font-size: 30rpx;
 	font-weight: 600;
 	color: #222;
-	padding: 20rpx 0 8rpx;
+	padding: 24rpx 0 16rpx;
+	&::after {
+		content: '';
+		position: absolute;
+		left: 0;
+		bottom: 8rpx;
+		width: 100%;
+		height: 4rpx;
+		background: #449aff;
+		border-radius: 2rpx;
+	}
 }
 .row {
 	display: flex;
@@ -826,7 +848,7 @@ export default {
 		flex: 1;
 		text-align: right;
 		font-size: 28rpx;
-		color: #666;
+		color: #333;
 		&.link {
 			color: #449aff;
 		}
@@ -835,7 +857,17 @@ export default {
 		flex: 1;
 		text-align: right;
 		font-size: 28rpx;
+		color: #333;
 	}
+	.arrow-down {
+		width: 25rpx;
+		height: 25rpx;
+		margin-left: 10rpx;
+		flex-shrink: 0;
+	}
+}
+.ph {
+	color: #c0c4cc;
 }
 .spec-tip {
 	font-size: 22rpx;
@@ -845,6 +877,9 @@ export default {
 .upload-row {
 	padding: 20rpx 0;
 	border-bottom: 1rpx solid #f0f0f0;
+	&.last {
+		border-bottom: none;
+	}
 	.label {
 		font-size: 28rpx;
 		color: #333;
@@ -859,8 +894,22 @@ export default {
 		color: #999;
 		margin: 8rpx 0 16rpx;
 	}
-	::v-deep .u-add-tips {
-		margin-top: 10rpx;
+}
+.upload-btn {
+	width: 140rpx;
+	height: 140rpx;
+	background: #f5f6f8;
+	border-radius: 8rpx;
+	display: flex;
+	flex-direction: column;
+	align-items: center;
+	justify-content: center;
+	color: #999;
+	font-size: 24rpx;
+	.upload-icon {
+		width: 48rpx;
+		height: 48rpx;
+		margin-bottom: 8rpx;
 	}
 }
 .spec-block {
@@ -884,15 +933,28 @@ export default {
 		gap: 16rpx;
 	}
 	.tag {
-		padding: 10rpx 28rpx;
+		position: relative;
+		min-width: 120rpx;
+		padding: 16rpx 28rpx;
 		border-radius: 8rpx;
-		font-size: 24rpx;
-		background: #f5f5f5;
+		font-size: 26rpx;
+		text-align: center;
+		background: #fff;
 		color: #666;
+		border: 1rpx solid #e8e8e8;
+		box-sizing: border-box;
+		overflow: hidden;
 		&.on {
-			background: rgba(68, 154, 255, 0.12);
+			background: rgba(68, 154, 255, 0.08);
 			color: #449aff;
-			border: 1rpx solid #449aff;
+			border-color: #449aff;
+		}
+		.tag-check {
+			position: absolute;
+			right: 0;
+			bottom: 0;
+			width: 28rpx;
+			height: 28rpx;
 		}
 	}
 }

+ 168 - 111
pages/merchantDish/dish/list.vue

@@ -1,11 +1,10 @@
 <template>
 	<view class="page">
-		<u-navbar :placeholder="true" :border-bottom="false" :custom-back="goBack">
-			<view class="nav-title">菜品列表</view>
+		<u-navbar :placeholder="true" :border-bottom="false" :custom-back="goBack" title="菜品列表">
 			<view slot="right" class="nav-right">
 				<template v-if="!batchMode">
-					<u-icon name="search" size="40" color="#333" @click="showSearch = !showSearch"></u-icon>
-					<u-icon name="list-dot" size="40" color="#333" style="margin-left: 24rpx" @click="enterBatch"></u-icon>
+					<image class="nav-icon" src="/static/merchantDish/search.png" mode="aspectFit" @click="showSearch = !showSearch"></image>
+					<image class="nav-icon" src="/static/merchantDish/batch.png" mode="aspectFit" @click="enterBatch"></image>
 				</template>
 				<text v-else class="cancel-btn" @click="exitBatch">取消</text>
 			</view>
@@ -24,19 +23,22 @@
 
 		<view class="filters">
 			<view class="filter-item" @click="openPicker('status')">
-				{{ statusLabel }} <u-icon name="arrow-down" size="22" color="#666"></u-icon>
+				{{ statusLabel }}
+				<image class="filter-arrow" src="/static/merchantDish/selete.png" mode="aspectFit"></image>
 			</view>
 			<view class="filter-item" @click="openPicker('type')">
-				{{ typeLabel }} <u-icon name="arrow-down" size="22" color="#666"></u-icon>
+				{{ typeLabel }}
+				<image class="filter-arrow" src="/static/merchantDish/selete.png" mode="aspectFit"></image>
 			</view>
 			<view class="filter-item" @click="openPicker('category')">
-				{{ categoryLabel }} <u-icon name="arrow-down" size="22" color="#666"></u-icon>
+				{{ categoryLabel }}
+				<image class="filter-arrow" src="/static/merchantDish/selete.png" mode="aspectFit"></image>
 			</view>
 		</view>
 
 		<!-- 团餐报名提示条 -->
 		<view class="banner" v-if="bannerVisible" @click="onBannerClick">
-			<text>{{ bannerText }}</text>
+			<rich-text :nodes="bannerNodes"></rich-text>
 		</view>
 
 		<view class="list-wrap" :style="{ paddingBottom: batchMode ? '140rpx' : '160rpx' }">
@@ -52,39 +54,45 @@
 					<view class="list">
 						<view class="card" v-for="item in data" :key="item.id" @click="toggleSelect(item)">
 							<view class="check" v-if="batchMode">
-								<view :class="['dot', selectedIds.includes(item.id) ? 'on' : '']"></view>
+								<view :class="['dot', selectedIds.includes(item.id) ? 'on' : '']">
+									<u-icon v-if="selectedIds.includes(item.id)" name="checkmark" color="#fff" size="20"></u-icon>
+								</view>
 							</view>
 							<view class="thumb-wrap">
 								<image class="thumb" :src="item.image" mode="aspectFill"></image>
-								<view class="tag" :class="item.belong">{{ item.belong === 'group' ? '团餐' : '门店' }}</view>
+								<image
+									class="belong-tag"
+									:src="item.belong === 'group' ? '/static/merchantDish/groupmeal.png' : '/static/merchantDish/store.png'"
+									mode="heightFix"
+								></image>
 							</view>
 							<view class="info">
 								<view class="row-top">
 									<text class="name">{{ item.name }}</text>
-									<text class="status">{{ statusText[item.status] || item.statusName }}</text>
+									<text :class="['status', item.status]">{{ statusText[item.status] || item.statusName }}</text>
 								</view>
 								<view class="desc">{{ item.desc }}</view>
+								<view class="meta">
+									每日库存: {{ item.stock != null ? item.stock : 0 }}
+									<text class="meta-gap">合计销量: {{ formatSales(item.sales) }}</text>
+								</view>
 								<view class="price-line">
-									<text class="price">¥{{ item.price }}</text>
-									<text class="sub">原价¥{{ item.originPrice }}</text>
-									<text class="sub">库存{{ item.stock }}</text>
+									<text class="price">¥{{ formatPrice(item.price) }}</text>
+									<text class="origin" v-if="item.originPrice != null && item.originPrice !== ''">{{ formatPrice(item.originPrice) }}</text>
 								</view>
-								<view class="row-bottom">
-									<text class="sales">合计销量: {{ item.sales }}</text>
-									<view class="actions" v-if="!batchMode" @click.stop>
-										<template v-if="item.status === 'selling' || item.status === 'soldout'">
-											<view class="btn primary" @click="onOffShelf(item)">下架</view>
-										</template>
-										<template v-else-if="item.status === 'pending'">
-											<view class="btn" @click="onDelete(item)">删除</view>
-											<view class="btn" @click="goEdit(item)">编辑</view>
-											<view class="btn primary" @click="onOnShelf(item)">上架</view>
-										</template>
-										<template v-else-if="item.status === 'rejected'">
-											<view class="btn" @click="onDelete(item)">删除</view>
-											<view class="btn" @click="goEdit(item)">编辑</view>
-										</template>
-									</view>
+								<view class="actions" v-if="!batchMode" @click.stop>
+									<template v-if="item.status === 'selling' || item.status === 'soldout'">
+										<view class="btn primary" @click="onOffShelf(item)">下架</view>
+									</template>
+									<template v-else-if="item.status === 'pending'">
+										<view class="btn" @click="onDelete(item)">删除</view>
+										<view class="btn" @click="goEdit(item)">编辑</view>
+										<view class="btn primary" @click="onOnShelf(item)">上架</view>
+									</template>
+									<template v-else-if="item.status === 'rejected'">
+										<view class="btn" @click="onDelete(item)">删除</view>
+										<view class="btn" @click="goEdit(item)">编辑</view>
+									</template>
 								</view>
 							</view>
 						</view>
@@ -95,11 +103,13 @@
 
 		<!-- 底部:新建 / 批量操作 -->
 		<view class="footer" v-if="!batchMode">
-			<u-button type="primary" shape="circle" @click="goCreate">新建菜品</u-button>
+			<view class="primary-btn" @click="goCreate">新建菜品</view>
 		</view>
 		<view class="batch-footer" v-else>
 			<view class="all" @click="toggleAll">
-				<view :class="['dot', isAllSelected ? 'on' : '']"></view>
+				<view :class="['dot', isAllSelected ? 'on' : '']">
+					<u-icon v-if="isAllSelected" name="checkmark" color="#fff" size="20"></u-icon>
+				</view>
 				全选
 			</view>
 			<view class="batch-btns">
@@ -198,7 +208,6 @@ export default {
 			return params;
 		},
 		currentList() {
-			// listVersion 用于操作后触发重新读取
 			void this.listVersion;
 			const scroll = this.$refs.listScroll;
 			return (scroll && scroll.dataList) || [];
@@ -211,10 +220,18 @@ export default {
 		bannerVisible() {
 			return this.applyStatus !== 1;
 		},
-		bannerText() {
-			if (this.applyStatus === 0) return '提示:平台现已增加团餐活动,如您需要,点击报名参与';
-			if (this.applyStatus === 3) return '提示:团餐活动报名审核中,请耐心等待';
-			if (this.applyStatus === 2) return '提示:团餐报名未通过,点击重新报名';
+		bannerNodes() {
+			const wrap = (html) => `<span style="color:#B8860B;font-size:14px;">${html}</span>`;
+			const mark = (word) => `<span style="color:#F5A623;font-weight:600;">${word}</span>`;
+			if (this.applyStatus == 0) {
+				return wrap(`提示:平台现已增加团餐活动,如您需要,点击${mark('报名')}参与`);
+			}
+			if (this.applyStatus == 3) {
+				return wrap('提示:团餐活动报名审核中,请耐心等待');
+			}
+			if (this.applyStatus == 2) {
+				return wrap(`提示:团餐报名未通过,点击${mark('重新报名')}`);
+			}
 			return '';
 		}
 	},
@@ -222,7 +239,6 @@ export default {
 		this.loadSpecialCategories();
 	},
 	onShow() {
-		// 首次进入交给 ListScrollView 自动加载,避免重复请求;返回本页时再刷新
 		if (this.listReady) {
 			this.reloadList();
 		} else {
@@ -231,6 +247,16 @@ export default {
 		this.fetchApplyStatus();
 	},
 	methods: {
+		formatPrice(price) {
+			const n = Number(price);
+			if (Number.isNaN(n)) return '0.00';
+			return n.toFixed(2);
+		},
+		formatSales(sales) {
+			const n = Number(sales);
+			if (Number.isNaN(n)) return '0';
+			return String(n).replace(/\B(?=(\d{3})+(?!\d))/g, ',');
+		},
 		goBack() {
 			uni.navigateBack({ delta: 1 });
 		},
@@ -411,7 +437,7 @@ export default {
 <style lang="scss" scoped>
 .page {
 	height: 100vh;
-	background: #f7f8fc;
+	background: #f7f8fa;
 	display: flex;
 	flex-direction: column;
 	overflow: hidden;
@@ -425,6 +451,11 @@ export default {
 	display: flex;
 	align-items: center;
 	padding-right: 24rpx;
+	gap: 28rpx;
+}
+.nav-icon {
+	width: 56rpx;
+	height: 56rpx;
 }
 .cancel-btn {
 	font-size: 28rpx;
@@ -438,26 +469,32 @@ export default {
 }
 .filters {
 	display: flex;
+	justify-content: space-between;
+	align-items: center;
 	background: #fff;
 	padding: 16rpx 24rpx 20rpx;
 	flex-shrink: 0;
 	.filter-item {
 		margin-right: 36rpx;
-		font-size: 26rpx;
+		font-size: 30rpx;
 		color: #333;
 		display: flex;
 		align-items: center;
-		gap: 6rpx;
+	}
+	.filter-arrow {
+		width: 20rpx;
+		height: 20rpx;
+		margin-left: 8rpx;
 	}
 }
 .banner {
-	margin: 16rpx 24rpx 0;
+	// margin: 16rpx 24rpx 0;
+	height: 80rpx;
+	line-height: 80rpx;
 	background: #fff8e6;
-	color: #b8860b;
-	font-size: 24rpx;
-	padding: 16rpx 20rpx;
-	border-radius: 8rpx;
-	flex-shrink: 0;
+	font-size: 28rpx;
+	// border-radius: 8rpx;
+	text-align: center;
 }
 .list-wrap {
 	flex: 1;
@@ -472,11 +509,12 @@ export default {
 	display: flex;
 	background: #fff;
 	border-radius: 16rpx;
-	padding: 20rpx;
+	padding: 24rpx;
 	margin-bottom: 16rpx;
 	.check {
 		display: flex;
-		align-items: center;
+		align-items: flex-start;
+		padding-top: 40rpx;
 		margin-right: 16rpx;
 	}
 	.dot {
@@ -484,28 +522,19 @@ export default {
 		height: 36rpx;
 		border-radius: 50%;
 		border: 2rpx solid #ccc;
+		box-sizing: border-box;
+		display: flex;
+		align-items: center;
+		justify-content: center;
 		&.on {
-			background: #ff4d4f;
-			border-color: #ff4d4f;
-			position: relative;
-			&::after {
-				content: '';
-				position: absolute;
-				left: 10rpx;
-				top: 4rpx;
-				width: 10rpx;
-				height: 18rpx;
-				border: 3rpx solid #fff;
-				border-top: 0;
-				border-left: 0;
-				transform: rotate(45deg);
-			}
+			background: #449aff;
+			border-color: #449aff;
 		}
 	}
 	.thumb-wrap {
 		position: relative;
-		width: 140rpx;
-		height: 140rpx;
+		width: 160rpx;
+		height: 160rpx;
 		flex-shrink: 0;
 		.thumb {
 			width: 100%;
@@ -513,88 +542,102 @@ export default {
 			border-radius: 12rpx;
 			background: #eee;
 		}
-		.tag {
+		.belong-tag {
 			position: absolute;
 			left: 0;
 			top: 0;
-			font-size: 18rpx;
-			color: #fff;
-			padding: 2rpx 10rpx;
-			border-radius: 12rpx 0 12rpx 0;
-			&.group {
-				background: #ff6b35;
-			}
-			&.store {
-				background: #449aff;
-			}
+			height: 36rpx;
+			width: auto;
 		}
 	}
 	.info {
 		flex: 1;
-		margin-left: 16rpx;
+		margin-left: 20rpx;
 		min-width: 0;
+		display: flex;
+		flex-direction: column;
 	}
 	.row-top {
 		display: flex;
 		justify-content: space-between;
+		align-items: flex-start;
 		.name {
+			flex: 1;
 			font-size: 30rpx;
 			font-weight: 600;
 			color: #222;
+			overflow: hidden;
+			text-overflow: ellipsis;
+			white-space: nowrap;
+			padding-right: 12rpx;
 		}
 		.status {
 			font-size: 24rpx;
-			color: #449aff;
 			flex-shrink: 0;
-			margin-left: 12rpx;
+			&.selling {
+				color: #19be6b;
+			}
+			&.soldout {
+				color: #999;
+			}
+			&.pending {
+				color: #ff9900;
+			}
+			&.reviewing {
+				color: #f5a623;
+			}
+			&.rejected {
+				color: #ff4d4f;
+			}
 		}
 	}
 	.desc {
 		font-size: 22rpx;
 		color: #999;
-		margin-top: 6rpx;
+		margin-top: 8rpx;
 		overflow: hidden;
 		white-space: nowrap;
 		text-overflow: ellipsis;
 	}
-	.price-line {
+	.meta {
 		margin-top: 8rpx;
+		font-size: 22rpx;
+		color: #999;
+		.meta-gap {
+			margin-left: 20rpx;
+		}
+	}
+	.price-line {
+		margin-top: 10rpx;
 		.price {
 			color: #ff4d4f;
-			font-size: 30rpx;
+			font-size: 32rpx;
 			font-weight: 600;
 			margin-right: 12rpx;
 		}
-		.sub {
-			font-size: 22rpx;
+		.origin {
+			font-size: 24rpx;
 			color: #999;
-			margin-right: 12rpx;
+			text-decoration: line-through;
 		}
 	}
-	.row-bottom {
+	.actions {
 		display: flex;
-		align-items: center;
-		justify-content: space-between;
-		margin-top: 12rpx;
-		.sales {
-			font-size: 22rpx;
-			color: #999;
-		}
-		.actions {
-			display: flex;
-			gap: 12rpx;
-		}
-		.btn {
-			font-size: 22rpx;
-			padding: 6rpx 18rpx;
-			border: 1rpx solid #ddd;
-			border-radius: 28rpx;
-			color: #333;
-			&.primary {
-				background: #449aff;
-				border-color: #449aff;
-				color: #fff;
-			}
+		justify-content: flex-end;
+		gap: 12rpx;
+		margin-top: 16rpx;
+	}
+	.btn {
+		font-size: 24rpx;
+		padding: 8rpx 24rpx;
+		border: 1rpx solid #ddd;
+		border-radius: 28rpx;
+		color: #666;
+		background: #fff;
+		&.primary {
+			background: #449aff;
+			border-color: #449aff;
+			color: #fff;
 		}
 	}
 }
@@ -603,9 +646,19 @@ export default {
 	left: 0;
 	right: 0;
 	bottom: 0;
+	z-index: 20;
 	padding: 20rpx 40rpx calc(20rpx + env(safe-area-inset-bottom));
 	background: #fff;
 }
+.primary-btn {
+	height: 88rpx;
+	line-height: 88rpx;
+	text-align: center;
+	color: #fff;
+	font-size: 32rpx;
+	border-radius: 44rpx;
+	background: linear-gradient(90deg, #77b6ff 0%, #449aff 100%);
+}
 .batch-footer {
 	position: fixed;
 	left: 0;
@@ -627,9 +680,13 @@ export default {
 			border-radius: 50%;
 			border: 2rpx solid #ccc;
 			margin-right: 10rpx;
+			box-sizing: border-box;
+			display: flex;
+			align-items: center;
+			justify-content: center;
 			&.on {
-				background: #ff4d4f;
-				border-color: #ff4d4f;
+				background: #449aff;
+				border-color: #449aff;
 			}
 		}
 	}

BIN=BIN
static/merchantDish/batch.png


BIN=BIN
static/merchantDish/groupmeal.png


BIN=BIN
static/merchantDish/photo.png


BIN=BIN
static/merchantDish/search.png


BIN=BIN
static/merchantDish/selete-true.png


BIN=BIN
static/merchantDish/selete.png


BIN=BIN
static/merchantDish/store.png