fix(user): remove obsolete withdrawal modal and recompile mp-weixin to dedicated withdraw page
这个提交包含在:
@@ -497,13 +497,30 @@ export async function rechargeBalance(userId = 1001, amount) {
|
||||
|
||||
/**
|
||||
* 佣金提现申请 (支持微信零钱、支付宝、银行卡多渠道及账号信息)
|
||||
/**
|
||||
* 佣金提现申请 (支持多渠道: 微信 WECHAT / 支付宝 ALIPAY / 银行卡 BANK)
|
||||
* 支持 (userId, amount, options) 与 (amount, channel, userId) 两种调用签名
|
||||
*/
|
||||
export async function withdrawCommission(userId = 1001, amount, options = {}) {
|
||||
export async function withdrawCommission(arg1, arg2, arg3 = {}) {
|
||||
try {
|
||||
const payload = typeof options === 'string'
|
||||
? { amount, channel: options }
|
||||
: { amount, ...options };
|
||||
const res = await http.post(`/users/${userId}/withdraw`, payload);
|
||||
let uid = 1001;
|
||||
let amt = 0;
|
||||
let opt = {};
|
||||
|
||||
if (typeof arg1 === 'number' && (typeof arg2 === 'number' || !isNaN(Number(arg2)))) {
|
||||
uid = arg1;
|
||||
amt = Number(arg2);
|
||||
opt = typeof arg3 === 'object' ? arg3 : { channel: arg3 || 'WECHAT' };
|
||||
} else {
|
||||
amt = Number(arg1) || 0;
|
||||
opt = typeof arg2 === 'object' ? (arg2 || {}) : { channel: arg2 || 'WECHAT' };
|
||||
uid = Number(arg3) || 1001;
|
||||
}
|
||||
|
||||
const payload = typeof opt === 'string'
|
||||
? { amount: amt, channel: opt }
|
||||
: { amount: amt, ...opt };
|
||||
const res = await http.post(`/users/${uid}/withdraw`, payload);
|
||||
return res;
|
||||
} catch (err) {
|
||||
console.warn('[API] 提现申请接口异常:', err.message);
|
||||
@@ -977,19 +994,3 @@ export async function getDistributionRecords(userId = 1001) {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 佣金提现申请
|
||||
*/
|
||||
export async function withdrawCommission(amount, channel = 'WECHAT', userId = 1001) {
|
||||
try {
|
||||
const res = await http.post(`/users/${userId}/withdraw`, { amount, channel });
|
||||
return res;
|
||||
} catch (err) {
|
||||
console.warn('[API] 佣金提现申请异常:', err.message);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -38,6 +38,8 @@
|
||||
<view class="edit-btn btn-active" v-if="isLoggedIn" @click.stop="editProfile" title="设置资料">
|
||||
<image class="edit-svg" :src="ICONS.settings" mode="aspectFit" />
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="uid-phone-row" @click.stop="handleAvatarOrNameClick">
|
||||
<text class="user-uid">{{ isLoggedIn ? `UID: ${user.id}` : '登录后享受完整陪伴服务' }}</text>
|
||||
<text class="user-phone-tag" v-if="isLoggedIn && displayPhone">{{ displayPhone }}</text>
|
||||
@@ -276,125 +278,6 @@
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 多渠道提现申请弹窗 -->
|
||||
<view class="profile-edit-modal-mask" v-if="showWithdrawModal" @click="showWithdrawModal = false">
|
||||
<view class="profile-edit-modal withdraw-modal-box" @click.stop>
|
||||
<view class="modal-header">
|
||||
<text class="modal-title">佣金收益提现申请</text>
|
||||
<view class="btn-close btn-active" @click="showWithdrawModal = false">
|
||||
<image class="close-svg" :src="ICONS.close" mode="aspectFit" />
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="modal-body">
|
||||
<!-- 提现渠道切换 -->
|
||||
<view class="channel-tabs-row">
|
||||
<view
|
||||
class="channel-pill btn-active"
|
||||
:class="{ active: withdrawForm.channel === 'WECHAT' }"
|
||||
@click="withdrawForm.channel = 'WECHAT'"
|
||||
>
|
||||
微信零钱
|
||||
</view>
|
||||
<view
|
||||
class="channel-pill btn-active"
|
||||
:class="{ active: withdrawForm.channel === 'ALIPAY' }"
|
||||
@click="withdrawForm.channel = 'ALIPAY'"
|
||||
>
|
||||
支付宝
|
||||
</view>
|
||||
<view
|
||||
class="channel-pill btn-active"
|
||||
:class="{ active: withdrawForm.channel === 'BANK' }"
|
||||
@click="withdrawForm.channel = 'BANK'"
|
||||
>
|
||||
银行卡
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 提现金额输入 -->
|
||||
<view class="edit-field">
|
||||
<view class="field-title-row">
|
||||
<text class="field-label">提现金额 (元)</text>
|
||||
<text class="field-tip">可提现 ¥{{ user.commission || '0.00' }}</text>
|
||||
</view>
|
||||
<view class="amount-input-wrap">
|
||||
<text class="currency-symbol">¥</text>
|
||||
<input
|
||||
class="field-input amount-val-input"
|
||||
type="digit"
|
||||
v-model="withdrawForm.amount"
|
||||
:placeholder="`最低 ¥${minWithdrawAmount} 起提`"
|
||||
placeholder-class="field-placeholder"
|
||||
/>
|
||||
<text class="btn-all-in btn-active" @click="withdrawForm.amount = String(user.commission || '0')">全部</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 渠道补充信息 -->
|
||||
<view v-if="withdrawForm.channel === 'WECHAT'" class="channel-hint-card">
|
||||
<text class="hint-text">资金将通过微信企业付款直达当前绑定微信号零钱钱包,预计 1-24 小时内到账。</text>
|
||||
</view>
|
||||
|
||||
<view v-if="withdrawForm.channel === 'ALIPAY'">
|
||||
<view class="edit-field">
|
||||
<text class="field-label">支付宝账号</text>
|
||||
<input
|
||||
class="field-input"
|
||||
v-model="withdrawForm.alipayAccount"
|
||||
placeholder="请输入支付宝登录账号/手机号/邮箱"
|
||||
placeholder-class="field-placeholder"
|
||||
/>
|
||||
</view>
|
||||
<view class="edit-field">
|
||||
<text class="field-label">收款人真实姓名</text>
|
||||
<input
|
||||
class="field-input"
|
||||
v-model="withdrawForm.realName"
|
||||
placeholder="需与支付宝实名认证姓名一致"
|
||||
placeholder-class="field-placeholder"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view v-if="withdrawForm.channel === 'BANK'">
|
||||
<view class="edit-field">
|
||||
<text class="field-label">银行卡卡号</text>
|
||||
<input
|
||||
class="field-input"
|
||||
type="number"
|
||||
v-model="withdrawForm.bankCard"
|
||||
placeholder="请输入储蓄卡卡号"
|
||||
placeholder-class="field-placeholder"
|
||||
/>
|
||||
</view>
|
||||
<view class="edit-field">
|
||||
<text class="field-label">开户银行名称</text>
|
||||
<input
|
||||
class="field-input"
|
||||
v-model="withdrawForm.bankName"
|
||||
placeholder="例如:中国工商银行 / 招商银行"
|
||||
placeholder-class="field-placeholder"
|
||||
/>
|
||||
</view>
|
||||
<view class="edit-field">
|
||||
<text class="field-label">持卡人姓名</text>
|
||||
<input
|
||||
class="field-input"
|
||||
v-model="withdrawForm.realName"
|
||||
placeholder="需与银行卡开户姓名一致"
|
||||
placeholder-class="field-placeholder"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="modal-footer">
|
||||
<button class="btn-modal btn-cancel btn-active" @click="showWithdrawModal = false">取消</button>
|
||||
<button class="btn-modal btn-save btn-active" @click="submitWithdraw">确认提现</button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 提现历史与审批记录跟踪弹窗 -->
|
||||
<view class="profile-edit-modal-mask" v-if="showWithdrawRecordsModal" @click="showWithdrawRecordsModal = false">
|
||||
@@ -1275,21 +1158,15 @@ const handleRecharge = async () => {
|
||||
});
|
||||
};
|
||||
|
||||
const showWithdrawModal = ref(false);
|
||||
const showWithdrawRecordsModal = ref(false);
|
||||
const userWithdrawalsList = ref([]);
|
||||
const withdrawForm = ref({
|
||||
channel: 'WECHAT',
|
||||
amount: '',
|
||||
alipayAccount: '',
|
||||
bankCard: '',
|
||||
bankName: '',
|
||||
realName: ''
|
||||
|
||||
const financeRules = computed(() => {
|
||||
return platformConfigs.value.finance_rules || {};
|
||||
});
|
||||
|
||||
const minWithdrawAmount = computed(() => {
|
||||
const finRules = platformConfigs.value.finance_rules || {};
|
||||
return Number(finRules.minWithdrawAmount) || 50;
|
||||
return Number(financeRules.value.minWithdrawAmount) || 50;
|
||||
});
|
||||
|
||||
const openWithdrawModal = () => {
|
||||
@@ -1299,6 +1176,14 @@ const openWithdrawModal = () => {
|
||||
});
|
||||
};
|
||||
|
||||
const handleWithdraw = () => {
|
||||
openWithdrawModal();
|
||||
};
|
||||
|
||||
const navToWithdraw = () => {
|
||||
openWithdrawModal();
|
||||
};
|
||||
|
||||
const openWithdrawRecordsModal = async () => {
|
||||
if (!ensureLoggedIn()) return;
|
||||
try {
|
||||
@@ -1310,88 +1195,6 @@ const openWithdrawRecordsModal = async () => {
|
||||
showWithdrawRecordsModal.value = true;
|
||||
};
|
||||
|
||||
const submitWithdraw = async () => {
|
||||
const comm = Number(user.value.commission || 0);
|
||||
const amount = Number(withdrawForm.value.amount || 0);
|
||||
const minLimit = minWithdrawAmount.value;
|
||||
|
||||
if (isNaN(amount) || amount <= 0) {
|
||||
uni.showToast({ title: '请输入有效的提现金额', icon: 'none' });
|
||||
return;
|
||||
}
|
||||
if (amount < minLimit) {
|
||||
uni.showToast({ title: `提现金额须满 ¥${minLimit} 起提`, icon: 'none' });
|
||||
return;
|
||||
}
|
||||
if (amount > comm) {
|
||||
uni.showToast({ title: '提现金额超出可提余额', icon: 'none' });
|
||||
return;
|
||||
}
|
||||
if (amount > 20000) {
|
||||
uni.showToast({ title: '单笔提现最高 ¥20000', icon: 'none' });
|
||||
return;
|
||||
}
|
||||
|
||||
// 渠道账号校验
|
||||
if (withdrawForm.value.channel === 'ALIPAY') {
|
||||
if (!withdrawForm.value.alipayAccount.trim()) {
|
||||
uni.showToast({ title: '请输入支付宝账号', icon: 'none' });
|
||||
return;
|
||||
}
|
||||
if (!withdrawForm.value.realName.trim()) {
|
||||
uni.showToast({ title: '请输入真实姓名', icon: 'none' });
|
||||
return;
|
||||
}
|
||||
} else if (withdrawForm.value.channel === 'BANK') {
|
||||
if (!withdrawForm.value.bankCard.trim()) {
|
||||
uni.showToast({ title: '请输入银行卡号', icon: 'none' });
|
||||
return;
|
||||
}
|
||||
if (!withdrawForm.value.bankName.trim()) {
|
||||
uni.showToast({ title: '请输入开户行全称', icon: 'none' });
|
||||
return;
|
||||
}
|
||||
if (!withdrawForm.value.realName.trim()) {
|
||||
uni.showToast({ title: '请输入持卡人姓名', icon: 'none' });
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
uni.showLoading({ title: '正在提交申请...' });
|
||||
const payload = {
|
||||
channel: withdrawForm.value.channel,
|
||||
alipayAccount: withdrawForm.value.alipayAccount.trim(),
|
||||
bankCard: withdrawForm.value.bankCard.trim(),
|
||||
bankName: withdrawForm.value.bankName.trim(),
|
||||
realName: withdrawForm.value.realName.trim()
|
||||
};
|
||||
const result = await withdrawCommission(user.value.id || 1001, amount, payload);
|
||||
uni.hideLoading();
|
||||
if (result && result.commission !== undefined) {
|
||||
user.value.commission = result.commission;
|
||||
} else {
|
||||
user.value.commission = Math.max(0, comm - amount).toFixed(2);
|
||||
}
|
||||
showWithdrawModal.value = false;
|
||||
uni.showToast({
|
||||
title: '提现申请已提交',
|
||||
icon: 'success',
|
||||
duration: 2000
|
||||
});
|
||||
} catch (err) {
|
||||
uni.hideLoading();
|
||||
uni.showToast({
|
||||
title: err.message || '提现申请失败',
|
||||
icon: 'none'
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const handleWithdraw = () => {
|
||||
openWithdrawModal();
|
||||
};
|
||||
|
||||
// 手机号脱敏展示
|
||||
const displayPhone = computed(() => {
|
||||
const phone = user.value.phone;
|
||||
@@ -3682,5 +3485,7 @@ const navTo = (url) => {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
|
||||
@@ -628,14 +628,14 @@ describe('ContentSecurityService & Compliance Architecture (TDD 微信内容安
|
||||
expect(wsContent).toContain('showWithdrawRecordsModal');
|
||||
});
|
||||
|
||||
it('前端用户中心 (user/index.vue) 必须支持多渠道提现与提现记录看板', () => {
|
||||
it('前端用户中心 (user/index.vue) 必须支持多渠道提现路由跳转与提现记录看板', () => {
|
||||
const userPath = path.join(rootDir, 'pwuniapp', 'pages', 'user', 'index.vue');
|
||||
const userContent = fs.readFileSync(userPath, 'utf-8');
|
||||
expect(userContent).toContain('openWithdrawModal');
|
||||
expect(userContent).toContain('openWithdrawRecordsModal');
|
||||
expect(userContent).toContain('showWithdrawModal');
|
||||
expect(userContent).toContain('/pages/user/withdraw');
|
||||
expect(userContent).toContain('showWithdrawRecordsModal');
|
||||
expect(userContent).toContain('withdrawForm');
|
||||
expect(userContent).toContain('userWithdrawalsList');
|
||||
});
|
||||
|
||||
it('前端动态广场与大神主页必须分别提供本人动态删除与评价回复感谢老板', () => {
|
||||
|
||||
在新工单中引用
屏蔽一个用户