From 952d3be4a98f28e6e2e348239f1f23867fe50a47 Mon Sep 17 00:00:00 2001 From: whitechiina <1293616053@qq.com> Date: Mon, 27 Apr 2026 16:48:12 +0800 Subject: [PATCH] first commit --- .lanhu-home.png | Bin 0 -> 63817 bytes App.vue | 78 +++ api/assets.js | 850 +++++++++++++++++++++++++++++ components/asset-confirm-popup.vue | 267 +++++++++ components/asset-page-shell.vue | 126 +++++ components/asset-record-list.vue | 184 +++++++ components/wallet-action-popup.vue | 101 ++++ config/service.js | 25 + index.html | 29 + main.js | 22 + manifest.json | 72 +++ pages.json | 75 +++ pages/assets/bmt-exchange.vue | 694 +++++++++++++++++++++++ pages/assets/ledger.vue | 474 ++++++++++++++++ pages/assets/points-convert.vue | 337 ++++++++++++ pages/assets/power-exchange.vue | 743 +++++++++++++++++++++++++ pages/assets/transfer.vue | 793 +++++++++++++++++++++++++++ pages/assets/wallet-form.vue | 367 +++++++++++++ pages/assets/wallet.vue | 371 +++++++++++++ pages/assets/withdraw.vue | 667 ++++++++++++++++++++++ pages/index/index.vue | 620 +++++++++++++++++++++ static/logo.png | Bin 0 -> 4023 bytes styles/common.scss | 509 +++++++++++++++++ styles/tokens.scss | 27 + uni.promisify.adaptor.js | 13 + uni.scss | 76 +++ utils/request.js | 100 ++++ utils/webview-token.js | 62 +++ 28 files changed, 7682 insertions(+) create mode 100644 .lanhu-home.png create mode 100644 App.vue create mode 100644 api/assets.js create mode 100644 components/asset-confirm-popup.vue create mode 100644 components/asset-page-shell.vue create mode 100644 components/asset-record-list.vue create mode 100644 components/wallet-action-popup.vue create mode 100644 config/service.js create mode 100644 index.html create mode 100644 main.js create mode 100644 manifest.json create mode 100644 pages.json create mode 100644 pages/assets/bmt-exchange.vue create mode 100644 pages/assets/ledger.vue create mode 100644 pages/assets/points-convert.vue create mode 100644 pages/assets/power-exchange.vue create mode 100644 pages/assets/transfer.vue create mode 100644 pages/assets/wallet-form.vue create mode 100644 pages/assets/wallet.vue create mode 100644 pages/assets/withdraw.vue create mode 100644 pages/index/index.vue create mode 100644 static/logo.png create mode 100644 styles/common.scss create mode 100644 styles/tokens.scss create mode 100644 uni.promisify.adaptor.js create mode 100644 uni.scss create mode 100644 utils/request.js create mode 100644 utils/webview-token.js diff --git a/.lanhu-home.png b/.lanhu-home.png new file mode 100644 index 0000000000000000000000000000000000000000..60f80f842c8be6c2084d4716c69379f20ea68d05 GIT binary patch literal 63817 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 literal 0 HcmV?d00001 diff --git a/App.vue b/App.vue new file mode 100644 index 0000000..ba00ee5 --- /dev/null +++ b/App.vue @@ -0,0 +1,78 @@ + + + diff --git a/api/assets.js b/api/assets.js new file mode 100644 index 0000000..0e44df0 --- /dev/null +++ b/api/assets.js @@ -0,0 +1,850 @@ +import serviceConfig from "../config/service"; +import request from "../utils/request"; + +function createError(message, raw) { + return { + message: message || "接口请求失败", + raw: raw, + }; +} + +function toNumber(value) { + const number = Number(value || 0); + return Number.isFinite(number) ? number : 0; +} + +function toFixedNumber(value, digits) { + return toNumber(value).toFixed(digits); +} + +function formatHomeNumber(value, digits) { + const number = toNumber(value); + + if (digits > 0) { + const fixed = number.toFixed(digits); + const parts = fixed.split("."); + parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ","); + return parts.join("."); + } + + return Math.round(number) + .toString() + .replace(/\B(?=(\d{3})+(?!\d))/g, ","); +} + +function isSuccessPayload(payload) { + if (!payload || typeof payload !== "object") { + return false; + } + + const statusCode = + payload.code !== undefined ? Number(payload.code) : Number(payload.status); + + return statusCode === 200; +} + +function unwrapPayload(payload, fallbackMessage) { + if (isSuccessPayload(payload)) { + return payload.data; + } + + if (payload && typeof payload === "object") { + throw createError( + payload.msg || payload.message || fallbackMessage || "接口请求失败", + payload, + ); + } + + throw createError(fallbackMessage || "接口返回异常", payload); +} + +async function fetchPayload(options, fallbackMessage) { + try { + const payload = await request(options); + return unwrapPayload(payload, fallbackMessage); + } catch (error) { + if (error && error.message) { + throw error; + } + + throw createError(fallbackMessage || "接口请求失败", error); + } +} + +function createRequestOptions(baseOptions, requestOptions) { + return Object.assign({}, baseOptions, requestOptions || {}); +} + +function normalizeTicker(data) { + const close = toNumber(data && (data.close || data.cnyPrice)); + const lastDayClose = toNumber(data && data.lastDayClose); + const rawChange = data && data.change; + let change = typeof rawChange === "string" ? rawChange : ""; + + if (!change) { + if (close && lastDayClose) { + const percent = ((close - lastDayClose) / lastDayClose) * 100; + const prefix = percent >= 0 ? "+" : ""; + change = prefix + percent.toFixed(2) + "%"; + } else { + change = "0.00%"; + } + } + + return { + symbol: (data && data.symbol) || "BMT/CNY", + close: close, + cnyPrice: + (data && data.cnyPrice) || (close ? close.toFixed(2) : "0.00"), + lastDayClose: lastDayClose, + change: change, + }; +} + +function normalizeBalances(data) { + return { + points: toNumber(data && data.point), + power: toNumber(data && data.c_power), + bmt: toNumber(data && data.bmt_num), + withdrawableBmt: toNumber(data && data.bmt_num), + voucher: toNumber(data && data.coin), + coupon: toNumber(data && data.diamond_balance), + }; +} + +function buildHomeOverview(balanceData, tickerData) { + const balances = normalizeBalances(balanceData); + const ticker = normalizeTicker(tickerData); + + return { + title: "数字资产", + ticker: ticker, + topStats: [ + { + key: "wallet-bmt", + title: "可提取BMT", + value: toFixedNumber(balances.withdrawableBmt, 2), + unit: "BMT", + accent: "gold", + }, + { + key: "ticker", + title: "BMT实时价格", + value: toFixedNumber(ticker.close || ticker.cnyPrice, 3), + unit: "CNY/BMT", + accent: "green", + }, + ], + quickAssets: [ + { + key: "points", + title: "积分", + value: formatHomeNumber(balances.points, 0), + accent: "gold", + }, + { + key: "voucher", + title: "抵用券", + value: formatHomeNumber(balances.voucher, 2), + accent: "rose", + }, + { + key: "coupon", + title: "消费券", + value: formatHomeNumber(balances.coupon, 0), + accent: "teal", + }, + { + key: "power", + title: "算力", + value: formatHomeNumber(balances.power, 0), + accent: "violet", + }, + ], + features: [ + { + key: "bmt-exchange", + title: "BMT兑换", + desc: "积分与算力兑换 BMT", + accent: "mint", + }, + { + key: "power-exchange", + title: "算力兑换", + desc: "抵用券与消费券兑换算力", + accent: "amber", + }, + { + key: "transfer", + title: "转赠中心", + desc: "积分或算力转赠好友", + accent: "indigo", + }, + { + key: "withdraw", + title: "BMT提取", + desc: "钱包中的 BMT 可提取到交易所进行交易", + accent: "pink", + }, + { + key: "points-convert", + title: "积分转换", + desc: "释放中的积分转换为可用积分", + accent: "pink", + }, + ], + notice: + "数字资产是您在平台上的虚拟资产,请谨慎管理;BMT可在交易所中进行交易。", + }; +} + +function buildTransferTips(feePercent) { + const percentText = toNumber(feePercent) || 10; + + return { + points: [ + "只能转赠100的整数倍", + "凌晨0点-凌晨01点系统维护不可赠送", + "转赠系统会扣除" + percentText + "%的手续费", + ], + power: [ + "只能转赠1的整数倍", + "转赠系统会扣除" + percentText + "%的手续费", + ], + }; +} + +function buildWalletList(address) { + const normalizedAddress = String(address || "").trim(); + + if (!normalizedAddress) { + return []; + } + + return [ + { + id: "default-wallet", + name: serviceConfig.WALLET_NAME, + address: normalizedAddress, + isDefault: true, + }, + ]; +} + +function buildWalletPayload(address) { + return { + wallets: buildWalletList(address), + instructions: [ + "点击交易所 App 底部“资产”进入钱包页", + "搜索或输入大写字母 BMT", + "点击“充币 / 充值”进入收款地址页面", + "复制钱包地址后回填到当前页面", + ], + }; +} + +function formatTransferRecordNumber(value) { + const number = toNumber(value); + return formatHomeNumber(number, Number.isInteger(number) ? 0 : 2); +} + +function getTransferRecordUnit(item) { + return Number(item && item.type) === 0 ? "算力" : "积分"; +} + +function getTransferRecordTone(item) { + return Number(item && item.io_type) === 1 ? "success" : "danger"; +} + +function getTransferRecordTag(item) { + return Number(item && item.io_type) === 1 ? "收" : "赠"; +} + +function getTransferRecordDirection(item) { + return Number(item && item.io_type) === 1 ? "转入" : "转出"; +} + +function getTransferRecordTitle(item) { + const unit = getTransferRecordUnit(item); + return Number(item && item.io_type) === 1 ? unit + "获赠" : unit + "转赠"; +} + +function getTransferRecordSymbol(item) { + return Number(item && item.io_type) === 1 ? "+" : "-"; +} + +function getTransferRecordAmount(item) { + const numberText = formatTransferRecordNumber(item && item.num); + return getTransferRecordSymbol(item) + numberText; +} + +function getTransferRecordFee(item) { + if ( + item && + item.fee !== undefined && + item.fee !== null && + String(item.fee).trim() !== "" + ) { + return toNumber(item.fee); + } + + return (toNumber(item && item.num) * toNumber(item && item.fee_percent)) / 100; +} + +function getTransferRecordFeeText(item) { + const percent = toNumber(item && item.fee_percent); + const unit = getTransferRecordUnit(item); + const feeText = formatTransferRecordNumber(getTransferRecordFee(item)); + + if (percent > 0) { + return ( + "手续费 " + + feeText + + " " + + unit + + " (" + + formatTransferRecordNumber(percent) + + "%)" + ); + } + + return "手续费 " + feeText + " " + unit; +} + +function getTransferRecordBalance(item) { + const unit = getTransferRecordUnit(item); + return "结余 " + toFixedNumber(item && item.balance, 2) + " " + unit; +} + +function getTransferRecordBalanceLabel(item) { + const unit = getTransferRecordUnit(item); + return "剩余" + unit + ":" + formatTransferRecordNumber(item && item.balance); +} + +function mapTransferRecords(list) { + return (Array.isArray(list) ? list : []).map(function (item) { + return { + id: item.order_sn || item.id || String(Math.random()), + title: item.title || getTransferRecordTitle(item), + subtitle: item.order_sn ? "单号 " + item.order_sn : getTransferRecordDirection(item), + time: item.add_time || "", + amount: getTransferRecordAmount(item), + balance: getTransferRecordBalance(item), + balanceLabel: getTransferRecordBalanceLabel(item), + assetLabel: getTransferRecordUnit(item), + feeText: getTransferRecordFeeText(item), + directionLabel: getTransferRecordDirection(item), + actionSymbol: getTransferRecordSymbol(item), + orderSn: item.order_sn || "", + tag: getTransferRecordTag(item), + tone: getTransferRecordTone(item), + cardTone: getTransferRecordTone(item), + }; + }); +} + +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 { + id: String(item.id || ""), + title: item.title || "积分记录", + subtitle: "可转数量 " + transferCoinText, + time: item.add_time || "", + amount: "+" + numberText, + balance: releaseTotal ? "释放总量 " + releaseTotal : "", + tag: "积", + tone: "success", + }; + }); +} + +function buildDefaultLedger(type, balances) { + const map = { + power: { + title: "兑换记录", + subtitle: "算力兑换记录", + }, + bmt: { + title: "兑换记录", + subtitle: "BMT兑换记录", + }, + withdraw: { + title: "提取记录", + subtitle: "BMT提取流水", + }, + coupon: { + title: "消费券", + subtitle: "当前消费券 " + toFixedNumber(balances.coupon, 2), + }, + voucher: { + title: "抵用券记录", + subtitle: "可用抵用券 " + toFixedNumber(balances.voucher, 2), + }, + }; + + return { + type: type, + title: map[type].title, + subtitle: map[type].subtitle, + records: [], + }; +} + +function normalizeTransferTarget(data, fallbackId) { + if (data && typeof data === "object" && !Array.isArray(data)) { + const id = String(data.uid || data.id || fallbackId || "").trim(); + if (!id) { + throw createError("未查询到好友", data); + } + + return { + id: id, + nickname: + data.nickname || data.nick_name || data.username || "用户" + id, + phone: data.mobile || data.phone || "ID已通过校验", + avatar: data.avatar || data.headimg || "", + }; + } + + if (data === true) { + const id = String(fallbackId || "").trim(); + if (!id) { + throw createError("未查询到好友", data); + } + + return { + id: id, + nickname: "用户" + id, + phone: "ID已通过校验", + avatar: "", + }; + } + + throw createError("未查询到好友", data); +} + +function sumBy(list, key) { + return (Array.isArray(list) ? list : []).reduce(function (total, item) { + return total + toNumber(item && item[key]); + }, 0); +} + +async function fetchPriceData(requestOptions) { + return fetchPayload( + createRequestOptions({ + url: serviceConfig.ENDPOINTS.price, + }, requestOptions), + "实时价格加载失败", + ); +} + +async function fetchHomeBalanceData(requestOptions) { + return fetchPayload( + createRequestOptions({ + url: serviceConfig.ENDPOINTS.homeBalance, + }, requestOptions), + "首页资产加载失败", + ); +} + +async function fetchBmtPowerRateData(requestOptions) { + return fetchPayload( + createRequestOptions({ + url: serviceConfig.ENDPOINTS.bmtRedeemPowerRate, + }, requestOptions), + "兑换比例加载失败", + ); +} + +async function fetchTransferFeeData(requestOptions) { + return fetchPayload( + createRequestOptions({ + url: serviceConfig.ENDPOINTS.transferFee, + }, requestOptions), + "手续费比例加载失败", + ); +} + +async function fetchWalletAddressData(requestOptions) { + return fetchPayload( + createRequestOptions({ + url: serviceConfig.ENDPOINTS.walletDetail, + }, requestOptions), + "钱包加载失败", + ); +} + +async function fetchPointsConvertList(requestOptions) { + return fetchPayload( + createRequestOptions({ + url: serviceConfig.ENDPOINTS.pointsConvertList, + data: { + interval: serviceConfig.POINTS_CONVERT_INTERVAL, + }, + }, requestOptions), + "积分转换列表加载失败", + ); +} + +async function fetchTransferLedgerData(requestOptions) { + return fetchPayload( + createRequestOptions({ + url: serviceConfig.ENDPOINTS.transferLedger, + }, requestOptions), + "转赠记录加载失败", + ); +} + +export async function fetchAssetHome(requestOptions) { + const result = await Promise.all([ + fetchPriceData(requestOptions), + fetchHomeBalanceData(requestOptions), + ]); + return buildHomeOverview(result[1], result[0]); +} + +export async function fetchPointsConvertDetail(requestOptions) { + const result = await Promise.all([ + fetchHomeBalanceData(requestOptions), + fetchPointsConvertList(requestOptions), + ]); + const balances = normalizeBalances(result[0]); + const pointList = Array.isArray(result[1] && result[1].list) + ? result[1].list + : []; + + 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点积分系统维护不可兑换。", + ], + }; +} + +export async function submitAssetPointsConvert(payload, requestOptions) { + const ids = Array.isArray(payload && payload.ids) ? payload.ids : []; + + if (!ids.length) { + throw createError("暂无可转换积分"); + } + + await fetchPayload( + createRequestOptions({ + url: serviceConfig.ENDPOINTS.pointsConvertSubmit, + method: "POST", + data: { + ids: ids.join(","), + type: 1, + }, + }, requestOptions), + "积分转换失败", + ); + + return { + success: true, + message: "转换成功", + }; +} + +export async function fetchTransferDetail(requestOptions) { + const result = await Promise.all([ + fetchHomeBalanceData(requestOptions), + fetchTransferFeeData(requestOptions), + ]); + const balances = normalizeBalances(result[0]); + const feePercent = toNumber(result[1] && result[1].r) || 10; + + return { + balances: { + points: toFixedNumber(balances.points, 0), + power: toFixedNumber(balances.power, 0), + }, + feePercent: feePercent, + tips: buildTransferTips(feePercent), + }; +} + +export async function searchTransferUser(uid, requestOptions) { + const keyword = String(uid || "").trim(); + if (!keyword) { + throw createError("请输入被赠人ID"); + } + + const data = await fetchPayload( + createRequestOptions({ + url: serviceConfig.ENDPOINTS.transferUser, + method: "POST", + data: { + uid: keyword, + }, + }, requestOptions), + "查询好友失败", + ); + + return normalizeTransferTarget(data, keyword); +} + +export async function submitAssetTransfer(payload, requestOptions) { + const transferType = payload && payload.type === "power" ? "power" : "points"; + const targetId = String(payload && payload.targetId ? payload.targetId : "").trim(); + const amount = toNumber(payload && payload.amount); + + if (!targetId) { + throw createError("请选择被赠送人"); + } + + if (!amount) { + throw createError("请输入转赠数量"); + } + + const result = await Promise.all([ + fetchTransferFeeData(requestOptions), + fetchPayload( + createRequestOptions({ + url: + transferType === "power" + ? serviceConfig.ENDPOINTS.transferPowerSubmit + : serviceConfig.ENDPOINTS.transferPointsSubmit, + method: "POST", + data: { + uid: targetId, + number: String(amount), + }, + }, requestOptions), + "转赠失败", + ), + ]); + const feePercent = toNumber(result[0] && result[0].r) || 10; + const fee = (amount * feePercent) / 100; + const received = amount - fee; + + return { + success: true, + fee: toFixedNumber(fee, 2), + received: toFixedNumber(received, 2), + }; +} + +export async function fetchPowerExchangeDetail(requestOptions) { + const result = await Promise.all([ + fetchPriceData(requestOptions), + fetchHomeBalanceData(requestOptions), + ]); + const ticker = normalizeTicker(result[0]); + const balances = normalizeBalances(result[1]); + + return { + ticker: ticker, + balances: { + coupon: toFixedNumber(balances.coupon, 2), + voucher: toFixedNumber(balances.voucher, 2), + power: toFixedNumber(balances.power, 0), + }, + tips: [ + "算力 = 抵用券或消费券 ÷ BMT实时价格;", + "抵用券和消费券总数小于100券的不可兑换;", + "算力用于兑换BMT使用。", + ], + }; +} + +export async function submitAssetPowerExchange(payload, requestOptions) { + const mode = payload && payload.mode === "coupon" ? "coupon" : "voucher"; + const amount = toNumber(payload && payload.amount); + + if (!amount) { + throw createError("请输入兑换数量"); + } + + await fetchPayload( + createRequestOptions({ + url: serviceConfig.ENDPOINTS.powerExchangeSubmit, + method: "POST", + data: { + type: mode === "coupon" ? 1 : 0, + number: String(amount), + }, + }, requestOptions), + "算力兑换失败", + ); + + return { + success: true, + }; +} + +export async function fetchBmtExchangeDetail(requestOptions) { + const result = await Promise.all([ + fetchPriceData(requestOptions), + fetchHomeBalanceData(requestOptions), + fetchBmtPowerRateData(requestOptions), + ]); + const ticker = normalizeTicker(result[0]); + const balances = normalizeBalances(result[1]); + const powerRate = toNumber(result[2]); + + return { + ticker: ticker, + powerRate: powerRate, + balances: { + points: toFixedNumber(balances.points, 0), + power: toFixedNumber(balances.power, 2), + bmt: toFixedNumber(balances.bmt, 2), + voucher: toFixedNumber(balances.voucher, 2), + coupon: toFixedNumber(balances.coupon, 2), + }, + tips: [ + "BMT=输入的积分数量,提交时会同步校验所需算力。", + "兑换所需算力按后端返回比例实时计算。", + "只能兑换100的整数倍,小于100积分不可兑换。", + "凌晨0点至凌晨1点积分系统维护期间不可兑换。", + ], + }; +} + +export async function submitAssetBmtExchange(payload, requestOptions) { + const amount = toNumber(payload && payload.amount); + + if (!amount) { + throw createError("请输入积分数量"); + } + + await fetchPayload( + createRequestOptions({ + url: serviceConfig.ENDPOINTS.bmtExchangeSubmit, + method: "POST", + data: { + number: String(amount), + }, + }, requestOptions), + "BMT兑换失败", + ); + + return { + success: true, + }; +} + +export async function fetchWithdrawDetail(requestOptions) { + const result = await Promise.all([ + fetchPriceData(requestOptions), + fetchHomeBalanceData(requestOptions), + fetchWalletAddressData(requestOptions), + ]); + const ticker = normalizeTicker(result[0]); + const balances = normalizeBalances(result[1]); + const walletPayload = buildWalletPayload(result[2] && result[2].address); + + return { + ticker: ticker, + withdrawableBmt: toFixedNumber(balances.withdrawableBmt, 2), + wallets: walletPayload.wallets, + defaultWallet: walletPayload.wallets[0] || null, + }; +} + +export function submitAssetWithdraw(payload, requestOptions) { + return Promise.reject( + createError("当前接口文档未提供 BMT 提取提交接口"), + ); +} + +export async function fetchLedgerDetail(type, requestOptions) { + if (type === "transfer") { + const data = await fetchTransferLedgerData(requestOptions); + return { + type: type, + title: "转赠记录", + subtitle: "积分与算力转赠流水", + records: mapTransferRecords(data && data.list), + }; + } + + if (type === "points") { + const result = await Promise.all([ + fetchHomeBalanceData(requestOptions), + fetchPointsConvertList(requestOptions), + ]); + const balances = normalizeBalances(result[0]); + const pointList = Array.isArray(result[1] && result[1].list) + ? result[1].list + : []; + + return { + type: type, + title: "我的积分", + subtitle: "可转换积分记录", + summary: { + label: "有效积分", + value: toFixedNumber(balances.points, 0), + }, + records: mapPointsConvertRecords(pointList), + }; + } + + const homeData = await fetchHomeBalanceData(requestOptions); + const balances = normalizeBalances(homeData); + return buildDefaultLedger(type, balances); +} + +export async function fetchWalletDetail(requestOptions) { + const data = await fetchWalletAddressData(requestOptions); + return buildWalletPayload(data && data.address); +} + +export async function saveAssetWallet(payload, requestOptions) { + const address = String(payload && payload.address ? payload.address : "").trim(); + + if (!address) { + throw createError("请输入钱包地址"); + } + + await fetchPayload( + createRequestOptions({ + url: serviceConfig.ENDPOINTS.walletSave, + method: "POST", + data: { + address: address, + }, + }, requestOptions), + "保存失败", + ); + + return { + success: true, + }; +} + +export async function deleteAssetWallet(id, requestOptions) { + await fetchPayload( + createRequestOptions({ + url: serviceConfig.ENDPOINTS.walletSave, + method: "POST", + data: { + address: "", + }, + }, requestOptions), + "删除失败", + ); + + return { + success: true, + }; +} diff --git a/components/asset-confirm-popup.vue b/components/asset-confirm-popup.vue new file mode 100644 index 0000000..263c96b --- /dev/null +++ b/components/asset-confirm-popup.vue @@ -0,0 +1,267 @@ + + + + + diff --git a/components/asset-page-shell.vue b/components/asset-page-shell.vue new file mode 100644 index 0000000..243b573 --- /dev/null +++ b/components/asset-page-shell.vue @@ -0,0 +1,126 @@ + + + + + diff --git a/components/asset-record-list.vue b/components/asset-record-list.vue new file mode 100644 index 0000000..ff489be --- /dev/null +++ b/components/asset-record-list.vue @@ -0,0 +1,184 @@ + + + + + diff --git a/components/wallet-action-popup.vue b/components/wallet-action-popup.vue new file mode 100644 index 0000000..97e09c2 --- /dev/null +++ b/components/wallet-action-popup.vue @@ -0,0 +1,101 @@ + + + + + diff --git a/config/service.js b/config/service.js new file mode 100644 index 0000000..74edb41 --- /dev/null +++ b/config/service.js @@ -0,0 +1,25 @@ +const serviceConfig = { + BASE_URL: "https://tpoint.agrimedia.cn", + TIMEOUT: 10000, + WALLET_NAME: "海南农综交易所", + POINTS_CONVERT_INTERVAL: "0,999999999", + ENDPOINTS: { + price: "/api/hn/getPrice", + homeBalance: "/api/hn/getAllBalance", + powerExchangeSubmit: "/api/hn/redeem/power", + bmtRedeemPowerRate: "/api/hn/redeem/getRedeemPowerRate", + bmtExchangeSubmit: "/api/hn/redeem/redeem_bmt", + transferFee: "/api/hn/transfer/getProp", + transferUser: "/api/hn/transfer/getUserInfo", + transferPowerSubmit: "/api/hn/transfer/transferPower", + transferPointsSubmit: "/api/hn/transfer/transferPoint", + transferLedger: "/api/hn/transfer/transferList", + walletDetail: "/api/hn/wallet/getWalletAddress", + walletSave: "/api/hn/wallet/saveAddress", + pointsConvertList: "/api/integral/transferList", + pointsConvertSubmit: "/api/integral/doTransfer", + pointsConvertInfo: "/api/integral/transferInfo", + }, +}; + +export default serviceConfig; diff --git a/index.html b/index.html new file mode 100644 index 0000000..2501934 --- /dev/null +++ b/index.html @@ -0,0 +1,29 @@ + + + + + + + + + + + +
+ + + diff --git a/main.js b/main.js new file mode 100644 index 0000000..c1caf36 --- /dev/null +++ b/main.js @@ -0,0 +1,22 @@ +import App from './App' + +// #ifndef VUE3 +import Vue from 'vue' +import './uni.promisify.adaptor' +Vue.config.productionTip = false +App.mpType = 'app' +const app = new Vue({ + ...App +}) +app.$mount() +// #endif + +// #ifdef VUE3 +import { createSSRApp } from 'vue' +export function createApp() { + const app = createSSRApp(App) + return { + app + } +} +// #endif \ No newline at end of file diff --git a/manifest.json b/manifest.json new file mode 100644 index 0000000..721e850 --- /dev/null +++ b/manifest.json @@ -0,0 +1,72 @@ +{ + "name" : "白马交易所", + "appid" : "__UNI__3EC3CC8", + "description" : "", + "versionName" : "1.0.0", + "versionCode" : "100", + "transformPx" : false, + /* 5+App特有相关 */ + "app-plus" : { + "usingComponents" : true, + "nvueStyleCompiler" : "uni-app", + "compilerVersion" : 3, + "splashscreen" : { + "alwaysShowBeforeRender" : true, + "waiting" : true, + "autoclose" : true, + "delay" : 0 + }, + /* 模块配置 */ + "modules" : {}, + /* 应用发布信息 */ + "distribute" : { + /* android打包配置 */ + "android" : { + "permissions" : [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ] + }, + /* ios打包配置 */ + "ios" : {}, + /* SDK配置 */ + "sdkConfigs" : {} + } + }, + /* 快应用特有相关 */ + "quickapp" : {}, + /* 小程序特有相关 */ + "mp-weixin" : { + "appid" : "", + "setting" : { + "urlCheck" : false + }, + "usingComponents" : true + }, + "mp-alipay" : { + "usingComponents" : true + }, + "mp-baidu" : { + "usingComponents" : true + }, + "mp-toutiao" : { + "usingComponents" : true + }, + "uniStatistics" : { + "enable" : false + }, + "vueVersion" : "2" +} diff --git a/pages.json b/pages.json new file mode 100644 index 0000000..e3ae41e --- /dev/null +++ b/pages.json @@ -0,0 +1,75 @@ +{ + "pages": [ + //pages数组中第一项表示应用启动页,参考:https://uniapp.dcloud.io/collocation/pages + { + "path": "pages/index/index", + "style": { + "navigationStyle": "custom", + "backgroundColor": "#191E32" + } + }, + { + "path": "pages/assets/transfer", + "style": { + "navigationStyle": "custom", + "backgroundColor": "#191E32" + } + }, + { + "path": "pages/assets/power-exchange", + "style": { + "navigationStyle": "custom", + "backgroundColor": "#191E32" + } + }, + { + "path": "pages/assets/bmt-exchange", + "style": { + "navigationStyle": "custom", + "backgroundColor": "#191E32" + } + }, + { + "path": "pages/assets/withdraw", + "style": { + "navigationStyle": "custom", + "backgroundColor": "#191E32" + } + }, + { + "path": "pages/assets/points-convert", + "style": { + "navigationStyle": "custom", + "backgroundColor": "#191E32" + } + }, + { + "path": "pages/assets/ledger", + "style": { + "navigationStyle": "custom", + "backgroundColor": "#191E32" + } + }, + { + "path": "pages/assets/wallet", + "style": { + "navigationStyle": "custom", + "backgroundColor": "#191E32" + } + }, + { + "path": "pages/assets/wallet-form", + "style": { + "navigationStyle": "custom", + "backgroundColor": "#191E32" + } + } + ], + "globalStyle": { + "navigationBarTextStyle": "white", + "navigationBarTitleText": "数字资产", + "navigationBarBackgroundColor": "#191E32", + "backgroundColor": "#191E32" + }, + "uniIdRouter": {} +} diff --git a/pages/assets/bmt-exchange.vue b/pages/assets/bmt-exchange.vue new file mode 100644 index 0000000..c47bc32 --- /dev/null +++ b/pages/assets/bmt-exchange.vue @@ -0,0 +1,694 @@ + + + + + diff --git a/pages/assets/ledger.vue b/pages/assets/ledger.vue new file mode 100644 index 0000000..5534109 --- /dev/null +++ b/pages/assets/ledger.vue @@ -0,0 +1,474 @@ + + + + + diff --git a/pages/assets/points-convert.vue b/pages/assets/points-convert.vue new file mode 100644 index 0000000..559f9f8 --- /dev/null +++ b/pages/assets/points-convert.vue @@ -0,0 +1,337 @@ + + + + + diff --git a/pages/assets/power-exchange.vue b/pages/assets/power-exchange.vue new file mode 100644 index 0000000..ad6ba08 --- /dev/null +++ b/pages/assets/power-exchange.vue @@ -0,0 +1,743 @@ + + + + + diff --git a/pages/assets/transfer.vue b/pages/assets/transfer.vue new file mode 100644 index 0000000..276e9f7 --- /dev/null +++ b/pages/assets/transfer.vue @@ -0,0 +1,793 @@ + + + + + diff --git a/pages/assets/wallet-form.vue b/pages/assets/wallet-form.vue new file mode 100644 index 0000000..078f732 --- /dev/null +++ b/pages/assets/wallet-form.vue @@ -0,0 +1,367 @@ + + + + + diff --git a/pages/assets/wallet.vue b/pages/assets/wallet.vue new file mode 100644 index 0000000..a0b3fc0 --- /dev/null +++ b/pages/assets/wallet.vue @@ -0,0 +1,371 @@ + + + + + diff --git a/pages/assets/withdraw.vue b/pages/assets/withdraw.vue new file mode 100644 index 0000000..18a8037 --- /dev/null +++ b/pages/assets/withdraw.vue @@ -0,0 +1,667 @@ + + + + + diff --git a/pages/index/index.vue b/pages/index/index.vue new file mode 100644 index 0000000..83e0c71 --- /dev/null +++ b/pages/index/index.vue @@ -0,0 +1,620 @@ + + + + + diff --git a/static/logo.png b/static/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..b5771e209bb677e2ebd5ff766ad5ee11790f305a GIT binary patch literal 4023 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 SYs}WS&%*SCNx89m_ { + res.then((res) => { + if (!res) return resolve(res) + return res[0] ? reject(res[0]) : resolve(res[1]) + }); + }); + }, +}); \ No newline at end of file diff --git a/uni.scss b/uni.scss new file mode 100644 index 0000000..62eb87b --- /dev/null +++ b/uni.scss @@ -0,0 +1,76 @@ +/** + * 这里是uni-app内置的常用样式变量 + * + * uni-app 官方扩展插件及插件市场(https://ext.dcloud.net.cn)上很多三方插件均使用了这些样式变量 + * 如果你是插件开发者,建议你使用scss预处理,并在插件代码中直接使用这些变量(无需 import 这个文件),方便用户通过搭积木的方式开发整体风格一致的App + * + */ + +/** + * 如果你是App开发者(插件使用者),你可以通过修改这些变量来定制自己的插件主题,实现自定义主题功能 + * + * 如果你的项目同样使用了scss预处理,你也可以直接在你的 scss 代码中使用如下变量,同时无需 import 这个文件 + */ + +/* 颜色变量 */ + +/* 行为相关颜色 */ +$uni-color-primary: #007aff; +$uni-color-success: #4cd964; +$uni-color-warning: #f0ad4e; +$uni-color-error: #dd524d; + +/* 文字基本颜色 */ +$uni-text-color:#333;//基本色 +$uni-text-color-inverse:#fff;//反色 +$uni-text-color-grey:#999;//辅助灰色,如加载更多的提示信息 +$uni-text-color-placeholder: #808080; +$uni-text-color-disable:#c0c0c0; + +/* 背景颜色 */ +$uni-bg-color:#ffffff; +$uni-bg-color-grey:#f8f8f8; +$uni-bg-color-hover:#f1f1f1;//点击状态颜色 +$uni-bg-color-mask:rgba(0, 0, 0, 0.4);//遮罩颜色 + +/* 边框颜色 */ +$uni-border-color:#c8c7cc; + +/* 尺寸变量 */ + +/* 文字尺寸 */ +$uni-font-size-sm:12px; +$uni-font-size-base:14px; +$uni-font-size-lg:16px; + +/* 图片尺寸 */ +$uni-img-size-sm:20px; +$uni-img-size-base:26px; +$uni-img-size-lg:40px; + +/* Border Radius */ +$uni-border-radius-sm: 2px; +$uni-border-radius-base: 3px; +$uni-border-radius-lg: 6px; +$uni-border-radius-circle: 50%; + +/* 水平间距 */ +$uni-spacing-row-sm: 5px; +$uni-spacing-row-base: 10px; +$uni-spacing-row-lg: 15px; + +/* 垂直间距 */ +$uni-spacing-col-sm: 4px; +$uni-spacing-col-base: 8px; +$uni-spacing-col-lg: 12px; + +/* 透明度 */ +$uni-opacity-disabled: 0.3; // 组件禁用态的透明度 + +/* 文章场景相关 */ +$uni-color-title: #2C405A; // 文章标题颜色 +$uni-font-size-title:20px; +$uni-color-subtitle: #555555; // 二级标题颜色 +$uni-font-size-subtitle:26px; +$uni-color-paragraph: #3F536E; // 文章段落颜色 +$uni-font-size-paragraph:15px; diff --git a/utils/request.js b/utils/request.js new file mode 100644 index 0000000..b79ec37 --- /dev/null +++ b/utils/request.js @@ -0,0 +1,100 @@ +import serviceConfig from "../config/service"; +import { getCurrentWebviewToken } from "./webview-token"; + +let loadingCount = 0; + +function isAbsoluteUrl(url) { + return /^https?:\/\//i.test(url || ""); +} + +function buildRequestUrl(url) { + if (isAbsoluteUrl(url)) { + return url; + } + + return serviceConfig.BASE_URL + url; +} + +function showGlobalLoading(options) { + if (!options || !options.showLoading) { + return false; + } + + loadingCount += 1; + + if (loadingCount === 1) { + uni.showLoading({ + title: options.loadingText || "加载中", + mask: options.loadingMask !== false, + }); + } + + return true; +} + +function hideGlobalLoading(shouldHide) { + if (!shouldHide) { + return; + } + + loadingCount = Math.max(0, loadingCount - 1); + + if (loadingCount === 0) { + uni.hideLoading(); + } +} + +export default function request(options) { + const method = options.method || "GET"; + const defaultContentType = + method === "POST" + ? "application/x-www-form-urlencoded; charset=UTF-8" + : "application/json"; + const token = getCurrentWebviewToken(); + const requestHeader = Object.assign( + { + "Content-Type": defaultContentType, + }, + options.header || {}, + ); + + if (token) { + const bearerToken = "Bearer " + token; + requestHeader["Authori-zation"] = bearerToken; + requestHeader.Authorization = bearerToken; + } + const shouldHandleLoading = showGlobalLoading(options); + + return new Promise(function (resolve, reject) { + uni.request({ + url: buildRequestUrl(options.url), + method: method, + data: options.data || {}, + header: requestHeader, + timeout: serviceConfig.TIMEOUT, + success: function (response) { + const statusCode = response.statusCode || 0; + if (statusCode >= 200 && statusCode < 300) { + resolve(response.data); + return; + } + + reject({ + statusCode: statusCode, + message: (response.data && response.data.message) || "接口请求失败", + raw: response, + }); + }, + fail: function (error) { + reject({ + statusCode: 0, + message: error.errMsg || "网络异常", + raw: error, + }); + }, + complete: function () { + hideGlobalLoading(shouldHandleLoading); + }, + }); + }); +} diff --git a/utils/webview-token.js b/utils/webview-token.js new file mode 100644 index 0000000..027dc48 --- /dev/null +++ b/utils/webview-token.js @@ -0,0 +1,62 @@ +function findTokenInText(text) { + if (!text) { + return ""; + } + + const queryIndex = text.indexOf("?"); + if (queryIndex === -1) { + return ""; + } + + const rawQueryText = text.slice(queryIndex + 1); + const hashIndex = rawQueryText.indexOf("#"); + const queryText = + hashIndex === -1 ? rawQueryText : rawQueryText.slice(0, hashIndex); + const search = new URLSearchParams(queryText); + return search.get("token") || ""; +} + +export function extractTokenFromUrl(url) { + if (!url) { + return ""; + } + + const directToken = findTokenInText(url); + if (directToken) { + return directToken; + } + + const hashIndex = url.indexOf("#"); + if (hashIndex === -1) { + return ""; + } + + return findTokenInText(url.slice(hashIndex + 1)); +} + +export function getCurrentWebviewUrl() { + // #ifdef H5 + return window.location.href || ""; + // #endif + + // #ifdef APP-PLUS + if (typeof plus === "undefined" || !plus.webview) { + return ""; + } + + const currentWebview = + plus.webview.currentWebview() || plus.webview.getLaunchWebview(); + + if (!currentWebview || typeof currentWebview.getURL !== "function") { + return ""; + } + + return currentWebview.getURL() || ""; + // #endif + + return ""; +} + +export function getCurrentWebviewToken() { + return extractTokenFromUrl(getCurrentWebviewUrl()); +}