Răsfoiți Sursa

Merge remote-tracking branch 'origin/development' into development

spy 2 săptămâni în urmă
părinte
comite
7736d8c1c4

+ 1 - 1
src/layouts/components/Header/components/PasswordDialog.vue

@@ -1,6 +1,6 @@
 <template>
   <!-- 修改密码对话框 -->
-  <el-dialog v-model="dialogVisible" title="修改密码1" width="500px" draggable :close-on-click-modal="false">
+  <el-dialog v-model="dialogVisible" title="修改密码" width="500px" draggable :close-on-click-modal="false">
     <el-form ref="passwordFormRef" :model="passwordForm" :rules="passwordRules" label-width="100px" label-position="left">
       <el-form-item label="输入原密码" prop="oldPassword">
         <el-input v-model="passwordForm.oldPassword" type="password" placeholder="请输入原密码" show-password clearable />

+ 25 - 16
src/stores/modules/auth.ts

@@ -36,24 +36,33 @@ export const useAuthStore = defineStore({
       const { data } = (await getAuthMenuListApi()) as any;
 
       const hasPermission = await usePermission();
-      if (!hasPermission) {
-        // 根据权限隐藏"门店装修"、"财务管理"和"证照管理"菜单
-        const hideMenuNames = ["storeDecoration", "financialManagement", "licenseManagement"];
-        // 递归查找并隐藏指定菜单
-        const hideMenus = (menuList: any[]) => {
-          menuList.forEach(menu => {
-            // 根据菜单名称判断是否需要隐藏
-            if (menu.name && hideMenuNames.includes(menu.name)) {
+      const hideMenuNames = ["storeDecoration", "financialManagement", "licenseManagement"];
+
+      // 递归处理菜单的显示/隐藏状态
+      const processMenus = (menuList: any[]) => {
+        menuList.forEach(menu => {
+          // 根据菜单名称判断是否需要处理
+          if (menu.name && hideMenuNames.includes(menu.name)) {
+            if (!hasPermission) {
+              // 如果没有权限,隐藏菜单
               menu.meta.isHide = true;
+            } else {
+              // 如果有权限,确保菜单显示(移除 isHide 或设置为 false)
+              if (menu.meta) {
+                menu.meta.isHide = false;
+              } else {
+                menu.meta = { isHide: false };
+              }
             }
-            // 递归处理子菜单
-            if (menu.children && menu.children.length > 0) {
-              hideMenus(menu.children);
-            }
-          });
-        };
-        hideMenus(data);
-      }
+          }
+          // 递归处理子菜单
+          if (menu.children && menu.children.length > 0) {
+            processMenus(menu.children);
+          }
+        });
+      };
+
+      processMenus(data);
 
       this.authMenuList = data;
     },

+ 19 - 16
src/utils/permission.ts

@@ -137,26 +137,29 @@ export async function checkMenuClickPermission(path?: string): Promise<{
     allowedPaths.push(FOOD_BUSINESS_LICENSE_PATH);
   }
 
+  const canClick = true;
   // 检查当前路径是否在允许访问的列表中
-  const canClick = allowedPaths.includes(path);
+  if (path) {
+    const canClick = allowedPaths.includes(path);
 
-  // 如果不可点击,根据权限状态显示相应的提示信息
-  if (!canClick) {
-    let message = "";
+    // 如果不可点击,根据权限状态显示相应的提示信息
+    if (!canClick) {
+      let message = "";
 
-    // 如果两者都为true,显示两行提示
-    if (contractManagement && foodBusinessLicense) {
-      message = "合同已到期,请上传最新合同。\n经营许可证已到期,请上传最新许可证。";
-    } else if (contractManagement) {
-      // 只有合同管理为true
-      message = "合同已到期,请上传最新合同。";
-    } else if (foodBusinessLicense) {
-      // 只有食品经营许可证为true
-      message = "经营许可证已到期,请上传最新许可证。";
-    }
+      // 如果两者都为true,显示两行提示
+      if (contractManagement && foodBusinessLicense) {
+        message = "合同已到期,请上传最新合同。\n经营许可证已到期,请上传最新许可证。";
+      } else if (contractManagement) {
+        // 只有合同管理为true
+        message = "合同已到期,请上传最新合同。";
+      } else if (foodBusinessLicense) {
+        // 只有食品经营许可证为true
+        message = "经营许可证已到期,请上传最新许可证。";
+      }
 
-    if (message) {
-      ElMessage.warning(message);
+      if (message) {
+        ElMessage.warning(message);
+      }
     }
   }
 

+ 16 - 6
src/views/financialManagement/cashApply.vue

@@ -11,7 +11,7 @@
       <!-- 可提现金额 -->
       <div class="section">
         <div class="section-title">可提现金额</div>
-        <div class="available-amount">¥{{ formatCurrency(availableAmount) }}</div>
+        <div class="available-amount">¥{{ formatNumber(availableAmount) }}</div>
       </div>
 
       <!-- 提现金额输入 -->
@@ -113,6 +113,21 @@ const cashDialogVisible = ref(false);
 const withdrawPassword = ref("");
 // 提现金额
 const withdrawAmount = ref();
+// 格式化数字为千分位
+const formatNumber = (value: any): string => {
+  if (value === null || value === undefined || value === "") {
+    return "0.00";
+  }
+  const num = typeof value === "string" ? parseFloat(value) : Number(value);
+  if (isNaN(num)) {
+    return "0.00";
+  }
+  // 保留两位小数并添加千分位
+  return num.toLocaleString("zh-CN", {
+    minimumFractionDigits: 2,
+    maximumFractionDigits: 2
+  });
+};
 // 密码输入处理(只允许数字)
 const handlePasswordInput = (value: string) => {
   withdrawPassword.value = value.replace(/\D/g, "");
@@ -148,11 +163,6 @@ const goBack = () => {
   router.back();
 };
 
-// 格式化金额
-const formatCurrency = (value: number) => {
-  return value.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 });
-};
-
 // 全部提现
 const handleWithdrawAll = () => {
   withdrawAmount.value = availableAmount.value.toString();

+ 18 - 2
src/views/financialManagement/index.vue

@@ -18,7 +18,7 @@
           <el-image :src="gold" class="gold" />
           <div class="summary-amount">
             <span class="currency">¥</span>
-            <span class="amount">{{ todayIncome }}</span>
+            <span class="amount">{{ formatNumber(todayIncome) }}</span>
             <span class="unit">元</span>
           </div>
         </div>
@@ -37,7 +37,7 @@
           </el-tooltip>
         </div>
         <div class="stat-amount">
-          {{ stat.amount }}
+          {{ formatNumber(stat.amount) }}
         </div>
         <!----:disabled="stat.key === 'withdraw' && isWithdrawDisabled(stat.amount)"-->
         <el-button type="primary" class="stat-btn" @click="handleAction(stat.key)">
@@ -176,6 +176,22 @@ const fetchGetTodayIncome = async () => {
 //   return numAmount === 0 || isNaN(numAmount);
 // };
 
+// 格式化数字为千分位
+const formatNumber = (value: any): string => {
+  if (value === null || value === undefined || value === "") {
+    return "0.00";
+  }
+  const num = typeof value === "string" ? parseFloat(value) : Number(value);
+  if (isNaN(num)) {
+    return "0.00";
+  }
+  // 保留两位小数并添加千分位
+  return num.toLocaleString("zh-CN", {
+    minimumFractionDigits: 2,
+    maximumFractionDigits: 2
+  });
+};
+
 const handleAction = async (key: string) => {
   if (key == "withdraw") {
     // 获取可提现金额

+ 18 - 3
src/views/financialManagement/reconciled.vue

@@ -25,15 +25,15 @@
           {{ reconciled.couponName }}
         </h3>
         <el-row class="couponRow">
-          <el-col :span="12"> 实际收益: +{{ ((reconciled.money || 0) / 100).toFixed(2) }} </el-col>
+          <el-col :span="12"> 实际收益: &yen;{{ formatNumber(reconciled.money / 100) }} </el-col>
           <el-col :span="12">
             <!-- {{ `技术服务费(${unposted.commission / 100 || 3}%)` }}: 后续后端会变成可控的-->
             {{ `技术服务费(${commissionRate}%):` }}
-            {{ reconciled.commission != null ? (reconciled.commission / 100).toFixed(2) : "--" }}
+            {{ formatNumber(reconciled.commission / 100) }}
           </el-col>
         </el-row>
         <el-row class="couponRow">
-          <el-col :span="12"> 售价: {{ reconciled.orderPrice != null ? reconciled.orderPrice : "--" }} </el-col>
+          <el-col :span="12"> 售价: &yen;{{ formatNumber(reconciled.orderPrice) }} </el-col>
         </el-row>
         <h3 class="orderInfo">订单信息</h3>
         <div>
@@ -67,6 +67,21 @@ const toDetail = (row: any) => {
   dialogVisible.value = true;
   reconciled.value = row;
 };
+// 格式化数字为千分位
+const formatNumber = (value: any): string => {
+  if (value === null || value === undefined || value === "") {
+    return "0.00";
+  }
+  const num = typeof value === "string" ? parseFloat(value) : Number(value);
+  if (isNaN(num)) {
+    return "0.00";
+  }
+  // 保留两位小数并添加千分位
+  return num.toLocaleString("zh-CN", {
+    minimumFractionDigits: 2,
+    maximumFractionDigits: 2
+  });
+};
 // ProTable 实例(需要在使用它的地方之前定义)
 const proTable = ref<ProTableInstance>();
 

+ 22 - 9
src/views/financialManagement/todayIncomeList.vue

@@ -25,16 +25,14 @@
           {{ unposted.storeName }}
         </h2>
         <el-row class="couponRow">
-          <el-col :span="12"> 实际收益: {{ ((unposted.money || 0) / 100).toFixed(2) }} </el-col>
+          <el-col :span="12"> 实际收益: &yen;{{ formatNumber(unposted.money / 100) }} </el-col>
           <el-col :span="12">
-            {{ `技术服务费(${commissionRate}%):` }}:
-            {{ unposted.commission != null ? (unposted.commission / 100).toFixed(2) : "--" }}
+            {{ `技术服务费(${commissionRate}%)` }}:
+            {{ formatNumber(unposted.commission / 100) }}
           </el-col>
         </el-row>
         <el-row class="couponRow">
-          <el-col :span="12">
-            售价: {{ ((Number(unposted.money) + Number(unposted.commission)) / 100).toFixed(2) || "0.00" }}
-          </el-col>
+          <el-col :span="12"> 售价: &yen;{{ formatNumber(unposted.orderPrice) }} </el-col>
         </el-row>
         <h3 class="orderInfo">订单信息</h3>
         <div>
@@ -67,6 +65,21 @@ const toDetail = (row: any) => {
   dialogVisible.value = true;
   unposted.value = row;
 };
+// 格式化数字为千分位
+const formatNumber = (value: any): string => {
+  if (value === null || value === undefined || value === "") {
+    return "0.00";
+  }
+  const num = typeof value === "string" ? parseFloat(value) : Number(value);
+  if (isNaN(num)) {
+    return "0.00";
+  }
+  // 保留两位小数并添加千分位
+  return num.toLocaleString("zh-CN", {
+    minimumFractionDigits: 2,
+    maximumFractionDigits: 2
+  });
+};
 // 返回
 const goBack = () => {
   router.back();
@@ -84,21 +97,21 @@ const columns = reactive<ColumnProps<any>[]>([
     prop: "money",
     label: "实际收益",
     render: scope => {
-      return ((scope.row.money || 0) / 100).toFixed(2) || "0.00";
+      return formatNumber(scope.row.money / 100);
     }
   },
   {
     prop: "price",
     label: "售价",
     render: scope => {
-      return ((Number(scope.row.money) + Number(scope.row.commission)) / 100).toFixed(2) || "0.00";
+      return formatNumber(Number(scope.row.money) + Number(scope.row.commission) / 100);
     }
   },
   {
     prop: "commission",
     label: "技术服务费",
     render: scope => {
-      return (scope.row.commission / 100).toFixed(2) || "0.00";
+      return formatNumber(scope.row.commission / 100);
     }
   },
   { prop: "operation", label: "操作", fixed: "right", width: 330 }

+ 19 - 6
src/views/financialManagement/unposted.vue

@@ -26,17 +26,15 @@
         </h2>
 
         <el-row class="couponRow">
-          <el-col :span="12">
-            实际收益: {{ unposted.incomeMoney || ((unposted?.money || 0) / 100).toFixed(2) || "0.00" }}
-          </el-col>
+          <el-col :span="12"> 实际收益: &yen;{{ formatNumber(unposted.money / 100) }} </el-col>
           <el-col :span="12">
             <!-- {{ `技术服务费(${unposted.commission / 100 || 3}%)` }}: 后续后端会变成可控的-->
-            {{ `技术服务费(${commissionRate}%):` }}:
-            {{ unposted.commission != null ? (unposted.commission / 100).toFixed(2) : "--" }}
+            {{ `技术服务费(${commissionRate}%)` }}:
+            {{ formatNumber(unposted.commission / 100) }}
           </el-col>
         </el-row>
         <el-row class="couponRow">
-          <el-col :span="12"> 售价: {{ unposted.orderPrice || "--" }} </el-col>
+          <el-col :span="12"> 售价: &yen;{{ formatNumber(unposted.orderPrice) }} </el-col>
         </el-row>
 
         <h3 class="orderInfo">订单信息</h3>
@@ -70,6 +68,21 @@ const toDetail = (row: any) => {
   dialogVisible.value = true;
   unposted.value = row;
 };
+// 格式化数字为千分位
+const formatNumber = (value: any): string => {
+  if (value === null || value === undefined || value === "") {
+    return "0.00";
+  }
+  const num = typeof value === "string" ? parseFloat(value) : Number(value);
+  if (isNaN(num)) {
+    return "0.00";
+  }
+  // 保留两位小数并添加千分位
+  return num.toLocaleString("zh-CN", {
+    minimumFractionDigits: 2,
+    maximumFractionDigits: 2
+  });
+};
 // ProTable 实例(需要在使用它的地方之前定义)
 const proTable = ref<ProTableInstance>();
 // 返回

+ 24 - 6
src/views/financialManagement/withdrawaRecord.vue

@@ -53,7 +53,7 @@
             </div>
             <div class="detail-item">
               <span class="detail-label">提现金额</span>
-              <span class="detail-value amount">¥{{ (withdrawalDetail.money / 100).toFixed(2) || "6146.6" }}</span>
+              <span class="detail-value amount">¥{{ formatNumber(withdrawalDetail.money / 100) }}</span>
             </div>
             <div class="detail-item">
               <span class="detail-label">发起提现时间</span>
@@ -90,14 +90,32 @@ import { ElMessageBox } from "element-plus/es";
 import { localGet } from "@/utils";
 const dialogVisible = ref(false);
 const withdrawalDetail = ref<any>({});
+// 格式化数字为千分位
+const formatNumber = (value: any): string => {
+  if (value === null || value === undefined || value === "") {
+    return "0.00";
+  }
+  const num = typeof value === "string" ? parseFloat(value) : Number(value);
+  if (isNaN(num)) {
+    return "0.00";
+  }
+  // 保留两位小数并添加千分位
+  return num.toLocaleString("zh-CN", {
+    minimumFractionDigits: 2,
+    maximumFractionDigits: 2
+  });
+};
 // ProTable 实例(需要在使用它的地方之前定义)
 const proTable = ref<ProTableInstance>();
 
 // 提现状态枚举
 const paymentStatusEnum = [
-  { label: "提现待审核", value: 3 },
+  { label: "提现中", value: 0 },
+  { label: "提现成功", value: 1 },
+  { label: "提现失败", value: 2 },
+  { label: "待审核", value: 3 },
   { label: "提现拒绝", value: 4 },
-  { label: "提现成功", value: 5 }
+  { label: "审核通过", value: 5 }
 ];
 
 // 表格配置项
@@ -141,16 +159,16 @@ const columns = reactive<ColumnProps<any>[]>([
     label: "提现状态",
     render: scope => {
       return scope.row.paymentStatus === 0
-        ? "提现中"
+        ? "进行中"
         : scope.row.paymentStatus === 1
           ? "提现成功"
           : scope.row.paymentStatus === 2
             ? "提现失败"
             : scope.row.paymentStatus === 3
-              ? "提现待审核"
+              ? "待审核"
               : scope.row.paymentStatus === 4
                 ? "提现拒绝"
-                : "提现待审核通过";
+                : "审核通过";
     },
     search: {
       el: "select",

+ 1 - 0
src/views/login/index.vue

@@ -929,6 +929,7 @@ const handleLogin = async () => {
         } else {
           localRemove("businessSection");
         }
+        sessionStorage.removeItem("ticketManagement_activeName");
         await initDynamicRouter();
 
         // 3.清空 tabs、keepAlive 数据

+ 15 - 4
src/views/ticketManagement/detail.vue

@@ -75,7 +75,7 @@
           <div class="detail-item">
             <div class="detail-label">库存</div>
             <div class="detail-value">
-              {{ voucherModel.singleQty + "张" || "--" }}
+              {{ hasValue(voucherModel.singleQty) ? voucherModel.singleQty + "张" : "--" }}
             </div>
           </div>
         </div>
@@ -89,14 +89,14 @@
           <div class="detail-item">
             <div class="detail-label">单日可用数量</div>
             <div class="detail-value">
-              {{ voucherModel.singleCanUse + "张" || "--" }}
+              {{ hasValue(voucherModel.singleCanUse) ? voucherModel.singleCanUse + "张" : "不限制" }}
             </div>
           </div>
           <!-- 限购数量 -->
           <div class="detail-item">
             <div class="detail-label">限购数量</div>
             <div class="detail-value">
-              {{ voucherModel.purchaseLimitCode + "张" || "--" }}
+              {{ hasValue(voucherModel.purchaseLimitCode) ? voucherModel.purchaseLimitCode + "张" : "不限制" }}
             </div>
           </div>
           <!-- 适用范围 -->
@@ -427,12 +427,23 @@ const getApplyScopeText = () => {
     return "全场通用";
   } else if (voucherModel.value.applyType === "2" || voucherModel.value.applyType == 2) {
     if (voucherModel.value.applyDesc) {
-      return `${voucherModel.value.applyDesc}外全场通用`;
+      return `${voucherModel.value.applyDesc}`;
     }
     return "全场通用";
   }
   return "--";
 };
+
+/**
+ * 判断值是否有意义(不是空、不是0、不是"0")
+ * @param value 要判断的值
+ * @returns 如果值有意义返回true,否则返回false
+ */
+const hasValue = (value: any): boolean => {
+  if (value === null || value === undefined) return false;
+  if (value === "" || value === "0" || value === 0) return false;
+  return true;
+};
 </script>
 
 <style scoped lang="scss">

+ 1 - 1
src/views/ticketManagement/index.vue

@@ -44,7 +44,7 @@
           v-if="canShowButton(scope.row.status, currentOperationPermissions.上架)"
           link
           type="primary"
-          @click="changeTypes(scope.row, isVoucher ? 1 : 5)"
+          @click="changeTypes(scope.row, 5)"
         >
           上架
         </el-button>

+ 3 - 36
src/views/ticketManagement/newCoupon.vue

@@ -108,7 +108,7 @@ import { ElMessage } from "element-plus";
 import { useRoute, useRouter } from "vue-router";
 import type { FormInstance } from "element-plus";
 import { getCouponDetail, addDiscountCoupon, editDiscountCoupon } from "@/api/modules/couponManagement";
-import { validatePositiveNumber, validatePositiveInteger, validateDateRange } from "@/utils/eleValidate";
+import { validatePositiveNumber, validatePositiveInteger, validateDateRange, validatePriceFormat } from "@/utils/eleValidate";
 import { localGet } from "@/utils";
 import { getVoucherDetail } from "@/api/modules/voucherManagement";
 // ==================== 响应式数据定义 ====================
@@ -126,7 +126,7 @@ const rules = reactive({
   nominalValue: [
     { required: true, message: "请输入面值" },
     {
-      validator: validatePositiveNumber("面值必须为正数"),
+      validator: validatePriceFormat("整数部分最多6位,小数部分最多2位"),
       trigger: "blur"
     }
   ],
@@ -175,23 +175,7 @@ const rules = reactive({
   minimumSpendingAmount: [
     { required: true, message: "请输入最低消费金额" },
     {
-      validator: (rule: any, value: any, callback: any) => {
-        if (couponModel.value.hasMinimumSpend === 1) {
-          if (!value || value.toString().trim() === "") {
-            callback(new Error("请输入最低消费金额"));
-            return;
-          }
-          const strValue = value.toString().trim();
-          // 检查是否有前导零(除了单独的"0"或"0."开头的小数)
-          if (strValue.length > 1 && strValue.startsWith("0") && strValue !== "0" && !strValue.startsWith("0.")) {
-            callback(new Error("最低消费金额必须为正数"));
-            return;
-          }
-          validatePositiveNumber("最低消费金额必须为正数")(rule, value, callback);
-        } else {
-          callback();
-        }
-      },
+      validator: validatePriceFormat("整数部分最多6位,小数部分最多2位"),
       trigger: "blur"
     }
   ]
@@ -291,23 +275,6 @@ watch(
   }
 );
 
-/**
- * 监听最低消费金额变化
- * 当最低消费金额大于0时,自动设置为"是",否则设置为"否"
- */
-// watch(
-//   () => couponModel.value.minimumSpendingAmount,
-//   newVal => {
-//     if (isInitializing.value) return;
-//     const amount = Number(newVal);
-//     if (!isNaN(amount) && amount > 0) {
-//       couponModel.value.hasMinimumSpend = 1;
-//     } else {
-//       couponModel.value.hasMinimumSpend = 0;
-//     }
-//   }
-// );
-
 // ==================== 事件处理函数 ====================
 /**
  * 组件挂载时初始化

+ 190 - 69
src/views/ticketManagement/newVoucher.vue

@@ -5,7 +5,7 @@
       <el-button @click="goBack"> 返回 </el-button>
       <h2 class="title">{{ type == "add" ? "新建" : "编辑" }}代金券</h2>
     </div>
-    <el-form :model="voucherModel" ref="ruleFormRef" :rules="rules" label-width="120px" class="formBox">
+    <el-form :model="voucherModel" ref="ruleFormRef" :rules="rules" label-width="130px" class="formBox">
       <div class="content">
         <!-- 左侧内容区域 -->
         <div class="contentLeft">
@@ -181,11 +181,25 @@
           <div class="model">
             <h3 style="font-weight: bold">使用规则:</h3>
             <!-- 单日可用数量 -->
-            <el-form-item label="单日可用数量(张)" prop="singleCanUse">
+            <el-form-item label="单日可用数量(张)" prop="singleCanUseType">
+              <el-radio-group v-model="voucherModel.singleCanUseType" class="ml-4">
+                <el-radio v-for="status in dailyUseLimitList" :value="status.value" :key="status.value">
+                  {{ status.label }}
+                </el-radio>
+              </el-radio-group>
+            </el-form-item>
+            <el-form-item label="" prop="singleCanUse" v-if="voucherModel.singleCanUseType == 2">
               <el-input v-model="voucherModel.singleCanUse" maxlength="15" placeholder="请输入" clearable />
             </el-form-item>
             <!-- 限购数量 -->
-            <el-form-item label="限购数量(张)" prop="purchaseLimitCode">
+            <el-form-item label="限购数量(张)" prop="purchaseLimitType">
+              <el-radio-group v-model="voucherModel.purchaseLimitType" class="ml-4">
+                <el-radio v-for="status in purchaseLimitList" :value="status.value" :key="status.value">
+                  {{ status.label }}
+                </el-radio>
+              </el-radio-group>
+            </el-form-item>
+            <el-form-item label="" prop="purchaseLimitCode" v-if="voucherModel.purchaseLimitType == 2">
               <el-input v-model="voucherModel.purchaseLimitCode" maxlength="15" placeholder="请输入" clearable />
             </el-form-item>
             <!-- 适用范围 -->
@@ -323,12 +337,12 @@ const rules = reactive({
           callback(new Error("开始售卖时间不能早于当前时间"));
           return;
         }
-        // 验证开始时间必须早于结束时间
+        // 验证开始时间不能晚于结束时间
         const endDate = voucherModel.value.endDate;
         if (endDate) {
           const end = new Date(endDate);
-          if (selectedDate >= end) {
-            callback(new Error("开始售卖时间必须早于结束售卖时间"));
+          if (selectedDate > end) {
+            callback(new Error("开始售卖时间不能晚于结束售卖时间"));
             return;
           }
         }
@@ -353,12 +367,12 @@ const rules = reactive({
           callback(new Error("结束售卖时间不能早于当前时间"));
           return;
         }
-        // 验证结束时间必须晚于开始时间
+        // 验证结束时间不能早于开始时间
         const startDate = voucherModel.value.startDate;
         if (startDate) {
           const start = new Date(startDate);
-          if (selectedDate <= start) {
-            callback(new Error("开始售卖时间必须早于结束售卖时间"));
+          if (selectedDate < start) {
+            callback(new Error("结束售卖时间不能早于开始售卖时间"));
             return;
           }
         }
@@ -488,13 +502,9 @@ const rules = reactive({
     }
   ],
   singleQty: [
+    { required: true, message: "请输入库存数量" },
     {
       validator: (rule: any, value: any, callback: any) => {
-        // 非必填,如果为空则直接通过
-        if (!value || value.toString().trim() === "") {
-          callback();
-          return;
-        }
         // 先验证是否为正整数
         validatePositiveInteger("库存必须为正整数", { required: false })(rule, value, (error: any) => {
           if (error) {
@@ -515,72 +525,88 @@ const rules = reactive({
       trigger: "blur"
     }
   ],
+  singleCanUseType: [{ required: true, message: "请选择单日可用数量类型" }],
   singleCanUse: [
     {
-      validator: validatePositiveInteger("单日可用数量必须为正整数", { required: false }),
-      trigger: "blur"
-    },
-    {
+      required: true,
       validator: (rule: any, value: any, callback: any) => {
-        // 如果值为空,不进行验证
-        if (!value || value.toString().trim() === "") {
-          callback();
-          return;
-        }
-        const stock = voucherModel.value.singleQty;
-        // 如果库存为空,不进行验证(由库存的验证规则处理)
-        if (!stock || stock.toString().trim() === "") {
-          callback();
-          return;
-        }
-        const useNum = Number(value);
-        const stockNum = Number(stock);
-        // 如果转换失败,不进行验证(由其他验证规则处理)
-        if (isNaN(useNum) || isNaN(stockNum)) {
+        if (voucherModel.value.singleCanUseType == 2) {
+          if (!value || value.toString().trim() === "") {
+            callback(new Error("请输入单日可用数量"));
+            return;
+          }
+          // 验证是否为正整数
+          validatePositiveInteger("单日可用数量必须为正整数", { required: false })(rule, value, (error: any) => {
+            if (error) {
+              callback(error);
+              return;
+            }
+            const stock = voucherModel.value.singleQty;
+            // 如果库存为空,不进行验证(由库存的验证规则处理)
+            if (!stock || stock.toString().trim() === "") {
+              callback();
+              return;
+            }
+            const useNum = Number(value);
+            const stockNum = Number(stock);
+            // 如果转换失败,不进行验证(由其他验证规则处理)
+            if (isNaN(useNum) || isNaN(stockNum)) {
+              callback();
+              return;
+            }
+            // 验证单日可用数量不能多于库存
+            if (useNum > stockNum) {
+              callback(new Error("单日可用数量不能多于库存"));
+              return;
+            }
+            callback();
+          });
+        } else {
           callback();
-          return;
-        }
-        // 验证单日可用数量不能多于库存
-        if (useNum > stockNum) {
-          callback(new Error("单日可用数量不能多于库存"));
-          return;
         }
-        callback();
       },
       trigger: "blur"
     }
   ],
+  purchaseLimitType: [{ required: true, message: "请选择限购数量类型" }],
   purchaseLimitCode: [
     {
-      validator: validatePositiveInteger("限购数量必须为正整数", { required: false }),
-      trigger: "blur"
-    },
-    {
+      required: true,
       validator: (rule: any, value: any, callback: any) => {
-        // 如果值为空,不进行验证
-        if (!value || value.toString().trim() === "") {
-          callback();
-          return;
-        }
-        const stock = voucherModel.value.singleQty;
-        // 如果库存为空,不进行验证(由库存的验证规则处理)
-        if (!stock || stock.toString().trim() === "") {
-          callback();
-          return;
-        }
-        const limitNum = Number(value);
-        const stockNum = Number(stock);
-        // 如果转换失败,不进行验证(由其他验证规则处理)
-        if (isNaN(limitNum) || isNaN(stockNum)) {
+        if (voucherModel.value.purchaseLimitType == 2) {
+          if (!value || value.toString().trim() === "") {
+            callback(new Error("请输入限购数量"));
+            return;
+          }
+          // 验证是否为正整数
+          validatePositiveInteger("限购数量必须为正整数", { required: false })(rule, value, (error: any) => {
+            if (error) {
+              callback(error);
+              return;
+            }
+            const stock = voucherModel.value.singleQty;
+            // 如果库存为空,不进行验证(由库存的验证规则处理)
+            if (!stock || stock.toString().trim() === "") {
+              callback();
+              return;
+            }
+            const limitNum = Number(value);
+            const stockNum = Number(stock);
+            // 如果转换失败,不进行验证(由其他验证规则处理)
+            if (isNaN(limitNum) || isNaN(stockNum)) {
+              callback();
+              return;
+            }
+            // 验证限购数量不能多于库存
+            if (limitNum > stockNum) {
+              callback(new Error("限购数量不能多于库存"));
+              return;
+            }
+            callback();
+          });
+        } else {
           callback();
-          return;
-        }
-        // 验证限购数量不能多于库存
-        if (limitNum > stockNum) {
-          callback(new Error("限购数量不能多于库存"));
-          return;
         }
-        callback();
       },
       trigger: "blur"
     }
@@ -636,8 +662,12 @@ const voucherModel = ref<any>({
   disableDateList: [],
   // 库存
   singleQty: "",
+  // 单日可用数量类型:1-不限制,2-限制
+  singleCanUseType: "1",
   // 单日可用数量
   singleCanUse: "",
+  // 限购数量类型:1-不限制,2-限制
+  purchaseLimitType: "1",
   // 限购数量
   purchaseLimitCode: "",
   // 适用范围类型:0-全场通用,1-部分不可用
@@ -677,6 +707,18 @@ const applicableScopeList = ref([
   { value: "2", label: "部分不可用" }
 ]);
 
+// 单日可用数量类型列表
+const dailyUseLimitList = ref([
+  { value: "1", label: "不限制" },
+  { value: "2", label: "限制" }
+]);
+
+// 限购数量类型列表
+const purchaseLimitList = ref([
+  { value: "1", label: "不限制" },
+  { value: "2", label: "限制" }
+]);
+
 // 星期选项列表
 const weekdayList = ref([
   { name: "周一", id: "0", oName: "星期一" },
@@ -768,12 +810,12 @@ watch(
   () => voucherModel.value.singleQty,
   () => {
     if (isInitializing.value) return;
-    if (voucherModel.value.singleCanUse) {
+    if (voucherModel.value.singleCanUseType == 2 && voucherModel.value.singleCanUse) {
       nextTick(() => {
         ruleFormRef.value?.validateField("singleCanUse");
       });
     }
-    if (voucherModel.value.purchaseLimitCode) {
+    if (voucherModel.value.purchaseLimitType == 2 && voucherModel.value.purchaseLimitCode) {
       nextTick(() => {
         ruleFormRef.value?.validateField("purchaseLimitCode");
       });
@@ -782,6 +824,54 @@ watch(
 );
 
 /**
+ * 监听单日可用数量类型变化
+ * 当切换到"不限制"时,清空输入框的值
+ */
+watch(
+  () => voucherModel.value.singleCanUseType,
+  newVal => {
+    if (newVal == 1) {
+      voucherModel.value.singleCanUse = "";
+      nextTick(() => {
+        ruleFormRef.value?.clearValidate("singleCanUse");
+      });
+    }
+  }
+);
+
+/**
+ * 监听限购数量类型变化
+ * 当切换到"不限制"时,清空输入框的值
+ */
+watch(
+  () => voucherModel.value.purchaseLimitType,
+  newVal => {
+    if (newVal == 1) {
+      voucherModel.value.purchaseLimitCode = "";
+      nextTick(() => {
+        ruleFormRef.value?.clearValidate("purchaseLimitCode");
+      });
+    }
+  }
+);
+
+/**
+ * 监听适用范围类型变化
+ * 当切换到"全场通用"时,清空输入框的值
+ */
+watch(
+  () => voucherModel.value.applyType,
+  newVal => {
+    if (newVal == 1) {
+      voucherModel.value.applyDesc = "";
+      nextTick(() => {
+        ruleFormRef.value?.clearValidate("applyDesc");
+      });
+    }
+  }
+);
+
+/**
  * 监听使用开始时间变化
  * 更新虚拟字段以支持表单验证
  */
@@ -876,6 +966,27 @@ onMounted(async () => {
         voucherModel.value.disableDateList = [null];
       }
     }
+    // 处理单日可用数量类型:如果有值,设置为"限制",否则设置为"不限制"
+    if (voucherModel.value.singleCanUse && voucherModel.value.singleCanUse.toString().trim() !== "") {
+      voucherModel.value.singleCanUseType = "2";
+    } else {
+      voucherModel.value.singleCanUseType = "1";
+      voucherModel.value.singleCanUse = "";
+    }
+    // 处理限购数量类型:如果有值,设置为"限制",否则设置为"不限制"
+    if (voucherModel.value.purchaseLimitCode && voucherModel.value.purchaseLimitCode.toString().trim() !== "") {
+      voucherModel.value.purchaseLimitType = "2";
+    } else {
+      voucherModel.value.purchaseLimitType = "1";
+      voucherModel.value.purchaseLimitCode = "";
+    }
+    // 处理适用范围类型:如果有值,设置为"部分不可用",否则设置为"全场通用"
+    if (voucherModel.value.applyDesc && voucherModel.value.applyDesc.toString().trim() !== "") {
+      voucherModel.value.applyType = "2";
+    } else {
+      voucherModel.value.applyType = "1";
+      voucherModel.value.applyDesc = "";
+    }
     console.log(voucherModel.value);
   }
 
@@ -994,10 +1105,20 @@ const handleSubmit = async (submitType?: string) => {
         .join(";");
     }
   }
+  // 处理单日可用数量:如果选择"不限制",清空值
+  if (params.singleCanUseType == 1) {
+    params.singleCanUse = "";
+  }
+  // 处理限购数量:如果选择"不限制",清空值
+  if (params.purchaseLimitType == 1) {
+    params.purchaseLimitCode = "";
+  }
   params.dataType = submitType ? 1 : 0;
   delete params.unavailableWeekdays;
   delete params.unavailableHolidays;
   delete params.disableDateList;
+  delete params.singleCanUseType;
+  delete params.purchaseLimitType;
   console.log("提交参数:", params);
   if (submitType) {
     if (!voucherModel.value.name) {
@@ -1047,7 +1168,7 @@ const disabledEndDate = (time: Date) => {
   if (voucherModel.value.startDate) {
     const startDate = new Date(voucherModel.value.startDate);
     startDate.setHours(0, 0, 0, 0);
-    return time.getTime() <= startDate.getTime();
+    return time.getTime() < startDate.getTime();
   }
   return false;
 };