|
|
@@ -1,683 +0,0 @@
|
|
|
-<template>
|
|
|
- <div class="table-box button-table friend-relation-container">
|
|
|
- <ProTable ref="proTable" :columns="columns" :request-api="getTableList" :init-param="initParam" :data-callback="dataCallback">
|
|
|
- <!-- 表格 header 按钮 -->
|
|
|
- <template #tableHeader="scope">
|
|
|
- <div class="header-button">
|
|
|
- <el-button type="primary" @click="openAddDialog"> 添加活动 </el-button>
|
|
|
- </div>
|
|
|
- </template>
|
|
|
-
|
|
|
- <!-- 状态列 -->
|
|
|
- <template #status="scope">
|
|
|
- <el-tag :type="getStatusType(scope.row.status)">
|
|
|
- {{ getStatusText(scope.row.status) }}
|
|
|
- </el-tag>
|
|
|
- </template>
|
|
|
-
|
|
|
- <!-- 表格操作 -->
|
|
|
- <template #operation="scope">
|
|
|
- <el-button link type="primary" @click="editRow(scope.row)"> 编辑 </el-button>
|
|
|
- <el-button link type="primary" @click="deleteRow(scope.row)"> 删除 </el-button>
|
|
|
- </template>
|
|
|
- </ProTable>
|
|
|
-
|
|
|
- <!-- 添加/编辑活动对话框 -->
|
|
|
- <el-dialog v-model="dialogVisible" :title="dialogTitle" width="700px" @close="closeDialog">
|
|
|
- <el-form ref="formRef" :model="formData" :rules="formRules" label-width="140px">
|
|
|
- <el-form-item label="活动名称" prop="acName">
|
|
|
- <el-input v-model="formData.acName" placeholder="请输入" clearable />
|
|
|
- </el-form-item>
|
|
|
-
|
|
|
- <el-form-item label="赠送类型">
|
|
|
- <el-radio-group v-model="formData.distributeType" @change="onDistributeTypeChange">
|
|
|
- <el-radio :label="1"> 满减券 </el-radio>
|
|
|
- <el-radio :label="2"> 折扣券 </el-radio>
|
|
|
- </el-radio-group>
|
|
|
- </el-form-item>
|
|
|
-
|
|
|
- <el-form-item label="消费门槛金额(¥)">
|
|
|
- <div style="display: flex; gap: 10px; align-items: center; width: 100%">
|
|
|
- <el-form-item prop="moneyLow" style="flex: 1; margin-bottom: 0">
|
|
|
- <el-input
|
|
|
- v-model="formData.moneyLow"
|
|
|
- type="number"
|
|
|
- :min="0"
|
|
|
- step="0.01"
|
|
|
- placeholder="0.00"
|
|
|
- clearable
|
|
|
- @input="handleMoneyInput('moneyLow')"
|
|
|
- >
|
|
|
- <template #prefix> ¥ </template>
|
|
|
- </el-input>
|
|
|
- </el-form-item>
|
|
|
- <span>~</span>
|
|
|
- <el-form-item prop="moneyHigh" style="flex: 1; margin-bottom: 0">
|
|
|
- <el-input
|
|
|
- v-model="formData.moneyHigh"
|
|
|
- type="number"
|
|
|
- :min="0"
|
|
|
- step="0.01"
|
|
|
- placeholder="0.00"
|
|
|
- clearable
|
|
|
- @input="handleMoneyInput('moneyHigh')"
|
|
|
- >
|
|
|
- <template #prefix> ¥ </template>
|
|
|
- </el-input>
|
|
|
- </el-form-item>
|
|
|
- </div>
|
|
|
- </el-form-item>
|
|
|
-
|
|
|
- <el-form-item label="来源商家及优惠券">
|
|
|
- <div class="merchant-coupon-list">
|
|
|
- <div v-for="(item, index) in formData.coupons" :key="index" class="merchant-coupon-item">
|
|
|
- <el-select
|
|
|
- v-model="item.merchant"
|
|
|
- placeholder="选择商家"
|
|
|
- style="width: 200px; margin-right: 10px"
|
|
|
- filterable
|
|
|
- @change="handleMerchantChange(index)"
|
|
|
- >
|
|
|
- <el-option
|
|
|
- v-for="(m, idx) in effectiveMerchantOptions"
|
|
|
- :key="m.label ? `${String(m.value)}_${m.label}_${idx}` : String(m.value)"
|
|
|
- :label="m.label"
|
|
|
- :value="m.value"
|
|
|
- />
|
|
|
- </el-select>
|
|
|
- <el-select
|
|
|
- v-model="item.coupon"
|
|
|
- :placeholder="formData.distributeType === 2 ? '选择折扣券' : '选择满减券'"
|
|
|
- style="width: 200px; margin-right: 10px"
|
|
|
- filterable
|
|
|
- @change="handleCouponChange(index)"
|
|
|
- >
|
|
|
- <el-option
|
|
|
- v-for="c in getCouponOptions(formData.distributeType)"
|
|
|
- :key="c.value"
|
|
|
- :label="c.label"
|
|
|
- :value="c.value"
|
|
|
- />
|
|
|
- </el-select>
|
|
|
- <span v-if="item.coupon" class="remaining-text">剩余{{ item.remaining }}张</span>
|
|
|
- <el-button type="danger" link @click="removeMerchantCoupon(index)" v-if="formData.coupons.length > 1">
|
|
|
- 删除
|
|
|
- </el-button>
|
|
|
- </div>
|
|
|
- <el-button type="primary" link @click="addMerchantCoupon" style="margin-top: 10px">
|
|
|
- <el-icon><Plus /></el-icon>
|
|
|
- 添加商家优惠券
|
|
|
- </el-button>
|
|
|
- </div>
|
|
|
- </el-form-item>
|
|
|
- </el-form>
|
|
|
-
|
|
|
- <template #footer>
|
|
|
- <div class="dialog-footer">
|
|
|
- <el-button @click="closeDialog"> 取消 </el-button>
|
|
|
- <el-button type="primary" @click="handleSubmit"> 确定 </el-button>
|
|
|
- </div>
|
|
|
- </template>
|
|
|
- </el-dialog>
|
|
|
- </div>
|
|
|
-</template>
|
|
|
-
|
|
|
-<script setup lang="tsx" name="friendRelation">
|
|
|
-import { computed, onMounted, reactive, ref } from "vue";
|
|
|
-import type { FormInstance, FormRules } from "element-plus";
|
|
|
-import { ElMessage, ElMessageBox } from "element-plus";
|
|
|
-import { Plus } from "@element-plus/icons-vue";
|
|
|
-import ProTable from "@/components/ProTable/index.vue";
|
|
|
-import { ColumnProps, ProTableInstance } from "@/components/ProTable/interface";
|
|
|
-import { localGet } from "@/utils";
|
|
|
-
|
|
|
-import {
|
|
|
- getRuleList,
|
|
|
- saveFriendCouponRule,
|
|
|
- getMutualAttention,
|
|
|
- delFriendCouponRule,
|
|
|
- getRuleById,
|
|
|
- getVoucherList,
|
|
|
- getIssueCouponList
|
|
|
-} from "@/api/modules/newLoginApi";
|
|
|
-
|
|
|
-// ProTable 实例
|
|
|
-const proTable = ref<ProTableInstance>();
|
|
|
-
|
|
|
-// 对话框相关
|
|
|
-const dialogVisible = ref(false);
|
|
|
-const dialogTitle = computed(() => (isEdit.value ? "编辑活动" : "添加活动"));
|
|
|
-const isEdit = ref(false);
|
|
|
-const currentEditId = ref("");
|
|
|
-
|
|
|
-// 表单引用
|
|
|
-const formRef = ref<FormInstance>();
|
|
|
-
|
|
|
-// 商家列表(互相关注接口,仅显示 phoneId 带 store 的商家)
|
|
|
-const merchantList = ref<Array<{ value: string | number; label: string; raw?: any }>>([]);
|
|
|
-const merchantListRaw = ref<any[]>([]);
|
|
|
-
|
|
|
-// 优惠券/折扣券选项缓存 key: '1-couponList' | '2-couponList'
|
|
|
-const couponOptionsMap = ref<Record<string, Array<{ value: string; label: string }>>>({});
|
|
|
-const couponDataMap = ref<Record<string, any[]>>({});
|
|
|
-
|
|
|
-const normalizeCouponValue = (v: any) => (v != null && v !== "" ? String(v) : "");
|
|
|
-
|
|
|
-// 编辑时合并详情中的 storeName,使商家下拉能正确显示;按 label 去重,避免同一商家出现多次
|
|
|
-const effectiveMerchantOptions = computed(() => {
|
|
|
- const base = merchantList.value || [];
|
|
|
- const fromDetail = (formData.coupons || [])
|
|
|
- .filter((c: any) => c.merchant != null && c.merchant !== "" && c.storeName)
|
|
|
- .map((c: any) => ({ value: c.merchant, label: c.storeName }));
|
|
|
- const seenValue = new Set(base.map((o: any) => o.value));
|
|
|
- const extra = fromDetail.filter((o: any) => {
|
|
|
- if (seenValue.has(o.value)) return false;
|
|
|
- seenValue.add(o.value);
|
|
|
- return true;
|
|
|
- });
|
|
|
- const merged = [...base, ...extra];
|
|
|
- // 按 label(店名)去重:同一店名只保留一项,优先保留在 form 中已选中的 value,避免下拉重复显示
|
|
|
- const usedValues = new Set((formData.coupons || []).map((c: any) => c.merchant).filter((v: any) => v != null && v !== ""));
|
|
|
- const byLabel = new Map<string, { value: string | number; label: string }>();
|
|
|
- for (const o of merged) {
|
|
|
- const label = o.label || "";
|
|
|
- const existing = byLabel.get(label);
|
|
|
- if (!existing) {
|
|
|
- byLabel.set(label, o);
|
|
|
- } else if (usedValues.has(o.value) && !usedValues.has(existing.value)) {
|
|
|
- byLabel.set(label, o);
|
|
|
- }
|
|
|
- }
|
|
|
- return Array.from(byLabel.values());
|
|
|
-});
|
|
|
-
|
|
|
-const getCouponOptions = (distributeType: number) => {
|
|
|
- const key = distributeType === 2 ? "2-couponList" : "1-couponList";
|
|
|
- return couponOptionsMap.value[key] || [];
|
|
|
-};
|
|
|
-
|
|
|
-// 表单数据
|
|
|
-const formData = reactive({
|
|
|
- acName: "",
|
|
|
- distributeType: 1 as 1 | 2, // 1-满减券 2-折扣券
|
|
|
- moneyLow: "" as string | number,
|
|
|
- moneyHigh: "" as string | number,
|
|
|
- coupons: [] as Array<{
|
|
|
- merchant: string | number | null;
|
|
|
- coupon: string | null;
|
|
|
- remaining: number;
|
|
|
- storeName?: string;
|
|
|
- }>
|
|
|
-});
|
|
|
-
|
|
|
-// 金额验证器
|
|
|
-const validateMoneyLow = (rule: any, value: any, callback: any) => {
|
|
|
- if (value === "" || value === null || value === undefined) {
|
|
|
- callback(new Error("请输入最低消费金额"));
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- const numValue = Number(value);
|
|
|
- if (isNaN(numValue)) {
|
|
|
- callback(new Error("请输入有效的金额"));
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- if (numValue < 0) {
|
|
|
- callback(new Error("金额不能为负数"));
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- // 验证小数位数不超过2位
|
|
|
- const decimalPart = String(value).split(".")[1];
|
|
|
- if (decimalPart && decimalPart.length > 2) {
|
|
|
- callback(new Error("最多支持2位小数"));
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- // 如果最高金额已填写,验证最低金额不能大于最高金额
|
|
|
- if (formData.moneyHigh !== "" && formData.moneyHigh !== null && formData.moneyHigh !== undefined) {
|
|
|
- const highValue = Number(formData.moneyHigh);
|
|
|
- if (!isNaN(highValue) && numValue > highValue) {
|
|
|
- callback(new Error("最低金额不能大于最高金额"));
|
|
|
- return;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- callback();
|
|
|
-};
|
|
|
-
|
|
|
-const validateMoneyHigh = (rule: any, value: any, callback: any) => {
|
|
|
- if (value === "" || value === null || value === undefined) {
|
|
|
- callback(new Error("请输入最高消费金额"));
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- const numValue = Number(value);
|
|
|
- if (isNaN(numValue)) {
|
|
|
- callback(new Error("请输入有效的金额"));
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- if (numValue < 0) {
|
|
|
- callback(new Error("金额不能为负数"));
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- // 验证小数位数不超过2位
|
|
|
- const decimalPart = String(value).split(".")[1];
|
|
|
- if (decimalPart && decimalPart.length > 2) {
|
|
|
- callback(new Error("最多支持2位小数"));
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- // 如果最低金额已填写,验证最高金额不能小于最低金额
|
|
|
- if (formData.moneyLow !== "" && formData.moneyLow !== null && formData.moneyLow !== undefined) {
|
|
|
- const lowValue = Number(formData.moneyLow);
|
|
|
- if (!isNaN(lowValue) && numValue < lowValue) {
|
|
|
- callback(new Error("最高金额不能小于最低金额"));
|
|
|
- return;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- callback();
|
|
|
-};
|
|
|
-
|
|
|
-// 表单验证规则
|
|
|
-const formRules = reactive<FormRules>({
|
|
|
- acName: [{ required: true, message: "请输入活动名称", trigger: "blur" }],
|
|
|
- moneyLow: [{ required: true, validator: validateMoneyLow, trigger: "blur" }],
|
|
|
- moneyHigh: [{ required: true, validator: validateMoneyHigh, trigger: "blur" }]
|
|
|
-});
|
|
|
-
|
|
|
-// 表格列配置
|
|
|
-const columns = reactive<ColumnProps<any>[]>([
|
|
|
- {
|
|
|
- prop: "acName",
|
|
|
- label: "活动名称",
|
|
|
- search: { el: "input", props: { placeholder: "请输入活动名称" } }
|
|
|
- },
|
|
|
- {
|
|
|
- prop: "endDate",
|
|
|
- label: "有效期至"
|
|
|
- },
|
|
|
- {
|
|
|
- prop: "relationType",
|
|
|
- label: "消费门槛",
|
|
|
- render: (scope: any) => {
|
|
|
- return scope.row.moneyLow + "元" + "~" + scope.row.moneyHigh + "元";
|
|
|
- }
|
|
|
- },
|
|
|
- {
|
|
|
- prop: "status",
|
|
|
- label: "状态",
|
|
|
- enum: [
|
|
|
- { label: "启用", value: 0 },
|
|
|
- { label: "禁用", value: 1 }
|
|
|
- ],
|
|
|
- search: { el: "select", props: { placeholder: "请选择状态" } },
|
|
|
- fieldNames: { label: "label", value: "value" },
|
|
|
- render: (scope: any) => {
|
|
|
- return scope.row.status == 0 ? "启用" : "禁用";
|
|
|
- }
|
|
|
- },
|
|
|
- { prop: "operation", label: "操作", fixed: "right", width: 250 }
|
|
|
-]);
|
|
|
-
|
|
|
-// 初始化请求参数
|
|
|
-const initParam = reactive({
|
|
|
- storeId: localGet("createdId") || ""
|
|
|
-});
|
|
|
-
|
|
|
-// 数据回调处理:兼容接口返回数组或 { records/list, total } 格式,确保有数据时分页显示正确总数(iOS 上 total 需为明确数字)
|
|
|
-const dataCallback = (data: any) => {
|
|
|
- const list = Array.isArray(data) ? data : (data?.records ?? data?.list ?? []);
|
|
|
- const totalNum =
|
|
|
- typeof data?.total === "number" && Number.isFinite(data.total) ? data.total : Array.isArray(list) ? list.length : 0;
|
|
|
- const total = Math.max(0, Math.floor(Number(totalNum)) || 0);
|
|
|
- return {
|
|
|
- list,
|
|
|
- total
|
|
|
- };
|
|
|
-};
|
|
|
-
|
|
|
-// 获取表格列表
|
|
|
-const getTableList = (params: any) => {
|
|
|
- return getRuleList(params);
|
|
|
-};
|
|
|
-
|
|
|
-// 获取状态文本
|
|
|
-const getStatusText = (status: number) => {
|
|
|
- const statusMap: Record<number, string> = {
|
|
|
- 0: "待同意",
|
|
|
- 1: "已同意",
|
|
|
- 2: "已拒绝"
|
|
|
- };
|
|
|
- return statusMap[status] || "--";
|
|
|
-};
|
|
|
-
|
|
|
-// 获取状态类型
|
|
|
-const getStatusType = (status: number): "success" | "warning" | "info" | "danger" => {
|
|
|
- const typeMap: Record<number, "success" | "warning" | "info" | "danger"> = {
|
|
|
- 0: "warning",
|
|
|
- 1: "success",
|
|
|
- 2: "info"
|
|
|
- };
|
|
|
- return typeMap[status] || "info";
|
|
|
-};
|
|
|
-
|
|
|
-// 获取商家列表(互相关注接口,仅显示 phoneId 带 store 的商家)- 与 group_merchant eachOtherInterest 参数一致
|
|
|
-const loadAddActivityMerchants = async () => {
|
|
|
- const phone = localGet("iphone") || localGet("geeker-user")?.userInfo?.phone || "";
|
|
|
- try {
|
|
|
- const res: any = await getMutualAttention({
|
|
|
- page: 1,
|
|
|
- size: 1000,
|
|
|
- fansId: `store_${phone}`
|
|
|
- });
|
|
|
- const data = res?.data || res;
|
|
|
- const records = data?.records || data?.list || (Array.isArray(data) ? data : []);
|
|
|
- const list = Array.isArray(records) ? records : [];
|
|
|
- const merchantListFiltered = list.filter((item: any) => {
|
|
|
- const pid = String(item.phoneId ?? item.id ?? "");
|
|
|
- return pid.includes("store");
|
|
|
- });
|
|
|
- merchantListRaw.value = merchantListFiltered;
|
|
|
- // 按 value(id/storeId/phoneId)去重,避免同一商家在接口中多次返回导致下拉重复
|
|
|
- const seen = new Set<string | number>();
|
|
|
- merchantList.value = merchantListFiltered
|
|
|
- .map((item: any) => ({
|
|
|
- value: item.id ?? item.storeId ?? item.phoneId,
|
|
|
- label: item.storeName ?? item.name ?? "",
|
|
|
- raw: item
|
|
|
- }))
|
|
|
- .filter((o: any) => {
|
|
|
- if (seen.has(o.value)) return false;
|
|
|
- seen.add(o.value);
|
|
|
- return true;
|
|
|
- });
|
|
|
- } catch (error) {
|
|
|
- console.error("获取商家列表失败", error);
|
|
|
- merchantList.value = [];
|
|
|
- merchantListRaw.value = [];
|
|
|
- }
|
|
|
-};
|
|
|
-
|
|
|
-// 打开添加对话框
|
|
|
-const openAddDialog = async () => {
|
|
|
- isEdit.value = false;
|
|
|
- currentEditId.value = "";
|
|
|
- await loadAddActivityMerchants();
|
|
|
- couponOptionsMap.value = {};
|
|
|
- couponDataMap.value = {};
|
|
|
- formData.distributeType = 1;
|
|
|
- formData.coupons = [{ merchant: null, coupon: null, remaining: 0 }];
|
|
|
- formData.acName = "";
|
|
|
- formData.moneyLow = "";
|
|
|
- formData.moneyHigh = "";
|
|
|
- dialogVisible.value = true;
|
|
|
-};
|
|
|
-
|
|
|
-// 处理金额输入
|
|
|
-const handleMoneyInput = (field: "moneyLow" | "moneyHigh") => {
|
|
|
- // 当一个金额字段改变时,触发另一个字段的验证
|
|
|
- if (formRef.value) {
|
|
|
- const otherField = field === "moneyLow" ? "moneyHigh" : "moneyLow";
|
|
|
- // 如果另一个字段有值,触发其验证
|
|
|
- if (formData[otherField] !== "" && formData[otherField] !== null && formData[otherField] !== undefined) {
|
|
|
- formRef.value.validateField(otherField, () => {});
|
|
|
- }
|
|
|
- }
|
|
|
-};
|
|
|
-
|
|
|
-// 关闭对话框
|
|
|
-const closeDialog = () => {
|
|
|
- dialogVisible.value = false;
|
|
|
- formRef.value?.resetFields();
|
|
|
- Object.assign(formData, {
|
|
|
- acName: "",
|
|
|
- distributeType: 1,
|
|
|
- moneyLow: "",
|
|
|
- moneyHigh: "",
|
|
|
- coupons: []
|
|
|
- });
|
|
|
- currentEditId.value = "";
|
|
|
-};
|
|
|
-
|
|
|
-// 添加商家优惠券
|
|
|
-const addMerchantCoupon = () => {
|
|
|
- formData.coupons.push({
|
|
|
- merchant: null,
|
|
|
- coupon: null,
|
|
|
- remaining: 0
|
|
|
- });
|
|
|
-};
|
|
|
-
|
|
|
-// 移除商家优惠券
|
|
|
-const removeMerchantCoupon = (index: number) => {
|
|
|
- formData.coupons.splice(index, 1);
|
|
|
-};
|
|
|
-
|
|
|
-// 赠送类型切换:清空选项缓存并重置行内选择(与 group_merchant setDistributeType 一致)
|
|
|
-const onDistributeTypeChange = () => {
|
|
|
- couponOptionsMap.value = {};
|
|
|
- couponDataMap.value = {};
|
|
|
- formData.coupons = formData.coupons.map(() => ({
|
|
|
- merchant: null,
|
|
|
- coupon: null,
|
|
|
- remaining: 0
|
|
|
- }));
|
|
|
- if (formData.coupons.length !== 1) formData.coupons = [{ merchant: null, coupon: null, remaining: 0 }];
|
|
|
- loadAddActivityMerchants();
|
|
|
-};
|
|
|
-
|
|
|
-// 加载当前类型下的优惠券/折扣券选项
|
|
|
-const loadCouponOptionsByType = async (distributeType: number) => {
|
|
|
- const key = distributeType === 2 ? "2-couponList" : "1-couponList";
|
|
|
- if (couponOptionsMap.value[key]?.length) return;
|
|
|
- const storeId = localGet("createdId") || "";
|
|
|
- try {
|
|
|
- const res: any = await getIssueCouponList({
|
|
|
- storeId,
|
|
|
- tab: 1,
|
|
|
- size: 100,
|
|
|
- page: 1,
|
|
|
- couponName: "",
|
|
|
- couponsFromType: 1,
|
|
|
- couponType: formData.distributeType
|
|
|
- });
|
|
|
- const records = res?.data?.records ?? res?.data ?? [];
|
|
|
- const list = Array.isArray(records) ? records : [];
|
|
|
- couponDataMap.value[key] = list;
|
|
|
- couponOptionsMap.value[key] = list.map((item: any) => ({
|
|
|
- value: String(item.id ?? item.couponId ?? ""),
|
|
|
- label: item.couponName ?? item.name ?? ""
|
|
|
- }));
|
|
|
- } catch (e) {
|
|
|
- couponDataMap.value[key] = [];
|
|
|
- couponOptionsMap.value[key] = [];
|
|
|
- }
|
|
|
-};
|
|
|
-
|
|
|
-// 商家选择改变
|
|
|
-const handleMerchantChange = async (index: number) => {
|
|
|
- const item = formData.coupons[index];
|
|
|
- item.coupon = null;
|
|
|
- item.remaining = 0;
|
|
|
- if (item.merchant) {
|
|
|
- const raw = merchantListRaw.value.find(
|
|
|
- (m: any) => (m.id ?? m.friendStoreUserId) === item.merchant || (m.storeId ?? m.phoneId) === item.merchant
|
|
|
- );
|
|
|
- if (raw) item.remaining = raw.singleQty ?? raw.couponNum ?? 0;
|
|
|
- await loadCouponOptionsByType(formData.distributeType);
|
|
|
- }
|
|
|
-};
|
|
|
-
|
|
|
-// 优惠券/折扣券选择改变
|
|
|
-const handleCouponChange = (index: number) => {
|
|
|
- const item = formData.coupons[index];
|
|
|
- const key = formData.distributeType === 2 ? "2-couponList" : "1-couponList";
|
|
|
- const list = couponDataMap.value[key] || [];
|
|
|
- const idKey = formData.distributeType === 2 ? "voucherId" : "couponId";
|
|
|
- if (item.coupon && list.length) {
|
|
|
- const found = list.find((c: any) => String(c[idKey] ?? c.couponId ?? c.id ?? "") === String(item.coupon));
|
|
|
- if (found) item.remaining = found.singleQty ?? found.couponNum ?? 0;
|
|
|
- }
|
|
|
-};
|
|
|
-
|
|
|
-// 编辑行数据(与 group_merchant editActivity 逻辑及 getRuleById 回显一致)
|
|
|
-const editRow = async (row: any) => {
|
|
|
- isEdit.value = true;
|
|
|
- currentEditId.value = row.id;
|
|
|
- const id = row.id;
|
|
|
- if (!id) return;
|
|
|
-
|
|
|
- await loadAddActivityMerchants();
|
|
|
- const type = row.type === 2 ? 2 : 1;
|
|
|
- formData.distributeType = type;
|
|
|
- couponOptionsMap.value = {};
|
|
|
- couponDataMap.value = {};
|
|
|
-
|
|
|
- try {
|
|
|
- const res: any = await getRuleById({ id });
|
|
|
- if (res.code != 200 || !res.data) {
|
|
|
- ElMessage.error(res.msg || "获取活动详情失败");
|
|
|
- return;
|
|
|
- }
|
|
|
- const d = res.data;
|
|
|
- formData.acName = d.acName;
|
|
|
- formData.moneyLow = d.moneyLow;
|
|
|
- formData.moneyHigh = d.moneyHigh;
|
|
|
- formData.distributeType = d.couponType;
|
|
|
- formData.coupons = (d.lifeDiscountCouponFriendRuleDetailVos || []).map((vo: any) => ({
|
|
|
- merchant: vo.friendStoreUserId ?? null,
|
|
|
- coupon: normalizeCouponValue(vo.couponId ?? vo.voucherId),
|
|
|
- remaining: vo.singleQty ?? vo.couponNum ?? 0,
|
|
|
- storeName: vo.storeName ?? ""
|
|
|
- }));
|
|
|
- if (formData.coupons.length === 0) {
|
|
|
- formData.coupons = [{ merchant: null, coupon: null, remaining: 0 }];
|
|
|
- }
|
|
|
- await loadCouponOptionsByType(formData.distributeType);
|
|
|
- // 编辑回显:从已加载的券列表中按券 id 同步剩余张数,避免详情接口未返回 singleQty/couponNum 时一直显示 0
|
|
|
- const key = formData.distributeType === 2 ? "2-couponList" : "1-couponList";
|
|
|
- const list = couponDataMap.value[key] || [];
|
|
|
- const idKey = formData.distributeType === 2 ? "voucherId" : "couponId";
|
|
|
- formData.coupons.forEach((row: any) => {
|
|
|
- if (!row.coupon) return;
|
|
|
- const found = list.find((c: any) => String(c[idKey] ?? c.couponId ?? c.id ?? "") === String(row.coupon));
|
|
|
- if (found) row.remaining = found.singleQty ?? found.couponNum ?? 0;
|
|
|
- });
|
|
|
- dialogVisible.value = true;
|
|
|
- } catch (error: any) {
|
|
|
- ElMessage.error(error?.msg || "获取活动详情失败");
|
|
|
- }
|
|
|
-};
|
|
|
-
|
|
|
-// 删除行数据
|
|
|
-const deleteRow = (row: any) => {
|
|
|
- ElMessageBox.confirm("确定要删除这个活动吗?", "提示", {
|
|
|
- confirmButtonText: "确定",
|
|
|
- cancelButtonText: "取消",
|
|
|
- type: "warning"
|
|
|
- })
|
|
|
- .then(async () => {
|
|
|
- try {
|
|
|
- const res: any = await delFriendCouponRule({ id: row.id });
|
|
|
- if (res.code == 200) {
|
|
|
- ElMessage.success("删除成功");
|
|
|
- proTable.value?.getTableList();
|
|
|
- } else {
|
|
|
- ElMessage.error(res.msg || "删除失败");
|
|
|
- }
|
|
|
- } catch (error: any) {
|
|
|
- ElMessage.error(error?.msg || "删除失败");
|
|
|
- }
|
|
|
- })
|
|
|
- .catch(() => {
|
|
|
- // 用户取消删除
|
|
|
- });
|
|
|
-};
|
|
|
-
|
|
|
-// 提交表单(与 group_merchant saveActivity 请求参数一致)
|
|
|
-const handleSubmit = async () => {
|
|
|
- if (!formRef.value) return;
|
|
|
-
|
|
|
- await formRef.value.validate(async (valid: boolean) => {
|
|
|
- if (!valid) return;
|
|
|
-
|
|
|
- if (!formData.coupons.length) {
|
|
|
- ElMessage.warning("请至少添加一个商家优惠券");
|
|
|
- return;
|
|
|
- }
|
|
|
- const hasEmpty = formData.coupons.some((item: any) => !item.merchant || !item.coupon);
|
|
|
- if (hasEmpty) {
|
|
|
- ElMessage.warning("请完善所有商家优惠券信息");
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- const isVoucher = formData.distributeType === 2;
|
|
|
- const details = formData.coupons.map((item: any) =>
|
|
|
- isVoucher
|
|
|
- ? { voucherId: item.coupon, friendStoreUserId: item.merchant }
|
|
|
- : { couponId: item.coupon, friendStoreUserId: item.merchant }
|
|
|
- );
|
|
|
-
|
|
|
- const requestData: any = {
|
|
|
- storeId: localGet("createdId") || "",
|
|
|
- acName: formData.acName.trim(),
|
|
|
- couponType: formData.distributeType,
|
|
|
- moneyHigh: Number(formData.moneyHigh),
|
|
|
- moneyLow: Number(formData.moneyLow),
|
|
|
- details
|
|
|
- };
|
|
|
- if (isEdit.value && currentEditId.value) {
|
|
|
- requestData.id = currentEditId.value;
|
|
|
- }
|
|
|
-
|
|
|
- try {
|
|
|
- const res: any = await saveFriendCouponRule(requestData);
|
|
|
- if (res.code == 200) {
|
|
|
- ElMessage.success(isEdit.value ? "编辑成功" : "添加成功");
|
|
|
- closeDialog();
|
|
|
- proTable.value?.getTableList();
|
|
|
- } else {
|
|
|
- ElMessage.error(res.msg || "操作失败");
|
|
|
- }
|
|
|
- } catch (error: any) {
|
|
|
- ElMessage.error(error?.msg || (isEdit.value ? "编辑失败" : "添加失败"));
|
|
|
- }
|
|
|
- });
|
|
|
-};
|
|
|
-
|
|
|
-// 页面加载时触发查询
|
|
|
-onMounted(() => {
|
|
|
- proTable.value?.getTableList();
|
|
|
-});
|
|
|
-</script>
|
|
|
-
|
|
|
-<style lang="scss" scoped>
|
|
|
-.friend-relation-container {
|
|
|
- .header-button {
|
|
|
- margin-bottom: 16px;
|
|
|
- }
|
|
|
- .merchant-coupon-list {
|
|
|
- width: 100%;
|
|
|
- .merchant-coupon-item {
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- margin-bottom: 10px;
|
|
|
- }
|
|
|
- .remaining-text {
|
|
|
- margin-right: 10px;
|
|
|
- font-size: 13px;
|
|
|
- color: var(--el-text-color-regular);
|
|
|
- }
|
|
|
- }
|
|
|
- .dialog-footer {
|
|
|
- display: flex;
|
|
|
- gap: 10px;
|
|
|
- justify-content: flex-end;
|
|
|
- }
|
|
|
-}
|
|
|
-</style>
|