This commit is contained in:
whitechiina 2026-04-30 11:15:29 +08:00
parent 322651e507
commit df61e1614d
28 changed files with 202 additions and 111 deletions

View File

@ -1,6 +1,9 @@
import serviceConfig from "../config/service"; import serviceConfig from "../config/service";
import request from "../utils/request"; import request from "../utils/request";
const HOME_TICKER_STORAGE_KEY = "asset_home_ticker_cache";
let runtimeHomeTickerCache = null;
function createError(message, raw) { function createError(message, raw) {
return { return {
message: message || "接口请求失败", message: message || "接口请求失败",
@ -90,7 +93,6 @@ function normalizeTicker(data) {
change = "0.00%"; change = "0.00%";
} }
} }
return { return {
symbol: (data && data.symbol) || "BMT/CNY", symbol: (data && data.symbol) || "BMT/CNY",
close: close, close: close,
@ -101,6 +103,40 @@ function normalizeTicker(data) {
}; };
} }
function setHomeTickerCache(ticker) {
const normalizedTicker = normalizeTicker(ticker);
runtimeHomeTickerCache = normalizedTicker;
try {
if (typeof uni !== "undefined" && uni.setStorageSync) {
uni.setStorageSync(HOME_TICKER_STORAGE_KEY, normalizedTicker);
}
} catch (error) {
// Ignore storage failures and keep runtime cache fallback.
}
return normalizedTicker;
}
function getHomeTickerCache() {
if (runtimeHomeTickerCache) {
return runtimeHomeTickerCache;
}
try {
if (typeof uni !== "undefined" && uni.getStorageSync) {
const storedTicker = uni.getStorageSync(HOME_TICKER_STORAGE_KEY);
if (storedTicker && typeof storedTicker === "object") {
runtimeHomeTickerCache = normalizeTicker(storedTicker);
}
}
} catch (error) {
// Ignore storage failures.
}
return runtimeHomeTickerCache || normalizeTicker(null);
}
function normalizeBalances(data) { function normalizeBalances(data) {
return { return {
points: toNumber(data && data.point), points: toNumber(data && data.point),
@ -358,7 +394,7 @@ function buildPagingRequestData(baseData, pagination) {
return Object.assign({}, baseData || {}, { return Object.assign({}, baseData || {}, {
page: normalizedPagination.page, page: normalizedPagination.page,
page_size: normalizedPagination.pageSize, limit: normalizedPagination.pageSize,
}); });
} }
@ -971,6 +1007,7 @@ function mapPointsConvertRecords(list) {
amount: "+" + formatLedgerRecordNumber(amountValue), amount: "+" + formatLedgerRecordNumber(amountValue),
amountValue: toNumber(amountValue), amountValue: toNumber(amountValue),
transferPointValue: toNumber(rawTransferPointValue), transferPointValue: toNumber(rawTransferPointValue),
transfer_point_num: toNumber(rawTransferPointValue),
statusText: statusText, statusText: statusText,
disabled: disabled, disabled: disabled,
balance: balance:
@ -1369,12 +1406,39 @@ async function fetchWalletAddressData(requestOptions) {
); );
} }
async function fetchPointsConvertList(pagination, requestOptions) { function normalizePointsConvertInterval(value) {
const rawInterval = String(
value === undefined || value === null ? "" : value,
).trim();
if (!rawInterval) {
return serviceConfig.POINTS_CONVERT_INTERVAL;
}
const matcher = rawInterval.match(
/^(-?\d+(?:\.\d+)?)\s*,\s*(-?\d+(?:\.\d+)?)$/,
);
if (!matcher) {
return serviceConfig.POINTS_CONVERT_INTERVAL;
}
const start = toNumber(matcher[1]);
const end = toNumber(matcher[2]);
if (!Number.isFinite(start) || !Number.isFinite(end)) {
return serviceConfig.POINTS_CONVERT_INTERVAL;
}
return String(start) + "," + String(end);
}
async function fetchPointsConvertList(pagination, requestOptions, interval) {
const normalizedInterval = normalizePointsConvertInterval(interval);
return fetchPayload( return fetchPayload(
createRequestOptions({ createRequestOptions({
url: serviceConfig.ENDPOINTS.pointsConvertAvailableList, url: serviceConfig.ENDPOINTS.pointsConvertAvailableList,
data: buildPagingRequestData({ data: buildPagingRequestData({
interval: serviceConfig.POINTS_CONVERT_INTERVAL, interval: normalizedInterval,
}, pagination), }, pagination),
}, requestOptions), }, requestOptions),
"积分转换列表加载失败", "积分转换列表加载失败",
@ -1442,7 +1506,9 @@ export async function fetchAssetHome(requestOptions) {
fetchPriceData(requestOptions), fetchPriceData(requestOptions),
fetchHomeBalanceData(requestOptions), fetchHomeBalanceData(requestOptions),
]); ]);
return buildHomeOverview(result[1], result[0]); const overview = buildHomeOverview(result[1], result[0]);
setHomeTickerCache(overview.ticker);
return overview;
} }
export async function fetchPointsConvertHome(month, requestOptions) { export async function fetchPointsConvertHome(month, requestOptions) {
@ -1468,6 +1534,11 @@ export async function fetchPointsConvertSelection(
paginationOrRequestOptions, paginationOrRequestOptions,
requestOptions, requestOptions,
) { ) {
const interval =
paginationOrRequestOptions &&
typeof paginationOrRequestOptions === "object"
? paginationOrRequestOptions.interval
: "";
const params = resolvePagingArguments( const params = resolvePagingArguments(
paginationOrRequestOptions, paginationOrRequestOptions,
requestOptions, requestOptions,
@ -1475,6 +1546,7 @@ export async function fetchPointsConvertSelection(
const data = await fetchPointsConvertList( const data = await fetchPointsConvertList(
params.pagination, params.pagination,
params.requestOptions, params.requestOptions,
interval,
); );
const items = mapPointsConvertRecords(data); const items = mapPointsConvertRecords(data);
const pagination = buildPaginationMeta(data, params.pagination); const pagination = buildPaginationMeta(data, params.pagination);
@ -1627,7 +1699,6 @@ export async function fetchPowerExchangeDetail(requestOptions) {
]); ]);
const ticker = normalizeTicker(result[0]); const ticker = normalizeTicker(result[0]);
const balances = normalizeBalances(result[1]); const balances = normalizeBalances(result[1]);
return { return {
ticker: ticker, ticker: ticker,
balances: { balances: {
@ -1636,7 +1707,7 @@ export async function fetchPowerExchangeDetail(requestOptions) {
power: toFixedNumber(balances.power, 0), power: toFixedNumber(balances.power, 0),
}, },
tips: [ tips: [
"算力 = 抵用券或消费券 ÷ BMT实时价格", "算力 = 抵用券或消费券 × BMT实时价格",
"抵用券和消费券总数小于100券的不可兑换", "抵用券和消费券总数小于100券的不可兑换",
"算力用于兑换BMT使用。", "算力用于兑换BMT使用。",
], ],
@ -1668,31 +1739,33 @@ export async function submitAssetPowerExchange(payload, requestOptions) {
}; };
} }
// BMT兑换
export async function fetchBmtExchangeDetail(requestOptions) { export async function fetchBmtExchangeDetail(requestOptions) {
const result = await Promise.all([ const result = await Promise.all([
fetchPriceData(requestOptions),
fetchHomeBalanceData(requestOptions), fetchHomeBalanceData(requestOptions),
fetchBmtPowerRateData(requestOptions), fetchBmtPowerRateData(requestOptions),
]); ]);
const ticker = normalizeTicker(result[0]);
const balances = normalizeBalances(result[1]); const ticker = getHomeTickerCache();
const powerRate = resolveRedeemPowerRate(result[2]); const balances = normalizeBalances(result[0]);
const powerRate = resolveRedeemPowerRate(result[1]);
return { return {
ticker: ticker, ticker: ticker,
powerRate: powerRate, powerRate: powerRate,
balances: { balances: {
points: toFixedNumber(balances.points, 0), points: balances.points,
power: toFixedNumber(balances.power, 0), power: balances.power,
bmt: toFixedNumber(balances.bmt, 2), bmt: balances.bmt,
voucher: toFixedNumber(balances.voucher, 2), voucher: balances.voucher,
coupon: toFixedNumber(balances.coupon, 2), coupon: balances.coupon,
}, },
tips: [ tips: [
"BMT=输入的积分数量,提交时会同步校验所需算力。", "预估 BMT数= 输入可用积分数÷BMT 实时价格。",
"兑换所需算力按后端返回比例实时计算。", `兑换会同步消耗算力, 1 点可用积分,需同步消耗${powerRate}点算力。`,
"只能兑换100的整数倍小于100积分不可兑换。", "仅支持 100 的正整数倍, 不足 100的可用积分无法发起兑换。",
"凌晨0点至凌晨1点积分系统维护期间不可兑换。", "凌晨 00:00 至 01:00 为积分系统维护时段,期间暂停兑换服务,请避开该时间段操作。",
], ],
}; };
} }

View File

@ -2,7 +2,7 @@ const serviceConfig = {
BASE_URL: "https://tpoint.agrimedia.cn", BASE_URL: "https://tpoint.agrimedia.cn",
TIMEOUT: 10000, TIMEOUT: 10000,
WALLET_NAME: "海南农综交易所", WALLET_NAME: "海南农综交易所",
POINTS_CONVERT_INTERVAL: "0,999999999", POINTS_CONVERT_INTERVAL: "0,20",
ENDPOINTS: { ENDPOINTS: {
price: "/api/hn/getPrice", price: "/api/hn/getPrice",
homeBalance: "/api/hn/getAllBalance", homeBalance: "/api/hn/getAllBalance",

View File

@ -203,8 +203,12 @@ export default {
if (!this.pointsValue) { if (!this.pointsValue) {
return "0"; return "0";
} }
const price = this.priceNumber;
if (!price) {
return "0";
}
return this.formatAmount(this.pointsValue, 0); return this.formatAmount(this.pointsValue / price, 2);
}, },
powerCost() { powerCost() {
if (!this.pointsValue || !this.powerRateNumber) { if (!this.pointsValue || !this.powerRateNumber) {
@ -214,21 +218,19 @@ export default {
return (this.pointsValue * this.powerRateNumber).toFixed(2); return (this.pointsValue * this.powerRateNumber).toFixed(2);
}, },
allEstimateBmt() { allEstimateBmt() {
const pointsLimit = Number(this.detail.balances.points || 0); const points = Number(this.detail.balances.points || 0);
const powerLimit = Number(this.detail.balances.power || 0); const compute = Number(this.detail.balances.power || 0);
const price = this.priceNumber;
if (!this.powerRateNumber) { if (!price) {
return "0"; return "0";
} }
const estimatedBmt = Math.min(points, compute * 10) / price;
const maxByPower = powerLimit / this.powerRateNumber; return this.formatAmount(Math.max(0, estimatedBmt), 2);
const available = Math.max(0, Math.min(pointsLimit, maxByPower || 0));
return this.formatAmount(available, 2);
}, },
priceNumber() { priceNumber() {
return Number( return Number(
this.detail.ticker.close || this.detail.ticker.cnyPrice || 0, this.detail.ticker.close || 0,
); );
}, },
displayBmt() { displayBmt() {
@ -241,7 +243,7 @@ export default {
return this.detail.balances.points; return this.detail.balances.points;
}, },
displayPrice() { displayPrice() {
return this.priceNumber ? this.priceNumber.toFixed(2) : "0.00"; return this.priceNumber ? this.priceNumber : "0.00";
}, },
normalizedTips() { normalizedTips() {
if (this.detail.tips && this.detail.tips.length) { if (this.detail.tips && this.detail.tips.length) {
@ -636,7 +638,6 @@ export default {
.tips-block { .tips-block {
margin-top: 24rpx; margin-top: 24rpx;
padding: 0rpx 10rpx;
} }
.tips-block__title { .tips-block__title {

View File

@ -173,7 +173,7 @@ export default {
}, },
activeTab: "", activeTab: "",
page: 1, page: 1,
pageSize: 20, pageSize: 10,
hasMore: false, hasMore: false,
loadingMore: false, loadingMore: false,
}; };

View File

@ -35,7 +35,7 @@
:key="tab.key" :key="tab.key"
class="range-tabs__item" class="range-tabs__item"
:class="{ 'range-tabs__item--active': activeRange === tab.key }" :class="{ 'range-tabs__item--active': activeRange === tab.key }"
@click="activeRange = tab.key" @click="switchRange(tab.key)"
> >
{{ tab.label }} {{ tab.label }}
</view> </view>
@ -82,8 +82,8 @@
}}</text> }}</text>
</view> </view>
<view class="selection-item__side" style="display: flex"> <view class="selection-item__side" style="display: flex; align-items: center;">
<text class="selection-item__label">积分</text> <text class="selection-item__label" style="margin-top: 6rpx">积分</text>
<text class="selection-item__amount asset-number-font">{{ <text class="selection-item__amount asset-number-font">{{
item.amount item.amount
}}</text> }}</text>
@ -171,7 +171,7 @@ export default {
data() { data() {
return { return {
hasShown: false, hasShown: false,
activeRange: "", activeRange: "below-20",
submitting: false, submitting: false,
confirmVisible: false, confirmVisible: false,
selectedIds: [], selectedIds: [],
@ -179,7 +179,7 @@ export default {
items: [], items: [],
}, },
page: 1, page: 1,
pageSize: 20, pageSize: 10,
hasMore: false, hasMore: false,
loadingMore: false, loadingMore: false,
}; };
@ -190,30 +190,42 @@ export default {
{ {
key: "below-20", key: "below-20",
label: "20以下", label: "20以下",
interval: "0,20",
}, },
{ {
key: "20-100", key: "20-100",
label: "20-100", label: "20-100",
interval: "20,100",
}, },
{ {
key: "100-200", key: "100-200",
label: "100-200", label: "100-200",
interval: "100,200",
}, },
{ {
key: "200-500", key: "200-500",
label: "200-500", label: "200-500",
interval: "200,500",
}, },
{ {
key: "500-plus", key: "500-plus",
label: "500以上", label: "500以上",
interval: "500,10000",
}, },
]; ];
}, },
currentInterval() {
const currentTab = this.rangeTabs.find(
(item) => item.key === this.activeRange,
);
return (currentTab && currentTab.interval) || "0,20";
},
items() { items() {
return Array.isArray(this.detail.items) ? this.detail.items : []; return Array.isArray(this.detail.items) ? this.detail.items : [];
}, },
filteredItems() { filteredItems() {
return this.items.filter((item) => this.matchRange(item)); return this.items;
}, },
selectedItems() { selectedItems() {
return this.items.filter( return this.items.filter(
@ -348,61 +360,39 @@ export default {
.toString() .toString()
.replace(/\B(?=(\d{3})+(?!\d))/g, ","); .replace(/\B(?=(\d{3})+(?!\d))/g, ",");
}, },
matchRange(item) { switchRange(nextRangeKey) {
const amount = Number(item && item.amountValue ? item.amountValue : 0); const targetRangeKey = String(nextRangeKey || "");
if (!targetRangeKey || targetRangeKey === this.activeRange) {
if (!this.activeRange) { return;
return true;
} }
if (this.activeRange === "below-20") { this.activeRange = targetRangeKey;
return amount < 20; this.selectedIds = [];
} this.resetPagingState();
this.loadPage(true, 1);
if (this.activeRange === "20-100") {
return amount >= 20 && amount < 100;
}
if (this.activeRange === "100-200") {
return amount >= 100 && amount < 200;
}
if (this.activeRange === "200-500") {
return amount >= 200 && amount < 500;
}
if (this.activeRange === "500-plus") {
return amount >= 500;
}
return false;
},
resolveRangeByAmount(amount) {
const numericAmount = Number(amount || 0);
if (numericAmount < 20) {
return "below-20";
}
if (numericAmount < 100) {
return "20-100";
}
if (numericAmount < 200) {
return "100-200";
}
if (numericAmount < 500) {
return "200-500";
}
return "500-plus";
}, },
isChecked(item) { isChecked(item) {
return this.selectedIds.indexOf(item.id) > -1; return this.selectedIds.indexOf(item.id) > -1;
}, },
toggleItem(item) { toggleItem(item) {
if (!item || item.disabled) { if (!item) {
return;
}
const transferPointNum = Number(
item.transfer_point_num !== undefined
? item.transfer_point_num
: item.transferPointValue || 0,
);
if (transferPointNum === 0) {
uni.showToast({
title: "当前订单无可用积分",
icon: "none",
});
return;
}
if (item.disabled) {
return; return;
} }
@ -453,6 +443,7 @@ export default {
{ {
page: page, page: page,
pageSize: this.pageSize, pageSize: this.pageSize,
interval: this.currentInterval,
}, },
requestOptions, requestOptions,
); );
@ -473,14 +464,6 @@ export default {
(id) => validIds.indexOf(id) > -1, (id) => validIds.indexOf(id) > -1,
); );
const rangeKeys = this.rangeTabs.map((item) => item.key);
if (rangeKeys.indexOf(this.activeRange) === -1) {
const firstItem = this.items[0];
this.activeRange = firstItem
? this.resolveRangeByAmount(firstItem.amountValue)
: this.rangeTabs[0].key;
}
this.updatePaging(result, page, incomingItems.length); this.updatePaging(result, page, incomingItems.length);
if (isLoadMore && mergedItems.length <= previousCount) { if (isLoadMore && mergedItems.length <= previousCount) {
@ -699,7 +682,7 @@ export default {
} }
.selection-item--disabled { .selection-item--disabled {
opacity: 0.78; opacity: 0.6;
} }
.selection-item__checkbox, .selection-item__checkbox,

View File

@ -221,7 +221,7 @@ export default {
return "0"; return "0";
} }
return this.formatAmount(this.amountValue / this.priceNumber, 0); return this.formatAmount(this.amountValue * this.priceNumber, 2);
}, },
allEstimatePower() { allEstimatePower() {
if (!this.priceNumber) { if (!this.priceNumber) {
@ -232,19 +232,19 @@ export default {
Number(this.detail.balances.voucher || 0) + Number(this.detail.balances.voucher || 0) +
Number(this.detail.balances.coupon || 0); Number(this.detail.balances.coupon || 0);
return this.formatAmount(totalTickets / this.priceNumber, 0); return this.formatAmount(totalTickets / this.priceNumber, 2);
}, },
displayPower() { displayPower() {
return this.formatAmount(this.detail.balances.power, 2); return this.formatAmount(this.detail.balances.power, 0);
}, },
displayVoucher() { displayVoucher() {
return this.formatAmount(this.detail.balances.voucher, 0); return this.formatAmount(this.detail.balances.voucher, 0);
}, },
displayCoupon() { displayCoupon() {
return this.formatAmount(this.detail.balances.coupon, 2); return this.formatAmount(this.detail.balances.coupon, 0);
}, },
displayPrice() { displayPrice() {
return this.priceNumber ? this.priceNumber.toFixed(2) : "0.00"; return this.priceNumber ? this.priceNumber : "0.00";
}, },
normalizedTips() { normalizedTips() {
if (this.detail.tips && this.detail.tips.length) { if (this.detail.tips && this.detail.tips.length) {
@ -252,7 +252,7 @@ export default {
} }
return [ return [
"算力 = 抵用券或消费券 ÷ BMT实时价格", "算力 = 抵用券或消费券 * BMT实时价格",
"抵用券和消费券总数小于100券的不可兑换", "抵用券和消费券总数小于100券的不可兑换",
"算力用于兑换BMT使用。", "算力用于兑换BMT使用。",
]; ];

View File

@ -23,7 +23,7 @@
:placeholder="form.id ? '粘贴新钱包地址' : '粘贴新钱包地址'" :placeholder="form.id ? '粘贴新钱包地址' : '粘贴新钱包地址'"
placeholder-class="wallet-input__placeholder" placeholder-class="wallet-input__placeholder"
/> />
<text class="wallet-input__paste" @click="paste">粘贴</text> <!-- <text class="wallet-input__paste" @click="paste">粘贴</text> -->
</view> </view>
<text class="wallet-form-panel__helper"> <text class="wallet-form-panel__helper">

View File

@ -115,9 +115,9 @@
placeholder="粘贴新钱包地址" placeholder="粘贴新钱包地址"
placeholder-style="color:rgba(165,175,208,0.82);font-size:28rpx;" placeholder-style="color:rgba(165,175,208,0.82);font-size:28rpx;"
/> />
<text class="wallet-edit-dialog__paste" @click.stop="pasteEditAddress"> <!-- <text class="wallet-edit-dialog__paste" @click.stop="pasteEditAddress">
粘贴 粘贴
</text> </text> -->
</view> </view>
<text class="wallet-edit-dialog__desc asset-number-font"> <text class="wallet-edit-dialog__desc asset-number-font">
请仔细核对钱包地址以免造成财产损失 请仔细核对钱包地址以免造成财产损失
@ -264,7 +264,7 @@ export default {
return; return;
} }
this.editAddress = this.currentWallet.address || ""; this.editAddress = "";
this.editDialogVisible = true; this.editDialogVisible = true;
}, },
closeEditDialog() { closeEditDialog() {
@ -273,10 +273,19 @@ export default {
this.editingAddress = false; this.editingAddress = false;
}, },
pasteEditAddress() { pasteEditAddress() {
const that = this;
uni.getClipboardData({ uni.getClipboardData({
success(result) { success: (result) => {
that.editAddress = result.data || ""; const clipboardValue =
result && result.data !== undefined && result.data !== null
? String(result.data)
: "";
this.editAddress = clipboardValue;
},
fail: () => {
uni.showToast({
title: "粘贴失败,请重试",
icon: "none",
});
}, },
}); });
}, },

View File

@ -191,7 +191,6 @@ export default {
if (!Number.isFinite(price) || price <= 0) { if (!Number.isFinite(price) || price <= 0) {
return "0.000"; return "0.000";
} }
return price.toFixed(3); return price.toFixed(3);
}, },
walletDisplayAddress() { walletDisplayAddress() {

2
unpackage/dist/build/web/index.html vendored Normal file
View File

@ -0,0 +1,2 @@
<!DOCTYPE html><html lang=zh-CN><head><meta charset=utf-8><meta http-equiv=X-UA-Compatible content="IE=edge"><title>白马交易所</title><script>var coverSupport = 'CSS' in window && typeof CSS.supports === 'function' && (CSS.supports('top: env(a)') || CSS.supports('top: constant(a)'))
document.write('<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0' + (coverSupport ? ', viewport-fit=cover' : '') + '" />')</script><link rel=stylesheet href=/bmt/static/index.883130ca.css></head><body><noscript><strong>Please enable JavaScript to continue.</strong></noscript><div id=app></div><script src=/bmt/static/js/chunk-vendors.98a0fd8f.js></script><script src=/bmt/static/js/index.3dd40b51.js></script></body></html>

Binary file not shown.

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

BIN
unpackage/dist/build/web/static/logo.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB