|
|
@@ -3,18 +3,17 @@
|
|
|
<div>
|
|
|
<el-drawer :model-value="show" @update:model-value="$emit('update:show', $event)" title="权益选择"
|
|
|
:direction="direction" size="1100px">
|
|
|
-
|
|
|
<el-form :model="form" label-width="80px" label-position="left">
|
|
|
<el-row :gutter="20">
|
|
|
<el-col :span="24">
|
|
|
<el-form-item label="接收人">
|
|
|
<el-radio-group v-model="form.recipient">
|
|
|
<el-radio v-for="item in props.recipientInfo" :key="item.title" :value="item.title">{{ item.title
|
|
|
- }}</el-radio>
|
|
|
- <el-radio :value="'other'">其它
|
|
|
- <el-input class="ml-2" v-model="form.otherRecipient" style="width: 200px" placeholder="请输入" />
|
|
|
- </el-radio>
|
|
|
+ }}</el-radio>
|
|
|
+ <el-radio :value="'其他'">其他</el-radio>
|
|
|
</el-radio-group>
|
|
|
+ <el-input v-if="form.recipient == '其他'" class="ml-2" v-model="form.otherRecipient" style="width: 200px"
|
|
|
+ placeholder="请输入" />
|
|
|
</el-form-item>
|
|
|
</el-col>
|
|
|
</el-row>
|
|
|
@@ -35,15 +34,16 @@
|
|
|
</div>
|
|
|
<div>
|
|
|
<span>已使用金额</span>
|
|
|
- <span>¥{{ insFeeOrders.usedAmount || 0 }}</span>
|
|
|
+ <span>¥{{ calcUsedAndRemaining.usedAmount }}</span>
|
|
|
</div>
|
|
|
- <div>
|
|
|
+ <div style="font-weight: bold;">
|
|
|
<span>剩余金额</span>
|
|
|
- <span style="color: #FF8C21;"> ¥{{ insFeeOrders.remainingAmount || 0 }}</span>
|
|
|
+ <span style="color: #FF8C21;"> ¥{{ calcUsedAndRemaining.remainingAmount }}</span>
|
|
|
</div>
|
|
|
- <div>
|
|
|
+ <div style="font-weight: bold;">
|
|
|
<span>已选权益价值</span>
|
|
|
- <span style="color: #FF8C21;"> ¥{{insOrderRightsPackageList.length > 0 ? totalPriceCount : totalPriceCount1 || 0 }}</span>
|
|
|
+ <span style="color: #FF8C21;"> ¥{{ insOrderRightsPackageList.length > 0 ? totalPriceCount : totalPriceCount1
|
|
|
+ || 0 }}</span>
|
|
|
</div>
|
|
|
</div>
|
|
|
<!-- 备注信息 -->
|
|
|
@@ -67,26 +67,46 @@
|
|
|
|
|
|
<div class="PackageselectedList mt-[16px] flex " v-if="insOrderRightsPackageList.length > 0">
|
|
|
<div class="view-card mr-[20px]">
|
|
|
- <div class="view-item mb-[10px] " :class="{ 'active': index === benefitPackageIndex }"
|
|
|
+ <div class="view-item mb-[10px] " :class="index == benefitPackageIndex ? 'view-card-item-active' : ''"
|
|
|
v-for="(item, index) in insOrderRightsPackageList" :key="index" @click="rightsDetails(item, index)">
|
|
|
<div class="flex f-c ">
|
|
|
<div class="flex a-c j-s">
|
|
|
<span class="equityPackageName text-[14px] text-[#333]">{{ item.equityPackageName }}</span>
|
|
|
<span class="rightsCount text-[14px] text-[#333]">x{{ item.rightsCount }}</span>
|
|
|
</div>
|
|
|
- <div class="mt-5 flex a-c j-s">
|
|
|
- <span v-if="item.totalNumber" class="text-[12px] text-[#666]">数量:{{ item.totalNumber }}张</span>
|
|
|
- <span class="text-[12px] text-[#666]">价格:{{ item.packagePrice }}元</span>
|
|
|
- <el-icon @click="removeSelectedRight(index)" color="#666">
|
|
|
+ <div class="mt-5 flex a-c ">
|
|
|
+ <span v-if="item.totalNumber" class="text-[12px] text-[#666]">数量:{{ item.totalNumber }}张</span>
|
|
|
+ <span class="text-[12px] text-[#666] ml-[16px]">价格:{{ item.packagePrice }}元</span>
|
|
|
+ <el-icon @click="removeSelectedRight(index)" color="#666" style="margin-left: auto;">
|
|
|
<Delete />
|
|
|
</el-icon>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
- <el-table class="details" :data="selectedPackageDetail.rightsDetailsList" max-height="300px"
|
|
|
- style="flex: 1;" border>
|
|
|
- <el-table-column prop="rightsName" label="权益名称" width="180" align="center" />
|
|
|
+ <el-table class="details" :data="selectedPackageDetail" max-height="300px"
|
|
|
+ :header-cell-style="{ color: '#333333' }" style="flex: 1;" border>
|
|
|
+ <template #empty>
|
|
|
+ <div class="flex f-c a-c ">
|
|
|
+ <img src="@/assets/images/empty.png" alt="">
|
|
|
+ <span style="font-size: 14px;color: #909399;">暂无数据</span>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ <el-table-column prop="rightsName" label="权益名称" width="180" align="center">
|
|
|
+ <template #default="scope">
|
|
|
+ <el-popover placement="right" trigger="hover" :width="324">
|
|
|
+ <div class="iframe-container" v-show="!iframeLoading">
|
|
|
+ <iframe :src="iframeUrl" frameborder="0" class="external-iframe"></iframe>
|
|
|
+ </div>
|
|
|
+ <div class="iframe-loading" v-show="iframeLoading">加载中...</div>
|
|
|
+ <template #reference>
|
|
|
+ <span class="rights-name-link" @mouseenter="benefitDetail(scope.row)">
|
|
|
+ {{ scope.row.rightsName }}
|
|
|
+ </span>
|
|
|
+ </template>
|
|
|
+ </el-popover>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
<el-table-column prop="number" label="数量" align="center" />
|
|
|
<el-table-column prop="contractRate" label="价格" align="center"></el-table-column>
|
|
|
<el-table-column prop="marketPrice" label="价值" align="center">
|
|
|
@@ -99,16 +119,23 @@
|
|
|
</el-table>
|
|
|
</div>
|
|
|
<div class="RightselectedList mt-[16px] " v-if="insOrderRightsList.length > 0">
|
|
|
- <el-table class="details" :data="insOrderRightsList" max-height="300px" style="flex: 1;cursor: pointer;"
|
|
|
- border>
|
|
|
+ <el-table class="details" :data="insOrderRightsList" max-height="300px"
|
|
|
+ :header-cell-style="{ color: '#333333' }" style="flex: 1;cursor: pointer;" border>
|
|
|
+ <template #empty>
|
|
|
+ <div class="flex f-c a-c ">
|
|
|
+ <img src="@/assets/images/empty.png" alt="" style="width: 100px;">
|
|
|
+ <span style="font-size: 14px;color: #909399;">暂无数据</span>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
<el-table-column prop="rightsName" label="权益名称" align="center">
|
|
|
<template #default="scope">
|
|
|
- <el-popover placement="right" trigger="click" :width="324">
|
|
|
- <div class="iframe-container">
|
|
|
+ <el-popover placement="right" trigger="hover" :width="324">
|
|
|
+ <div class="iframe-container" v-show="!iframeLoading">
|
|
|
<iframe :src="iframeUrl" frameborder="0" class="external-iframe"></iframe>
|
|
|
</div>
|
|
|
+ <div class="iframe-loading" v-show="iframeLoading">加载中...</div>
|
|
|
<template #reference>
|
|
|
- <span @click="benefitDetail(scope.row)" :class="{ 'clicked': clickedRightsId === scope.row.id }">
|
|
|
+ <span class="rights-name-link" @mouseenter="benefitDetail(scope.row)">
|
|
|
{{ scope.row.rightsName }}
|
|
|
</span>
|
|
|
</template>
|
|
|
@@ -124,7 +151,8 @@
|
|
|
</el-table-column>
|
|
|
<el-table-column prop="number" label="数量" align="center">
|
|
|
<template #default="scope">
|
|
|
- <el-input-number size="small" :model-value="scope.row.rightsCount" style="width: 80px;"
|
|
|
+ <el-input-number class="rights-count-input" size="small" :model-value="scope.row.rightsCount"
|
|
|
+ style="width: 80px;"
|
|
|
@update:model-value="val => onRightsCountChange(val, scope.$index, 'insOrderRightsList', 'contractRate')"
|
|
|
:min="0" />
|
|
|
</template>
|
|
|
@@ -154,7 +182,7 @@
|
|
|
<Warning />
|
|
|
</el-icon>
|
|
|
<span>本次订单共计优惠<span class="font-size-[16px] font-bold">{{ insFeeOrders.availableAmount ||
|
|
|
- 0}}</span>元,您可使用部分优惠金额为客户购买车主服务。</span>
|
|
|
+ 0 }}</span>元,您可使用部分优惠金额为客户购买车主服务。</span>
|
|
|
</div>
|
|
|
<div class="flex a-c mt-[24px]">
|
|
|
<span style="flex-shrink: 0;" class="mr-[12px]">可用金额</span>
|
|
|
@@ -183,7 +211,7 @@
|
|
|
<script lang='ts' setup>
|
|
|
import { ref, reactive, computed, onBeforeMount, watch } from 'vue'
|
|
|
import api from '@/api'
|
|
|
-import { ElMessage, DrawerProps } from 'element-plus'
|
|
|
+import { ElMessage, DrawerProps, ElMessageBox } from 'element-plus'
|
|
|
import Decimal from 'decimal.js'
|
|
|
import EquitiesItem from './EquitiesItem.vue' // 权益单品模块
|
|
|
import EquitiesPage from './EquitiesPage.vue' // 权益套餐模块
|
|
|
@@ -197,7 +225,7 @@ const props = defineProps<{
|
|
|
}>();
|
|
|
console.log(props.EquitiesInfo)
|
|
|
const emits = defineEmits(['update:show', 'cancel', 'save']);
|
|
|
-
|
|
|
+const OtherRadio = ref('null')//其他接收人
|
|
|
// 子弹窗状态
|
|
|
const equitiesItemShow = ref(false);
|
|
|
const equitiesPageShow = ref(false);
|
|
|
@@ -235,7 +263,7 @@ const privilegeItem = ref(); //权益单品列表
|
|
|
const insOrderRightsPackageList = ref([]); //权益套餐选中列表
|
|
|
const insOrderRightsList = ref([]); //权益单品选中列表
|
|
|
const benefitPackageIndex = ref(null); //选中的权益套餐索引
|
|
|
-const selectedPackageDetail = ref<any>({}) //选中的权益套餐详情
|
|
|
+const selectedPackageDetail = ref<any>([]) //选中的权益套餐详情
|
|
|
const totalPriceCount = computed(() => {
|
|
|
// 计算权益套餐的总价
|
|
|
const packageTotal = insOrderRightsPackageList.value?.reduce((sum: Decimal, item: any) => {
|
|
|
@@ -261,6 +289,23 @@ const totalPriceCount1 = computed(() => {
|
|
|
const sum = new Decimal(itemTotal);
|
|
|
return sum.toString(); // 返回字符串
|
|
|
});
|
|
|
+// 根据可用金额与已选权益价值,高精度计算已使用/剩余金额
|
|
|
+// 已使用金额 = 已选权益价值;剩余金额 = 可用金额 - 已使用金额
|
|
|
+const calcUsedAndRemaining = computed(() => {
|
|
|
+ const available = new Decimal(insFeeOrders.value.availableAmount || 0)
|
|
|
+ const selectedValue = new Decimal(
|
|
|
+ insOrderRightsPackageList.value.length > 0 ? totalPriceCount.value : (totalPriceCount1.value || 0)
|
|
|
+ )
|
|
|
+ const usedAmount = selectedValue
|
|
|
+ const remainingAmount = available.minus(usedAmount)
|
|
|
+ // 同步赋值给 insFeeOrders,供模板及其他逻辑使用
|
|
|
+ insFeeOrders.value.usedAmount = usedAmount.toFixed(2)
|
|
|
+ insFeeOrders.value.remainingAmount = remainingAmount.toFixed(2)
|
|
|
+ return {
|
|
|
+ usedAmount: usedAmount.toFixed(2),
|
|
|
+ remainingAmount: remainingAmount.toFixed(2),
|
|
|
+ }
|
|
|
+});
|
|
|
//合并所有已选权益套餐和权益单品
|
|
|
const selectedRights = computed(() => {
|
|
|
const selectedPackages = insOrderRightsPackageList.value?.filter((item: any) => item.rightsCount > 0) || []
|
|
|
@@ -343,14 +388,8 @@ const tabslist = ref([
|
|
|
|
|
|
// 选中的权益套餐详情
|
|
|
const rightsDetails = async (item: any, index: any) => {
|
|
|
- selectedPackageDetail.value = item;
|
|
|
+ selectedPackageDetail.value = item.rightsDetailsList || [];
|
|
|
benefitPackageIndex.value = index;
|
|
|
- try {
|
|
|
- const response = await api.additionalApi.rightsGrant(item.id);
|
|
|
- selectedPackageDetail.value.rightsDetailsList = response.data || {};
|
|
|
- } catch (error) {
|
|
|
- console.error('获取权益套餐详情失败:', error);
|
|
|
- }
|
|
|
}
|
|
|
// 地区选项
|
|
|
const regionOptions = ref();
|
|
|
@@ -378,21 +417,47 @@ const provinceChange = (value: any) => {
|
|
|
}
|
|
|
const PackageBenefits = () => {
|
|
|
if (insOrderRightsList.value.length > 0) {
|
|
|
- return ElMessage({
|
|
|
- type: 'warning',
|
|
|
- message: '套餐和单品只能选择其中1种',
|
|
|
- plain: true,
|
|
|
- })
|
|
|
+ // 已选单品权益,提醒二选一,确认后清空单品再选套餐
|
|
|
+ ElMessageBox.confirm(
|
|
|
+ '您已选择单品权益,套餐和单品只能二选一。是否清空已选单品权益,继续选择套餐?',
|
|
|
+ '提示',
|
|
|
+ {
|
|
|
+ confirmButtonText: '清空并选择套餐',
|
|
|
+ cancelButtonText: '取消',
|
|
|
+ type: 'warning',
|
|
|
+ center: true,
|
|
|
+ }
|
|
|
+ )
|
|
|
+ .then(() => {
|
|
|
+ insOrderRightsList.value = [] // 清空已选单品权益
|
|
|
+ equitiesPageShow.value = true
|
|
|
+ })
|
|
|
+ .catch(() => {
|
|
|
+ })
|
|
|
+ return
|
|
|
}
|
|
|
equitiesPageShow.value = true;
|
|
|
}
|
|
|
const RightsBenefits = () => {
|
|
|
if (insOrderRightsPackageList.value.length > 0) {
|
|
|
- return ElMessage({
|
|
|
- type: 'warning',
|
|
|
- message: '套餐和单品只能选择其中1种',
|
|
|
- plain: true,
|
|
|
- })
|
|
|
+ // 已选套餐权益,提醒二选一,确认后清空套餐再选单品
|
|
|
+ ElMessageBox.confirm(
|
|
|
+ '您已选择套餐权益,套餐和单品只能二选一。是否清空已选套餐权益,继续选择单品?',
|
|
|
+ '提示',
|
|
|
+ {
|
|
|
+ confirmButtonText: '清空并选择单品',
|
|
|
+ cancelButtonText: '取消',
|
|
|
+ type: 'warning',
|
|
|
+ center: true,
|
|
|
+ }
|
|
|
+ )
|
|
|
+ .then(() => {
|
|
|
+ insOrderRightsPackageList.value = [] // 清空已选套餐权益
|
|
|
+ equitiesItemShow.value = true
|
|
|
+ })
|
|
|
+ .catch(() => {
|
|
|
+ })
|
|
|
+ return
|
|
|
}
|
|
|
equitiesItemShow.value = true;
|
|
|
}
|
|
|
@@ -407,7 +472,11 @@ const handleEquitiesItemSave = (selectedItems: any[]) => {
|
|
|
insOrderRightsList.value = selectedItems;
|
|
|
}
|
|
|
const saveEquitiesPage = (selectedItems: any[]) => {
|
|
|
+ console.log(selectedItems)
|
|
|
insOrderRightsPackageList.value = selectedItems;
|
|
|
+ selectedPackageDetail.value = selectedItems[0].rightsDetailsList || [];
|
|
|
+ benefitPackageIndex.value = 0;
|
|
|
+
|
|
|
}
|
|
|
const adjustDiscountAmount = () => {
|
|
|
adjustDiscountAmountShow.value = true;
|
|
|
@@ -450,6 +519,8 @@ const adjustDiscountAmountconfirm = () => {
|
|
|
});
|
|
|
}
|
|
|
const save = () => {
|
|
|
+ console.log(form.recipient)
|
|
|
+ // return
|
|
|
if (!form.recipient) {
|
|
|
ElMessage({
|
|
|
type: 'warning',
|
|
|
@@ -476,16 +547,31 @@ const save = () => {
|
|
|
emits("save", insOrderRightsInfoDto)
|
|
|
}
|
|
|
const iframeUrl = ref('');//权益单品详情
|
|
|
-const clickedRightsId = ref<string | number | null>(null); // 记录点击的权益ID
|
|
|
+const iframeLoading = ref(false); // 详情加载中,显示加载占位
|
|
|
+const rightsUrlCache = new Map<string | number, string>(); // 权益详情地址缓存
|
|
|
+let latestRequestId = 0; // 竞态标记:只让最后一次移入的请求生效
|
|
|
const benefitDetail = (item: any) => {
|
|
|
- clickedRightsId.value = item.id; // 设置点击状态
|
|
|
+ // 缓存命中:直接显示,不发请求,不闪
|
|
|
+ const cachedUrl = rightsUrlCache.get(item.id);
|
|
|
+ if (cachedUrl) {
|
|
|
+ iframeUrl.value = cachedUrl;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ // 未命中:显示加载占位并请求详情(不清空 iframeUrl,保留旧内容直到新内容就绪)
|
|
|
+ const requestId = ++latestRequestId;
|
|
|
+ iframeLoading.value = true;
|
|
|
api.additionalApi.rightsProduct({
|
|
|
rightsId: item.id,
|
|
|
}).then((res: any) => {
|
|
|
+ if (requestId !== latestRequestId) {
|
|
|
+ return; // 已有更新的移入,丢弃过期响应
|
|
|
+ }
|
|
|
if (res.code == '200') {
|
|
|
- iframeUrl.value = `https://life.baoxianzhanggui.com/custh5/#/packageF/pages/home/details-channel?productId=${res.data[0].productId}`
|
|
|
- } else {
|
|
|
+ const url = `https://life.baoxianzhanggui.com/custh5/#/packageF/pages/home/details-channel?productId=${res.data[0].productId}`
|
|
|
+ rightsUrlCache.set(item.id, url);
|
|
|
+ iframeUrl.value = url;
|
|
|
}
|
|
|
+ iframeLoading.value = false;
|
|
|
});
|
|
|
console.log(item)
|
|
|
}
|
|
|
@@ -571,18 +657,21 @@ const benefitDetail = (item: any) => {
|
|
|
padding: 10px;
|
|
|
box-sizing: border-box;
|
|
|
border-radius: 4px 4px 4px 4px;
|
|
|
+ border: 1px solid #F7F7F7;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ .view-card-item-active {
|
|
|
+ border: 1px solid #0083FF;
|
|
|
}
|
|
|
|
|
|
.view-item:hover {
|
|
|
- background: #dfdfdf;
|
|
|
+ background: #F6FBFF;
|
|
|
+
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
- .view-card .active {
|
|
|
- background: #dfdfdf;
|
|
|
- color: #fff;
|
|
|
- }
|
|
|
}
|
|
|
|
|
|
// 自定义抽屉样式
|
|
|
@@ -625,9 +714,54 @@ const benefitDetail = (item: any) => {
|
|
|
border: none;
|
|
|
}
|
|
|
|
|
|
-// 点击权益名称变色效果
|
|
|
-.clicked {
|
|
|
- color: #409EFF;
|
|
|
+// 权益详情加载占位
|
|
|
+.iframe-loading {
|
|
|
+ width: 300px;
|
|
|
+ height: 600px;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ color: #909399;
|
|
|
+ font-size: 14px;
|
|
|
+}
|
|
|
+
|
|
|
+// 移入权益名称变色效果
|
|
|
+.linkrights-name- {
|
|
|
+ cursor: pointer;
|
|
|
+
|
|
|
+ &:hover {
|
|
|
+ color: #409EFF;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 权益数量步进器:加减号背景白色、图标固定蓝色(默认和悬停均为蓝色)
|
|
|
+.rights-count-input {
|
|
|
+
|
|
|
+ :deep(.el-input-number__increase),
|
|
|
+ :deep(.el-input-number__decrease) {
|
|
|
+ background-color: #fff !important;
|
|
|
+ color: #0083FF !important;
|
|
|
+
|
|
|
+ .el-icon {
|
|
|
+ color: #0083FF !important;
|
|
|
+ }
|
|
|
+
|
|
|
+ &:hover {
|
|
|
+ background-color: #fff !important;
|
|
|
+ color: #0083FF !important;
|
|
|
+
|
|
|
+ .el-icon {
|
|
|
+ color: #0083FF !important;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 去掉鼠标移入时的蓝色边框,保持原灰色边框
|
|
|
+ :deep(.el-input__wrapper) {
|
|
|
+ &:hover {
|
|
|
+ box-shadow: 0 0 0 1px var(--el-input-border-color, #dcdfe6) inset;
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
// 权益金额调整弹窗
|
|
|
@@ -641,4 +775,18 @@ const benefitDetail = (item: any) => {
|
|
|
padding: 10px 16px;
|
|
|
box-sizing: border-box;
|
|
|
}
|
|
|
+
|
|
|
+// 移入权益名称变色效果
|
|
|
+.rights-name-link {
|
|
|
+ cursor: pointer;
|
|
|
+
|
|
|
+ &:hover {
|
|
|
+ color: #409EFF;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 移入权益名称时当前单元格背景色(!important 压过 el-table 行 hover 背景)
|
|
|
+:deep(.el-table__body td.el-table__cell:has(.rights-name-link:hover)) {
|
|
|
+ background-color: #F6FBFF !important;
|
|
|
+}
|
|
|
</style>
|