fix(fsgx): 修复 issues-0325-1 前端与后端问题

UniApp:会员码图片兜底、海报下载 Promise、账单移除公排退款、
佣金状态与资产页 NavBar、资产接口 total_points_earned。

后端:推荐人须自报单才得周期佣金;升级前快照等级再发积分;
积分按报单商品数量倍乘;伞下级差按伞下基数传递;直推/伞下任务
统计补充 refund_status;周期佣金在事务内锁推荐人行防竞态;
新增 hjf:verify-agent-config 命令做等级与任务 e2e 验收。

Made-with: Cursor
This commit is contained in:
panchengyong
2026-03-28 10:23:20 +08:00
parent 8d109cbc01
commit ec56ae3286
13 changed files with 437 additions and 126 deletions

View File

@@ -1,5 +1,8 @@
<template>
<view class="hjf-assets-page" :style="colorStyle">
<!-- #ifdef MP -->
<NavBar titleText="我的资产" :iconColor="iconColor" :textColor="iconColor" showBack :isScrolling="isScrolling"></NavBar>
<!-- #endif -->
<view class="assets-wrapper">
<view class="assets-header">
@@ -116,14 +119,25 @@
<script>
import { getAssetsOverview } from '@/api/hjfAssets.js';
import colors from '@/mixins/color.js';
// #ifdef MP
import NavBar from '@/components/NavBar.vue';
// #endif
export default {
name: 'AssetsIndex',
mixins: [colors],
components: {
// #ifdef MP
NavBar,
// #endif
},
data() {
return {
iconColor: '#FFFFFF',
isScrolling: false,
assetsInfo: null,
loading: false
};
@@ -146,7 +160,8 @@ export default {
},
formattedTotalPoints() {
if (!this.assetsInfo) return '0';
return Number(this.assetsInfo.total_points_earned).toLocaleString();
const val = Number(this.assetsInfo.total_points_earned);
return isNaN(val) ? '0' : val.toLocaleString();
}
},
@@ -160,6 +175,16 @@ export default {
}
},
onPageScroll(e) {
if (e.scrollTop > 50) {
this.isScrolling = true;
this.iconColor = '#333333';
} else {
this.isScrolling = false;
this.iconColor = '#FFFFFF';
}
},
methods: {
fetchAssetsOverview() {
this.loading = true;

View File

@@ -1,5 +1,8 @@
<template>
<view class="brokerage-page" :style="colorStyle">
<!-- #ifdef MP -->
<NavBar titleText="佣金状态" :iconColor="iconColor" :textColor="iconColor" showBack :isScrolling="isScrolling"></NavBar>
<!-- #endif -->
<!-- 顶部渐变区域 -->
<view class="header-gradient">
<view class="header-gradient__circle header-gradient__circle--1"></view>
@@ -88,14 +91,26 @@ import HjfRefundNotice from '@/components/HjfRefundNotice.vue';
import emptyPage from '@/components/emptyPage.vue';
import colors from '@/mixins/color.js';
import { spreadOrder } from '@/api/user.js';
// #ifdef MP
import NavBar from '@/components/NavBar.vue';
// #endif
export default {
name: 'BrokerageStatus',
mixins: [colors],
components: { HjfQueueProgress, HjfRefundNotice, emptyPage },
components: {
HjfQueueProgress,
HjfRefundNotice,
emptyPage,
// #ifdef MP
NavBar,
// #endif
},
data() {
return {
iconColor: '#FFFFFF',
isScrolling: false,
progressData: {},
records: [],
loading: false,
@@ -108,6 +123,16 @@ export default {
};
},
onPageScroll(e) {
if (e.scrollTop > 50) {
this.isScrolling = true;
this.iconColor = '#333333';
} else {
this.isScrolling = false;
this.iconColor = '#FFFFFF';
}
},
onLoad() {
this.loadProgress();
this.loadRecords();

View File

@@ -18,11 +18,6 @@
:class='type == 2 ? "on" : ""'
@click='changeType(2)'
>储值</view>
<view
class='item'
:class='type == "queue_refund" ? "on" : ""'
@click='changeType("queue_refund")'
>公排退款</view>
</view>
<!-- 账单列表 -->
@@ -37,14 +32,9 @@
:key="indexn"
>
<view>
<view class='name line1'>
{{ vo.title }}
<!-- 公排退款标记 -->
<text
v-if="vo.type === 'queue_refund'"
class='queue-refund-tag'
>公排退款</text>
</view>
<view class='name line1'>
{{ vo.title }}
</view>
<view class='time-text'>{{ vo.add_time }}</view>
</view>
<view class='num' :class="vo.pm ? 'num-add' : 'num-sub'">
@@ -86,7 +76,6 @@
* - 0: 全部
* - 1: 消费
* - 2: 储值
* - "queue_refund": 公排退款type=queue_refund 时显示专属标记)
*
* 列表按日期分组,支持上拉分页加载。
*
@@ -109,11 +98,11 @@
page: 1,
/** @type {number} 每页条数 */
limit: 15,
/**
* 当前筛选类型
* 0=全部 1=消费 2=储值 "queue_refund"=公排退款
* @type {number|string}
*/
/**
* 当前筛选类型
* 0=全部 1=消费 2=储值
* @type {number|string}
*/
type: 0,
/** @type {Array<Object>} 按日期分组的账单列表 */
userBillList: [],
@@ -201,12 +190,12 @@
});
},
/**
* 切换账单筛选类型并重置列表
*
* @param {number|string} type - 目标类型0全部 1消费 2储值 "queue_refund"公排退款
* @returns {void}
*/
/**
* 切换账单筛选类型并重置列表
*
* @param {number|string} type - 目标类型0全部 1消费 2储值
* @returns {void}
*/
changeType(type) {
if (this.type === type) return;
this.type = type;
@@ -267,19 +256,6 @@
color: #333333;
}
/* 公排退款标记 */
.queue-refund-tag {
display: inline-block;
margin-left: 10rpx;
padding: 2rpx 12rpx;
border-radius: 20rpx;
font-size: 20rpx;
color: #fff;
background: var(--view-theme);
vertical-align: middle;
line-height: 1.6;
}
/* 顶部类型筛选导航 */
.bill-details .nav {
background-color: #fff;

View File

@@ -13,9 +13,9 @@
<w-barcode :options="config.bar"></w-barcode>
</view> -->
<view class="acea-row row-center-wrapper" style="margin-top: 56rpx;">
<!-- #ifdef MP -->
<image :src="qrc" class="qrcode"></image>
<!-- #endif -->
<!-- #ifdef MP -->
<image v-if="qrc" :src="qrc" class="qrcode"></image>
<!-- #endif -->
<!-- #ifdef H5 -->
<image v-if="$wechat.isWeixin()" :src="qrc" class="qrcode"></image>
<w-qrcode v-else :options="config.qrc"></w-qrcode>
@@ -132,14 +132,14 @@
routineUrl,
wechatUrl
} = res.data;
// #ifdef MP
this.qrc = routineUrl;
// #endif
// #ifdef H5
if (this.$wechat.isWeixin()) {
this.qrc = wechatUrl;
}
// #endif
// #ifdef MP
this.qrc = routineUrl || '';
// #endif
// #ifdef H5
if (this.$wechat.isWeixin()) {
this.qrc = wechatUrl || '';
}
// #endif
});
},
goDetail(val) {

View File

@@ -205,22 +205,23 @@
if (url.indexOf('https://') > -1) return url;
else return url.replace('http://', 'https://');
},
//获取图片
async spreadMsg() {
let res = await spreadMsg()
this.spreadData = res.data.spread
this.nickName = res.data.nickname
this.siteName = res.data.site_name
uni.showLoading({
title: '海报生成中',
mask: true
});
//获取图片
async spreadMsg() {
let res = await spreadMsg()
this.spreadData = res.data.spread
this.nickName = res.data.nickname
this.siteName = res.data.site_name
uni.showLoading({
title: '海报生成中',
mask: true
});
try {
for (let i = 0; i < res.data.spread.length; i++) {
let that = this
let arr2 = [];
let img = await this.downloadFilestoreImage(res.data.spread[i].pic);
let avatar = await this.downloadFilestoreImage(res.data.avatar);
let followCode = res.data.qrcode?await this.downloadFilestoreImage(res.data.qrcode):'';
let followCode = res.data.qrcode ? await this.downloadFilestoreImage(res.data.qrcode) : '';
// #ifdef H5
arr2 = [followCode || this.codeSrc, img, avatar]
// #endif
@@ -231,8 +232,12 @@
// #ifdef APP-PLUS
arr2 = [this.codeSrc, img, avatar]
// #endif
if (!img) {
console.warn('[海报] 背景图下载失败,跳过第', i, '张海报生成');
continue;
}
this.$nextTick(function(){
that.$util.userPosterCanvas(arr2, res.data.nickname, res.data.site_name, i, this.wd, this.hg, (
that.$util.userPosterCanvas(arr2, res.data.nickname, res.data.site_name, i, that.wd, that.hg, (
tempFilePath) => {
that.$set(that.posterImage, i, tempFilePath);
// #ifdef MP
@@ -245,8 +250,12 @@
});
})
}
} catch (e) {
console.error('[海报] 生成异常:', e);
} finally {
uni.hideLoading();
},
}
},
// #ifdef MP
async routineCode() {
let res = await routineCode()
@@ -350,23 +359,26 @@
});
},
// #endif
//图片转符合安全域名路径
downloadFilestoreImage(url) {
return new Promise((resolve, reject) => {
let that = this;
uni.downloadFile({
url: that.setDomain(url),
success: function(res) {
resolve(res.tempFilePath);
},
fail: function() {
return that.$util.Tips({
title: ''
});
}
});
})
},
//图片转符合安全域名路径
downloadFilestoreImage(url) {
return new Promise((resolve, reject) => {
let that = this;
if (!url) {
resolve('');
return;
}
uni.downloadFile({
url: that.setDomain(url),
success: function(res) {
resolve(res.tempFilePath);
},
fail: function(err) {
console.error('[海报] 图片下载失败:', url, err);
resolve('');
}
});
})
},
setShareInfoStatus: function() {
if (this.$wechat.isWeixin()) {
if (this.isLogin) {