gaoluyang
2026-06-24 712aa51536236d43e87273e4ce45ac5691dffad8
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
<script lang="ts" setup>
import type { MallCouponTemplateApi } from '#/api/mall/promotion/coupon/couponTemplate';
import type { MallRewardActivityApi } from '#/api/mall/promotion/reward/rewardActivity';
 
import { nextTick, onMounted, ref, watch } from 'vue';
 
import { CouponTemplateTakeTypeEnum, DICT_TYPE } from '..\..\..\..\..\packages\constants\src';
 
import { useVModel } from '@vueuse/core';
import { Button, Input } from 'ant-design-vue';
 
import { getCouponTemplateList } from '#/api/mall/promotion/coupon/couponTemplate';
import { DictTag } from '#/components/dict-tag';
import { CouponSelect } from '#/views/mall/promotion/coupon/components';
import { discountFormat } from '#/views/mall/promotion/coupon/formatter';
 
defineOptions({ name: 'RewardRuleCouponSelect' });
 
const props = defineProps<{
  modelValue: MallRewardActivityApi.RewardRule;
}>();
 
const emits = defineEmits<{
  (e: 'update:modelValue', v: any): void;
}>();
 
/** 选择赠送的优惠类型拓展 */
interface GiveCoupon extends MallCouponTemplateApi.CouponTemplate {
  giveCount?: number;
}
 
const rewardRule = useVModel(props, 'modelValue', emits);
const list = ref<GiveCoupon[]>([]); // 选择的优惠劵列表
 
/** 选择优惠券 */
const selectRef = ref<InstanceType<typeof CouponSelect>>();
function handleSelect() {
  selectRef.value?.open();
}
 
/** 选择优惠券后的回调 */
function handleChange(val: any[]) {
  for (const item of val) {
    if (list.value.some((v) => v.id === item.id)) {
      continue;
    }
    list.value.push(item);
  }
}
 
/** 删除优惠券 */
function handleDelete(index: number) {
  list.value.splice(index, 1);
}
 
/** 初始化赠送的优惠券列表 */
async function initGiveCouponList() {
  // 校验优惠券存在
  if (
    !rewardRule.value ||
    !rewardRule.value.giveCouponTemplateCounts ||
    Object.keys(rewardRule.value.giveCouponTemplateCounts).length === 0
  ) {
    return;
  }
  const tempLateIds = Object.keys(
    rewardRule.value.giveCouponTemplateCounts,
  ) as unknown as number[];
  const data = await getCouponTemplateList(tempLateIds);
  if (!data) {
    return;
  }
  data.forEach((coupon) => {
    list.value.push({
      ...coupon,
      giveCount: rewardRule.value.giveCouponTemplateCounts![coupon.id],
    });
  });
}
 
/** 监听 list 变化,自动同步到 rewardRule */
watch(
  list,
  (val) => {
    if (!rewardRule.value) {
      return;
    }
    // 核心:清空 giveCouponTemplateCounts,解决删除不生效的问题
    rewardRule.value.giveCouponTemplateCounts = {};
    // 设置优惠券和其数量的对应
    val.forEach((item) => {
      rewardRule.value.giveCouponTemplateCounts![item.id] = item.giveCount!;
    });
  },
  { deep: true },
);
 
onMounted(async () => {
  await nextTick();
  await initGiveCouponList();
});
</script>
 
<template>
  <div>
    <!-- 已选优惠券列表 -->
    <div v-if="list.length > 0" class="mb-2 flex flex-col gap-2">
      <div
        v-for="(item, index) in list"
        :key="item.id"
        class="flex items-center justify-between rounded-md border border-gray-200 bg-white px-3 py-2 transition-all hover:border-blue-400 hover:shadow-sm"
      >
        <div class="flex flex-wrap items-center gap-3">
          <span class="font-medium text-gray-800">{{ item.name }}</span>
          <span class="flex items-center gap-1 text-sm text-gray-500">
            <DictTag
              :type="DICT_TYPE.PROMOTION_PRODUCT_SCOPE"
              :value="item.productScope"
            />
          </span>
          <span class="flex items-center gap-1 text-sm text-gray-500">
            <DictTag
              :type="DICT_TYPE.PROMOTION_DISCOUNT_TYPE"
              :value="item.discountType"
            />
            {{ discountFormat(item) }}
          </span>
        </div>
        <div class="flex shrink-0 items-center gap-2">
          <span class="text-gray-500">送</span>
          <Input
            v-model:value="item.giveCount"
            class="!w-20"
            placeholder=""
            type="number"
            size="small"
          />
          <span class="text-gray-500">张</span>
          <Button type="link" danger size="small" @click="handleDelete(index)">
            删除
          </Button>
        </div>
      </div>
    </div>
 
    <!-- 添加按钮 -->
    <Button type="link" class="!pl-0" @click="handleSelect">
      + 添加优惠券
    </Button>
 
    <!-- 优惠券选择弹窗 -->
    <CouponSelect
      ref="selectRef"
      :take-type="CouponTemplateTakeTypeEnum.ADMIN.type"
      @change="handleChange"
    />
  </div>
</template>