f
This commit is contained in:
@@ -41,17 +41,17 @@ onMounted(async () => {
|
|||||||
}
|
}
|
||||||
getWeixinAuthUrl();
|
getWeixinAuthUrl();
|
||||||
|
|
||||||
// 延迟配置微信分享
|
// 延迟配置微信分享(带上当前路由信息)
|
||||||
setTimeout(async () => {
|
setTimeout(async () => {
|
||||||
if (isWeChat.value && window.jWeixin) {
|
if (isWeChat.value && window.jWeixin) {
|
||||||
await setDynamicShare();
|
await setDynamicShare(route);
|
||||||
}
|
}
|
||||||
}, 1000);
|
}, 1000);
|
||||||
|
|
||||||
// 监听路由变化更新分享配置
|
// 监听路由变化更新分享配置
|
||||||
router.afterEach(async () => {
|
router.afterEach(async (to) => {
|
||||||
if (isWeChat.value && window.jWeixin && !authStore.isWeixinAuthing) {
|
if (isWeChat.value && window.jWeixin && !authStore.isWeixinAuthing) {
|
||||||
await setDynamicShare();
|
await setDynamicShare(to);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -278,3 +278,68 @@ export function getInviteLink(params) {
|
|||||||
const queryString = buildQueryString(params || {});
|
const queryString = buildQueryString(params || {});
|
||||||
return useApiFetch(`/agent/invite_link${queryString}`).get().json();
|
return useApiFetch(`/agent/invite_link${queryString}`).get().json();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ==================== 白名单相关接口 ====================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取可屏蔽的feature列表(带价格)
|
||||||
|
*/
|
||||||
|
export function getWhitelistFeatures() {
|
||||||
|
return useApiFetch("/agent/whitelist/features").get().json();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建白名单订单
|
||||||
|
* @param {object} params - 创建参数
|
||||||
|
* @param {string} params.id_card - 身份证号
|
||||||
|
* @param {string[]} params.feature_ids - 要屏蔽的feature ID列表
|
||||||
|
* @param {string} params.order_id - 关联的查询订单ID(可选)
|
||||||
|
*/
|
||||||
|
export function createWhitelistOrder(params) {
|
||||||
|
return useApiFetch("/agent/whitelist/order/create").post(params).json();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询白名单列表
|
||||||
|
* @param {object} params - 查询参数
|
||||||
|
* @param {number} params.page - 页码
|
||||||
|
* @param {number} params.page_size - 每页数量
|
||||||
|
* @param {string} params.id_card - 身份证号(可选,用于筛选)
|
||||||
|
*/
|
||||||
|
export function getWhitelistList(params) {
|
||||||
|
const queryString = buildQueryString(params || {});
|
||||||
|
return useApiFetch(`/agent/whitelist/list${queryString}`).get().json();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查模块是否已下架
|
||||||
|
* @param {object} params - 查询参数
|
||||||
|
* @param {string} params.id_card - 身份证号
|
||||||
|
* @param {string} params.feature_api_id - Feature的API标识
|
||||||
|
*/
|
||||||
|
export function checkFeatureWhitelistStatus(params) {
|
||||||
|
const queryString = buildQueryString(params || {});
|
||||||
|
return useApiFetch(`/agent/whitelist/check${queryString}`).get().json();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 下架单个模块(创建订单并支付/或免费下架)
|
||||||
|
* @param {object} params - 下架参数
|
||||||
|
* @param {string} params.id_card - 身份证号
|
||||||
|
* @param {string} params.feature_api_id - Feature的API标识
|
||||||
|
* @param {string} params.order_id - 关联的查询订单ID(可选)
|
||||||
|
* @param {string} params.query_id - 查询记录ID(用于后端删除报告数据)
|
||||||
|
*/
|
||||||
|
export function offlineFeature(params) {
|
||||||
|
return useApiFetch("/agent/whitelist/offline").post(params).json();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查订单是否属于当前代理推广
|
||||||
|
* @param {object} params - 查询参数
|
||||||
|
* @param {string} params.order_id - 订单ID
|
||||||
|
*/
|
||||||
|
export function checkOrderAgent(params) {
|
||||||
|
const queryString = buildQueryString(params || {});
|
||||||
|
return useApiFetch(`/agent/order/agent${queryString}`).get().json();
|
||||||
|
}
|
||||||
|
|||||||
@@ -3,12 +3,18 @@ import ShareReportButton from "./ShareReportButton.vue";
|
|||||||
import TitleBanner from "./TitleBanner.vue";
|
import TitleBanner from "./TitleBanner.vue";
|
||||||
import VerificationCard from "./VerificationCard.vue";
|
import VerificationCard from "./VerificationCard.vue";
|
||||||
import StyledTabs from "./StyledTabs.vue";
|
import StyledTabs from "./StyledTabs.vue";
|
||||||
|
import WhitelistModuleDialog from "./WhitelistModuleDialog.vue";
|
||||||
|
import Payment from "./Payment.vue";
|
||||||
import { splitDWBG8B4DForTabs } from '@/ui/CDWBG8B4D/utils/simpleSplitter.js';
|
import { splitDWBG8B4DForTabs } from '@/ui/CDWBG8B4D/utils/simpleSplitter.js';
|
||||||
import { splitDWBG6A2CForTabs } from '@/ui/DWBG6A2C/utils/simpleSplitter.js';
|
import { splitDWBG6A2CForTabs } from '@/ui/DWBG6A2C/utils/simpleSplitter.js';
|
||||||
import { splitJRZQ7F1AForTabs } from '@/ui/JRZQ7F1A/utils/simpleSplitter.js';
|
import { splitJRZQ7F1AForTabs } from '@/ui/JRZQ7F1A/utils/simpleSplitter.js';
|
||||||
import { splitCJRZQ5E9FForTabs } from '@/ui/CJRZQ5E9F/utils/simpleSplitter.js';
|
import { splitCJRZQ5E9FForTabs } from '@/ui/CJRZQ5E9F/utils/simpleSplitter.js';
|
||||||
import { splitCQYGL3F8EForTabs } from '@/ui/CQYGL3F8E/utils/simpleSplitter.js';
|
import { splitCQYGL3F8EForTabs } from '@/ui/CQYGL3F8E/utils/simpleSplitter.js';
|
||||||
import { useAppStore } from "@/stores/appStore";
|
import { useAppStore } from "@/stores/appStore";
|
||||||
|
import { useAgentStore } from "@/stores/agentStore";
|
||||||
|
import { storeToRefs } from 'pinia';
|
||||||
|
import { showFailToast } from 'vant';
|
||||||
|
import { checkFeatureWhitelistStatus, offlineFeature, checkOrderAgent } from '@/api/agent';
|
||||||
|
|
||||||
// 动态导入产品背景图片的函数
|
// 动态导入产品背景图片的函数
|
||||||
const loadProductBackground = async (productType) => {
|
const loadProductBackground = async (productType) => {
|
||||||
@@ -51,6 +57,11 @@ const props = defineProps({
|
|||||||
type: String,
|
type: String,
|
||||||
default: "",
|
default: "",
|
||||||
},
|
},
|
||||||
|
queryId: {
|
||||||
|
type: String,
|
||||||
|
required: false,
|
||||||
|
default: "",
|
||||||
|
},
|
||||||
feature: {
|
feature: {
|
||||||
type: String,
|
type: String,
|
||||||
required: true,
|
required: true,
|
||||||
@@ -96,8 +107,26 @@ const {
|
|||||||
isEmpty,
|
isEmpty,
|
||||||
isDone,
|
isDone,
|
||||||
isExample,
|
isExample,
|
||||||
|
orderId,
|
||||||
|
orderNo,
|
||||||
|
queryId,
|
||||||
} = toRefs(props);
|
} = toRefs(props);
|
||||||
|
|
||||||
|
// 代理信息
|
||||||
|
const agentStore = useAgentStore()
|
||||||
|
const { isDiamond } = storeToRefs(agentStore)
|
||||||
|
|
||||||
|
// 屏蔽模块弹窗(已废弃,保留用于兼容)
|
||||||
|
const showWhitelistDialog = ref(false)
|
||||||
|
|
||||||
|
// 订单是否属于当前代理推广
|
||||||
|
const isAgentOrder = ref(false)
|
||||||
|
|
||||||
|
// 获取身份证号(从 reportParams 中,用于展示与接口)
|
||||||
|
const idCard = computed(() => {
|
||||||
|
return reportParams.value?.id_card || ''
|
||||||
|
})
|
||||||
|
|
||||||
const active = ref(null);
|
const active = ref(null);
|
||||||
const backgroundContainerRef = ref(null); // 背景容器的引用
|
const backgroundContainerRef = ref(null); // 背景容器的引用
|
||||||
|
|
||||||
@@ -108,15 +137,272 @@ const imageAspectRatio = ref(0); // 缓存图片宽高比
|
|||||||
const MAX_BACKGROUND_HEIGHT = 211; // 最大背景高度,防止图片过高变形
|
const MAX_BACKGROUND_HEIGHT = 211; // 最大背景高度,防止图片过高变形
|
||||||
const trapezoidBgImage = ref(''); // 牌匾背景图片
|
const trapezoidBgImage = ref(''); // 牌匾背景图片
|
||||||
|
|
||||||
|
// 模块下架状态映射:主模块ID -> { isOfflined, whitelistPrice, isSubmitting }
|
||||||
|
const featureOfflineStatus = ref(new Map())
|
||||||
|
|
||||||
|
// 提取主模块ID(去掉下划线后的部分)
|
||||||
|
const getMainApiId = (apiId) => {
|
||||||
|
if (!apiId) return ''
|
||||||
|
const index = apiId.indexOf('_')
|
||||||
|
return index > 0 ? apiId.substring(0, index) : apiId
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查模块下架状态
|
||||||
|
const checkFeatureStatus = async (featureApiId, forceRefresh = false) => {
|
||||||
|
if (!idCard.value || !featureApiId) return
|
||||||
|
|
||||||
|
const mainApiId = getMainApiId(featureApiId)
|
||||||
|
if (!mainApiId) return
|
||||||
|
|
||||||
|
if (!forceRefresh && featureOfflineStatus.value.has(mainApiId)) return
|
||||||
|
|
||||||
|
try {
|
||||||
|
const { data, error } = await checkFeatureWhitelistStatus({
|
||||||
|
id_card: idCard.value,
|
||||||
|
feature_api_id: mainApiId,
|
||||||
|
query_id: queryId.value || '',
|
||||||
|
})
|
||||||
|
if (data.value && !error.value && data.value.code === 200) {
|
||||||
|
const isWhitelisted = data.value.data.is_whitelisted || false
|
||||||
|
const dataDeleted = data.value.data.data_deleted !== undefined ? data.value.data.data_deleted : true
|
||||||
|
const status = {
|
||||||
|
isOfflined: isWhitelisted && dataDeleted,
|
||||||
|
whitelistPrice: data.value.data.whitelist_price || 0,
|
||||||
|
isSubmitting: false,
|
||||||
|
}
|
||||||
|
featureOfflineStatus.value.set(mainApiId, status)
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error('检查模块状态失败:', err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 批量检查所有模块的下架状态
|
||||||
|
const checkAllFeaturesStatus = async () => {
|
||||||
|
if (!idCard.value || !isAgentOrder.value || isExample.value) return
|
||||||
|
|
||||||
|
const featureApiIds = processedReportData.value.map(item => item.data.apiID)
|
||||||
|
const mainApiIds = [...new Set(featureApiIds.map(id => getMainApiId(id)))]
|
||||||
|
|
||||||
|
for (const mainApiId of mainApiIds) {
|
||||||
|
if (mainApiId) {
|
||||||
|
await checkFeatureStatus(mainApiId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取模块下架状态
|
||||||
|
const getFeatureStatus = (featureApiId) => {
|
||||||
|
const mainApiId = getMainApiId(featureApiId)
|
||||||
|
const status = featureOfflineStatus.value.get(mainApiId) || {
|
||||||
|
isOfflined: false,
|
||||||
|
whitelistPrice: 0,
|
||||||
|
isSubmitting: false,
|
||||||
|
}
|
||||||
|
return status
|
||||||
|
}
|
||||||
|
|
||||||
|
// 当前正在下架的模块信息(用于支付确认弹窗)
|
||||||
|
const currentOfflineFeature = ref(null)
|
||||||
|
const showOfflineConfirmDialog = ref(false)
|
||||||
|
|
||||||
|
// 处理下架按钮点击
|
||||||
|
const handleOfflineClick = async (featureApiId, featureName) => {
|
||||||
|
const mainApiId = getMainApiId(featureApiId)
|
||||||
|
const status = getFeatureStatus(mainApiId)
|
||||||
|
|
||||||
|
// 如果已下架,不允许再次点击
|
||||||
|
if (status.isOfflined) {
|
||||||
|
showFailToast('该模块已下架')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果 whitelistPrice = 0,直接下架(免费),不需要支付确认
|
||||||
|
if (status.whitelistPrice <= 0) {
|
||||||
|
await confirmOfflineDirectly(mainApiId, featureName)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果 whitelistPrice > 0,需要支付确认
|
||||||
|
currentOfflineFeature.value = {
|
||||||
|
featureApiId: mainApiId,
|
||||||
|
featureName,
|
||||||
|
whitelistPrice: status.whitelistPrice,
|
||||||
|
}
|
||||||
|
showOfflineConfirmDialog.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// 白名单下架支付弹窗相关状态
|
||||||
|
const showWhitelistPayment = ref(false)
|
||||||
|
const whitelistPaymentData = ref({ product_name: '', sell_price: 0 })
|
||||||
|
const whitelistPaymentId = ref('')
|
||||||
|
const whitelistPaymentType = ref('whitelist')
|
||||||
|
|
||||||
|
// 获取当前报告页面的 URL(用于支付成功后返回)
|
||||||
|
const getCurrentReportUrl = () => {
|
||||||
|
if (orderNo.value) {
|
||||||
|
return `/report?orderNo=${orderNo.value}`
|
||||||
|
} else if (orderId.value) {
|
||||||
|
return `/report?orderId=${orderId.value}`
|
||||||
|
}
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
|
||||||
|
// 直接下架(免费)
|
||||||
|
const confirmOfflineDirectly = async (mainApiId, featureName) => {
|
||||||
|
if (!idCard.value || !mainApiId) return
|
||||||
|
|
||||||
|
const status = getFeatureStatus(mainApiId)
|
||||||
|
status.isSubmitting = true
|
||||||
|
featureOfflineStatus.value.set(mainApiId, { ...status })
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (!queryId.value) {
|
||||||
|
showFailToast('缺少查询记录ID,无法下架')
|
||||||
|
const currentStatus = getFeatureStatus(mainApiId)
|
||||||
|
currentStatus.isSubmitting = false
|
||||||
|
featureOfflineStatus.value.set(mainApiId, { ...currentStatus })
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const { data, error } = await offlineFeature({
|
||||||
|
query_id: queryId.value,
|
||||||
|
feature_api_id: mainApiId,
|
||||||
|
})
|
||||||
|
|
||||||
|
if (!data.value || error.value || data.value.code !== 200) {
|
||||||
|
showFailToast(data.value?.msg || '下架失败')
|
||||||
|
const currentStatus = getFeatureStatus(mainApiId)
|
||||||
|
currentStatus.isSubmitting = false
|
||||||
|
featureOfflineStatus.value.set(mainApiId, { ...currentStatus })
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const resp = data.value.data || {}
|
||||||
|
if (resp.need_pay) {
|
||||||
|
const currentStatus = getFeatureStatus(mainApiId)
|
||||||
|
currentStatus.isSubmitting = false
|
||||||
|
currentStatus.whitelistPrice = resp.amount || 0
|
||||||
|
featureOfflineStatus.value.set(mainApiId, { ...currentStatus })
|
||||||
|
|
||||||
|
whitelistPaymentData.value = {
|
||||||
|
product_name: `${featureName || '模块'} 下架`,
|
||||||
|
sell_price: resp.amount || 0,
|
||||||
|
}
|
||||||
|
whitelistPaymentId.value = `${idCard.value}|${mainApiId}`
|
||||||
|
whitelistPaymentType.value = 'whitelist'
|
||||||
|
showWhitelistPayment.value = true
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
showFailToast('下架成功')
|
||||||
|
|
||||||
|
const updatedStatus = getFeatureStatus(mainApiId)
|
||||||
|
updatedStatus.isSubmitting = false
|
||||||
|
updatedStatus.isOfflined = true
|
||||||
|
featureOfflineStatus.value.set(mainApiId, { ...updatedStatus })
|
||||||
|
|
||||||
|
if (queryId.value || orderId.value) {
|
||||||
|
window.location.reload()
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error('下架模块失败:', err)
|
||||||
|
showFailToast('下架模块失败')
|
||||||
|
const currentStatus = getFeatureStatus(mainApiId)
|
||||||
|
currentStatus.isSubmitting = false
|
||||||
|
featureOfflineStatus.value.set(mainApiId, { ...currentStatus })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 确认下架(付费场景)
|
||||||
|
const confirmOffline = async () => {
|
||||||
|
if (!currentOfflineFeature.value) return
|
||||||
|
|
||||||
|
const { featureApiId } = currentOfflineFeature.value
|
||||||
|
const mainApiId = featureApiId
|
||||||
|
|
||||||
|
if (!queryId.value) {
|
||||||
|
showFailToast('缺少查询记录ID,无法下架')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const status = getFeatureStatus(mainApiId)
|
||||||
|
status.isSubmitting = true
|
||||||
|
featureOfflineStatus.value.set(mainApiId, { ...status })
|
||||||
|
|
||||||
|
try {
|
||||||
|
const { data, error } = await offlineFeature({
|
||||||
|
query_id: queryId.value,
|
||||||
|
feature_api_id: mainApiId,
|
||||||
|
})
|
||||||
|
|
||||||
|
if (!data.value || error.value || data.value.code !== 200) {
|
||||||
|
showFailToast(data.value?.msg || '下架失败')
|
||||||
|
const currentStatus = getFeatureStatus(mainApiId)
|
||||||
|
currentStatus.isSubmitting = false
|
||||||
|
featureOfflineStatus.value.set(mainApiId, { ...currentStatus })
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const resp = data.value.data || {}
|
||||||
|
if (resp.need_pay) {
|
||||||
|
showOfflineConfirmDialog.value = false
|
||||||
|
|
||||||
|
whitelistPaymentData.value = {
|
||||||
|
product_name: `${currentOfflineFeature.value?.featureName || '模块'} 下架`,
|
||||||
|
sell_price: resp.amount || 0,
|
||||||
|
}
|
||||||
|
whitelistPaymentId.value = `${idCard.value}|${mainApiId}`
|
||||||
|
whitelistPaymentType.value = 'whitelist'
|
||||||
|
showWhitelistPayment.value = true
|
||||||
|
|
||||||
|
const currentStatus = getFeatureStatus(mainApiId)
|
||||||
|
currentStatus.isSubmitting = false
|
||||||
|
featureOfflineStatus.value.set(mainApiId, { ...currentStatus })
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
showFailToast('下架成功')
|
||||||
|
showOfflineConfirmDialog.value = false
|
||||||
|
currentOfflineFeature.value = null
|
||||||
|
|
||||||
|
const updatedStatus = getFeatureStatus(mainApiId)
|
||||||
|
updatedStatus.isSubmitting = false
|
||||||
|
featureOfflineStatus.value.set(mainApiId, { ...updatedStatus })
|
||||||
|
|
||||||
|
if (queryId.value || orderId.value) {
|
||||||
|
window.location.reload()
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error('下架模块失败:', err)
|
||||||
|
showFailToast('下架模块失败')
|
||||||
|
const currentStatus = getFeatureStatus(mainApiId)
|
||||||
|
currentStatus.isSubmitting = false
|
||||||
|
featureOfflineStatus.value.set(mainApiId, { ...currentStatus })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 打开屏蔽模块弹窗(已废弃,保留用于兼容)
|
||||||
|
const openWhitelistDialog = () => {
|
||||||
|
if (!idCard.value) {
|
||||||
|
console.error('无法获取身份证号')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
showWhitelistDialog.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// 屏蔽成功后的回调(已废弃,保留用于兼容)
|
||||||
|
const onWhitelistSuccess = () => {
|
||||||
|
console.log('模块已屏蔽')
|
||||||
|
}
|
||||||
|
|
||||||
// 计算背景高度
|
// 计算背景高度
|
||||||
const calculateBackgroundHeight = () => {
|
const calculateBackgroundHeight = () => {
|
||||||
if (imageAspectRatio.value > 0) {
|
if (imageAspectRatio.value > 0) {
|
||||||
// 获取容器的实际宽度,而不是整个窗口宽度
|
|
||||||
const containerWidth = backgroundContainerRef.value
|
const containerWidth = backgroundContainerRef.value
|
||||||
? backgroundContainerRef.value.offsetWidth
|
? backgroundContainerRef.value.offsetWidth
|
||||||
: window.innerWidth;
|
: window.innerWidth;
|
||||||
const calculatedHeight = containerWidth * imageAspectRatio.value;
|
const calculatedHeight = containerWidth * imageAspectRatio.value;
|
||||||
// 限制最大高度,防止图片过高
|
|
||||||
backgroundHeight.value = Math.min(calculatedHeight, MAX_BACKGROUND_HEIGHT);
|
backgroundHeight.value = Math.min(calculatedHeight, MAX_BACKGROUND_HEIGHT);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -126,13 +412,10 @@ const loadBackgroundImage = async () => {
|
|||||||
const background = await loadProductBackground(feature.value);
|
const background = await loadProductBackground(feature.value);
|
||||||
productBackground.value = background || '';
|
productBackground.value = background || '';
|
||||||
|
|
||||||
// 加载图片后计算高度
|
|
||||||
if (background) {
|
if (background) {
|
||||||
const img = new Image();
|
const img = new Image();
|
||||||
img.onload = () => {
|
img.onload = () => {
|
||||||
// 缓存图片宽高比
|
|
||||||
imageAspectRatio.value = img.height / img.width;
|
imageAspectRatio.value = img.height / img.width;
|
||||||
// 图片加载完成后,等待下一帧再计算高度,确保容器已渲染
|
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
calculateBackgroundHeight();
|
calculateBackgroundHeight();
|
||||||
});
|
});
|
||||||
@@ -149,8 +432,23 @@ onMounted(async () => {
|
|||||||
await loadBackgroundImage();
|
await loadBackgroundImage();
|
||||||
await loadTrapezoidBackground();
|
await loadTrapezoidBackground();
|
||||||
|
|
||||||
// 监听窗口大小变化,重新计算高度
|
|
||||||
window.addEventListener('resize', handleResize);
|
window.addEventListener('resize', handleResize);
|
||||||
|
|
||||||
|
// 检查订单是否属于当前代理推广
|
||||||
|
if (!isExample.value && orderId.value) {
|
||||||
|
try {
|
||||||
|
const { data, error } = await checkOrderAgent({ order_id: orderId.value })
|
||||||
|
if (data.value && !error.value && data.value.code === 200) {
|
||||||
|
isAgentOrder.value = data.value.data.is_agent_order
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error('检查订单代理状态失败:', err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isAgentOrder.value && idCard.value && !isExample.value) {
|
||||||
|
checkAllFeaturesStatus()
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// 处理窗口大小变化(带防抖)
|
// 处理窗口大小变化(带防抖)
|
||||||
@@ -160,7 +458,7 @@ const handleResize = () => {
|
|||||||
}
|
}
|
||||||
resizeTimer = setTimeout(() => {
|
resizeTimer = setTimeout(() => {
|
||||||
calculateBackgroundHeight();
|
calculateBackgroundHeight();
|
||||||
}, 100); // 100ms 防抖延迟
|
}, 100);
|
||||||
};
|
};
|
||||||
|
|
||||||
// 组件卸载时移除监听器
|
// 组件卸载时移除监听器
|
||||||
@@ -171,23 +469,13 @@ onUnmounted(() => {
|
|||||||
window.removeEventListener('resize', handleResize);
|
window.removeEventListener('resize', handleResize);
|
||||||
});
|
});
|
||||||
|
|
||||||
// 处理数据拆分(支持DWBG8B4D、DWBG6A2C、CJRZQ5E9F和CQYGL3F8E)
|
// 处理数据拆分
|
||||||
const processedReportData = computed(() => {
|
const processedReportData = computed(() => {
|
||||||
let data = reportData.value;
|
let data = reportData.value;
|
||||||
// 拆分DWBG8B4D数据
|
|
||||||
data = splitDWBG8B4DForTabs(data);
|
data = splitDWBG8B4DForTabs(data);
|
||||||
|
|
||||||
// 拆分DWBG6A2C数据
|
|
||||||
data = splitDWBG6A2CForTabs(data);
|
data = splitDWBG6A2CForTabs(data);
|
||||||
|
|
||||||
// 拆分JRZQ7F1A数据
|
|
||||||
data = splitJRZQ7F1AForTabs(data);
|
data = splitJRZQ7F1AForTabs(data);
|
||||||
// // 拆分CJRZQ5E9F数据
|
|
||||||
// data = splitCJRZQ5E9FForTabs(data);
|
|
||||||
|
|
||||||
// 拆分CQYGL3F8E数据
|
|
||||||
data = splitCQYGL3F8EForTabs(data);
|
data = splitCQYGL3F8EForTabs(data);
|
||||||
// 过滤掉在featureMap中没有对应的项
|
|
||||||
return data.filter(item => featureMap[item.data.apiID]);
|
return data.filter(item => featureMap[item.data.apiID]);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -202,7 +490,7 @@ const backgroundContainerStyle = computed(() => {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
height: '180px', // 默认高度
|
height: '180px',
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -211,10 +499,10 @@ const backgroundImageStyle = computed(() => {
|
|||||||
if (getProductBackground.value) {
|
if (getProductBackground.value) {
|
||||||
return {
|
return {
|
||||||
backgroundImage: `url(${getProductBackground.value})`,
|
backgroundImage: `url(${getProductBackground.value})`,
|
||||||
backgroundSize: '100% auto', // 宽度100%,高度自动保持比例
|
backgroundSize: '100% auto',
|
||||||
backgroundPosition: 'center', // 向上偏移20px
|
backgroundPosition: 'center',
|
||||||
backgroundRepeat: 'no-repeat',
|
backgroundRepeat: 'no-repeat',
|
||||||
overflow: 'hidden', // 超出部分裁剪
|
overflow: 'hidden',
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return {};
|
return {};
|
||||||
@@ -752,10 +1040,8 @@ const calculateScore = () => {
|
|||||||
const apiID = item.data?.apiID;
|
const apiID = item.data?.apiID;
|
||||||
if (!apiID) return;
|
if (!apiID) return;
|
||||||
|
|
||||||
// 获取风险权重(如果不在配置中,默认为 3)
|
|
||||||
const weight = featureRiskLevels[apiID] ?? 3;
|
const weight = featureRiskLevels[apiID] ?? 3;
|
||||||
|
|
||||||
// 跳过权重为 0 的复合报告主模块(它们由子模块计算)
|
|
||||||
if (weight === 0) return;
|
if (weight === 0) return;
|
||||||
|
|
||||||
presentFeatures.push({
|
presentFeatures.push({
|
||||||
@@ -765,49 +1051,21 @@ const calculateScore = () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
if (presentFeatures.length === 0) return 100; // 无有效特征时返回满分(最安全)
|
if (presentFeatures.length === 0) return 100;
|
||||||
|
|
||||||
// 累计总风险分数
|
|
||||||
let totalRiskScore = 0;
|
let totalRiskScore = 0;
|
||||||
const riskDetails = []; // 用于调试
|
|
||||||
|
|
||||||
presentFeatures.forEach(({ apiID, index, weight }) => {
|
presentFeatures.forEach(({ apiID, index, weight }) => {
|
||||||
// 从组件风险评分中获取评分(0-100分,分数越高越安全)
|
|
||||||
const key = `${apiID}_${index}`;
|
const key = `${apiID}_${index}`;
|
||||||
const componentScore = componentRiskScores.value[key] ?? 100; // 默认100分(最安全)
|
const componentScore = componentRiskScores.value[key] ?? 100;
|
||||||
|
|
||||||
// 将组件评分转换为风险分数(0-100 -> 100-0)
|
|
||||||
const componentRisk = 100 - componentScore;
|
const componentRisk = 100 - componentScore;
|
||||||
|
const weightMultiplier = 1.5;
|
||||||
// 计算该模块的风险贡献(固定分值,不按占比)
|
|
||||||
// 使用权重系数放大高风险模块的影响
|
|
||||||
// 高风险模块(权重10)如果风险分数是0,扣20分(权重10 × 系数2)
|
|
||||||
// 中风险模块(权重7)如果风险分数是0,扣14分(权重7 × 系数2)
|
|
||||||
// 低风险模块(权重3)如果风险分数是0,扣6分(权重3 × 系数2)
|
|
||||||
const weightMultiplier = 1.5; // 权重系数,可以调整这个值来控制影响程度
|
|
||||||
const riskContribution = (componentRisk / 100) * weight * weightMultiplier;
|
const riskContribution = (componentRisk / 100) * weight * weightMultiplier;
|
||||||
|
|
||||||
riskDetails.push({
|
|
||||||
apiID,
|
|
||||||
index,
|
|
||||||
weight,
|
|
||||||
componentScore,
|
|
||||||
componentRisk,
|
|
||||||
riskContribution,
|
|
||||||
hasStatus: key in componentRiskScores.value
|
|
||||||
});
|
|
||||||
|
|
||||||
// 累加风险分数
|
|
||||||
totalRiskScore += riskContribution;
|
totalRiskScore += riskContribution;
|
||||||
});
|
});
|
||||||
|
|
||||||
// 将总风险分数限制在 0-90 范围内(确保最低分为10分)
|
|
||||||
const finalRiskScore = Math.max(0, Math.min(90, Math.round(totalRiskScore)));
|
const finalRiskScore = Math.max(0, Math.min(90, Math.round(totalRiskScore)));
|
||||||
|
|
||||||
// 转换为安全分数:分数越高越安全(100 - 风险分数)
|
|
||||||
// 最终分数范围:10-100分
|
|
||||||
const safetyScore = 100 - finalRiskScore;
|
const safetyScore = 100 - finalRiskScore;
|
||||||
|
|
||||||
return safetyScore;
|
return safetyScore;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -815,21 +1073,6 @@ const calculateScore = () => {
|
|||||||
watch([reportData, componentRiskScores], () => {
|
watch([reportData, componentRiskScores], () => {
|
||||||
reportScore.value = calculateScore();
|
reportScore.value = calculateScore();
|
||||||
|
|
||||||
// 将评分系统数据整理到一个对象中
|
|
||||||
const scoreData = {
|
|
||||||
timestamp: new Date().toISOString(),
|
|
||||||
finalScore: reportScore.value,
|
|
||||||
reportModules: processedReportData.value.map((item, index) => ({
|
|
||||||
apiID: item.data.apiID,
|
|
||||||
name: featureMap[item.data.apiID]?.name || '未知',
|
|
||||||
index: index,
|
|
||||||
riskScore: componentRiskScores.value[`${item.data.apiID}_${index}`] ?? '未上报',
|
|
||||||
weight: featureRiskLevels[item.data.apiID] ?? 0
|
|
||||||
})),
|
|
||||||
componentScores: componentRiskScores.value,
|
|
||||||
riskLevels: featureRiskLevels
|
|
||||||
};
|
|
||||||
|
|
||||||
}, { immediate: true, deep: true });
|
}, { immediate: true, deep: true });
|
||||||
|
|
||||||
// 从环境变量获取配置
|
// 从环境变量获取配置
|
||||||
|
|||||||
227
src/components/WhitelistModuleDialog.vue
Normal file
227
src/components/WhitelistModuleDialog.vue
Normal file
@@ -0,0 +1,227 @@
|
|||||||
|
<template>
|
||||||
|
<van-popup v-model:show="show" position="bottom" round :style="{ height: '70%' }" class="whitelist-module-dialog">
|
||||||
|
<div class="flex flex-col h-full">
|
||||||
|
<!-- 标题栏 -->
|
||||||
|
<div class="flex items-center justify-between p-4 border-b">
|
||||||
|
<h3 class="text-lg font-bold">屏蔽模块</h3>
|
||||||
|
<van-icon name="cross" size="20" @click="close" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 内容区域 -->
|
||||||
|
<div class="flex-1 overflow-y-auto p-4">
|
||||||
|
<div v-if="loading" class="flex items-center justify-center h-40">
|
||||||
|
<van-loading type="spinner" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-else-if="featureList.length === 0" class="flex items-center justify-center h-40 text-gray-500">
|
||||||
|
暂无可屏蔽的模块
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-else>
|
||||||
|
<div class="mb-4 text-sm text-gray-600">
|
||||||
|
选择要屏蔽的模块,屏蔽后该身份证号查询时将不显示这些模块的数据
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 模块列表 -->
|
||||||
|
<van-checkbox-group v-model="selectedFeatureIds">
|
||||||
|
<div v-for="feature in featureList" :key="feature.feature_id" class="mb-3">
|
||||||
|
<van-cell :title="feature.feature_name" :label="`价格:¥${feature.whitelist_price.toFixed(2)}`"
|
||||||
|
clickable @click="toggleFeature(feature.feature_id)">
|
||||||
|
<template #right-icon>
|
||||||
|
<van-checkbox :name="feature.feature_id" />
|
||||||
|
</template>
|
||||||
|
</van-cell>
|
||||||
|
</div>
|
||||||
|
</van-checkbox-group>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 底部操作栏 -->
|
||||||
|
<div class="p-4 border-t bg-gray-50">
|
||||||
|
<div class="mb-3 flex items-center justify-between">
|
||||||
|
<span class="text-sm text-gray-600">已选择:{{ selectedFeatureIds.length }} 个模块</span>
|
||||||
|
<span class="text-lg font-bold text-red-500">
|
||||||
|
总计:¥{{ totalAmount.toFixed(2) }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<van-button type="primary" block round :loading="isSubmitting"
|
||||||
|
:disabled="selectedFeatureIds.length === 0" @click="handleConfirm">
|
||||||
|
确认屏蔽
|
||||||
|
</van-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 支付弹窗 -->
|
||||||
|
<Payment v-model="showPayment" :data="paymentData"
|
||||||
|
:id="paymentId" :type="paymentType" />
|
||||||
|
</van-popup>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, computed, watch } from 'vue'
|
||||||
|
import { getWhitelistFeatures, createWhitelistOrder } from '@/api/agent'
|
||||||
|
import { showSuccessToast, showFailToast, showConfirmDialog } from 'vant'
|
||||||
|
import { useAgentStore } from '@/stores/agentStore'
|
||||||
|
import { storeToRefs } from 'pinia'
|
||||||
|
import Payment from './Payment.vue'
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
idCard: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
orderId: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const show = defineModel('show', { type: Boolean, default: false })
|
||||||
|
|
||||||
|
const agentStore = useAgentStore()
|
||||||
|
const { isDiamond } = storeToRefs(agentStore)
|
||||||
|
|
||||||
|
const loading = ref(false)
|
||||||
|
const featureList = ref([])
|
||||||
|
const selectedFeatureIds = ref([])
|
||||||
|
const isSubmitting = ref(false)
|
||||||
|
|
||||||
|
// 支付相关状态
|
||||||
|
const showPayment = ref(false)
|
||||||
|
const paymentData = ref({
|
||||||
|
product_name: '',
|
||||||
|
sell_price: 0,
|
||||||
|
})
|
||||||
|
const paymentId = ref('')
|
||||||
|
const paymentType = ref('whitelist')
|
||||||
|
const currentOrderId = ref('')
|
||||||
|
|
||||||
|
// 计算总金额
|
||||||
|
const totalAmount = computed(() => {
|
||||||
|
return featureList.value
|
||||||
|
.filter(f => selectedFeatureIds.value.includes(f.feature_id))
|
||||||
|
.reduce((sum, f) => sum + f.whitelist_price, 0)
|
||||||
|
})
|
||||||
|
|
||||||
|
// 切换选择
|
||||||
|
const toggleFeature = (featureId) => {
|
||||||
|
const index = selectedFeatureIds.value.indexOf(featureId)
|
||||||
|
if (index > -1) {
|
||||||
|
selectedFeatureIds.value.splice(index, 1)
|
||||||
|
} else {
|
||||||
|
selectedFeatureIds.value.push(featureId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 关闭弹窗
|
||||||
|
const close = () => {
|
||||||
|
show.value = false
|
||||||
|
selectedFeatureIds.value = []
|
||||||
|
}
|
||||||
|
|
||||||
|
// 加载可屏蔽的模块列表
|
||||||
|
const loadFeatures = async () => {
|
||||||
|
loading.value = true
|
||||||
|
try {
|
||||||
|
const { data, error } = await getWhitelistFeatures()
|
||||||
|
if (data.value && !error.value && data.value.code === 200) {
|
||||||
|
featureList.value = data.value.data.list || []
|
||||||
|
} else {
|
||||||
|
showFailToast(data.value?.msg || '获取模块列表失败')
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error('获取模块列表失败:', err)
|
||||||
|
showFailToast('获取模块列表失败')
|
||||||
|
} finally {
|
||||||
|
loading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 确认屏蔽
|
||||||
|
const handleConfirm = async () => {
|
||||||
|
if (selectedFeatureIds.value.length === 0) {
|
||||||
|
showFailToast('请至少选择一个模块')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 确认对话框
|
||||||
|
try {
|
||||||
|
await showConfirmDialog({
|
||||||
|
title: '确认屏蔽',
|
||||||
|
message: `确定要屏蔽 ${selectedFeatureIds.value.length} 个模块吗?总费用:¥${totalAmount.value.toFixed(2)}`,
|
||||||
|
})
|
||||||
|
} catch {
|
||||||
|
return // 用户取消
|
||||||
|
}
|
||||||
|
|
||||||
|
isSubmitting.value = true
|
||||||
|
try {
|
||||||
|
// 1. 创建订单
|
||||||
|
const { data: orderData, error: orderError } = await createWhitelistOrder({
|
||||||
|
id_card: props.idCard,
|
||||||
|
feature_ids: selectedFeatureIds.value,
|
||||||
|
order_id: props.orderId || undefined,
|
||||||
|
})
|
||||||
|
|
||||||
|
if (!orderData.value || orderError.value || orderData.value.code !== 200) {
|
||||||
|
showFailToast(orderData.value?.msg || '创建订单失败')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const orderId = orderData.value.data.order_id
|
||||||
|
const orderNo = orderData.value.data.order_no
|
||||||
|
const totalAmount = orderData.value.data.total_amount
|
||||||
|
|
||||||
|
// 2. 使用统一支付组件进行支付
|
||||||
|
// PaymentReq.Id 约定格式:白名单订单使用 "{idCard}|{featureApiId}" 格式
|
||||||
|
// 但批量订单使用订单号,需要根据后端接口调整
|
||||||
|
// 这里先使用订单号,如果后端需要特定格式,需要调整
|
||||||
|
paymentData.value = {
|
||||||
|
product_name: `模块屏蔽(${selectedFeatureIds.value.length}个模块)`,
|
||||||
|
sell_price: totalAmount,
|
||||||
|
}
|
||||||
|
paymentId.value = orderNo // 使用订单号作为支付ID
|
||||||
|
paymentType.value = 'whitelist'
|
||||||
|
currentOrderId.value = orderId
|
||||||
|
showPayment.value = true
|
||||||
|
} catch (err) {
|
||||||
|
console.error('屏蔽模块失败:', err)
|
||||||
|
showFailToast('屏蔽模块失败')
|
||||||
|
} finally {
|
||||||
|
isSubmitting.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 监听支付弹窗关闭,如果支付成功会跳转到支付结果页面
|
||||||
|
watch(showPayment, (newVal) => {
|
||||||
|
if (!newVal && currentOrderId.value) {
|
||||||
|
// 支付弹窗关闭,可能是支付完成(会跳转到结果页面)或用户取消
|
||||||
|
// 这里不做特殊处理,因为支付成功会跳转到结果页面
|
||||||
|
currentOrderId.value = ''
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const emit = defineEmits(['success'])
|
||||||
|
|
||||||
|
// 监听弹窗显示,加载数据
|
||||||
|
watch(show, (newVal) => {
|
||||||
|
if (newVal) {
|
||||||
|
// 验证是否为钻石代理
|
||||||
|
if (!isDiamond.value) {
|
||||||
|
showFailToast('只有钻石代理可以操作白名单')
|
||||||
|
close()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
loadFeatures()
|
||||||
|
selectedFeatureIds.value = []
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.whitelist-module-dialog {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
@@ -185,43 +185,38 @@ export function useWeixinShare() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据当前页面动态设置分享内容
|
* 根据当前路由动态设置分享内容
|
||||||
|
* @param {object} routeInfo - vue-router 的 route 对象,可选
|
||||||
*/
|
*/
|
||||||
const setDynamicShare = async () => {
|
const setDynamicShare = async (routeInfo) => {
|
||||||
const route = window.location.pathname;
|
// 某些页面(如 inquire / promotionInquire / example)有自定义分享逻辑
|
||||||
let shareConfig = {};
|
if (routeInfo && routeInfo.meta && routeInfo.meta.shareCustom) {
|
||||||
|
return;
|
||||||
// 根据不同的路由设置不同的分享内容
|
|
||||||
if (route.includes("/example")) {
|
|
||||||
shareConfig = {
|
|
||||||
title: import.meta.env.VITE_SHARE_TITLE,
|
|
||||||
desc: import.meta.env.VITE_SHARE_DESC,
|
|
||||||
link: window.location.href.split("#")[0],
|
|
||||||
imgUrl: import.meta.env.VITE_SHARE_IMG,
|
|
||||||
};
|
|
||||||
} else if (route.includes("/agent")) {
|
|
||||||
shareConfig = {
|
|
||||||
title: import.meta.env.VITE_SHARE_TITLE,
|
|
||||||
desc: import.meta.env.VITE_SHARE_DESC,
|
|
||||||
link: window.location.href.split("#")[0],
|
|
||||||
imgUrl: import.meta.env.VITE_SHARE_IMG,
|
|
||||||
};
|
|
||||||
} else if (route.includes("/help")) {
|
|
||||||
shareConfig = {
|
|
||||||
title: import.meta.env.VITE_SHARE_TITLE,
|
|
||||||
desc: import.meta.env.VITE_SHARE_DESC,
|
|
||||||
link: window.location.href.split("#")[0],
|
|
||||||
imgUrl: import.meta.env.VITE_SHARE_IMG,
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
shareConfig = {
|
|
||||||
title: import.meta.env.VITE_SHARE_TITLE,
|
|
||||||
desc: import.meta.env.VITE_SHARE_DESC,
|
|
||||||
link: window.location.href.split("#")[0],
|
|
||||||
imgUrl: import.meta.env.VITE_SHARE_IMG,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const fullPath = window.location.href.split("#")[0];
|
||||||
|
const baseShareTitle = import.meta.env.VITE_SHARE_TITLE || "";
|
||||||
|
const appName = import.meta.env.VITE_APP_NAME || "";
|
||||||
|
|
||||||
|
const routeMetaTitle = routeInfo && routeInfo.meta && routeInfo.meta.title;
|
||||||
|
const routeName = routeInfo && routeInfo.name;
|
||||||
|
|
||||||
|
let title = baseShareTitle;
|
||||||
|
|
||||||
|
// 除首页之外,如果有路由标题,则加到分享标题中
|
||||||
|
if (routeMetaTitle && routeName !== "index") {
|
||||||
|
title = appName
|
||||||
|
? `${routeMetaTitle}|${appName}`
|
||||||
|
: `${routeMetaTitle}|${baseShareTitle}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
const shareConfig = {
|
||||||
|
title,
|
||||||
|
desc: import.meta.env.VITE_SHARE_DESC,
|
||||||
|
link: fullPath,
|
||||||
|
imgUrl: import.meta.env.VITE_SHARE_IMG,
|
||||||
|
};
|
||||||
|
|
||||||
await configWeixinShare(shareConfig);
|
await configWeixinShare(shareConfig);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -132,7 +132,7 @@ const router = createRouter({
|
|||||||
path: "/example",
|
path: "/example",
|
||||||
name: "example",
|
name: "example",
|
||||||
component: () => import("@/views/Example.vue"),
|
component: () => import("@/views/Example.vue"),
|
||||||
meta: { title: "示例报告", notNeedBindPhone: true },
|
meta: { title: "示例报告", notNeedBindPhone: true, shareCustom: true },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: "/vant-theme-test",
|
path: "/vant-theme-test",
|
||||||
@@ -173,7 +173,7 @@ const router = createRouter({
|
|||||||
path: "/inquire/:feature",
|
path: "/inquire/:feature",
|
||||||
name: "inquire",
|
name: "inquire",
|
||||||
component: () => import("@/views/Inquire.vue"),
|
component: () => import("@/views/Inquire.vue"),
|
||||||
meta: { title: "查询报告" },
|
meta: { title: "查询报告", shareCustom: true },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: "/authorization",
|
path: "/authorization",
|
||||||
@@ -398,7 +398,7 @@ const router = createRouter({
|
|||||||
path: "/agent/promotionInquire/:linkIdentifier",
|
path: "/agent/promotionInquire/:linkIdentifier",
|
||||||
name: "promotionInquire",
|
name: "promotionInquire",
|
||||||
component: () => import("@/views/PromotionInquire.vue"),
|
component: () => import("@/views/PromotionInquire.vue"),
|
||||||
meta: { notNeedBindPhone: true },
|
meta: { notNeedBindPhone: true, shareCustom: true },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: "/agent/invitationAgentApply/:linkIdentifier",
|
path: "/agent/invitationAgentApply/:linkIdentifier",
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { aesDecrypt } from "@/utils/crypto";
|
import { aesDecrypt } from "@/utils/crypto";
|
||||||
|
import { useWeixinShare } from "@/composables/useWeixinShare";
|
||||||
|
|
||||||
const AES_KEY = import.meta.env.VITE_INQUIRE_AES_KEY;
|
const AES_KEY = import.meta.env.VITE_INQUIRE_AES_KEY;
|
||||||
|
|
||||||
@@ -20,6 +21,18 @@ const isEmpty = ref(false);
|
|||||||
const isDone = ref(false);
|
const isDone = ref(false);
|
||||||
const active = ref(0);
|
const active = ref(0);
|
||||||
|
|
||||||
|
const { configWeixinShare } = useWeixinShare();
|
||||||
|
|
||||||
|
const updateExampleWeixinShare = async () => {
|
||||||
|
if (!reportName.value) return;
|
||||||
|
const baseTitle = reportName.value;
|
||||||
|
const title = `${baseTitle}(示例报告)`;
|
||||||
|
|
||||||
|
await configWeixinShare({
|
||||||
|
title,
|
||||||
|
desc: import.meta.env.VITE_SHARE_DESC,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
onBeforeMount(() => {
|
onBeforeMount(() => {
|
||||||
const query = new URLSearchParams(window.location.search);
|
const query = new URLSearchParams(window.location.search);
|
||||||
@@ -72,6 +85,9 @@ const getReport = async () => {
|
|||||||
reportParams.value = decryptedData.query_params || {};
|
reportParams.value = decryptedData.query_params || {};
|
||||||
reportName.value = decryptedData.product_name || "";
|
reportName.value = decryptedData.product_name || "";
|
||||||
reportDateTime.value = decryptedData.create_time || null;
|
reportDateTime.value = decryptedData.create_time || null;
|
||||||
|
|
||||||
|
// 更新示例报告的微信分享文案
|
||||||
|
await updateExampleWeixinShare();
|
||||||
} else if (data.value.code === 200003) {
|
} else if (data.value.code === 200003) {
|
||||||
isEmpty.value = true;
|
isEmpty.value = true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { ref, onMounted, computed } from "vue";
|
import { ref, onMounted } from "vue";
|
||||||
import { useRoute, useRouter } from "vue-router";
|
import { useRoute, useRouter } from "vue-router";
|
||||||
import { useAgentStore } from "@/stores/agentStore";
|
import { useAgentStore } from "@/stores/agentStore";
|
||||||
import { useUserStore } from "@/stores/userStore";
|
import { useUserStore } from "@/stores/userStore";
|
||||||
|
import { useWeixinShare } from "@/composables/useWeixinShare";
|
||||||
import { storeToRefs } from "pinia";
|
import { storeToRefs } from "pinia";
|
||||||
import { showToast } from "vant";
|
import { showToast } from "vant";
|
||||||
|
|
||||||
@@ -18,6 +19,31 @@ const feature = ref(route.params.feature);
|
|||||||
// 获取产品信息
|
// 获取产品信息
|
||||||
const featureData = ref({});
|
const featureData = ref({});
|
||||||
|
|
||||||
|
// 微信分享
|
||||||
|
const { configWeixinShare } = useWeixinShare();
|
||||||
|
|
||||||
|
// 去掉富文本 HTML 标签,保留纯文本
|
||||||
|
const stripHtml = (html) => {
|
||||||
|
if (!html) return "";
|
||||||
|
return html.replace(/<[^>]*>/g, "").replace(/\s+/g, " ").trim();
|
||||||
|
};
|
||||||
|
|
||||||
|
const updateWeixinShareForProduct = async () => {
|
||||||
|
if (!featureData.value || !featureData.value.product_name) return;
|
||||||
|
|
||||||
|
const appName = import.meta.env.VITE_APP_NAME || "";
|
||||||
|
const baseTitle = featureData.value.product_name;
|
||||||
|
const title = appName ? `${baseTitle}|${appName}风险报告` : baseTitle;
|
||||||
|
const desc =
|
||||||
|
stripHtml(featureData.value.description) ||
|
||||||
|
import.meta.env.VITE_SHARE_DESC;
|
||||||
|
|
||||||
|
await configWeixinShare({
|
||||||
|
title,
|
||||||
|
desc,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
// 检查登录状态
|
// 检查登录状态
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
// 检查支付回调
|
// 检查支付回调
|
||||||
@@ -64,6 +90,9 @@ async function getProduct() {
|
|||||||
return 0;
|
return 0;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
console.log('featureData', featureData.value);
|
||||||
|
// 更新微信分享文案
|
||||||
|
await updateWeixinShareForProduct();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -31,18 +31,25 @@
|
|||||||
<span class="text-gray-800">{{
|
<span class="text-gray-800">{{
|
||||||
paymentType === "agent_upgrade"
|
paymentType === "agent_upgrade"
|
||||||
? "代理升级"
|
? "代理升级"
|
||||||
|
: paymentType === "whitelist"
|
||||||
|
? "模块下架"
|
||||||
: "查询服务"
|
: "查询服务"
|
||||||
}}</span>
|
}}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="paymentType === 'agent_upgrade'" class="text-center text-gray-600 mb-4">恭喜你升级代理等级成功,享受更多权益
|
<div v-if="paymentType === 'agent_upgrade'" class="text-center text-gray-600 mb-4">恭喜你升级代理等级成功,享受更多权益
|
||||||
</div>
|
</div>
|
||||||
|
<div v-else-if="paymentType === 'whitelist'" class="text-center text-gray-600 mb-4">
|
||||||
|
模块下架成功,该身份证号查询时将不显示此模块的数据
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="action-buttons grid grid-cols-1 gap-4">
|
<div class="action-buttons grid grid-cols-1 gap-4">
|
||||||
<van-button block type="primary" class="rounded-lg" @click="handleNavigation">
|
<van-button block type="primary" class="rounded-lg" @click="handleNavigation">
|
||||||
{{
|
{{
|
||||||
paymentType === "agent_upgrade"
|
paymentType === "agent_upgrade"
|
||||||
? "查看代理信息"
|
? "查看代理信息"
|
||||||
|
: paymentType === "whitelist"
|
||||||
|
? "返回报告"
|
||||||
: "查看查询结果"
|
: "查看查询结果"
|
||||||
}}
|
}}
|
||||||
</van-button>
|
</van-button>
|
||||||
@@ -74,6 +81,8 @@
|
|||||||
<span class="text-gray-800">{{
|
<span class="text-gray-800">{{
|
||||||
paymentType === "agent_upgrade"
|
paymentType === "agent_upgrade"
|
||||||
? "代理升级"
|
? "代理升级"
|
||||||
|
: paymentType === "whitelist"
|
||||||
|
? "模块下架"
|
||||||
: "查询服务"
|
: "查询服务"
|
||||||
}}</span>
|
}}</span>
|
||||||
</div>
|
</div>
|
||||||
@@ -137,6 +146,8 @@
|
|||||||
<span class="text-gray-800">{{
|
<span class="text-gray-800">{{
|
||||||
paymentType === "agent_upgrade"
|
paymentType === "agent_upgrade"
|
||||||
? "代理升级"
|
? "代理升级"
|
||||||
|
: paymentType === "whitelist"
|
||||||
|
? "模块下架"
|
||||||
: "查询服务"
|
: "查询服务"
|
||||||
}}</span>
|
}}</span>
|
||||||
</div>
|
</div>
|
||||||
@@ -329,6 +340,25 @@ const checkPaymentStatus = async () => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 对于白名单类型,如果状态是已支付,跳转回报告页面
|
||||||
|
if (
|
||||||
|
paymentType.value === "whitelist" &&
|
||||||
|
newStatus === "paid"
|
||||||
|
) {
|
||||||
|
stopPolling();
|
||||||
|
// 优先使用 returnUrl,否则返回上一页
|
||||||
|
const returnUrl = route.query.returnUrl;
|
||||||
|
if (returnUrl) {
|
||||||
|
router.replace(returnUrl);
|
||||||
|
} else if (window.history.length > 1) {
|
||||||
|
router.go(-1);
|
||||||
|
} else {
|
||||||
|
// 如果没有历史记录,跳转到首页
|
||||||
|
router.replace("/");
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// 如果状态不是 pending,停止轮询
|
// 如果状态不是 pending,停止轮询
|
||||||
if (newStatus !== "pending") {
|
if (newStatus !== "pending") {
|
||||||
stopPolling();
|
stopPolling();
|
||||||
@@ -414,6 +444,17 @@ function handleNavigation() {
|
|||||||
router.replace("/agent");
|
router.replace("/agent");
|
||||||
agentStore.fetchAgentStatus();
|
agentStore.fetchAgentStatus();
|
||||||
userStore.fetchUserInfo();
|
userStore.fetchUserInfo();
|
||||||
|
} else if (paymentType.value === "whitelist") {
|
||||||
|
// 白名单支付:优先使用 returnUrl,否则返回上一页
|
||||||
|
const returnUrl = route.query.returnUrl;
|
||||||
|
if (returnUrl) {
|
||||||
|
router.replace(returnUrl);
|
||||||
|
} else if (window.history.length > 1) {
|
||||||
|
router.go(-1);
|
||||||
|
} else {
|
||||||
|
// 如果没有历史记录,跳转到首页
|
||||||
|
router.replace("/");
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// 跳转到查询结果页面
|
// 跳转到查询结果页面
|
||||||
router.replace({
|
router.replace({
|
||||||
|
|||||||
@@ -15,8 +15,8 @@ export default defineConfig({
|
|||||||
strictPort: true, // 如果端口被占用则抛出错误而不是使用下一个可用端口
|
strictPort: true, // 如果端口被占用则抛出错误而不是使用下一个可用端口
|
||||||
proxy: {
|
proxy: {
|
||||||
"/api/v1": {
|
"/api/v1": {
|
||||||
target: "http://127.0.0.1:8888", // 本地接口地址
|
// target: "http://127.0.0.1:8888", // 本地接口地址
|
||||||
// target: "https://yuyuecha.com", // 本地接口地址
|
target: "https://www.yuyuecha.com", // 本地接口地址
|
||||||
changeOrigin: true,
|
changeOrigin: true,
|
||||||
rewrite: (path) => path, // 可选:确保路径不被修改
|
rewrite: (path) => path, // 可选:确保路径不被修改
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user