feat: 存储空间管理、虚拟支付接入与容量守卫

- 新增存储空间管理:会员套餐配置、用户容量/到期管理、后台支付记录查询
- 接入个人主体小程序虚拟支付:下单/发货推送/兜底查单(query_order)
- 修复 adminStorageUsers 等接口鉴权、out_trade_no 长度、前端 requestVirtualPayment 参数
- 前端上传前容量预检,超容引导升级无限空间
- 我的页会员卡片展示「无限空间」与已用容量/到期时间
- 后台「存储空间管理」新增支付记录标签页
This commit is contained in:
CodeBuddy
2026-10-30 23:45:39 +08:00
parent b7c6224e54
commit bf99e52937
41 changed files with 2387 additions and 108 deletions
+26
View File
@@ -63,6 +63,25 @@ function formatUploadError(data) {
return msg;
}
// 存储配额错误码(与后端一致),上传超限时引导用户付费。
var STORAGE_QUOTA_EXCEEDED = 10001;
function isStorageQuotaError(data) {
return !!(data && data.code === STORAGE_QUOTA_EXCEEDED);
}
function maybeRedirectStorage(data) {
if (!isStorageQuotaError(data)) return false;
wx.showModal({
title: '存储空间不足',
content: '免费空间已用完,升级为无限空间会员后即可继续上传。',
confirmText: '去升级',
cancelText: '暂不',
success: function (res) {
if (res.confirm) wx.navigateTo({ url: '/pages/storage/storage' });
}
});
return true;
}
/**
* 通用请求方法
* @param {string} action - API action 名称
@@ -219,6 +238,7 @@ const api = {
);
wx.hideLoading();
if (data && !data.error && (data.path || data.success)) { dataCache.mutation('uploadAvatar', data); return data; }
maybeRedirectStorage(data);
wx.showToast({ title: formatUploadError(data), icon: 'none' });
throw data || { error: '上传失败' };
} catch(e) {
@@ -239,6 +259,7 @@ const api = {
);
wx.hideLoading();
if (data && !data.error && (data.path || data.success)) { dataCache.mutation('uploadAvatar', data); return data; }
maybeRedirectStorage(data);
wx.showToast({ title: formatUploadError(data), icon: 'none' });
throw data || { error: '上传失败' };
} catch(e) {
@@ -336,6 +357,7 @@ const api = {
});
wx.hideLoading();
if (data && !data.error && (data.success || data.path || data.uploaded)) { dataCache.mutation('photoUpload', data); return data; }
maybeRedirectStorage(data);
wx.showToast({ title: formatUploadError(data), icon: 'none' });
throw data || { error: '上传失败' };
} catch(e) {
@@ -376,6 +398,10 @@ const api = {
getBgConfig: () => request('getBgConfig', null, 'GET'),
deleteBgImage: () => request('deleteBgImage', {}),
// 存储空间
storageInfo: () => request('storageInfo', null, 'GET'),
storageCreateOrder: (data) => request('storageCreateOrder', data),
// 操作记录
activityLogList: (data) => request('activityLogList', data, 'GET'),
+43
View File
@@ -0,0 +1,43 @@
// utils/storage-guard.js
// 存储空间统一拦截:上传照片/图片前检查剩余空间,超出时在按钮处直接阻止上传。
const { api } = require('./request');
// 判断是否超出配额(会员无限空间,不拦截)
function quotaExceeded(d, extraBytes) {
if (!d) return false;
const isVip = d.is_vip || d.isVip;
if (isVip) return false;
const free = d.free_bytes || d.freeBytes || 0;
const used = d.used_bytes || d.usedBytes || 0;
return used + (extraBytes || 0) > free;
}
// 空间不足时的统一提示
function showQuotaBlocked() {
wx.showModal({
title: '存储空间不足',
content: '当前存储空间已满,请升级为无限空间会员后再上传照片。',
confirmText: '去升级',
cancelText: '取消',
success: function (res) {
if (res.confirm) wx.navigateTo({ url: '/pages/storage/storage' });
}
});
}
// 上传前检查:空间充足 resolve(true);不足则弹窗提示并 resolve(false);查询失败不阻断上传(由服务端二次校验兜底)。
function guardStorageSpace(extraBytes) {
return api.storageInfo()
.then(function (d) {
if (quotaExceeded(d, extraBytes || 0)) {
showQuotaBlocked();
return false;
}
return true;
})
.catch(function () {
return true;
});
}
module.exports = { guardStorageSpace, quotaExceeded, showQuotaBlocked };