diff --git a/api/assets.js b/api/assets.js index 3562475..4fa33a3 100644 --- a/api/assets.js +++ b/api/assets.js @@ -395,6 +395,7 @@ function mapWalletFlowRecords(list, meta) { return { id: buildRecordId(item, meta.key || "flow"), + sourceId: String(pickFirstValue(item, ["id", "log_id", "uid"]) || ""), title: title, subtitle: orderSn ? "单号 " + orderSn : noteText || direction, time: pickFirstValue(item, [ @@ -420,6 +421,7 @@ function mapWalletFlowRecords(list, meta) { directionLabel: direction, actionSymbol: directionPresentation.actionSymbol, orderSn: orderSn, + noteText: noteText, tag: directionPresentation.income ? "收" : "支", tone: directionPresentation.income ? "success" : "danger", cardTone: directionPresentation.income ? "success" : "danger", @@ -631,30 +633,321 @@ function mapTransferRecords(list) { } function mapPointsConvertRecords(list) { - return (Array.isArray(list) ? list : []).map(function (item) { - const numberText = toFixedNumber(item.number, 2); - const transferCoinText = toFixedNumber(item.transfer_coin_num, 0); - const releaseTotal = - item && - item.userBillRelease && - item.userBillRelease.total !== undefined && - item.userBillRelease.total !== null - ? String(item.userBillRelease.total) - : ""; + return normalizeListData(list).map(function (item) { + const amountValue = pickFirstValue(item, [ + "number", + "transfer_coin_num", + "point_num", + "num", + "amount", + "value", + ]); + const rawStatusText = String( + pickFirstValue(item, [ + "status_text", + "status_name", + "status_desc", + "transfer_status_text", + ]) || "", + ); + const rawStatusCode = String( + pickFirstValue(item, ["status", "state", "transfer_status"]) || "", + ); + let statusText = rawStatusText; + let disabled = false; + + if (!statusText) { + if (rawStatusCode === "1") { + statusText = "兑换中"; + } else if (rawStatusCode === "2") { + statusText = "已转换"; + } else if (rawStatusCode === "3") { + statusText = "转换失败"; + } + } + + if ( + /中/.test(statusText) || + /完成/.test(statusText) || + /成功/.test(statusText) || + /失败/.test(statusText) + ) { + disabled = true; + } return { - id: String(item.id || ""), - title: item.title || "积分记录", - subtitle: "可转数量 " + transferCoinText, - time: item.add_time || "", - amount: "+" + numberText, - balance: releaseTotal ? "释放总量 " + releaseTotal : "", + id: String( + pickFirstValue(item, ["id", "bill_id", "log_id", "sn"]) || + Math.random(), + ), + sourceId: String(pickFirstValue(item, ["id", "bill_id", "log_id"]) || ""), + orderSn: String( + pickFirstValue(item, ["order_sn", "trade_no", "bill_no", "sn"]) || "", + ), + title: + pickFirstValue(item, ["title", "name", "type_name"]) || + "系统赠送积分", + subtitle: + "可转数量 " + + formatTransferRecordNumber( + pickFirstValue(item, ["transfer_coin_num", "coin_num", "value"]) || 0, + ), + time: pickFirstValue(item, [ + "add_time", + "create_time", + "created_at", + "time", + "update_time", + ]), + amount: "+" + formatLedgerRecordNumber(amountValue), + amountValue: toNumber(amountValue), + statusText: statusText, + disabled: disabled, + balance: + item && + item.userBillRelease && + item.userBillRelease.total !== undefined && + item.userBillRelease.total !== null + ? "释放总量 " + formatTransferRecordNumber(item.userBillRelease.total) + : "", tag: "积", - tone: "success", + tone: disabled ? "warning" : "success", }; }); } +function extractMonthLabel(value) { + const raw = String(value || "").trim(); + + if (!raw) { + const currentDate = new Date(); + const year = currentDate.getFullYear(); + const month = String(currentDate.getMonth() + 1).padStart(2, "0"); + return year + "-" + month; + } + + const matcher = raw.match(/(\d{4})[-/.](\d{1,2})/); + if (matcher) { + return matcher[1] + "-" + String(matcher[2]).padStart(2, "0"); + } + + const date = new Date(raw.replace(/-/g, "/")); + if (Number.isNaN(date.getTime())) { + return raw.slice(0, 7); + } + + return ( + date.getFullYear() + + "-" + + String(date.getMonth() + 1).padStart(2, "0") + ); +} + +function buildPointsHistoryRecords(list) { + return mapWalletFlowRecords(list, { + key: "points-convert-history", + unit: "积分", + title: "积分记录", + subtitle: "可用积分流水", + }).map(function (item) { + return Object.assign({}, item, { + month: extractMonthLabel(item.time), + detailAvailable: canOpenPointsConvertRecordDetail(item), + amountTone: item.actionSymbol === "+" ? "increase" : "decrease", + }); + }); +} + +function buildMonthOptions(list) { + const months = (Array.isArray(list) ? list : []).reduce(function ( + result, + item, + ) { + const month = item && item.month ? item.month : extractMonthLabel(item && item.time); + if (month && result.indexOf(month) === -1) { + result.push(month); + } + return result; + }, []); + + months.sort(function (left, right) { + return right.localeCompare(left); + }); + + if (!months.length) { + months.push(extractMonthLabel("")); + } + + return months; +} + +function canOpenPointsConvertRecordDetail(item) { + const target = item && typeof item === "object" ? item : {}; + const contentText = [ + target.title, + target.subtitle, + target.noteText, + target.feeText, + target.directionLabel, + ] + .join(" ") + .toLowerCase(); + + return ( + Boolean(target.orderSn || target.sourceId) && + /转换/.test(contentText) && + !/bmt/.test(contentText) + ); +} + +function extractPointsConvertDetailItems(data) { + if (Array.isArray(data)) { + return data; + } + + if (!data || typeof data !== "object") { + return []; + } + + if (Array.isArray(data.list)) { + return data.list; + } + + if (Array.isArray(data.items)) { + return data.items; + } + + if (Array.isArray(data.details)) { + return data.details; + } + + if (Array.isArray(data.records)) { + return data.records; + } + + return []; +} + +function buildPointsConvertDetailFallback(record) { + const fallback = record || {}; + const amountValue = String(fallback.amount || "").replace(/[^\d.-]/g, ""); + + return { + orderSn: fallback.orderSn || "", + totalAmount: + fallback.amount && String(fallback.amount).trim() + ? String(fallback.amount) + : "+" + formatLedgerRecordNumber(amountValue), + time: fallback.time || "", + details: [ + { + id: fallback.id || fallback.orderSn || "fallback-record", + title: fallback.title || "积分转换", + amount: + fallback.amount && String(fallback.amount).trim() + ? String(fallback.amount) + : "+" + formatLedgerRecordNumber(amountValue), + time: fallback.time || "", + }, + ], + }; +} + +function buildPointsConvertDetailPayload(data, fallbackRecord) { + const detailItems = extractPointsConvertDetailItems(data); + const summarySource = + data && typeof data === "object" && !Array.isArray(data) ? data : {}; + const fallback = fallbackRecord || {}; + const totalValue = + pickFirstValue(summarySource, [ + "number", + "num", + "amount", + "point_num", + "transfer_coin_num", + "total", + ]) || sumBy(detailItems, "number"); + const totalAmountText = + totalValue !== "" + ? "+" + formatLedgerRecordNumber(totalValue) + : fallback.amount || "+0"; + const detailList = detailItems.map(function (item, index) { + const amountValue = pickFirstValue(item, [ + "number", + "num", + "amount", + "point_num", + "transfer_coin_num", + "value", + ]); + + return { + id: String( + pickFirstValue(item, ["id", "bill_id", "log_id", "sn"]) || + "detail-" + index, + ), + title: + pickFirstValue(item, ["title", "name", "type_name"]) || + fallback.title || + "系统赠送积分", + amount: "+" + formatLedgerRecordNumber(amountValue), + time: + pickFirstValue(item, [ + "add_time", + "create_time", + "created_at", + "time", + "update_time", + ]) || fallback.time || "", + }; + }); + + if (!detailList.length) { + return buildPointsConvertDetailFallback({ + id: fallback.id, + orderSn: + String( + pickFirstValue(summarySource, [ + "order_sn", + "trade_no", + "bill_no", + "sn", + ]) || fallback.orderSn || "", + ), + title: + pickFirstValue(summarySource, ["title", "name", "type_name"]) || + fallback.title, + amount: totalAmountText, + time: + pickFirstValue(summarySource, [ + "add_time", + "create_time", + "created_at", + "time", + "update_time", + ]) || fallback.time, + }); + } + + return { + orderSn: String( + pickFirstValue(summarySource, ["order_sn", "trade_no", "bill_no", "sn"]) || + fallback.orderSn || + "", + ), + totalAmount: totalAmountText, + time: + pickFirstValue(summarySource, [ + "add_time", + "create_time", + "created_at", + "time", + "update_time", + ]) || fallback.time || "", + details: detailList, + }; +} + function buildDefaultLedger(type, balances) { const map = { power: { @@ -774,7 +1067,7 @@ async function fetchWalletAddressData(requestOptions) { async function fetchPointsConvertList(requestOptions) { return fetchPayload( createRequestOptions({ - url: serviceConfig.ENDPOINTS.pointsConvertList, + url: serviceConfig.ENDPOINTS.pointsConvertAvailableList, data: { interval: serviceConfig.POINTS_CONVERT_INTERVAL, }, @@ -783,6 +1076,18 @@ async function fetchPointsConvertList(requestOptions) { ); } +async function fetchPointsConvertHistoryListData(month, requestOptions) { + return fetchPayload( + createRequestOptions({ + url: serviceConfig.ENDPOINTS.pointsConvertHistoryList, + data: { + month: month, + }, + }, requestOptions), + "积分兑换列表加载失败", + ); +} + async function fetchTransferLedgerData(requestOptions) { return fetchPayload( createRequestOptions({ @@ -816,6 +1121,16 @@ async function fetchRedeemRecordListData(redeemType, requestOptions) { ); } +async function fetchPointsConvertInfoData(query, requestOptions) { + return fetchPayload( + createRequestOptions({ + url: serviceConfig.ENDPOINTS.pointsConvertRecordDetail, + data: query || {}, + }, requestOptions), + "积分转换详情加载失败", + ); +} + export async function fetchAssetHome(requestOptions) { const result = await Promise.all([ fetchPriceData(requestOptions), @@ -824,31 +1139,65 @@ export async function fetchAssetHome(requestOptions) { return buildHomeOverview(result[1], result[0]); } -export async function fetchPointsConvertDetail(requestOptions) { +export async function fetchPointsConvertHome(month, requestOptions) { const result = await Promise.all([ fetchHomeBalanceData(requestOptions), - fetchPointsConvertList(requestOptions), + fetchPointsConvertHistoryListData(month, requestOptions), ]); const balances = normalizeBalances(result[0]); - const pointList = Array.isArray(result[1] && result[1].list) - ? result[1].list - : []; + const records = buildPointsHistoryRecords(result[1]).map(function (item) { + return Object.assign({}, item, { + month: extractMonthLabel(item.time) || month, + detailAvailable: canOpenPointsConvertRecordDetail(item), + }); + }); return { - availablePoints: toFixedNumber(balances.points, 2), - pendingPoints: toFixedNumber(sumBy(pointList, "number"), 0), - ids: pointList - .map(function (item) { - return item && item.id; - }) - .filter(Boolean), - tips: [ - "释放中的积分,转换成可用积分后,方可兑换BMT;", - "凌晨0点-凌晨1点积分系统维护不可兑换。", - ], + availablePoints: formatHomeNumber(balances.points, 0), + records: records, }; } +export async function fetchPointsConvertSelection(requestOptions) { + const data = await fetchPointsConvertList(requestOptions); + const items = mapPointsConvertRecords(data); + + return { + items: items, + }; +} + +export async function fetchPointsConvertRecordDetail(record, requestOptions) { + const fallbackRecord = record || {}; + const query = {}; + + if (fallbackRecord.sourceId) { + query.id = fallbackRecord.sourceId; + } else if ( + fallbackRecord.id && + fallbackRecord.orderSn && + fallbackRecord.id !== fallbackRecord.orderSn + ) { + query.id = fallbackRecord.id; + } + + if (fallbackRecord.orderSn) { + query.order_sn = fallbackRecord.orderSn; + query.sn = fallbackRecord.orderSn; + } + + if (!Object.keys(query).length) { + return buildPointsConvertDetailFallback(fallbackRecord); + } + + try { + const data = await fetchPointsConvertInfoData(query, requestOptions); + return buildPointsConvertDetailPayload(data, fallbackRecord); + } catch (error) { + return buildPointsConvertDetailFallback(fallbackRecord); + } +} + export async function submitAssetPointsConvert(payload, requestOptions) { const ids = Array.isArray(payload && payload.ids) ? payload.ids : []; diff --git a/config/service.js b/config/service.js index e4260bb..08fe5e5 100644 --- a/config/service.js +++ b/config/service.js @@ -19,9 +19,10 @@ const serviceConfig = { walletDetail: "/api/hn/wallet/getWalletAddress", walletSave: "/api/hn/wallet/saveAddress", withdrawSubmit: "/api/hn/wallet/withdraw", - pointsConvertList: "/api/integral/transferList", + pointsConvertHistoryList: "/api/integral/getTransferList", + pointsConvertAvailableList: "/api/integral/transferList", pointsConvertSubmit: "/api/integral/doTransfer", - pointsConvertInfo: "/api/integral/transferInfo", + pointsConvertRecordDetail: "/api/integral/transferInfo", }, }; diff --git a/manifest.json b/manifest.json index 721e850..1f227c7 100644 --- a/manifest.json +++ b/manifest.json @@ -68,5 +68,10 @@ "uniStatistics" : { "enable" : false }, - "vueVersion" : "2" + "vueVersion" : "2", + "h5" : { + "router" : { + "base" : "/bmt/" + } + } } diff --git a/pages.json b/pages.json index e3ae41e..0fda7c9 100644 --- a/pages.json +++ b/pages.json @@ -43,6 +43,20 @@ "backgroundColor": "#191E32" } }, + { + "path": "pages/assets/points-convert-list", + "style": { + "navigationStyle": "custom", + "backgroundColor": "#191E32" + } + }, + { + "path": "pages/assets/points-convert-detail", + "style": { + "navigationStyle": "custom", + "backgroundColor": "#191E32" + } + }, { "path": "pages/assets/ledger", "style": { diff --git a/pages/assets/points-convert-detail.vue b/pages/assets/points-convert-detail.vue new file mode 100644 index 0000000..54bf07a --- /dev/null +++ b/pages/assets/points-convert-detail.vue @@ -0,0 +1,262 @@ + + + + + diff --git a/pages/assets/points-convert-list.vue b/pages/assets/points-convert-list.vue new file mode 100644 index 0000000..c5d1c16 --- /dev/null +++ b/pages/assets/points-convert-list.vue @@ -0,0 +1,658 @@ + + + + + diff --git a/pages/assets/points-convert.vue b/pages/assets/points-convert.vue index 2b445ca..1a86952 100644 --- a/pages/assets/points-convert.vue +++ b/pages/assets/points-convert.vue @@ -1,49 +1,83 @@