skyline 1 miesiąc temu
rodzic
commit
1c656056eb

+ 1 - 47
haha-admin-web/src/router/modules/marketing.ts

@@ -2,20 +2,13 @@
  * 营销中心路由配置
  *
  * 【统一入口说明】
- * - /marketing/activity  : 统一活动管理入口(已整合邀请有礼 activityType=4)
+ * - /marketing/activity  : 统一活动管理入口
  *   支持类型:1-首单立减 2-优惠折扣 3-商品满减 4-邀请有礼
  *   后端通过 UnifiedActivityService 根据 activityType 分发到对应 Service
  *
- * 【向后兼容路由】
- * - /marketing/invite     : 邀请活动独立管理页面(保留,向后兼容)
- *   包含子路由:index(活动管理) / statistics(数据统计) / records(邀请记录)
- *   该路由使用独立的 InviteActivity API(/marketing/invite/*),与统一入口共存
- *
  * 【小程序端 API】
  * - /invite/*             : 小程序端专属接口(haha-miniapp 模块的 InviteController)
- *   与管理端完全独立,直接调用 InviteActivityService
  */
-import Layout from "@/layout/index.vue";
 
 export default {
   path: "/marketing",
@@ -95,45 +88,6 @@ export default {
           }
         }
       ]
-    },
-    {
-      path: "/marketing/invite",
-      component: Layout,
-      redirect: "/marketing/invite/index",
-      meta: {
-        icon: "ep:present",
-        title: "邀请活动",
-        rank: 4
-      },
-      children: [
-        {
-          path: "index",
-          name: "InviteActivity",
-          component: () => import("@/views/marketing/invite/index.vue"),
-          meta: {
-            icon: "ep:list",
-            title: "活动管理"
-          }
-        },
-        {
-          path: "statistics",
-          name: "InviteStatistics",
-          component: () => import("@/views/marketing/invite/statistics.vue"),
-          meta: {
-            icon: "ep:data-analysis",
-            title: "数据统计"
-          }
-        },
-        {
-          path: "records",
-          name: "InviteRecords",
-          component: () => import("@/views/marketing/invite/records.vue"),
-          meta: {
-            icon: "ep:document",
-            title: "邀请记录"
-          }
-        }
-      ]
     }
   ]
 } satisfies RouteConfigsTable;

+ 31 - 103
haha-admin-web/src/views/marketing/activity/utils/components/InviteRewardBlock.vue

@@ -10,7 +10,7 @@
     <!-- 奖励规则类型 -->
     <el-form-item label="奖励规则类型">
       <el-select
-        v-model="localData.rewardRuleType"
+        :model-value="formData.rewardRuleType"
         disabled
         style="width: 200px"
       >
@@ -27,11 +27,12 @@
     <!-- 邀请人优惠券模板 -->
     <el-form-item label="邀请人优惠券" required>
       <el-select
-        v-model="localData.inviterCouponTemplateId"
+        :model-value="formData.inviterCouponTemplateId"
         placeholder="请选择邀请人优惠券模板"
         filterable
         clearable
         style="width: 100%"
+        @update:model-value="(val: any) => { formData.inviterCouponTemplateId = val }"
       >
         <el-option
           v-for="item in couponTemplateList"
@@ -51,11 +52,12 @@
     <!-- 被邀请人优惠券模板 -->
     <el-form-item label="被邀请人优惠券">
       <el-select
-        v-model="localData.inviteeCouponTemplateId"
+        :model-value="formData.inviteeCouponTemplateId"
         placeholder="可选:选择被邀请人新人券"
         filterable
         clearable
         style="width: 100%"
+        @update:model-value="(val: any) => { formData.inviteeCouponTemplateId = val }"
       >
         <el-option
           v-for="item in couponTemplateList"
@@ -75,12 +77,13 @@
     <!-- 每日邀请上限 -->
     <el-form-item label="每日邀请上限">
       <el-input-number
-        v-model="localData.dailyLimit"
+        :model-value="formData.dailyLimit"
         :min="1"
         :max="100"
         :step="1"
         placeholder="默认10"
         controls-position="right"
+        @update:model-value="(val: number) => { formData.dailyLimit = val }"
       />
       <span class="tip-text">每人每天最多可发送的邀请次数</span>
     </el-form-item>
@@ -88,12 +91,13 @@
     <!-- 总邀请上限 -->
     <el-form-item label="总邀请上限">
       <el-input-number
-        v-model="localData.totalLimit"
+        :model-value="formData.totalLimit"
         :min="1"
         :max="10000"
         :step="10"
         placeholder="不填则不限制"
         controls-position="right"
+        @update:model-value="(val: number) => { formData.totalLimit = val }"
       />
       <span class="tip-text">活动期间每人最多邀请人数(留空表示不限)</span>
     </el-form-item>
@@ -101,26 +105,26 @@
     <!-- 首单要求 -->
     <el-form-item label="首单要求">
       <el-switch
-        v-model="localData.requireFirstOrder"
-        :active-value="1"
-        :inactive-value="0"
+        :model-value="formData.requireFirstOrder === 1"
         active-text="要求完成首单"
         inactive-text="无要求"
+        @update:model-value="(val: boolean) => { formData.requireFirstOrder = val ? 1 : 0 }"
       />
     </el-form-item>
 
     <!-- 首单最低金额(条件显示) -->
     <el-form-item
-      v-if="localData.requireFirstOrder === 1"
+      v-if="formData.requireFirstOrder === 1"
       label="首单最低金额"
     >
       <el-input-number
-        v-model="localData.minOrderAmount"
+        :model-value="formData.minOrderAmount"
         :min="0"
         :precision="2"
         :step="10"
         placeholder="不填则不限金额"
         controls-position="right"
+        @update:model-value="(val: number) => { formData.minOrderAmount = val }"
       />
       <span class="tip-text">被邀请人首单需达到的最低消费金额(元)</span>
     </el-form-item>
@@ -142,13 +146,13 @@
         </li>
         <li>
           <strong>每日限制:</strong>
-          {{ localData.dailyLimit || 10 }} 次/天
+          {{ formData.dailyLimit || 10 }} 次/天
         </li>
         <li>
           <strong>首单要求:</strong>
           {{
-            localData.requireFirstOrder === 1
-              ? `需完成${localData.minOrderAmount || 0}元以上首单`
+            formData.requireFirstOrder === 1
+              ? `需完成${formData.minOrderAmount || 0}元以上首单`
               : "无"
           }}
         </li>
@@ -158,9 +162,8 @@
 </template>
 
 <script setup lang="ts">
-import { ref, watch } from "vue";
+import { computed } from "vue";
 
-/** 优惠券模板数据结构 */
 interface CouponTemplate {
   id: number;
   name: string;
@@ -168,112 +171,41 @@ interface CouponTemplate {
   [key: string]: any;
 }
 
-/** 邀请奖励配置数据结构 */
-interface InviteRewardConfig {
-  rewardRuleType: string;
-  inviterCouponTemplateId: number | null;
-  inviteeCouponTemplateId: number | null;
-  dailyLimit: number | null;
-  totalLimit: number | null;
-  requireFirstOrder: number;
-  minOrderAmount: number | null;
+interface InviteFormData {
+  rewardRuleType?: string;
+  inviterCouponTemplateId?: number | null;
+  inviteeCouponTemplateId?: number | null;
+  dailyLimit?: number | null;
+  totalLimit?: number | null;
+  requireFirstOrder?: number;
+  minOrderAmount?: number | null;
 }
 
 const props = withDefaults(
   defineProps<{
-    modelValue?: InviteRewardConfig;
+    formData: InviteFormData;
     couponTemplateList?: CouponTemplate[];
   }>(),
   {
-    modelValue: () => ({
-      rewardRuleType: "fixed",
-      inviterCouponTemplateId: null,
-      inviteeCouponTemplateId: null,
-      dailyLimit: 10,
-      totalLimit: null,
-      requireFirstOrder: 1,
-      minOrderAmount: null
-    }),
     couponTemplateList: () => []
   }
 );
 
-const emit = defineEmits<{
-  (e: "update:modelValue", value: InviteRewardConfig): void;
-}>();
-
-/** 本地数据副本 */
-const localData = ref<InviteRewardConfig>({
-  rewardRuleType: "fixed",
-  inviterCouponTemplateId: null,
-  inviteeCouponTemplateId: null,
-  dailyLimit: 10,
-  totalLimit: null,
-  requireFirstOrder: 1,
-  minOrderAmount: null
-});
-
-/** 监听 props 变化同步到 localData */
-watch(
-  () => props.modelValue,
-  (newVal) => {
-    if (newVal) {
-      Object.assign(localData.value, newVal);
-    }
-  },
-  { immediate: true, deep: true }
-);
-
-/** 监听 localData 变化通知父组件 */
-watch(
-  localData,
-  (newVal) => {
-    emit("update:modelValue", { ...newVal });
-  },
-  { deep: true }
-);
-
-/**
- * 获取邀请人优惠券名称
- * @returns 优惠券显示名称
- */
 function getInviterCouponName(): string {
-  if (!localData.value.inviterCouponTemplateId) return "";
+  if (!props.formData.inviterCouponTemplateId) return "";
   const coupon = props.couponTemplateList.find(
-    (item) => item.id === localData.value.inviterCouponTemplateId
+    (item) => item.id === props.formData.inviterCouponTemplateId
   );
   return coupon ? `${coupon.name} (${coupon.discountValue}元)` : "";
 }
 
-/**
- * 获取被邀请人优惠券名称
- * @returns 优惠券显示名称
- */
 function getInviteeCouponName(): string {
-  if (!localData.value.inviteeCouponTemplateId) return "";
+  if (!props.formData.inviteeCouponTemplateId) return "";
   const coupon = props.couponTemplateList.find(
-    (item) => item.id === localData.value.inviteeCouponTemplateId
+    (item) => item.id === props.formData.inviteeCouponTemplateId
   );
   return coupon ? `${coupon.name} (${coupon.discountValue}元)` : "";
 }
-
-/** 暴露方法供父组件调用 */
-defineExpose({
-  /** 获取当前配置数据 */
-  getConfig: (): InviteRewardConfig => ({ ...localData.value }),
-  /** 重置为默认值 */
-  reset: () => {
-    localData.value = {
-      rewardRuleType: "fixed",
-      inviterCouponTemplateId: null,
-      inviteeCouponTemplateId: null,
-      dailyLimit: 10,
-      totalLimit: null,
-      requireFirstOrder: 1,
-      minOrderAmount: null
-    };
-  }
-});
 </script>
 
 <style scoped lang="scss">
@@ -350,7 +282,6 @@ defineExpose({
   }
 }
 
-/* 表单项间距调整 */
 :deep(.el-form-item) {
   margin-bottom: 18px;
 
@@ -359,7 +290,6 @@ defineExpose({
   }
 }
 
-/* 分隔线样式调整 */
 :deep(.el-divider) {
   margin: 24px 0 18px;
 
@@ -369,12 +299,10 @@ defineExpose({
   }
 }
 
-/* 输入框数字控件宽度 */
 :deep(.el-input-number) {
   width: 200px;
 }
 
-/* 开关控件对齐 */
 :deep(.el-switch) {
   --el-switch-on-color: #f56c6c;
 }

+ 8 - 21
haha-admin-web/src/views/marketing/activity/utils/hook.tsx

@@ -728,7 +728,7 @@ export function useActivity() {
           {/* 邀请有礼配置 (type=4) - 使用 InviteRewardBlock 组件 */}
           {formData.activityType === 4 && (
             <InviteRewardBlock
-              v-model={formData}
+              formData={formData}
               couponTemplateList={couponTemplateList.value}
             />
           )}
@@ -926,7 +926,6 @@ export function useActivity() {
     shopIds: [] as number[],
     deviceIds: [] as string[],
     productIds: [] as number[],
-    // 邀请有礼特有字段 (type=4)
     rewardRuleType: "fixed",
     inviterCouponTemplateId: null as number | null,
     inviteeCouponTemplateId: null as number | null,
@@ -937,30 +936,19 @@ export function useActivity() {
     inviteCodePrefix: "INV"
   };
 
-  // 当前选中的活动类型(用于新增时预选)
-  const selectedType = ref<number | undefined>(undefined);
-
   function handleAdd() {
-    if (!selectedType.value) {
-      message("请先选择活动类型", { type: "warning" });
-      return;
-    }
-
     const formData = reactive<FormItemProps>({
       ...defaultFormData,
-      activityType: selectedType.value,
 
-      // 根据类型设置不同的默认值
-      ...(selectedType.value === 4 ? {
-        rewardRuleType: "fixed",
-        dailyLimit: 10,
-        requireFirstOrder: 1
-      } : {})
+      // 邀请有礼默认值(用户可在弹窗内切换类型)
+      rewardRuleType: "fixed",
+      dailyLimit: 10,
+      requireFirstOrder: 1
     });
 
     addDialog({
-      title: `新增${typeMap[selectedType.value]?.text || ''}活动`,
-      width: selectedType.value === 4 ? "900px" : "700px",  // 邀请表单更宽
+      title: "新增活动",
+      width: "700px",
       draggable: true,
       fullscreen: deviceDetection(),
       contentRenderer: () => renderForm(formData),
@@ -1003,8 +991,7 @@ export function useActivity() {
     applyScopeMap,
     deviceScopeMap,
     productScopeMap,
-    selectedType,           // 当前选中的活动类型
-    couponTemplateList,    // 优惠券模板列表
+    couponTemplateList,
     onSearch,
     resetForm,
     handleAdd,