diff --git a/api/assets.js b/api/assets.js
index 3f0698a..73b6854 100644
--- a/api/assets.js
+++ b/api/assets.js
@@ -137,6 +137,24 @@ function getHomeTickerCache() {
return runtimeHomeTickerCache || normalizeTicker(null);
}
+function appendTokenToTargetUrl(targetUrl) {
+ const token = String(getCurrentWebviewToken() || "").trim();
+ let nextTargetUrl = String(targetUrl || "").trim();
+
+ if (token) {
+ nextTargetUrl +=
+ (nextTargetUrl.indexOf("?") > -1 ? "&" : "?") +
+ "token=" +
+ encodeURIComponent(token);
+ }
+
+ return {
+ token: token,
+ targetUrl: nextTargetUrl,
+ encodedTargetUrl: encodeURIComponent(nextTargetUrl),
+ };
+}
+
function normalizeBalances(data) {
return {
points: toNumber(data && data.point),
@@ -1422,6 +1440,259 @@ function buildDefaultLedger(type, balances) {
};
}
+function buildFlowRecordId(item, groupKey, index) {
+ const directId = String(
+ pickFirstValue(item, ["id", "flow_id", "log_id", "record_id"]) || "",
+ ).trim();
+
+ if (directId) {
+ return directId;
+ }
+
+ return [
+ groupKey,
+ pickFirstValue(item, ["add_time", "time", "created_at"]),
+ pickFirstValue(item, ["title", "mark", "amount", "number"]),
+ index,
+ ]
+ .map((value) => String(value || ""))
+ .join("-");
+}
+
+function isPositiveFlowValue(value) {
+ const booleanLike = parseBooleanLike(value);
+
+ if (booleanLike !== null) {
+ return booleanLike;
+ }
+
+ return toNumber(value) > 0;
+}
+
+function resolveMonthLabel(dateText) {
+ const normalized = String(dateText || "").trim();
+
+ if (/^\d{6}$/.test(normalized)) {
+ return normalized.slice(4, 6) + "月";
+ }
+
+ return normalized || "本月";
+}
+
+function mapBalanceCenterItem(item, groupKey, index) {
+ const isIncome = isPositiveFlowValue(
+ pickFirstValue(item, ["pm", "io_type", "direction"]),
+ );
+ const amount = formatTransferRecordNumber(
+ pickFirstValue(item, ["number", "amount", "num"]),
+ );
+ const merchantName = pickFirstValue(item, ["merchant_name", "merchantName"]);
+ const frozenTime = pickFirstValue(item, [
+ "frozen_time_str",
+ "frozen_time",
+ "unlock_time",
+ ]);
+ const failReason = pickFirstValue(item, ["fail_msg", "reason", "remark"]);
+ const refunded =
+ String(pickFirstValue(item, ["status"]) || "").trim() === "-1" &&
+ isIncome;
+ const detailRows = [
+ {
+ label: "获得时间",
+ value: pickFirstValue(item, ["add_time", "time", "created_at"]) || "--",
+ },
+ ];
+
+ if (!isIncome && frozenTime && String(frozenTime) !== "0") {
+ detailRows.push({
+ label: "解冻时间",
+ value: String(frozenTime),
+ });
+ }
+
+ return {
+ id: buildFlowRecordId(item, groupKey, index),
+ title:
+ pickFirstValue(item, ["title", "mark", "type_name"]) ||
+ (isIncome ? "佣金获得" : "佣金支出"),
+ amount: (isIncome ? "+" : "-") + amount,
+ amountTone: isIncome ? "income" : "expense",
+ directionLabel: isIncome ? "佣金获得" : "佣金支出",
+ detailRows: detailRows,
+ merchantName: merchantName ? String(merchantName) : "",
+ note: failReason
+ ? "原因:" + failReason
+ : refunded
+ ? "已退单"
+ : "",
+ noteTone: failReason ? "danger" : refunded ? "expense" : "muted",
+ };
+}
+
+function mapBalanceCenterSections(data) {
+ const list = normalizeListData(data);
+ const groupOrder = [];
+ const groupedMap = {};
+ const sourceGroups = Array.isArray(data && data.time) ? data.time : [];
+
+ sourceGroups.forEach((groupKey) => {
+ const normalizedKey = String(groupKey || "").trim();
+ if (!normalizedKey || groupedMap[normalizedKey]) {
+ return;
+ }
+
+ groupedMap[normalizedKey] = {
+ key: normalizedKey,
+ label: normalizedKey,
+ items: [],
+ };
+ groupOrder.push(normalizedKey);
+ });
+
+ list.forEach((item, index) => {
+ const groupKey =
+ String(
+ pickFirstValue(item, ["time_key", "date_str", "date", "month"]) ||
+ groupOrder[0] ||
+ "最新记录",
+ ).trim() || "最新记录";
+
+ if (!groupedMap[groupKey]) {
+ groupedMap[groupKey] = {
+ key: groupKey,
+ label: groupKey,
+ items: [],
+ };
+ groupOrder.push(groupKey);
+ }
+
+ groupedMap[groupKey].items.push(mapBalanceCenterItem(item, groupKey, index));
+ });
+
+ return groupOrder
+ .map((groupKey) => groupedMap[groupKey])
+ .filter((section) => section && section.items.length);
+}
+
+function normalizeVoucherTab(tabKey) {
+ const normalizedKey = String(tabKey || "").trim();
+
+ if (normalizedKey === "normal" || normalizedKey === "3") {
+ return "normal";
+ }
+
+ if (normalizedKey === "order" || normalizedKey === "6") {
+ return "order";
+ }
+
+ return "all";
+}
+
+function resolveVoucherTabFilters(tabKey) {
+ const normalizedKey = normalizeVoucherTab(tabKey);
+
+ if (normalizedKey === "normal") {
+ return {
+ tabKey: normalizedKey,
+ is_release: 1,
+ coin_type: 3,
+ };
+ }
+
+ if (normalizedKey === "order") {
+ return {
+ tabKey: normalizedKey,
+ is_release: 1,
+ coin_type: 6,
+ };
+ }
+
+ return {
+ tabKey: "all",
+ is_release: 0,
+ coin_type: "",
+ };
+}
+
+function mapVoucherCenterItem(item, groupKey, index) {
+ const isIncome = isPositiveFlowValue(
+ pickFirstValue(item, ["io_type", "pm", "direction"]),
+ );
+ const coinType = pickFirstValue(item, ["coin_type", "coinType"]);
+ const dcNum = pickFirstValue(item, ["dc_num", "dcNum"]);
+ let title =
+ pickFirstValue(item, ["title", "mark", "type_name"]) ||
+ (isIncome ? "抵用券收入" : "抵用券支出");
+
+ if (dcNum !== "" && String(coinType) === "6") {
+ title += "(" + String(dcNum) + "代)";
+ }
+
+ return {
+ id: buildFlowRecordId(item, groupKey, index),
+ title: title,
+ amount:
+ (isIncome ? "+" : "-") +
+ formatTransferRecordNumber(
+ pickFirstValue(item, ["amount", "number", "num"]),
+ ),
+ amountTone: isIncome ? "income" : "expense",
+ time: pickFirstValue(item, ["add_time", "time", "created_at"]) || "--",
+ };
+}
+
+function mapVoucherCenterSections(data) {
+ const list = normalizeListData(data);
+ const statistics = Array.isArray(data && data.statistics)
+ ? data.statistics.slice().reverse()
+ : [];
+ const groupOrder = [];
+ const groupedMap = {};
+
+ statistics.forEach((item) => {
+ const groupKey = String(pickFirstValue(item, ["date_str", "month"]) || "").trim();
+ if (!groupKey || groupedMap[groupKey]) {
+ return;
+ }
+
+ groupedMap[groupKey] = {
+ key: groupKey,
+ label: resolveMonthLabel(groupKey),
+ income: formatTransferRecordNumber(
+ pickFirstValue(item, ["sum_io1", "income", "in_amount"]),
+ ),
+ expense: formatTransferRecordNumber(
+ pickFirstValue(item, ["sum_io0", "expense", "out_amount"]),
+ ),
+ items: [],
+ };
+ groupOrder.push(groupKey);
+ });
+
+ list.forEach((item, index) => {
+ const groupKey =
+ String(pickFirstValue(item, ["date_str", "month"]) || "").trim() ||
+ "latest";
+
+ if (!groupedMap[groupKey]) {
+ groupedMap[groupKey] = {
+ key: groupKey,
+ label: resolveMonthLabel(groupKey),
+ income: "0",
+ expense: "0",
+ items: [],
+ };
+ groupOrder.push(groupKey);
+ }
+
+ groupedMap[groupKey].items.push(mapVoucherCenterItem(item, groupKey, index));
+ });
+
+ return groupOrder
+ .map((groupKey) => groupedMap[groupKey])
+ .filter((section) => section && section.items.length);
+}
+
function normalizeTransferTarget(data, fallbackId) {
if (data && typeof data === "object" && !Array.isArray(data)) {
const id = String(data.uid || data.id || fallbackId || "").trim();
@@ -1484,6 +1755,18 @@ async function fetchHomeBalanceData(requestOptions) {
);
}
+async function fetchExtractBankData(requestOptions) {
+ return fetchPayload(
+ createRequestOptions(
+ {
+ url: serviceConfig.ENDPOINTS.extractBank,
+ },
+ requestOptions,
+ ),
+ "余额信息加载失败",
+ );
+}
+
async function fetchBmtPowerRateData(requestOptions) {
return fetchPayload(
createRequestOptions(
@@ -1642,6 +1925,19 @@ async function fetchCoinIndexData(requestOptions) {
);
}
+async function fetchCoinIndexSummaryData(query, requestOptions) {
+ return fetchPayload(
+ createRequestOptions(
+ {
+ url: serviceConfig.ENDPOINTS.coinIndex,
+ data: query || {},
+ },
+ requestOptions,
+ ),
+ "抵用券信息加载失败",
+ );
+}
+
async function fetchUserProfileData(requestOptions) {
return fetchPayload(
createRequestOptions(
@@ -1747,6 +2043,41 @@ async function fetchBmtrTransferLedgerData(pagination, requestOptions) {
);
}
+async function fetchSpreadCommissionListData(
+ recordType,
+ pagination,
+ requestOptions,
+ filters,
+) {
+ const filterSource = filters && typeof filters === "object" ? filters : {};
+
+ return fetchPayload(
+ createRequestOptions(
+ {
+ url: serviceConfig.ENDPOINTS.spreadCommission + "/" + recordType,
+ data: buildPagingRequestData(
+ {
+ pm:
+ pickFirstValue(filterSource, ["pm", "direction", "flow"]) || "",
+ start_time:
+ pickFirstValue(filterSource, [
+ "start_time",
+ "startTime",
+ "start",
+ ]) || "",
+ end_time:
+ pickFirstValue(filterSource, ["end_time", "endTime", "end"]) ||
+ "",
+ },
+ pagination,
+ ),
+ },
+ requestOptions,
+ ),
+ "余额记录加载失败",
+ );
+}
+
async function fetchWalletFlowListData(flowType, pagination, requestOptions) {
return fetchPayload(
createRequestOptions(
@@ -1765,6 +2096,37 @@ async function fetchWalletFlowListData(flowType, pagination, requestOptions) {
);
}
+async function fetchCoinReleaseListData(pagination, requestOptions, filters) {
+ const filterSource = filters && typeof filters === "object" ? filters : {};
+
+ return fetchPayload(
+ createRequestOptions(
+ {
+ url: serviceConfig.ENDPOINTS.coinList,
+ data: buildPagingRequestData(
+ {
+ is_release:
+ pickFirstValue(filterSource, [
+ "is_release",
+ "isRelease",
+ "release",
+ ]) || 0,
+ coin_type:
+ pickFirstValue(filterSource, [
+ "coin_type",
+ "coinType",
+ "type",
+ ]) || "",
+ },
+ pagination,
+ ),
+ },
+ requestOptions,
+ ),
+ "抵用券记录加载失败",
+ );
+}
+
async function fetchRedeemRecordListData(
redeemType,
pagination,
@@ -1820,9 +2182,20 @@ export async function fetchVoucherBrokerLinkData(requestOptions) {
throw createError("未获取到用户信息", data);
}
+ const targetUrl =
+ serviceConfig.EXTERNAL_H5_HOST +
+ "/JXH5/pages/users/user_broker/index?user_id=" +
+ encodeURIComponent(String(userId)) +
+ "&total=" +
+ encodeURIComponent(balance === "" ? "0" : String(balance));
+ const targetInfo = appendTokenToTargetUrl(targetUrl);
+
return {
userId: String(userId),
balance: balance === "" ? "0" : String(balance),
+ token: targetInfo.token,
+ targetUrl: targetInfo.targetUrl,
+ encodedTargetUrl: targetInfo.encodedTargetUrl,
};
}
@@ -1833,27 +2206,27 @@ export async function fetchCouponRedeemLinkData(requestOptions) {
"canRedeem",
"can_redeem",
]);
- const token = String(getCurrentWebviewToken() || "").trim();
- let targetUrl =
- serviceConfig.HTTP_REQUEST_URL +
+ const targetUrl =
+ serviceConfig.EXTERNAL_H5_HOST +
"/MD/pages/redeemVoucher/index?canRedeem=" +
encodeURIComponent(canRedeem === "" ? "0" : String(canRedeem));
-
- if (token) {
- targetUrl +=
- (targetUrl.indexOf("?") > -1 ? "&" : "?") +
- "token=" +
- encodeURIComponent(token);
- }
+ const targetInfo = appendTokenToTargetUrl(targetUrl);
return {
canRedeem: canRedeem === "" ? "0" : String(canRedeem),
- token: token,
- targetUrl: targetUrl,
- encodedTargetUrl: encodeURIComponent(targetUrl),
+ token: targetInfo.token,
+ targetUrl: targetInfo.targetUrl,
+ encodedTargetUrl: targetInfo.encodedTargetUrl,
};
}
+export function fetchBalanceSpreadLinkData() {
+ return appendTokenToTargetUrl(
+ serviceConfig.EXTERNAL_H5_HOST +
+ "/JXH5/pages/users/user_spread_money/index?type=2",
+ );
+}
+
export async function fetchPointsConvertHome(
month,
paginationOrRequestOptions,
@@ -2495,6 +2868,94 @@ export async function fetchLedgerDetail(
});
}
+export async function fetchBalanceCenterPage(
+ filters,
+ paginationOrRequestOptions,
+ requestOptions,
+) {
+ const params = resolvePagingArguments(
+ paginationOrRequestOptions,
+ requestOptions,
+ );
+ const pagination = params.pagination;
+ const mergedRequestOptions = params.requestOptions;
+ const [summaryData, listData] = await Promise.all([
+ fetchExtractBankData(mergedRequestOptions),
+ fetchSpreadCommissionListData(
+ 3,
+ pagination,
+ mergedRequestOptions,
+ filters,
+ ),
+ ]);
+
+ return {
+ summary: {
+ balance: formatTransferRecordNumber(
+ pickFirstValue(summaryData, ["brokerage_price", "balance"]),
+ ),
+ totalExtract: formatTransferRecordNumber(
+ pickFirstValue(summaryData, [
+ "extractTotalPrice",
+ "extract_total_price",
+ "total_extract",
+ ]),
+ ),
+ frozen: formatTransferRecordNumber(
+ pickFirstValue(summaryData, [
+ "broken_commission",
+ "frozen_amount",
+ "frozen",
+ ]),
+ ),
+ },
+ sections: mapBalanceCenterSections(listData),
+ pagination: buildPaginationMeta(listData, pagination),
+ };
+}
+
+export async function fetchVoucherCenterPage(
+ tabKey,
+ paginationOrRequestOptions,
+ requestOptions,
+) {
+ const params = resolvePagingArguments(
+ paginationOrRequestOptions,
+ requestOptions,
+ );
+ const pagination = params.pagination;
+ const mergedRequestOptions = params.requestOptions;
+ const tabFilters = resolveVoucherTabFilters(tabKey);
+ const [summaryData, listData] = await Promise.all([
+ fetchCoinIndexSummaryData(
+ {
+ sign: 1,
+ integral: 1,
+ all: 1,
+ },
+ mergedRequestOptions,
+ ),
+ fetchCoinReleaseListData(pagination, mergedRequestOptions, tabFilters),
+ ]);
+
+ return {
+ currentTab: tabFilters.tabKey,
+ summary: {
+ balance: formatTransferRecordNumber(
+ pickFirstValue(summaryData, ["balance", "coin", "total"]),
+ ),
+ totalIn: formatTransferRecordNumber(
+ pickFirstValue(summaryData, ["total_in", "totalIn"]),
+ ),
+ totalOut: formatTransferRecordNumber(
+ pickFirstValue(summaryData, ["total_out", "totalOut"]),
+ ),
+ },
+ sections: mapVoucherCenterSections(listData),
+ pagination: buildPaginationMeta(listData, pagination),
+ };
+}
+
export async function fetchWalletDetail(requestOptions) {
const data = await fetchWalletAddressData(requestOptions);
return buildWalletPayload(data && data.address);
diff --git a/config/service.js b/config/service.js
index 40d1867..d063f9b 100644
--- a/config/service.js
+++ b/config/service.js
@@ -1,16 +1,21 @@
-// const HOST_URL = "https://tpoint.agrimedia.cn";
-const HOST_URL = window.location.protocol + "//" + window.location.host;
+const CURRENT_SERVER_URL =
+ window.location.protocol + "//" + window.location.host;
+const EXTERNAL_H5_HOST = CURRENT_SERVER_URL;
const serviceConfig = {
- BASE_URL: HOST_URL,
- HTTP_REQUEST_URL: HOST_URL,
+ CURRENT_SERVER_URL: CURRENT_SERVER_URL,
+ EXTERNAL_H5_HOST: EXTERNAL_H5_HOST,
+ BASE_URL: CURRENT_SERVER_URL,
+ HTTP_REQUEST_URL: CURRENT_SERVER_URL,
TIMEOUT: 10000,
WALLET_NAME: "海南农综交易所",
POINTS_CONVERT_INTERVAL: "0,20",
ENDPOINTS: {
price: "/api/hn/getPrice",
homeBalance: "/api/hn/getAllBalance",
+ extractBank: "/api/extract/bank",
+ spreadCommission: "/api/spread/commission",
powerExchangeSubmit: "/api/hn/redeem/power",
bmtFlashExchangeSubmit: "/api/hn/redeem/justRedeem",
powerExchangeMuit: "/api/hn/redeem/getMuit",
@@ -29,6 +34,7 @@ const serviceConfig = {
walletFlowList: "/api/hn/wallet_flow/getList",
redeemRecordList: "/api/hn/redeem/redeemList",
coinIndex: "/api/coin/index",
+ coinList: "/api/coin/list",
userProfile: "/api/user",
walletDetail: "/api/hn/wallet/getWalletAddress",
walletSave: "/api/hn/wallet/saveAddress",
diff --git a/pages.json b/pages.json
index 9df4f42..4c231b0 100644
--- a/pages.json
+++ b/pages.json
@@ -72,6 +72,20 @@
"backgroundColor": "#191E32"
}
},
+ {
+ "path": "pages/assets/balance-center",
+ "style": {
+ "navigationStyle": "custom",
+ "backgroundColor": "#191E32"
+ }
+ },
+ {
+ "path": "pages/assets/voucher-center",
+ "style": {
+ "navigationStyle": "custom",
+ "backgroundColor": "#191E32"
+ }
+ },
{
"path": "pages/assets/wallet",
"style": {
diff --git a/pages/assets/balance-center.vue b/pages/assets/balance-center.vue
new file mode 100644
index 0000000..8c44684
--- /dev/null
+++ b/pages/assets/balance-center.vue
@@ -0,0 +1,902 @@
+
+