|
|
@@ -0,0 +1,1091 @@
|
|
|
+<template>
|
|
|
+ <div class="price-edit-page">
|
|
|
+ <!-- 顶部:标题 + 关闭 -->
|
|
|
+ <div class="page-header">
|
|
|
+ <div class="header-left" @click="goBack">
|
|
|
+ <el-icon class="back-icon">
|
|
|
+ <ArrowLeft />
|
|
|
+ </el-icon>
|
|
|
+ <span class="back-text">返回</span>
|
|
|
+ </div>
|
|
|
+ <h1 class="page-title">
|
|
|
+ {{ viewMode ? "详情" : id ? "编辑" : "新建" }}
|
|
|
+ </h1>
|
|
|
+ <el-button v-if="viewMode" type="primary" @click="goEdit"> 编辑 </el-button>
|
|
|
+ <div v-else class="header-right" @click="goBack">
|
|
|
+ <el-icon class="close-icon">
|
|
|
+ <Close />
|
|
|
+ </el-icon>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="page-content">
|
|
|
+ <el-form
|
|
|
+ ref="ruleFormRef"
|
|
|
+ :model="formModel"
|
|
|
+ :rules="formRules"
|
|
|
+ label-width="120px"
|
|
|
+ class="price-form two-column-form"
|
|
|
+ @submit.prevent
|
|
|
+ >
|
|
|
+ <!-- 左列 -->
|
|
|
+ <div class="form-column form-column-left">
|
|
|
+ <!-- 类型(仅美食类别显示菜品/套餐) -->
|
|
|
+ <el-form-item v-if="isFoodModule" label="类型" prop="formType" required>
|
|
|
+ <el-radio-group v-model="formModel.formType" :disabled="viewMode">
|
|
|
+ <el-radio value="dish"> 菜品 </el-radio>
|
|
|
+ <el-radio value="package"> 套餐 </el-radio>
|
|
|
+ </el-radio-group>
|
|
|
+ </el-form-item>
|
|
|
+
|
|
|
+ <!-- 图片 -->
|
|
|
+ <el-form-item label="图片" prop="images" required>
|
|
|
+ <div class="image-upload-wrap">
|
|
|
+ <UploadImgs
|
|
|
+ v-model:file-list="imageFileList"
|
|
|
+ :api="uploadImgStore"
|
|
|
+ :limit="9"
|
|
|
+ :file-size="5"
|
|
|
+ :disabled="viewMode"
|
|
|
+ class="price-list-upload"
|
|
|
+ @update:file-list="onImageListChange"
|
|
|
+ />
|
|
|
+ <div class="image-tip">({{ (formModel.images || "").split(",").filter(Boolean).length }}/9)</div>
|
|
|
+ </div>
|
|
|
+ </el-form-item>
|
|
|
+
|
|
|
+ <!-- 名称:美食为菜品/套餐名称,非美食为名称 -->
|
|
|
+ <el-form-item
|
|
|
+ :label="isFoodModule ? (formModel.formType === 'dish' ? '菜品名称' : '套餐名称') : '名称'"
|
|
|
+ prop="name"
|
|
|
+ required
|
|
|
+ >
|
|
|
+ <el-input
|
|
|
+ v-model="formModel.name"
|
|
|
+ placeholder="请输入"
|
|
|
+ maxlength="50"
|
|
|
+ show-word-limit
|
|
|
+ clearable
|
|
|
+ :disabled="viewMode"
|
|
|
+ class="form-input"
|
|
|
+ />
|
|
|
+ </el-form-item>
|
|
|
+
|
|
|
+ <!-- 价格 -->
|
|
|
+ <el-form-item label="价格(¥)" prop="totalPrice" required>
|
|
|
+ <el-input
|
|
|
+ v-model="formModel.totalPrice"
|
|
|
+ placeholder="请输入"
|
|
|
+ maxlength="15"
|
|
|
+ clearable
|
|
|
+ :disabled="viewMode"
|
|
|
+ class="form-input price-input"
|
|
|
+ />
|
|
|
+ </el-form-item>
|
|
|
+
|
|
|
+ <!-- 以下仅美食类别显示:菜品原料 / 价目表内容 -->
|
|
|
+ <template v-if="isFoodModule">
|
|
|
+ <!-- 菜品原料(仅美食-菜品) -->
|
|
|
+ <div v-if="formModel.formType === 'dish'" class="form-block">
|
|
|
+ <div class="block-head">
|
|
|
+ <span class="block-title">菜品原料</span>
|
|
|
+ <el-link v-if="!viewMode" type="primary" class="btn-add" @click="addIngredient"> 添加项目 </el-link>
|
|
|
+ <span v-if="!viewMode" class="block-tip">默认显示一个</span>
|
|
|
+ </div>
|
|
|
+ <div v-if="!formModel.foodIngredients.length" class="empty-tip">暂无原料,请添加项目</div>
|
|
|
+ <div v-for="(item, idx) in formModel.foodIngredients" :key="'ing-' + idx" class="block-item ingredient-item">
|
|
|
+ <el-form-item label="原料名称" required>
|
|
|
+ <el-input
|
|
|
+ v-model="item.ingredientName"
|
|
|
+ placeholder="请输入"
|
|
|
+ clearable
|
|
|
+ :disabled="viewMode"
|
|
|
+ class="form-input"
|
|
|
+ />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="所需重量(g)" required>
|
|
|
+ <el-input v-model="item.weight" placeholder="请输入" clearable :disabled="viewMode" class="form-input" />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="成本价(¥)" required>
|
|
|
+ <el-input v-model="item.costPrice" placeholder="请输入" clearable :disabled="viewMode" class="form-input" />
|
|
|
+ </el-form-item>
|
|
|
+ <el-link v-if="!viewMode" type="primary" class="link-delete" @click="removeIngredient(idx)"> 删除 </el-link>
|
|
|
+ </div>
|
|
|
+ <el-link v-if="!viewMode" type="primary" class="btn-recommend" @click="calcRecommendedPrice"> 推荐价格 </el-link>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 价目表内容(仅套餐) -->
|
|
|
+ <div v-if="formModel.formType === 'package'" class="form-block">
|
|
|
+ <div class="block-head">
|
|
|
+ <span class="block-title">价目表内容</span>
|
|
|
+ <el-link v-if="!viewMode" type="primary" class="btn-add" @click="addPriceListGroup"> 添加项目 </el-link>
|
|
|
+ <span v-if="!viewMode" class="block-tip">默认显示一个</span>
|
|
|
+ </div>
|
|
|
+ <div
|
|
|
+ v-for="(group, gIdx) in formModel.foodPackageCategories"
|
|
|
+ :key="'group-' + gIdx"
|
|
|
+ class="block-item price-list-group"
|
|
|
+ >
|
|
|
+ <el-form-item label="类别" required>
|
|
|
+ <el-input v-model="group.category" placeholder="请输入" clearable :disabled="viewMode" class="form-input" />
|
|
|
+ </el-form-item>
|
|
|
+ <template v-for="(dish, dIdx) in group.dishes" :key="'d-' + gIdx + '-' + dIdx">
|
|
|
+ <div class="dish-row">
|
|
|
+ <el-form-item label="菜品名称" required>
|
|
|
+ <el-select
|
|
|
+ v-model="dish.itemId"
|
|
|
+ placeholder="请选择"
|
|
|
+ filterable
|
|
|
+ clearable
|
|
|
+ :disabled="viewMode"
|
|
|
+ class="form-input dish-select"
|
|
|
+ @change="onPackageDishSelect(gIdx, dIdx, $event)"
|
|
|
+ >
|
|
|
+ <el-option v-for="opt in dishOptions" :key="opt.id" :label="opt.name" :value="String(opt.id)" />
|
|
|
+ </el-select>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="数量" required>
|
|
|
+ <el-input
|
|
|
+ v-model="dish.quantity"
|
|
|
+ placeholder="请输入"
|
|
|
+ clearable
|
|
|
+ :disabled="viewMode"
|
|
|
+ class="form-input qty-input"
|
|
|
+ />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="单位" required>
|
|
|
+ <el-select
|
|
|
+ v-model="dish.unit"
|
|
|
+ placeholder="请选择单位"
|
|
|
+ clearable
|
|
|
+ :disabled="viewMode"
|
|
|
+ class="form-input unit-select package-unit-select"
|
|
|
+ style="width: 100%; min-width: 120px"
|
|
|
+ >
|
|
|
+ <el-option v-for="u in UNIT_OPTIONS" :key="u" :label="u" :value="u" />
|
|
|
+ </el-select>
|
|
|
+ </el-form-item>
|
|
|
+ <el-link v-if="!viewMode" type="primary" class="link-delete" @click="removePackageDish(gIdx, dIdx)">
|
|
|
+ 删除菜品
|
|
|
+ </el-link>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ <div v-if="!viewMode" class="group-actions">
|
|
|
+ <el-link type="primary" class="btn-add-dish" @click="addPackageDish(gIdx)"> 添加菜品 </el-link>
|
|
|
+ <el-link type="primary" class="link-delete" @click="removePriceListGroup(gIdx)"> 删除项目 </el-link>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+
|
|
|
+ <!-- 休闲娱乐/生活服务:服务项目(添加项目) -->
|
|
|
+ <template v-if="!isFoodModule">
|
|
|
+ <div class="form-block">
|
|
|
+ <div class="block-head">
|
|
|
+ <span class="block-title">服务项目</span>
|
|
|
+ <el-link v-if="!viewMode" type="primary" class="btn-add" @click="addGeneralServiceItem"> 添加项目 </el-link>
|
|
|
+ <span v-if="!viewMode" class="block-tip">默认显示一个</span>
|
|
|
+ </div>
|
|
|
+ <div v-if="!formModel.generalServiceItems.length" class="empty-tip">暂无服务项目,请添加项目</div>
|
|
|
+ <div v-for="(item, idx) in formModel.generalServiceItems" :key="'svc-' + idx" class="block-item service-item">
|
|
|
+ <el-form-item label="服务名称" required>
|
|
|
+ <el-input v-model="item.serviceName" placeholder="请输入" clearable :disabled="viewMode" class="form-input" />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="数量" required>
|
|
|
+ <el-input
|
|
|
+ v-model="item.quantity"
|
|
|
+ placeholder="请输入"
|
|
|
+ clearable
|
|
|
+ :disabled="viewMode"
|
|
|
+ class="form-input qty-input"
|
|
|
+ />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="单位" required>
|
|
|
+ <el-select
|
|
|
+ v-model="item.unit"
|
|
|
+ placeholder="请选择单位"
|
|
|
+ clearable
|
|
|
+ :disabled="viewMode"
|
|
|
+ class="form-input unit-select service-unit-select"
|
|
|
+ style="width: 100%; min-width: 120px"
|
|
|
+ >
|
|
|
+ <el-option v-for="u in GENERAL_SERVICE_UNIT_OPTIONS" :key="u" :label="u" :value="u" />
|
|
|
+ </el-select>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="服务说明">
|
|
|
+ <el-input
|
|
|
+ v-model="item.description"
|
|
|
+ type="textarea"
|
|
|
+ :rows="2"
|
|
|
+ placeholder="请输入"
|
|
|
+ width="100%"
|
|
|
+ maxlength="200"
|
|
|
+ show-word-limit
|
|
|
+ resize="none"
|
|
|
+ :disabled="viewMode"
|
|
|
+ class="form-textarea"
|
|
|
+ />
|
|
|
+ </el-form-item>
|
|
|
+ <el-link v-if="!viewMode" type="primary" class="link-delete" @click="removeGeneralServiceItem(idx)">
|
|
|
+ 删除
|
|
|
+ </el-link>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+
|
|
|
+ <!-- 图文详情图片 -->
|
|
|
+ <el-form-item label="图文详情图片">
|
|
|
+ <div class="image-upload-wrap">
|
|
|
+ <UploadImgs
|
|
|
+ v-model:file-list="detailImageFileList"
|
|
|
+ :api="uploadImgStore"
|
|
|
+ :limit="9"
|
|
|
+ :file-size="5"
|
|
|
+ :disabled="viewMode"
|
|
|
+ class="price-list-upload"
|
|
|
+ @update:file-list="onDetailImageListChange"
|
|
|
+ />
|
|
|
+ <div class="image-tip">({{ (formModel.imageContent || "").split(",").filter(Boolean).length }}/9)</div>
|
|
|
+ </div>
|
|
|
+ </el-form-item>
|
|
|
+
|
|
|
+ <!-- 图文详情描述 -->
|
|
|
+ <el-form-item label="图文详情描述">
|
|
|
+ <el-input
|
|
|
+ v-model="formModel.detailContent"
|
|
|
+ type="textarea"
|
|
|
+ :rows="4"
|
|
|
+ placeholder="请输入"
|
|
|
+ maxlength="500"
|
|
|
+ show-word-limit
|
|
|
+ resize="none"
|
|
|
+ :disabled="viewMode"
|
|
|
+ class="form-textarea"
|
|
|
+ />
|
|
|
+ </el-form-item>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 右列 -->
|
|
|
+ <div class="form-column form-column-right">
|
|
|
+ <el-form-item label="补充说明">
|
|
|
+ <el-input
|
|
|
+ v-model="formModel.extraNote"
|
|
|
+ type="textarea"
|
|
|
+ :rows="4"
|
|
|
+ placeholder="请输入"
|
|
|
+ maxlength="300"
|
|
|
+ show-word-limit
|
|
|
+ resize="none"
|
|
|
+ :disabled="viewMode"
|
|
|
+ class="form-textarea"
|
|
|
+ />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="预约">
|
|
|
+ <el-radio-group v-model="formModel.needReserve" :disabled="viewMode">
|
|
|
+ <el-radio :value="0"> 无需预约 </el-radio>
|
|
|
+ <el-radio :value="1"> 需要预约 </el-radio>
|
|
|
+ </el-radio-group>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="预约规则">
|
|
|
+ <el-input
|
|
|
+ v-model="formModel.reserveRule"
|
|
|
+ type="textarea"
|
|
|
+ :rows="3"
|
|
|
+ placeholder="请输入"
|
|
|
+ maxlength="200"
|
|
|
+ show-word-limit
|
|
|
+ resize="none"
|
|
|
+ :disabled="viewMode"
|
|
|
+ class="form-textarea"
|
|
|
+ />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="适用人数">
|
|
|
+ <el-input v-model="formModel.peopleLimit" placeholder="请输入" clearable :disabled="viewMode" class="form-input" />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="使用规则">
|
|
|
+ <el-input
|
|
|
+ v-model="formModel.usageRule"
|
|
|
+ type="textarea"
|
|
|
+ :rows="4"
|
|
|
+ placeholder="请输入"
|
|
|
+ maxlength="300"
|
|
|
+ show-word-limit
|
|
|
+ resize="none"
|
|
|
+ :disabled="viewMode"
|
|
|
+ class="form-textarea"
|
|
|
+ />
|
|
|
+ </el-form-item>
|
|
|
+ <!-- 详情模式:提交时间、审核状态、审核时间、拒绝原因、在线状态 -->
|
|
|
+ <template v-if="viewMode">
|
|
|
+ <el-form-item label="提交时间">
|
|
|
+ <span class="view-only-value">{{ formModel.createTime || "--" }}</span>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="审核状态">
|
|
|
+ <span :class="['view-only-value', 'audit-status', 'audit-status--' + (formModel.auditStatus ?? '')]">
|
|
|
+ {{ auditStatusText(formModel.auditStatus) }}
|
|
|
+ </span>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="审核时间">
|
|
|
+ <span class="view-only-value">{{ formModel.auditTime || "--" }}</span>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="拒绝原因">
|
|
|
+ <span class="view-only-value">{{ formModel.rejectionReason || "无" }}</span>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="在线状态">
|
|
|
+ <span class="view-only-value">{{ shelfStatusText(formModel.shelfStatus) }}</span>
|
|
|
+ </el-form-item>
|
|
|
+ </template>
|
|
|
+ </div>
|
|
|
+ </el-form>
|
|
|
+
|
|
|
+ <!-- 底部操作:详情模式仅显示返回+编辑,编辑模式显示返回+确定 -->
|
|
|
+ <div class="page-footer">
|
|
|
+ <div class="footer-inner">
|
|
|
+ <el-button @click="goBack" size="large"> 返回 </el-button>
|
|
|
+ <template v-if="viewMode">
|
|
|
+ <el-button type="primary" size="large" @click="goEdit"> 编辑 </el-button>
|
|
|
+ </template>
|
|
|
+ <template v-else>
|
|
|
+ <el-button type="primary" size="large" :loading="submitting" @click="handleSubmit"> 确定 </el-button>
|
|
|
+ </template>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script setup lang="ts" name="priceListEdit">
|
|
|
+import { ref, reactive, computed, onMounted, watch } from "vue";
|
|
|
+import { ElMessage } from "element-plus";
|
|
|
+import { useRoute, useRouter } from "vue-router";
|
|
|
+import type { FormInstance, UploadUserFile } from "element-plus";
|
|
|
+import { ArrowLeft, Close } from "@element-plus/icons-vue";
|
|
|
+import {
|
|
|
+ getPriceListDetail,
|
|
|
+ addPriceItem,
|
|
|
+ updatePriceItem,
|
|
|
+ getCuisineSingleNameList,
|
|
|
+ CUISINE_TYPE,
|
|
|
+ getModuleTypeByBusinessSection,
|
|
|
+ MODULE_TYPES
|
|
|
+} from "@/api/modules/priceList";
|
|
|
+import { localGet } from "@/utils";
|
|
|
+import UploadImgs from "@/components/Upload/Imgs.vue";
|
|
|
+import { uploadImgStore } from "@/api/modules/upload";
|
|
|
+
|
|
|
+const router = useRouter();
|
|
|
+const route = useRoute();
|
|
|
+const ruleFormRef = ref<FormInstance>();
|
|
|
+
|
|
|
+const id = ref<string>("");
|
|
|
+const businessSection = ref<string>("1");
|
|
|
+const cuisineType = ref<number | undefined>(undefined);
|
|
|
+const submitting = ref(false);
|
|
|
+const dishOptions = ref<{ id: number | string; name: string }[]>([]);
|
|
|
+
|
|
|
+// 详情模式(从列表点「详情」进入,同一编辑页只读展示)
|
|
|
+const viewMode = computed(() => route.query.mode === "detail");
|
|
|
+
|
|
|
+const UNIT_OPTIONS = ["份", "人", "元", "个", "瓶", "杯", "碗", "盘", "只", "斤", "两", "克", "千克"];
|
|
|
+
|
|
|
+// 通用套餐-服务项目单位(休闲娱乐、生活服务,与商家端一致)
|
|
|
+const GENERAL_SERVICE_UNIT_OPTIONS = [
|
|
|
+ "份",
|
|
|
+ "次",
|
|
|
+ "人",
|
|
|
+ "个",
|
|
|
+ "瓶",
|
|
|
+ "杯",
|
|
|
+ "碗",
|
|
|
+ "盘",
|
|
|
+ "只",
|
|
|
+ "斤",
|
|
|
+ "两",
|
|
|
+ "克",
|
|
|
+ "千克",
|
|
|
+ "天",
|
|
|
+ "小时"
|
|
|
+];
|
|
|
+
|
|
|
+// 表单数据
|
|
|
+const formModel = reactive({
|
|
|
+ formType: "dish" as "dish" | "package",
|
|
|
+ name: "",
|
|
|
+ totalPrice: "",
|
|
|
+ images: "",
|
|
|
+ imageContent: "",
|
|
|
+ detailContent: "",
|
|
|
+ extraNote: "",
|
|
|
+ needReserve: 0 as 0 | 1,
|
|
|
+ reserveRule: "",
|
|
|
+ peopleLimit: "",
|
|
|
+ usageRule: "",
|
|
|
+ // 详情只读字段(详情模式显示)
|
|
|
+ createTime: "",
|
|
|
+ auditTime: "",
|
|
|
+ auditStatus: null as number | null,
|
|
|
+ rejectionReason: "",
|
|
|
+ shelfStatus: null as number | null,
|
|
|
+ // 菜品原料(菜品模式)
|
|
|
+ foodIngredients: [] as { ingredientName: string; weight: string; costPrice: string }[],
|
|
|
+ // 价目表内容(套餐模式)
|
|
|
+ foodPackageCategories: [] as {
|
|
|
+ category: string;
|
|
|
+ dishes: { itemId: string; dishName: string; quantity: string; unit: string }[];
|
|
|
+ }[],
|
|
|
+ // 通用套餐-服务项目(休闲娱乐、生活服务)
|
|
|
+ generalServiceItems: [] as {
|
|
|
+ serviceName: string;
|
|
|
+ quantity: string;
|
|
|
+ unit: string;
|
|
|
+ description: string;
|
|
|
+ }[]
|
|
|
+});
|
|
|
+
|
|
|
+const unitOptions = ref<string[]>(UNIT_OPTIONS);
|
|
|
+const imageFileList = ref<UploadUserFile[]>([]);
|
|
|
+const detailImageFileList = ref<UploadUserFile[]>([]);
|
|
|
+
|
|
|
+// 仅美食类别(经营板块为 1)才显示菜品/套餐分类
|
|
|
+const isFoodModule = computed(() => getModuleTypeByBusinessSection(businessSection.value) === MODULE_TYPES.FOOD);
|
|
|
+
|
|
|
+const formRules = reactive({
|
|
|
+ name: [{ required: true, message: "请输入名称", trigger: "blur" }],
|
|
|
+ totalPrice: [
|
|
|
+ { required: true, message: "请输入价格", trigger: "blur" },
|
|
|
+ {
|
|
|
+ pattern: /^(?:\d+|\d+\.\d{1,2})$/,
|
|
|
+ message: "请输入有效价格(最多两位小数)",
|
|
|
+ trigger: "blur"
|
|
|
+ }
|
|
|
+ ]
|
|
|
+});
|
|
|
+
|
|
|
+// 切换类型时初始化对应块
|
|
|
+watch(
|
|
|
+ () => formModel.formType,
|
|
|
+ val => {
|
|
|
+ if (val === "dish" && !formModel.foodIngredients.length) {
|
|
|
+ formModel.foodIngredients = [{ ingredientName: "", weight: "", costPrice: "" }];
|
|
|
+ }
|
|
|
+ if (val === "package" && !formModel.foodPackageCategories.length) {
|
|
|
+ formModel.foodPackageCategories = [{ category: "", dishes: [{ itemId: "", dishName: "", quantity: "1", unit: "份" }] }];
|
|
|
+ }
|
|
|
+ },
|
|
|
+ { immediate: false }
|
|
|
+);
|
|
|
+
|
|
|
+function addIngredient() {
|
|
|
+ formModel.foodIngredients.push({ ingredientName: "", weight: "", costPrice: "" });
|
|
|
+}
|
|
|
+
|
|
|
+function removeIngredient(idx: number) {
|
|
|
+ formModel.foodIngredients.splice(idx, 1);
|
|
|
+}
|
|
|
+
|
|
|
+function addPriceListGroup() {
|
|
|
+ formModel.foodPackageCategories.push({
|
|
|
+ category: "",
|
|
|
+ dishes: [{ itemId: "", dishName: "", quantity: "1", unit: "份" }]
|
|
|
+ });
|
|
|
+}
|
|
|
+
|
|
|
+function removePriceListGroup(gIdx: number) {
|
|
|
+ formModel.foodPackageCategories.splice(gIdx, 1);
|
|
|
+}
|
|
|
+
|
|
|
+function addPackageDish(gIdx: number) {
|
|
|
+ formModel.foodPackageCategories[gIdx].dishes.push({
|
|
|
+ itemId: "",
|
|
|
+ dishName: "",
|
|
|
+ quantity: "1",
|
|
|
+ unit: "份"
|
|
|
+ });
|
|
|
+}
|
|
|
+
|
|
|
+function removePackageDish(gIdx: number, dIdx: number) {
|
|
|
+ formModel.foodPackageCategories[gIdx].dishes.splice(dIdx, 1);
|
|
|
+}
|
|
|
+
|
|
|
+function onPackageDishSelect(gIdx: number, dIdx: number, itemId: string) {
|
|
|
+ const opt = dishOptions.value.find(o => String(o.id) === itemId);
|
|
|
+ if (opt) formModel.foodPackageCategories[gIdx].dishes[dIdx].dishName = opt.name;
|
|
|
+}
|
|
|
+
|
|
|
+function normalizeServiceUnit(unit: string | undefined): string {
|
|
|
+ const u = (unit || "份").trim();
|
|
|
+ return GENERAL_SERVICE_UNIT_OPTIONS.includes(u) ? u : "份";
|
|
|
+}
|
|
|
+
|
|
|
+function normalizePackageUnit(unit: string | undefined): string {
|
|
|
+ const u = (unit || "份").trim();
|
|
|
+ return UNIT_OPTIONS.includes(u) ? u : "份";
|
|
|
+}
|
|
|
+
|
|
|
+function addGeneralServiceItem() {
|
|
|
+ formModel.generalServiceItems.push({
|
|
|
+ serviceName: "",
|
|
|
+ quantity: "",
|
|
|
+ unit: "份",
|
|
|
+ description: ""
|
|
|
+ });
|
|
|
+}
|
|
|
+
|
|
|
+function removeGeneralServiceItem(idx: number) {
|
|
|
+ formModel.generalServiceItems.splice(idx, 1);
|
|
|
+}
|
|
|
+
|
|
|
+function calcRecommendedPrice() {
|
|
|
+ const total = formModel.foodIngredients.reduce((sum, it) => sum + (parseFloat(it.costPrice) || 0), 0) * 1.2;
|
|
|
+ if (total > 0) {
|
|
|
+ formModel.totalPrice = total.toFixed(2);
|
|
|
+ ElMessage.success("已根据原料成本计算推荐价格(约1.2倍)");
|
|
|
+ } else {
|
|
|
+ ElMessage.warning("请先填写原料成本");
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+function onImageListChange(list: UploadUserFile[]) {
|
|
|
+ const urls = list.map(f => (typeof f.url === "string" ? f.url : "")).filter(Boolean);
|
|
|
+ formModel.images = urls.join(",");
|
|
|
+}
|
|
|
+
|
|
|
+function onDetailImageListChange(list: UploadUserFile[]) {
|
|
|
+ const urls = list.map(f => (typeof f.url === "string" ? f.url : "")).filter(Boolean);
|
|
|
+ formModel.imageContent = urls.join(",");
|
|
|
+}
|
|
|
+
|
|
|
+function syncImageFileListFromModel() {
|
|
|
+ const str = formModel.images || "";
|
|
|
+ const urls = str ? str.split(",").filter(Boolean) : [];
|
|
|
+ imageFileList.value = urls.map((url, i) => ({ uid: i, name: `img-${i}`, url }));
|
|
|
+ const detailStr = formModel.imageContent || "";
|
|
|
+ const detailUrls = detailStr ? detailStr.split(",").filter(Boolean) : [];
|
|
|
+ detailImageFileList.value = detailUrls.map((url, i) => ({ uid: 1000 + i, name: `detail-${i}`, url }));
|
|
|
+}
|
|
|
+
|
|
|
+// 详情接口返回转表单(美食接口返回 data.data.data 结构,cuisineType 1=菜品 2=套餐;非美食仅通用字段)
|
|
|
+function applyDetailToForm(data: any) {
|
|
|
+ const d = data?.data?.data ?? data?.data ?? data;
|
|
|
+ if (!d) return;
|
|
|
+ const isFood = getModuleTypeByBusinessSection(businessSection.value) === MODULE_TYPES.FOOD;
|
|
|
+ formModel.name = d.name ?? "";
|
|
|
+ formModel.totalPrice = d.totalPrice !== undefined && d.totalPrice !== null ? String(d.totalPrice) : "";
|
|
|
+ formModel.images = d.images ? String(d.images).trim() : "";
|
|
|
+ formModel.imageContent = d.imageContent ? String(d.imageContent).trim() : "";
|
|
|
+ formModel.detailContent = d.detailContent ?? "";
|
|
|
+ formModel.extraNote = d.extraNote ?? "";
|
|
|
+ formModel.needReserve = d.needReserve === 1 ? 1 : 0;
|
|
|
+ formModel.reserveRule = d.reserveRule ?? "";
|
|
|
+ formModel.peopleLimit = d.peopleLimit != null ? String(d.peopleLimit) : "";
|
|
|
+ formModel.usageRule = d.usageRule ?? "";
|
|
|
+ formModel.createTime = d.createTime ?? d.submitTime ?? "";
|
|
|
+ formModel.auditTime = d.auditTime ?? d.updateTime ?? "";
|
|
|
+ formModel.auditStatus = d.status !== undefined && d.status !== null ? d.status : d.auditStatus != null ? d.auditStatus : null;
|
|
|
+ formModel.rejectionReason = d.rejectionReason ?? d.rejectReason ?? "";
|
|
|
+ formModel.shelfStatus = typeof d.shelfStatus === "number" ? d.shelfStatus : d.shelfStatus != null ? d.shelfStatus : null;
|
|
|
+ if (!isFood) {
|
|
|
+ try {
|
|
|
+ const serviceJson = d.serviceJson || "[]";
|
|
|
+ const items = JSON.parse(serviceJson);
|
|
|
+ formModel.generalServiceItems = Array.isArray(items)
|
|
|
+ ? items.map((it: any) => ({
|
|
|
+ serviceName: it.name ?? "",
|
|
|
+ quantity: it.num != null ? String(it.num) : "",
|
|
|
+ unit: normalizeServiceUnit(it.unit),
|
|
|
+ description: it.details ?? ""
|
|
|
+ }))
|
|
|
+ : [];
|
|
|
+ } catch {
|
|
|
+ formModel.generalServiceItems = [];
|
|
|
+ }
|
|
|
+ if (!formModel.generalServiceItems.length) {
|
|
|
+ formModel.generalServiceItems = [{ serviceName: "", quantity: "", unit: "份", description: "" }];
|
|
|
+ }
|
|
|
+ syncImageFileListFromModel();
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ const type = d.cuisineType;
|
|
|
+ if (type === CUISINE_TYPE.SINGLE) {
|
|
|
+ formModel.formType = "dish";
|
|
|
+ try {
|
|
|
+ const raw = d.rawJson ? JSON.parse(d.rawJson) : [];
|
|
|
+ formModel.foodIngredients = Array.isArray(raw)
|
|
|
+ ? raw.map((it: any) => ({
|
|
|
+ ingredientName: it.name ?? "",
|
|
|
+ weight: it.height ?? "",
|
|
|
+ costPrice: it.cost != null ? String(it.cost) : ""
|
|
|
+ }))
|
|
|
+ : [{ ingredientName: "", weight: "", costPrice: "" }];
|
|
|
+ } catch {
|
|
|
+ formModel.foodIngredients = [{ ingredientName: "", weight: "", costPrice: "" }];
|
|
|
+ }
|
|
|
+ if (!formModel.foodIngredients.length) formModel.foodIngredients = [{ ingredientName: "", weight: "", costPrice: "" }];
|
|
|
+ } else {
|
|
|
+ formModel.formType = "package";
|
|
|
+ try {
|
|
|
+ const groups = d.groupJson ? JSON.parse(d.groupJson) : [];
|
|
|
+ formModel.foodPackageCategories = Array.isArray(groups)
|
|
|
+ ? groups.map((g: any) => ({
|
|
|
+ category: g.categoryName ?? "",
|
|
|
+ dishes: (g.items || []).map((it: any) => ({
|
|
|
+ itemId: it.cuisineId != null ? String(it.cuisineId) : "",
|
|
|
+ dishName: it.cuisineName ?? "",
|
|
|
+ quantity: it.quantity != null ? String(it.quantity) : "1",
|
|
|
+ unit: normalizePackageUnit(it.unit)
|
|
|
+ }))
|
|
|
+ }))
|
|
|
+ : [];
|
|
|
+ } catch {
|
|
|
+ formModel.foodPackageCategories = [];
|
|
|
+ }
|
|
|
+ if (!formModel.foodPackageCategories.length) {
|
|
|
+ formModel.foodPackageCategories = [{ category: "", dishes: [{ itemId: "", dishName: "", quantity: "1", unit: "份" }] }];
|
|
|
+ }
|
|
|
+ }
|
|
|
+ syncImageFileListFromModel();
|
|
|
+}
|
|
|
+
|
|
|
+const fetchDetail = async () => {
|
|
|
+ try {
|
|
|
+ const res: any = await getPriceListDetail(id.value, businessSection.value, cuisineType.value);
|
|
|
+ if (res && res.code === 200 && res.data) {
|
|
|
+ applyDetailToForm(res);
|
|
|
+ } else {
|
|
|
+ const data = res?.data;
|
|
|
+ if (data) applyDetailToForm(res);
|
|
|
+ else ElMessage.error(res?.msg || "获取详情失败");
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.error("获取价目表详情失败:", error);
|
|
|
+ ElMessage.error("获取详情失败");
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+function buildSubmitPayload(isDraft: boolean) {
|
|
|
+ const storeId = localGet("createdId") as string;
|
|
|
+ const payload: any = {
|
|
|
+ storeId: storeId ? parseInt(storeId, 10) : undefined,
|
|
|
+ name: formModel.name.trim(),
|
|
|
+ totalPrice: parseFloat(formModel.totalPrice) || 0,
|
|
|
+ images: formModel.images || undefined,
|
|
|
+ imageContent: formModel.imageContent || undefined,
|
|
|
+ detailContent: formModel.detailContent?.trim() || undefined,
|
|
|
+ extraNote: formModel.extraNote?.trim() || undefined,
|
|
|
+ needReserve: formModel.needReserve,
|
|
|
+ reserveRule: formModel.reserveRule?.trim() || undefined,
|
|
|
+ peopleLimit: formModel.peopleLimit?.trim() || undefined,
|
|
|
+ usageRule: formModel.usageRule?.trim() || undefined
|
|
|
+ };
|
|
|
+ const moduleType = getModuleTypeByBusinessSection(businessSection.value);
|
|
|
+ if (moduleType === MODULE_TYPES.FOOD) {
|
|
|
+ if (formModel.formType === "dish") {
|
|
|
+ payload.cuisineType = CUISINE_TYPE.SINGLE;
|
|
|
+ payload.rawJson = JSON.stringify(
|
|
|
+ formModel.foodIngredients.map(it => ({
|
|
|
+ name: (it.ingredientName || "").trim(),
|
|
|
+ height: (it.weight || "").trim(),
|
|
|
+ cost: parseFloat(it.costPrice) || 0,
|
|
|
+ suggest: parseFloat(it.costPrice) || 0
|
|
|
+ }))
|
|
|
+ );
|
|
|
+ } else {
|
|
|
+ payload.cuisineType = CUISINE_TYPE.COMBO;
|
|
|
+ payload.groupJson = JSON.stringify(
|
|
|
+ formModel.foodPackageCategories
|
|
|
+ .filter(g => (g.dishes || []).length > 0)
|
|
|
+ .map(g => ({
|
|
|
+ categoryName: (g.category || "").trim(),
|
|
|
+ items: (g.dishes || []).map(d => ({
|
|
|
+ cuisineId: d.itemId || undefined,
|
|
|
+ cuisineName: (d.dishName || "").trim(),
|
|
|
+ quantity: parseInt(d.quantity, 10) || 1,
|
|
|
+ unit: (d.unit || "份").trim()
|
|
|
+ }))
|
|
|
+ }))
|
|
|
+ );
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ // 休闲娱乐、生活服务:服务项目 JSON(与商家端 generalPrice 一致)
|
|
|
+ payload.serviceJson = JSON.stringify(
|
|
|
+ formModel.generalServiceItems.map(it => ({
|
|
|
+ name: (it.serviceName || "").trim(),
|
|
|
+ num: parseInt(it.quantity, 10) || 1,
|
|
|
+ unit: (it.unit || "份").trim(),
|
|
|
+ details: (it.description || "").trim()
|
|
|
+ }))
|
|
|
+ );
|
|
|
+ }
|
|
|
+ if (id.value) payload.id = parseInt(id.value, 10);
|
|
|
+ return payload;
|
|
|
+}
|
|
|
+
|
|
|
+async function submit(isDraft: boolean) {
|
|
|
+ if (!ruleFormRef.value) return;
|
|
|
+ await ruleFormRef.value.validate(async valid => {
|
|
|
+ if (!valid) return;
|
|
|
+ submitting.value = true;
|
|
|
+ try {
|
|
|
+ const payload = buildSubmitPayload(isDraft);
|
|
|
+ const api = id.value ? updatePriceItem : addPriceItem;
|
|
|
+ const res: any = await api(payload);
|
|
|
+ if (res && res.code === 200) {
|
|
|
+ ElMessage.success(id.value ? "保存成功" : "新建成功");
|
|
|
+ router.back();
|
|
|
+ } else {
|
|
|
+ ElMessage.error(res?.msg || "操作失败");
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.error("提交失败:", error);
|
|
|
+ ElMessage.error("操作失败");
|
|
|
+ } finally {
|
|
|
+ submitting.value = false;
|
|
|
+ }
|
|
|
+ });
|
|
|
+}
|
|
|
+
|
|
|
+const handleSubmit = () => submit(false);
|
|
|
+const handleSaveDraft = () => submit(false); // 存草稿与确定共用提交,若后端有草稿状态可再区分
|
|
|
+
|
|
|
+const goBack = () => router.back();
|
|
|
+
|
|
|
+// 详情模式下点击「编辑」:去掉 mode=detail 进入编辑
|
|
|
+function goEdit() {
|
|
|
+ const query: Record<string, string> = {
|
|
|
+ id: id.value,
|
|
|
+ businessSection: businessSection.value
|
|
|
+ };
|
|
|
+ if (cuisineType.value !== undefined && cuisineType.value !== null) {
|
|
|
+ query.cuisineType = String(cuisineType.value);
|
|
|
+ }
|
|
|
+ router.replace({ path: "/priceList/edit", query });
|
|
|
+}
|
|
|
+
|
|
|
+function auditStatusText(status: number | null): string {
|
|
|
+ if (status === null || status === undefined) return "--";
|
|
|
+ const map: Record<number, string> = { 0: "审核中", 1: "已通过", 2: "已拒绝" };
|
|
|
+ return map[status] ?? "--";
|
|
|
+}
|
|
|
+
|
|
|
+function shelfStatusText(status: number | null): string {
|
|
|
+ if (status === 1) return "上架";
|
|
|
+ if (status === 2) return "下架";
|
|
|
+ return "--";
|
|
|
+}
|
|
|
+
|
|
|
+async function loadDishOptions() {
|
|
|
+ const moduleType = getModuleTypeByBusinessSection(businessSection.value);
|
|
|
+ if (moduleType !== MODULE_TYPES.FOOD) return;
|
|
|
+ try {
|
|
|
+ const res: any = await getCuisineSingleNameList();
|
|
|
+ if (res?.code === 200 && Array.isArray(res?.data)) {
|
|
|
+ dishOptions.value = (res.data as any[]).map((it: any) => ({
|
|
|
+ id: it.id ?? it.value,
|
|
|
+ name: it.name ?? it.label ?? ""
|
|
|
+ }));
|
|
|
+ }
|
|
|
+ } catch (e) {
|
|
|
+ console.error("获取单品列表失败", e);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+onMounted(() => {
|
|
|
+ id.value = (route.query.id as string) || "";
|
|
|
+ businessSection.value = (route.query.businessSection as string) || localGet("businessSection") || "1";
|
|
|
+ const ct = route.query.cuisineType;
|
|
|
+ cuisineType.value = ct !== undefined && ct !== null && ct !== "" ? Number(ct) : undefined;
|
|
|
+
|
|
|
+ // 特色美食新建:从列表页「新建」选择菜品/套餐带入的 createMode
|
|
|
+ const createMode = route.query.createMode as string;
|
|
|
+ if (!id.value && getModuleTypeByBusinessSection(businessSection.value) === MODULE_TYPES.FOOD) {
|
|
|
+ if (createMode === "package" || createMode === "dish") {
|
|
|
+ formModel.formType = createMode;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (formModel.formType === "dish" && !formModel.foodIngredients.length) {
|
|
|
+ formModel.foodIngredients = [{ ingredientName: "", weight: "", costPrice: "" }];
|
|
|
+ }
|
|
|
+ if (formModel.formType === "package" && !formModel.foodPackageCategories.length) {
|
|
|
+ formModel.foodPackageCategories = [{ category: "", dishes: [{ itemId: "", dishName: "", quantity: "1", unit: "份" }] }];
|
|
|
+ }
|
|
|
+
|
|
|
+ if (id.value) {
|
|
|
+ fetchDetail();
|
|
|
+ } else if (getModuleTypeByBusinessSection(businessSection.value) !== MODULE_TYPES.FOOD) {
|
|
|
+ // 休闲娱乐/生活服务新建时默认显示一个服务项
|
|
|
+ if (!formModel.generalServiceItems.length) {
|
|
|
+ formModel.generalServiceItems = [{ serviceName: "", quantity: "", unit: "份", description: "" }];
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (getModuleTypeByBusinessSection(businessSection.value) === MODULE_TYPES.FOOD) {
|
|
|
+ loadDishOptions();
|
|
|
+ }
|
|
|
+});
|
|
|
+</script>
|
|
|
+
|
|
|
+<style scoped lang="scss">
|
|
|
+.price-edit-page {
|
|
|
+ min-height: 100vh;
|
|
|
+ padding-bottom: 80px;
|
|
|
+ background-color: #f5f6f8;
|
|
|
+}
|
|
|
+.page-header {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ height: 56px;
|
|
|
+ padding: 0 24px;
|
|
|
+ background: #ffffff;
|
|
|
+ border-bottom: 1px solid #ebeef5;
|
|
|
+ .header-left {
|
|
|
+ display: flex;
|
|
|
+ gap: 6px;
|
|
|
+ align-items: center;
|
|
|
+ font-size: 14px;
|
|
|
+ color: #606266;
|
|
|
+ cursor: pointer;
|
|
|
+ &:hover {
|
|
|
+ color: #409eff;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .back-icon {
|
|
|
+ font-size: 18px;
|
|
|
+ }
|
|
|
+ .page-title {
|
|
|
+ flex: 1;
|
|
|
+ margin: 0;
|
|
|
+ margin-left: 24px;
|
|
|
+ font-size: 18px;
|
|
|
+ font-weight: 600;
|
|
|
+ color: #303133;
|
|
|
+ text-align: center;
|
|
|
+ }
|
|
|
+ .header-right {
|
|
|
+ padding: 4px;
|
|
|
+ color: #909399;
|
|
|
+ cursor: pointer;
|
|
|
+ &:hover {
|
|
|
+ color: #303133;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .close-icon {
|
|
|
+ font-size: 20px;
|
|
|
+ }
|
|
|
+}
|
|
|
+.page-content {
|
|
|
+ padding: 24px;
|
|
|
+}
|
|
|
+.two-column-form {
|
|
|
+ display: flex;
|
|
|
+ flex-wrap: wrap;
|
|
|
+ gap: 32px;
|
|
|
+ padding: 24px 32px 32px;
|
|
|
+ background: #ffffff;
|
|
|
+ border-radius: 8px;
|
|
|
+ box-shadow: 0 1px 4px rgb(0 0 0 / 6%);
|
|
|
+}
|
|
|
+.form-column {
|
|
|
+ flex: 1;
|
|
|
+ min-width: 320px;
|
|
|
+ max-width: 80%;
|
|
|
+}
|
|
|
+.form-column-left {
|
|
|
+ padding-right: 24px;
|
|
|
+ border-right: 1px solid #ebeef5;
|
|
|
+}
|
|
|
+.price-form {
|
|
|
+ :deep(.el-form-item) {
|
|
|
+ margin-bottom: 20px;
|
|
|
+ }
|
|
|
+ :deep(.el-form-item__label) {
|
|
|
+ font-size: 14px;
|
|
|
+ color: #606266;
|
|
|
+ }
|
|
|
+ .form-input {
|
|
|
+ width: 100%;
|
|
|
+ max-width: 360px;
|
|
|
+ &.price-input {
|
|
|
+ max-width: 200px;
|
|
|
+ }
|
|
|
+ &.dish-select,
|
|
|
+ &.unit-select {
|
|
|
+ max-width: 200px;
|
|
|
+ }
|
|
|
+ &.qty-input {
|
|
|
+ max-width: 100px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .form-textarea {
|
|
|
+ width: 100%;
|
|
|
+ max-width: 100%;
|
|
|
+ }
|
|
|
+}
|
|
|
+.form-block {
|
|
|
+ padding: 16px 0;
|
|
|
+ margin-bottom: 24px;
|
|
|
+ border-top: 1px solid #f0f0f0;
|
|
|
+ .block-head {
|
|
|
+ display: flex;
|
|
|
+ gap: 12px;
|
|
|
+ align-items: center;
|
|
|
+ margin-bottom: 12px;
|
|
|
+ }
|
|
|
+ .block-title {
|
|
|
+ font-size: 14px;
|
|
|
+ font-weight: 500;
|
|
|
+ color: #303133;
|
|
|
+ }
|
|
|
+ .btn-add {
|
|
|
+ font-size: 14px;
|
|
|
+ }
|
|
|
+ .block-tip {
|
|
|
+ margin-left: auto;
|
|
|
+ font-size: 12px;
|
|
|
+ color: #909399;
|
|
|
+ }
|
|
|
+ .empty-tip {
|
|
|
+ padding: 12px 0;
|
|
|
+ font-size: 13px;
|
|
|
+ color: #909399;
|
|
|
+ }
|
|
|
+ .block-item {
|
|
|
+ position: relative;
|
|
|
+ padding: 12px 0;
|
|
|
+ padding: 12px 16px;
|
|
|
+ margin-bottom: 12px;
|
|
|
+ background: #fafafa;
|
|
|
+ border: 1px solid #ebeef5;
|
|
|
+ border-radius: 6px;
|
|
|
+ }
|
|
|
+ .ingredient-item {
|
|
|
+ display: flex;
|
|
|
+ flex-flow: column wrap;
|
|
|
+ gap: 0 16px;
|
|
|
+ align-items: flex-start;
|
|
|
+ :deep(.el-form-item) {
|
|
|
+ margin-bottom: 12px;
|
|
|
+ }
|
|
|
+ .link-delete {
|
|
|
+ position: absolute;
|
|
|
+ top: 12px;
|
|
|
+ right: 12px;
|
|
|
+ font-size: 13px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .service-item {
|
|
|
+ display: flex;
|
|
|
+ flex-flow: column wrap;
|
|
|
+ gap: 0 16px;
|
|
|
+ align-items: flex-start;
|
|
|
+ :deep(.el-form-item) {
|
|
|
+ margin-bottom: 12px;
|
|
|
+ }
|
|
|
+ .form-textarea {
|
|
|
+ max-width: 360px;
|
|
|
+ }
|
|
|
+ .service-unit-select {
|
|
|
+ min-width: 120px;
|
|
|
+ :deep(.el-select__wrapper),
|
|
|
+ :deep(.el-input__wrapper) {
|
|
|
+ min-width: 120px;
|
|
|
+ }
|
|
|
+ :deep(.el-input__inner) {
|
|
|
+ min-width: 80px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .link-delete {
|
|
|
+ position: absolute;
|
|
|
+ top: 12px;
|
|
|
+ right: 12px;
|
|
|
+ font-size: 13px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .btn-recommend {
|
|
|
+ display: inline-block;
|
|
|
+ margin-top: 8px;
|
|
|
+ font-size: 14px;
|
|
|
+ }
|
|
|
+ .price-list-group {
|
|
|
+ .dish-row {
|
|
|
+ display: flex;
|
|
|
+ flex-flow: column wrap;
|
|
|
+ gap: 0 12px;
|
|
|
+ align-items: flex-start;
|
|
|
+ padding: 8px 0;
|
|
|
+ margin-bottom: 8px;
|
|
|
+ border-bottom: 1px dashed #ebeef5;
|
|
|
+ &:last-of-type {
|
|
|
+ border-bottom: none;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .package-unit-select {
|
|
|
+ min-width: 120px;
|
|
|
+ :deep(.el-select__wrapper),
|
|
|
+ :deep(.el-input__wrapper) {
|
|
|
+ min-width: 120px;
|
|
|
+ }
|
|
|
+ :deep(.el-input__inner) {
|
|
|
+ min-width: 80px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .group-actions {
|
|
|
+ display: flex;
|
|
|
+ gap: 16px;
|
|
|
+ margin-top: 12px;
|
|
|
+ }
|
|
|
+ .link-delete {
|
|
|
+ font-size: 13px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+.image-upload-wrap {
|
|
|
+ .price-list-upload {
|
|
|
+ :deep(.el-upload-list--picture-card) {
|
|
|
+ --el-upload-list-picture-card-size: 100px;
|
|
|
+ }
|
|
|
+ :deep(.el-upload--picture-card) {
|
|
|
+ width: 100px;
|
|
|
+ height: 100px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .image-tip {
|
|
|
+ margin-top: 4px;
|
|
|
+ font-size: 12px;
|
|
|
+ color: #909399;
|
|
|
+ }
|
|
|
+}
|
|
|
+.page-footer {
|
|
|
+ z-index: 100;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ height: 64px;
|
|
|
+ background: #ffffff;
|
|
|
+ border-top: 1px solid #ebeef5;
|
|
|
+}
|
|
|
+.footer-inner {
|
|
|
+ display: flex;
|
|
|
+ gap: 12px;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ width: 100%;
|
|
|
+ max-width: 1100px;
|
|
|
+ padding: 0 24px;
|
|
|
+}
|
|
|
+.view-only-value {
|
|
|
+ font-size: 14px;
|
|
|
+ color: #606266;
|
|
|
+}
|
|
|
+.audit-status {
|
|
|
+ font-weight: 500;
|
|
|
+ &.audit-status--0 {
|
|
|
+ color: #e6a23c;
|
|
|
+ }
|
|
|
+ &.audit-status--1 {
|
|
|
+ color: #67c23a;
|
|
|
+ }
|
|
|
+ &.audit-status--2 {
|
|
|
+ color: #f56c6c;
|
|
|
+ }
|
|
|
+}
|
|
|
+</style>
|