资产模块接口与页面开发
This commit is contained in:
parent
4b4f852afe
commit
939fe3dc11
|
|
@ -0,0 +1,267 @@
|
|||
# BMTR 资产接入实现文档
|
||||
|
||||
## 一、需求概述
|
||||
|
||||
在首页「我的资产」区域新增 **BMTR** 卡片,展示当前登录用户的 BMTR 数量。
|
||||
|
||||
数据来源:
|
||||
|
||||
```
|
||||
GET /api/mxj/api/get_user
|
||||
```
|
||||
|
||||
返回示例:
|
||||
|
||||
```json
|
||||
{
|
||||
"status": 200,
|
||||
"msg": "success",
|
||||
"data": {
|
||||
"uid": 94227,
|
||||
"nickname": "siediyer",
|
||||
"avatar": "https://thirdwx.qlogo.cn/...",
|
||||
"mxj_points": "99999.00",
|
||||
"bmtr": "11.0000",
|
||||
"is_check": 1,
|
||||
"is_idcard": 1,
|
||||
"is_sign": 1,
|
||||
"sign_time": 1781172245,
|
||||
"status": 1
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 二、API 请求运行方式
|
||||
|
||||
项目中的网络请求采用三层结构:
|
||||
|
||||
```
|
||||
页面 (pages/index/index.vue)
|
||||
↓ 调用
|
||||
api/assets.js 中的业务方法
|
||||
↓ 调用
|
||||
utils/request.js 中的通用 request 方法
|
||||
↓ 调用
|
||||
uni.request 发送 HTTP 请求
|
||||
```
|
||||
|
||||
### 2.1 配置层:`config/service.js`
|
||||
|
||||
定义了接口基础地址和 endpoint 映射表。
|
||||
|
||||
### 2.2 通用请求层:`utils/request.js`
|
||||
|
||||
- 自动拼接 `BASE_URL` 和 `url`
|
||||
- 统一注入 `Authori-zation` / `Authorization` Token
|
||||
- 统一处理 `showLoading` / `hideLoading`
|
||||
- 对响应进行 `statusCode` 校验,返回 `response.data`
|
||||
|
||||
### 2.3 业务 API 层:`api/assets.js`
|
||||
|
||||
- 封装 `fetchPayload` 统一处理 `{ status: 200, data: {...} }` 结构
|
||||
- 提供 `createRequestOptions` 合并请求参数
|
||||
- 提供 `buildHomeOverview` 将原始接口数据转换为页面渲染数据
|
||||
|
||||
---
|
||||
|
||||
## 三、本次改动文件
|
||||
|
||||
| 文件 | 改动内容 |
|
||||
| ----------------------- | ------------------------------------------------------------------ |
|
||||
| `config/service.js` | 新增 `getUser` endpoint |
|
||||
| `api/assets.js` | 新增 `fetchUserData`,修改 `buildHomeOverview` 和 `fetchAssetHome` |
|
||||
| `pages/index/index.vue` | 新增 BMTR 图标、背景、点击跳转 |
|
||||
| `BMTR.MD` | 本文档 |
|
||||
|
||||
---
|
||||
|
||||
## 四、具体改动
|
||||
|
||||
### 4.1 `config/service.js`
|
||||
|
||||
在 `ENDPOINTS` 中新增:
|
||||
|
||||
```javascript
|
||||
getUser: "/api/mxj/api/get_user",
|
||||
```
|
||||
|
||||
### 4.2 `api/assets.js`
|
||||
|
||||
#### 4.2.1 新增获取用户数据的函数
|
||||
|
||||
```javascript
|
||||
async function fetchUserData(requestOptions) {
|
||||
return fetchPayload(
|
||||
createRequestOptions(
|
||||
{
|
||||
url: serviceConfig.ENDPOINTS.getUser,
|
||||
},
|
||||
requestOptions,
|
||||
),
|
||||
"用户信息加载失败",
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
#### 4.2.2 修改 `buildHomeOverview`
|
||||
|
||||
函数签名从:
|
||||
|
||||
```javascript
|
||||
function buildHomeOverview(balanceData, tickerData) {
|
||||
```
|
||||
|
||||
改为:
|
||||
|
||||
```javascript
|
||||
function buildHomeOverview(balanceData, tickerData, userData) {
|
||||
```
|
||||
|
||||
在 `rawQuickAssets` 中新增 `bmtr`:
|
||||
|
||||
```javascript
|
||||
const rawQuickAssets = {
|
||||
balance: toRawDisplayValue(balanceData && balanceData.brokerage_price),
|
||||
points: toRawDisplayValue(balanceData && balanceData.point),
|
||||
voucher: toRawDisplayValue(balanceData && balanceData.coin),
|
||||
coupon: toRawDisplayValue(balanceData && balanceData.diamond_balance),
|
||||
power: toRawDisplayValue(balanceData && balanceData.c_power),
|
||||
bmtr: toRawDisplayValue(userData && userData.bmtr),
|
||||
};
|
||||
```
|
||||
|
||||
在 `quickAssets` 数组中新增 BMTR 项:
|
||||
|
||||
```javascript
|
||||
{
|
||||
key: "bmtr",
|
||||
title: "BMTR",
|
||||
value: rawQuickAssets.bmtr,
|
||||
accent: "orange",
|
||||
},
|
||||
```
|
||||
|
||||
> `value` 直接使用接口返回的 `bmtr` 字符串。
|
||||
> `accent` 设为 `orange`,与页面已有的 `.asset-mini-card--orange` 样式类对应。
|
||||
|
||||
#### 4.2.3 修改 `fetchAssetHome`
|
||||
|
||||
原来是同时请求价格 + 余额,现在增加用户信息请求:
|
||||
|
||||
```javascript
|
||||
export async function fetchAssetHome(requestOptions) {
|
||||
const result = await Promise.all([
|
||||
fetchPriceData(requestOptions),
|
||||
fetchHomeBalanceData(requestOptions),
|
||||
fetchUserData(requestOptions),
|
||||
]);
|
||||
const overview = buildHomeOverview(result[1], result[0], result[2]);
|
||||
setHomeTickerCache(overview.ticker);
|
||||
return overview;
|
||||
}
|
||||
```
|
||||
|
||||
三个请求并行执行,BMTR 接口失败不会阻塞其他两个请求(但会进入 `Promise.all` 的 catch 逻辑,页面会显示错误提示)。
|
||||
|
||||
### 4.3 `pages/index/index.vue`
|
||||
|
||||
#### 4.3.1 新增图标
|
||||
|
||||
在 `quickAssetIcon` 的 `iconMap` 中新增:
|
||||
|
||||
```javascript
|
||||
bmtr: "https://imgs.agrimedia.cn/bm-bmt/qianbao.png",
|
||||
```
|
||||
|
||||
> 当前复用已有的钱包图标,后续可替换为 BMTR 专属图标。
|
||||
|
||||
#### 4.3.2 新增背景
|
||||
|
||||
在 `quickAssetBg` 的 `bgMap` 中新增:
|
||||
|
||||
```javascript
|
||||
bmtr: "https://imgs.agrimedia.cn/bm-bmt/suanli-bg.png",
|
||||
```
|
||||
|
||||
> 当前复用算力卡片背景,后续可替换为 BMTR 专属背景。
|
||||
|
||||
#### 4.3.3 新增点击跳转
|
||||
|
||||
在 `openQuickAsset` 的 `urlMap` 中新增:
|
||||
|
||||
```javascript
|
||||
bmtr: "/pages/assets/bmtr",
|
||||
```
|
||||
|
||||
用户点击 BMTR 卡片后,会跳转到 `pages/assets/bmtr.vue` 页面。
|
||||
|
||||
---
|
||||
|
||||
## 五、首页资产卡片渲染顺序
|
||||
|
||||
修改后,首页「我的资产」区域共 6 个卡片,顺序如下:
|
||||
|
||||
1. 可用积分
|
||||
2. 算力
|
||||
3. 消费券
|
||||
4. 抵用券
|
||||
5. **BMTR(新增)**
|
||||
6. 余额
|
||||
|
||||
> 由于 `balance` 卡片设置了 `grid-column: 1 / -1`,会单独占一行,所以实际布局为:
|
||||
>
|
||||
> - 第一行:可用积分、算力
|
||||
> - 第二行:消费券、抵用券
|
||||
> - 第三行:BMTR
|
||||
> - 第四行:余额(整行)
|
||||
|
||||
如果希望调整 BMTR 的位置,修改 `api/assets.js` 中 `quickAssets` 数组的顺序即可。
|
||||
|
||||
---
|
||||
|
||||
## 六、待替换项
|
||||
|
||||
| 项目 | 当前值 | 说明 |
|
||||
| --------- | ------------------------------------------------------------ | ----------------------- |
|
||||
| BMTR 图标 | `https://imgs.agrimedia.cn/webimg/202607171808386371853.svg` | BMTR 专属图标(已替换) |
|
||||
| BMTR 背景 | `https://imgs.agrimedia.cn/webimg/202607201122331061368.svg` | BMTR 专属背景(已替换) |
|
||||
|
||||
---
|
||||
|
||||
## 七、接口字段说明
|
||||
|
||||
| 字段 | 类型 | 用途 |
|
||||
| ------------ | ------ | --------------------------- |
|
||||
| `uid` | number | 用户ID |
|
||||
| `nickname` | string | 用户昵称 |
|
||||
| `avatar` | string | 头像URL |
|
||||
| `mxj_points` | string | MXJ积分 |
|
||||
| `bmtr` | string | **BMTR 余额,本次使用字段** |
|
||||
| `is_check` | number | 是否通过某种校验 |
|
||||
| `is_idcard` | number | 是否实名认证 |
|
||||
| `is_sign` | number | 是否签到 |
|
||||
| `sign_time` | number | 签到时间戳 |
|
||||
| `status` | number | 用户状态 |
|
||||
|
||||
---
|
||||
|
||||
## 八、验证建议
|
||||
|
||||
1. 进入首页,确认「我的资产」区域出现 BMTR 卡片
|
||||
2. 确认 BMTR 显示的数值与 `/api/mxj/api/get_user` 返回的 `data.bmtr` 一致
|
||||
3. 点击 BMTR 卡片,确认能跳转到 `pages/assets/bmtr`
|
||||
4. 检查网络面板,确认三个请求并行发送:
|
||||
- `/api/hn/getPrice`
|
||||
- `/api/hn/getAllBalance`
|
||||
- `/api/mxj/api/get_user`
|
||||
5. 如果 BMTR 接口失败,首页应显示错误提示,不影响其他资产卡片的数据逻辑(但 Promise.all 会统一报错,如需降级处理可改为单独 catch)
|
||||
|
||||
---
|
||||
|
||||
## 九、可能的后续优化
|
||||
|
||||
1. **接口降级**:如果 `/api/mxj/api/get_user` 不稳定,可将 `fetchUserData` 从 `Promise.all` 中拆出,单独 catch 并给 BMTR 一个默认值 `0`。
|
||||
2. **数值格式化**:当前 `bmtr` 直接显示为字符串,如需统一显示为 `11.00` 或 `11.0000`,可在 `buildHomeOverview` 中使用 `toFixedNumber` 处理。
|
||||
3. **图标替换**:拿到 BMTR 专属图标和背景后,更新 `pages/index/index.vue` 中的 `iconMap` 和 `bgMap`。
|
||||
667
api/assets.js
667
api/assets.js
File diff suppressed because it is too large
Load Diff
|
|
@ -16,6 +16,7 @@ const serviceConfig = {
|
|||
powerExchangeMuit: "/api/hn/redeem/getMuit",
|
||||
bmtRedeemPowerRate: "/api/hn/redeem/getRedeemPowerRate",
|
||||
bmtExchangeSubmit: "/api/hn/redeem/redeem_bmt",
|
||||
getUser: "/api/mxj/api/get_user",
|
||||
transferFee: "/api/hn/transfer/getProp",
|
||||
transferUser: "/api/hn/transfer/getUserInfo",
|
||||
transferPowerSubmit: "/api/hn/transfer/transferPower",
|
||||
|
|
@ -33,6 +34,8 @@ const serviceConfig = {
|
|||
pointsConvertAvailableList: "/api/integral/transferList",
|
||||
pointsConvertSubmit: "/api/integral/doTransfer",
|
||||
pointsConvertRecordDetail: "/api/integral/transferInfo",
|
||||
bmtrMonthPoints: "/api/mxj/api/get_month_points",
|
||||
bmtrChargeList: "/api/mxj/api/get_charge_list",
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -73,6 +73,15 @@
|
|||
"router" : {
|
||||
"base" : "/bmt/",
|
||||
"mode" : "history"
|
||||
},
|
||||
"devServer" : {
|
||||
"proxy" : {
|
||||
"/api" : {
|
||||
"target" : "https://tpoint.agrimedia.cn",
|
||||
"changeOrigin" : true,
|
||||
"secure" : false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -85,6 +85,13 @@
|
|||
"navigationStyle": "custom",
|
||||
"backgroundColor": "#191E32"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/assets/bmtr",
|
||||
"style": {
|
||||
"navigationStyle": "custom",
|
||||
"backgroundColor": "#191E32"
|
||||
}
|
||||
}
|
||||
],
|
||||
"globalStyle": {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,535 @@
|
|||
<template>
|
||||
<view class="asset-page asset-theme bmtr-page">
|
||||
<asset-page-shell title="BMTR" />
|
||||
|
||||
<view class="bmtr-scroll">
|
||||
<view class="bmtr-hero">
|
||||
<view class="bmtr-hero__main">
|
||||
<view class="bmtr-hero__head">
|
||||
<view class="bmtr-hero__badge">
|
||||
<text class="bmtr-hero__badge-text">R</text>
|
||||
</view>
|
||||
<text class="bmtr-hero__title">BMTR</text>
|
||||
</view>
|
||||
<text class="bmtr-hero__label">可用 BMTR:</text>
|
||||
<text class="bmtr-hero__value asset-number-font">{{
|
||||
summary.available
|
||||
}}</text>
|
||||
<!-- <text class="bmtr-hero__total asset-number-font">累计:{{ summary.total }}</text> -->
|
||||
</view>
|
||||
<!-- 设计图右侧的钱包插图,替换 heroImage 为实际图片地址即可显示 -->
|
||||
<image v-if="heroImage" class="bmtr-hero__image" :src="heroImage" mode="aspectFit"></image>
|
||||
</view>
|
||||
|
||||
<view class="bmtr-address glass-panel" v-if="displayAddress">
|
||||
<view class="bmtr-address__head">
|
||||
<image class="bmtr-address__icon" src="https://imgs.agrimedia.cn/bm-bmt/qianbao.png" mode="aspectFit"></image>
|
||||
<text class="bmtr-address__title">白马提回地址</text>
|
||||
</view>
|
||||
<view class="bmtr-address__field">
|
||||
<view class="bmtr-address__content">
|
||||
<text class="bmtr-address__label">从交易所提回BMTR的地址</text>
|
||||
<text class="bmtr-address__value asset-number-font">{{ displayAddress }}</text>
|
||||
</view>
|
||||
<view class="bmtr-address__actions">
|
||||
<text class="bmtr-address__action" @click="toggleAddress">{{
|
||||
isAddressVisible ? "隐藏" : "显示"
|
||||
}}</text>
|
||||
<text class="bmtr-address__action" @click="copyAddress">复制</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<text class="bmtr-section-title">BMTR记录</text>
|
||||
|
||||
<view v-if="records.length" class="bmtr-records glass-panel">
|
||||
<view v-for="item in records" :key="item.id" class="bmtr-record">
|
||||
<view class="bmtr-record__main">
|
||||
<text class="bmtr-record__title">{{ item.title }}</text>
|
||||
<text class="bmtr-record__time">{{ item.time }}</text>
|
||||
</view>
|
||||
<text class="bmtr-record__amount asset-number-font" :class="item.amount >= 0
|
||||
? 'bmtr-record__amount--in'
|
||||
: 'bmtr-record__amount--out'
|
||||
">{{ formatAmount(item.amount) }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view v-else class="bmtr-records-empty glass-panel">
|
||||
<text class="bmtr-records-empty__text">暂无记录</text>
|
||||
</view>
|
||||
|
||||
<view v-if="showLoadMoreState" class="list-load-more">
|
||||
<text class="list-load-more__text asset-number-font">{{ loadMoreText }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import AssetPageShell from "../../components/asset-page-shell.vue";
|
||||
import { fetchBmtrDetail, fetchBmtrRecords } from "../../api/assets";
|
||||
|
||||
export default {
|
||||
components: {
|
||||
AssetPageShell,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
heroImage: "",
|
||||
summary: {
|
||||
available: "0.0000",
|
||||
total: "0.00",
|
||||
},
|
||||
address: "",
|
||||
isAddressVisible: false,
|
||||
records: [],
|
||||
page: 1,
|
||||
pageSize: 10,
|
||||
hasMore: false,
|
||||
loadingMore: false,
|
||||
hasShown: false,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
displayAddress() {
|
||||
if (this.isAddressVisible) {
|
||||
return this.address;
|
||||
}
|
||||
|
||||
return this.maskAddress(this.address);
|
||||
},
|
||||
showLoadMoreState() {
|
||||
return this.records.length > 0;
|
||||
},
|
||||
loadMoreText() {
|
||||
if (this.loadingMore) {
|
||||
return "加载中...";
|
||||
}
|
||||
|
||||
if (this.hasMore) {
|
||||
return "上拉加载更多";
|
||||
}
|
||||
|
||||
return "没有更多了";
|
||||
},
|
||||
},
|
||||
onLoad() {
|
||||
this.resetPagingState();
|
||||
this.loadDetail(true);
|
||||
this.loadRecords(false, 1);
|
||||
},
|
||||
onShow() {
|
||||
if (this.hasShown) {
|
||||
this.resetPagingState();
|
||||
this.loadDetail(false);
|
||||
this.loadRecords(false, 1);
|
||||
return;
|
||||
}
|
||||
|
||||
this.hasShown = true;
|
||||
},
|
||||
onReachBottom() {
|
||||
this.loadMore();
|
||||
},
|
||||
methods: {
|
||||
resetPagingState() {
|
||||
this.page = 1;
|
||||
this.hasMore = false;
|
||||
this.loadingMore = false;
|
||||
},
|
||||
updatePaging(result, requestedPage, receivedLength) {
|
||||
const pagination =
|
||||
result && result.pagination && typeof result.pagination === "object"
|
||||
? result.pagination
|
||||
: null;
|
||||
this.page =
|
||||
Number(pagination && pagination.page) || Number(requestedPage) || this.page || 1;
|
||||
|
||||
if (pagination && typeof pagination.hasMore === "boolean") {
|
||||
this.hasMore = pagination.hasMore;
|
||||
return;
|
||||
}
|
||||
|
||||
this.hasMore = receivedLength >= this.pageSize;
|
||||
},
|
||||
mergeRecords(currentRecords, nextRecords) {
|
||||
const mergedMap = {};
|
||||
const mergedList = [];
|
||||
const appendItem = (item) => {
|
||||
const key = String(item && item.id ? item.id : "").trim();
|
||||
|
||||
if (!key || mergedMap[key]) {
|
||||
return;
|
||||
}
|
||||
|
||||
mergedMap[key] = true;
|
||||
mergedList.push(item);
|
||||
};
|
||||
|
||||
(Array.isArray(currentRecords) ? currentRecords : []).forEach(appendItem);
|
||||
(Array.isArray(nextRecords) ? nextRecords : []).forEach(appendItem);
|
||||
return mergedList;
|
||||
},
|
||||
async loadDetail(showLoading) {
|
||||
try {
|
||||
const detail = await fetchBmtrDetail(
|
||||
showLoading
|
||||
? {
|
||||
showLoading: true,
|
||||
loadingText: "加载中",
|
||||
}
|
||||
: null,
|
||||
);
|
||||
|
||||
this.summary = Object.assign({}, this.summary, {
|
||||
available: detail.available,
|
||||
});
|
||||
this.address = detail.address;
|
||||
} catch (error) {
|
||||
uni.showToast({
|
||||
title: error.message || "页面加载失败",
|
||||
icon: "none",
|
||||
});
|
||||
}
|
||||
},
|
||||
async loadRecords(showLoading, targetPage) {
|
||||
const page = Number(targetPage || 1);
|
||||
const isLoadMore = page > 1;
|
||||
|
||||
if (isLoadMore && this.loadingMore) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isLoadMore) {
|
||||
this.loadingMore = true;
|
||||
}
|
||||
|
||||
try {
|
||||
const result = await fetchBmtrRecords(
|
||||
{
|
||||
page: page,
|
||||
pageSize: this.pageSize,
|
||||
},
|
||||
!isLoadMore && showLoading
|
||||
? {
|
||||
showLoading: true,
|
||||
loadingText: "加载中",
|
||||
}
|
||||
: null,
|
||||
);
|
||||
const incomingRecords = Array.isArray(result.records)
|
||||
? result.records
|
||||
: [];
|
||||
const previousCount = this.records.length;
|
||||
const mergedRecords = isLoadMore
|
||||
? this.mergeRecords(this.records, incomingRecords)
|
||||
: incomingRecords;
|
||||
this.records = mergedRecords;
|
||||
|
||||
this.updatePaging(result, page, incomingRecords.length);
|
||||
|
||||
if (isLoadMore && mergedRecords.length <= previousCount) {
|
||||
this.hasMore = false;
|
||||
}
|
||||
} catch (error) {
|
||||
uni.showToast({
|
||||
title: error.message || (isLoadMore ? "加载更多失败" : "页面加载失败"),
|
||||
icon: "none",
|
||||
});
|
||||
} finally {
|
||||
if (isLoadMore) {
|
||||
this.loadingMore = false;
|
||||
}
|
||||
}
|
||||
},
|
||||
loadMore() {
|
||||
if (this.loadingMore || !this.hasMore) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.loadRecords(false, this.page + 1);
|
||||
},
|
||||
maskAddress(address) {
|
||||
const safeAddress = String(address || "");
|
||||
|
||||
if (!safeAddress) {
|
||||
return "";
|
||||
}
|
||||
|
||||
if (safeAddress.length <= 4) {
|
||||
return "****";
|
||||
}
|
||||
|
||||
const headLength = Math.min(4, Math.ceil(safeAddress.length / 3));
|
||||
const tailLength = Math.min(4, Math.floor(safeAddress.length / 3));
|
||||
|
||||
return (
|
||||
safeAddress.slice(0, headLength) +
|
||||
"****" +
|
||||
safeAddress.slice(-tailLength)
|
||||
);
|
||||
},
|
||||
toggleAddress() {
|
||||
this.isAddressVisible = !this.isAddressVisible;
|
||||
},
|
||||
copyAddress() {
|
||||
uni.setClipboardData({
|
||||
data: this.address,
|
||||
success() {
|
||||
uni.showToast({
|
||||
title: "已复制",
|
||||
icon: "none",
|
||||
});
|
||||
},
|
||||
});
|
||||
},
|
||||
formatAmount(amount) {
|
||||
const number = Number(amount || 0);
|
||||
return (number >= 0 ? "+" : "-") + Math.abs(number);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import "../../styles/tokens.scss";
|
||||
@import "../../styles/common.scss";
|
||||
|
||||
.bmtr-page {
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.bmtr-scroll {
|
||||
padding: 12rpx 24rpx calc(env(safe-area-inset-bottom) + 36rpx);
|
||||
}
|
||||
|
||||
.bmtr-hero {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 32rpx;
|
||||
border-radius: 24rpx;
|
||||
border: 1px solid rgba(143, 167, 207, 0.16);
|
||||
background:
|
||||
url("https://imgs.agrimedia.cn/webimg/202607221601148466081.png") center /
|
||||
cover no-repeat,
|
||||
radial-gradient(circle at 88% 30%,
|
||||
rgba(76, 201, 255, 0.16),
|
||||
transparent 55%),
|
||||
linear-gradient(135deg, #1d2b52 0%, #14203f 100%);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.bmtr-hero__main {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.bmtr-hero__head {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.bmtr-hero__badge {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 64rpx;
|
||||
height: 64rpx;
|
||||
margin-right: 16rpx;
|
||||
border-radius: 50%;
|
||||
background: #ff5a5a;
|
||||
}
|
||||
|
||||
.bmtr-hero__badge-text {
|
||||
font-size: 36rpx;
|
||||
font-weight: 800;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.bmtr-hero__title {
|
||||
font-size: 36rpx;
|
||||
font-weight: 700;
|
||||
color: $asset-text-main;
|
||||
}
|
||||
|
||||
.bmtr-hero__label {
|
||||
margin-top: 24rpx;
|
||||
font-size: 26rpx;
|
||||
color: $asset-text-subtle;
|
||||
}
|
||||
|
||||
.bmtr-hero__value {
|
||||
margin-top: 8rpx;
|
||||
font-size: 56rpx;
|
||||
font-weight: 800;
|
||||
line-height: 1.1;
|
||||
color: $asset-text-main;
|
||||
}
|
||||
|
||||
.bmtr-hero__total {
|
||||
margin-top: 12rpx;
|
||||
font-size: 28rpx;
|
||||
font-weight: 600;
|
||||
color: #35d9a0;
|
||||
}
|
||||
|
||||
.bmtr-hero__image {
|
||||
width: 260rpx;
|
||||
height: 200rpx;
|
||||
flex: 0 0 auto;
|
||||
margin-left: 24rpx;
|
||||
}
|
||||
|
||||
.bmtr-address {
|
||||
margin-top: 24rpx;
|
||||
padding: 28rpx;
|
||||
}
|
||||
|
||||
.bmtr-address__head {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.bmtr-address__icon {
|
||||
width: 40rpx;
|
||||
height: 40rpx;
|
||||
margin-right: 12rpx;
|
||||
}
|
||||
|
||||
.bmtr-address__title {
|
||||
font-size: 32rpx;
|
||||
font-weight: 700;
|
||||
color: $asset-text-main;
|
||||
}
|
||||
|
||||
.bmtr-address__field {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-top: 24rpx;
|
||||
padding: 24rpx;
|
||||
border-radius: 14rpx;
|
||||
background: rgba(18, 25, 48, 0.72);
|
||||
border: 1px solid rgba(255, 255, 255, 0.08);
|
||||
}
|
||||
|
||||
.bmtr-address__content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.bmtr-address__label {
|
||||
font-size: 24rpx;
|
||||
color: rgba(255, 255, 255, 0.62);
|
||||
}
|
||||
|
||||
.bmtr-address__value {
|
||||
margin-top: 12rpx;
|
||||
font-size: 28rpx;
|
||||
font-weight: 600;
|
||||
word-break: break-all;
|
||||
color: $asset-text-main;
|
||||
}
|
||||
|
||||
.bmtr-address__actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex: 0 0 auto;
|
||||
margin-left: 24rpx;
|
||||
}
|
||||
|
||||
.bmtr-address__action {
|
||||
font-size: 26rpx;
|
||||
font-weight: 600;
|
||||
color: #38d0bd;
|
||||
}
|
||||
|
||||
.bmtr-address__action+.bmtr-address__action {
|
||||
margin-left: 28rpx;
|
||||
}
|
||||
|
||||
.bmtr-section-title {
|
||||
display: block;
|
||||
margin: 36rpx 0 20rpx;
|
||||
font-size: 32rpx;
|
||||
font-weight: 700;
|
||||
color: $asset-text-main;
|
||||
}
|
||||
|
||||
.bmtr-records {
|
||||
padding: 0 28rpx;
|
||||
}
|
||||
|
||||
.bmtr-record {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 28rpx 0;
|
||||
border-bottom: 1px solid rgba(255, 255, 255, 0.08);
|
||||
}
|
||||
|
||||
.bmtr-record:last-child {
|
||||
border-bottom: 0;
|
||||
}
|
||||
|
||||
.bmtr-record__main {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.bmtr-record__title {
|
||||
font-size: 30rpx;
|
||||
font-weight: 600;
|
||||
color: $asset-text-main;
|
||||
}
|
||||
|
||||
.bmtr-record__time {
|
||||
margin-top: 10rpx;
|
||||
font-size: 24rpx;
|
||||
color: rgba(255, 255, 255, 0.45);
|
||||
}
|
||||
|
||||
.bmtr-record__amount {
|
||||
flex: 0 0 auto;
|
||||
margin-left: 24rpx;
|
||||
font-size: 36rpx;
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
.bmtr-record__amount--in {
|
||||
color: #ff9440;
|
||||
}
|
||||
|
||||
.bmtr-record__amount--out {
|
||||
color: #35d9a0;
|
||||
}
|
||||
|
||||
.bmtr-records-empty {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
padding: 70rpx 24rpx;
|
||||
}
|
||||
|
||||
.bmtr-records-empty__text {
|
||||
font-size: 26rpx;
|
||||
color: rgba(158, 170, 204, 0.86);
|
||||
}
|
||||
|
||||
.list-load-more {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
padding: 12rpx 0 22rpx;
|
||||
}
|
||||
|
||||
.list-load-more__text {
|
||||
font-size: 22rpx;
|
||||
color: rgba(173, 182, 211, 0.9);
|
||||
}
|
||||
</style>
|
||||
|
|
@ -5,12 +5,9 @@
|
|||
<text class="home-topbar__title">{{ overview.title || "数字资产" }}</text>
|
||||
<view class="home-wallet-btn" @click="openWallet">
|
||||
<view class="home-wallet-btn__icon">
|
||||
<image
|
||||
src="https://imgs.agrimedia.cn/bm-bmt/qianbao.png"
|
||||
mode="widthFix"
|
||||
></image>
|
||||
<image src="https://imgs.agrimedia.cn/bm-bmt/qianbao.png" mode="widthFix"></image>
|
||||
</view>
|
||||
<text class="home-wallet-btn__text">钱包</text>
|
||||
<text class="home-wallet-btn__text">钱包1</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
|
|
@ -19,7 +16,8 @@
|
|||
<view class="home-skeleton__hero">
|
||||
<view class="home-skeleton__banner skeleton-block"></view>
|
||||
<view class="home-skeleton__stat-panel">
|
||||
<view v-for="index in 2" :key="'home-skeleton-stat-' + index" class="home-skeleton__stat-card skeleton-card">
|
||||
<view v-for="index in 2" :key="'home-skeleton-stat-' + index"
|
||||
class="home-skeleton__stat-card skeleton-card">
|
||||
<view class="home-skeleton__line home-skeleton__line--label skeleton-block"></view>
|
||||
<view class="home-skeleton__line home-skeleton__line--value skeleton-block"></view>
|
||||
</view>
|
||||
|
|
@ -29,7 +27,8 @@
|
|||
<view class="home-skeleton__section">
|
||||
<view class="home-skeleton__title skeleton-block"></view>
|
||||
<view class="home-skeleton__asset-grid">
|
||||
<view v-for="index in 5" :key="'home-skeleton-asset-' + index" class="home-skeleton__asset-card skeleton-card">
|
||||
<view v-for="index in 5" :key="'home-skeleton-asset-' + index"
|
||||
class="home-skeleton__asset-card skeleton-card">
|
||||
<view class="home-skeleton__line home-skeleton__line--asset-label skeleton-block"></view>
|
||||
<view class="home-skeleton__line home-skeleton__line--asset-value skeleton-block"></view>
|
||||
</view>
|
||||
|
|
@ -39,7 +38,8 @@
|
|||
<view class="home-skeleton__section">
|
||||
<view class="home-skeleton__title skeleton-block"></view>
|
||||
<view class="home-skeleton__feature-list">
|
||||
<view v-for="index in 6" :key="'home-skeleton-feature-' + index" class="home-skeleton__feature-item skeleton-card">
|
||||
<view v-for="index in 6" :key="'home-skeleton-feature-' + index"
|
||||
class="home-skeleton__feature-item skeleton-card">
|
||||
<view class="home-skeleton__feature-main">
|
||||
<view class="home-skeleton__feature-icon skeleton-block"></view>
|
||||
<view class="home-skeleton__line home-skeleton__line--feature skeleton-block"></view>
|
||||
|
|
@ -63,13 +63,8 @@
|
|||
<view class="brand-banner"></view>
|
||||
|
||||
<view class="stat-panel">
|
||||
<view
|
||||
v-for="item in overview.topStats"
|
||||
:key="item.key"
|
||||
class="stat-card"
|
||||
:class="'stat-card--' + item.accent"
|
||||
@click="openTopStat(item)"
|
||||
>
|
||||
<view v-for="item in overview.topStats" :key="item.key" class="stat-card"
|
||||
:class="'stat-card--' + item.accent" @click="openTopStat(item)">
|
||||
<view class="stat-card__body">
|
||||
<text class="stat-card__label">{{ item.title }}</text>
|
||||
<view class="stat-card__value-row">
|
||||
|
|
@ -86,21 +81,11 @@
|
|||
<text class="home-section__title">我的资产</text>
|
||||
</view>
|
||||
<view class="asset-grid">
|
||||
<view
|
||||
v-for="item in overview.quickAssets"
|
||||
:key="item.key"
|
||||
class="asset-mini-card"
|
||||
:class="[
|
||||
'asset-mini-card--' + item.accent,
|
||||
item.key === 'balance' ? 'asset-mini-card--full' : '',
|
||||
]"
|
||||
@click="openQuickAsset(item)"
|
||||
>
|
||||
<image
|
||||
class="asset-mini-card__bg"
|
||||
:src="quickAssetBg(item.key)"
|
||||
mode="aspectFill"
|
||||
></image>
|
||||
<view v-for="item in overview.quickAssets" :key="item.key" class="asset-mini-card" :class="[
|
||||
'asset-mini-card--' + item.accent,
|
||||
item.key === 'balance' ? 'asset-mini-card--full' : '',
|
||||
]" @click="openQuickAsset(item)">
|
||||
<image class="asset-mini-card__bg" :src="quickAssetBg(item.key)" mode="aspectFill"></image>
|
||||
<view class="asset-mini-card__head">
|
||||
<text class="asset-mini-card__label">{{ item.title }}</text>
|
||||
</view>
|
||||
|
|
@ -114,19 +99,11 @@
|
|||
<text class="home-section__title">功能中心</text>
|
||||
</view>
|
||||
<view class="feature-list">
|
||||
<view
|
||||
v-for="feature in overview.features"
|
||||
:key="feature.key"
|
||||
class="feature-list__item"
|
||||
@click="openFeature(feature.key)"
|
||||
>
|
||||
<view v-for="feature in overview.features" :key="feature.key" class="feature-list__item"
|
||||
@click="openFeature(feature.key)">
|
||||
<view class="feature-list__main">
|
||||
<view class="feature-list__icon">
|
||||
<image
|
||||
class="feature-list__icon-image"
|
||||
:src="featureIcon(feature.key)"
|
||||
mode="aspectFit"
|
||||
></image>
|
||||
<image class="feature-list__icon-image" :src="featureIcon(feature.key)" mode="aspectFit"></image>
|
||||
</view>
|
||||
<text class="feature-list__title">{{ feature.title }}</text>
|
||||
</view>
|
||||
|
|
@ -136,15 +113,12 @@
|
|||
</view>
|
||||
|
||||
<view class="notice-bar">
|
||||
<image
|
||||
class="notice-bar__icon"
|
||||
src="https://imgs.agrimedia.cn/bm-bmt/tips.png"
|
||||
mode="widthFix"
|
||||
></image>
|
||||
<image class="notice-bar__icon" src="https://imgs.agrimedia.cn/bm-bmt/tips.png" mode="widthFix"></image>
|
||||
<text class="notice-bar__text">{{ overview.notice }}</text>
|
||||
</view>
|
||||
|
||||
<image src="https://imgs.agrimedia.cn/bm-bmt/bottom.png" mode="widthFix" style="width: 100%; margin-top: 20rpx"></image>
|
||||
|
||||
<image src="https://imgs.agrimedia.cn/bm-bmt/bottom.png" mode="widthFix" style="width: 100%; margin-top: 20rpx">
|
||||
</image>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
|
@ -222,6 +196,7 @@ export default {
|
|||
voucher: "https://imgs.agrimedia.cn/bm-bmt/quan-icon.png",
|
||||
coupon: "https://imgs.agrimedia.cn/bm-bmt/xiaofei-icon.png",
|
||||
power: "https://imgs.agrimedia.cn/bm-bmt/suanli-icon.png",
|
||||
bmtr: "https://imgs.agrimedia.cn/webimg/202607171808386371853.svg",
|
||||
};
|
||||
|
||||
return iconMap[key] || "";
|
||||
|
|
@ -233,6 +208,7 @@ export default {
|
|||
voucher: "https://imgs.agrimedia.cn/bm-bmt/quan-bg.png",
|
||||
coupon: "https://imgs.agrimedia.cn/bm-bmt/xiaofei-bg.png",
|
||||
power: "https://imgs.agrimedia.cn/bm-bmt/suanli-bg.png",
|
||||
bmtr: "https://imgs.agrimedia.cn/webimg/202607201122331061368.svg",
|
||||
};
|
||||
|
||||
return bgMap[key] || "";
|
||||
|
|
@ -308,6 +284,7 @@ export default {
|
|||
const urlMap = {
|
||||
points: "/pages/assets/ledger?type=points",
|
||||
power: "/pages/assets/ledger?type=power-flow",
|
||||
bmtr: "/pages/assets/bmtr",
|
||||
};
|
||||
|
||||
const targetUrl = urlMap[item.key];
|
||||
|
|
@ -446,6 +423,7 @@ export default {
|
|||
width: 30rpx;
|
||||
height: 32rpx;
|
||||
margin-right: 8rpx;
|
||||
|
||||
image {
|
||||
width: 30rpx;
|
||||
height: 32rpx;
|
||||
|
|
@ -479,12 +457,10 @@ export default {
|
|||
bottom: 0;
|
||||
left: -140rpx;
|
||||
width: 140rpx;
|
||||
background: linear-gradient(
|
||||
90deg,
|
||||
rgba(255, 255, 255, 0) 0%,
|
||||
rgba(255, 255, 255, 0.24) 50%,
|
||||
rgba(255, 255, 255, 0) 100%
|
||||
);
|
||||
background: linear-gradient(90deg,
|
||||
rgba(255, 255, 255, 0) 0%,
|
||||
rgba(255, 255, 255, 0.24) 50%,
|
||||
rgba(255, 255, 255, 0) 100%);
|
||||
animation: home-skeleton-shimmer 1.35s linear infinite;
|
||||
}
|
||||
|
||||
|
|
@ -644,6 +620,7 @@ export default {
|
|||
0% {
|
||||
transform: translateX(0);
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: translateX(900rpx);
|
||||
}
|
||||
|
|
@ -660,13 +637,10 @@ export default {
|
|||
height: 380rpx;
|
||||
border-radius: 28rpx;
|
||||
background:
|
||||
linear-gradient(
|
||||
180deg,
|
||||
linear-gradient(180deg,
|
||||
rgba(5, 12, 28, 0.06) 0%,
|
||||
rgba(5, 12, 28, 0.16) 100%
|
||||
),
|
||||
url("https://imgs.agrimedia.cn/bm-bmt/home2-bg.png")
|
||||
no-repeat;
|
||||
rgba(5, 12, 28, 0.16) 100%),
|
||||
url("https://imgs.agrimedia.cn/bm-bmt/home2-bg.png") no-repeat;
|
||||
border: 1px solid rgba(112, 135, 196, 0.18);
|
||||
background-size: cover;
|
||||
box-shadow: 0 24rpx 48rpx rgba(7, 12, 32, 0.28);
|
||||
|
|
@ -710,11 +684,9 @@ export default {
|
|||
min-height: 126rpx;
|
||||
padding: 22rpx 22rpx 20rpx;
|
||||
border-radius: 8rpx;
|
||||
background: linear-gradient(
|
||||
180deg,
|
||||
rgba(42, 55, 82, 0.98) 0%,
|
||||
rgba(39, 51, 76, 0.98) 100%
|
||||
);
|
||||
background: linear-gradient(180deg,
|
||||
rgba(42, 55, 82, 0.98) 0%,
|
||||
rgba(39, 51, 76, 0.98) 100%);
|
||||
border: 1px solid rgba(121, 139, 190, 0.16);
|
||||
box-shadow: 0 14rpx 24rpx rgba(5, 11, 29, 0.2);
|
||||
}
|
||||
|
|
@ -742,19 +714,15 @@ export default {
|
|||
}
|
||||
|
||||
.stat-card__icon-box--gold {
|
||||
background: linear-gradient(
|
||||
135deg,
|
||||
rgba(20, 182, 255, 0.22) 0%,
|
||||
rgba(20, 182, 255, 0.08) 100%
|
||||
);
|
||||
background: linear-gradient(135deg,
|
||||
rgba(20, 182, 255, 0.22) 0%,
|
||||
rgba(20, 182, 255, 0.08) 100%);
|
||||
}
|
||||
|
||||
.stat-card__icon-box--green {
|
||||
background: linear-gradient(
|
||||
135deg,
|
||||
rgba(46, 233, 167, 0.22) 0%,
|
||||
rgba(46, 233, 167, 0.08) 100%
|
||||
);
|
||||
background: linear-gradient(135deg,
|
||||
rgba(46, 233, 167, 0.22) 0%,
|
||||
rgba(46, 233, 167, 0.08) 100%);
|
||||
}
|
||||
|
||||
.stat-card__body {
|
||||
|
|
@ -844,9 +812,9 @@ export default {
|
|||
background: rgba(35, 45, 79, 0.9);
|
||||
}
|
||||
|
||||
.asset-mini-card--full {
|
||||
grid-column: 1 / -1;
|
||||
}
|
||||
// .asset-mini-card--full {
|
||||
// grid-column: 1 / -1;
|
||||
// }
|
||||
|
||||
.asset-mini-card__bg {
|
||||
position: absolute;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,64 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="zh">
|
||||
<head>
|
||||
<script>
|
||||
if (window.parent !== window && !window.location.search.includes('be_nested=1')) {
|
||||
window.stop();
|
||||
}
|
||||
</script>
|
||||
<meta charset="UTF-8">
|
||||
<link rel="icon" href="https://cdn-static.gitcode.host/static/images/logo-favicon.png">
|
||||
<link rel="dns-prefetch" href="https://res.hc-cdn.com">
|
||||
<link rel="dns-prefetch" href="https://assets-cli.s2.udesk.cn">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta content='pc,mobile' name='applicable-device'>
|
||||
<meta property="og:image" content="https://cdn-img.gitcode.com/images/og-image.png">
|
||||
<meta property="og:image:secure_url" content="https://cdn-img.gitcode.com/images/og-image.png">
|
||||
<meta name="twitter:image" content="https://cdn-img.gitcode.com/images/og-image.png">
|
||||
<meta property="og:image:width" content="1200" />
|
||||
<meta property="og:image:height" content="630" />
|
||||
<meta property="og:image:alt" content="favicon">
|
||||
<meta property="og:image:type" content="image/png">
|
||||
<meta name="baidu-site-verification" content="codeva-zQ72KLO8Ne" />
|
||||
<title>AtomGit - 全球开发者的开源社区,开源代码托管平台</title>
|
||||
<meta name="description" content="AtomGit是面向全球开发者的开源社区,包括原创博客,开源代码托管,代码协作,项目管理等。与开发者社区互动,提升您的研发效率和质量。"/>
|
||||
<meta name="keywords" content="开源社区,开源代码,AtomGit"/>
|
||||
<style type="text/css">
|
||||
.icon {
|
||||
width: 1em; height: 1em;
|
||||
vertical-align: -0.15em;
|
||||
fill: currentColor;
|
||||
overflow: hidden;
|
||||
}
|
||||
</style>
|
||||
<script type="module" crossorigin src="https://cdn-static.gitcode.com/assets/index-7d5af48e.js"></script>
|
||||
<link rel="modulepreload" crossorigin href="https://cdn-static.gitcode.com/assets/vendor-3b648d5e.js">
|
||||
<link rel="modulepreload" crossorigin href="https://cdn-static.gitcode.com/assets/vendor-layout-5f380ef2.js">
|
||||
<link rel="stylesheet" href="https://cdn-static.gitcode.com/assets/vendor-layout-0f2324e7.css">
|
||||
<link rel="stylesheet" href="https://cdn-static.gitcode.com/assets/index-128d7750.css">
|
||||
</head>
|
||||
<body>
|
||||
<img src="https://cdn-static.gitcode.com/static/images/logo-favicon.png" style="position:absolute;left:-1000px;top:-1000px" alt="favicon">
|
||||
<div id="app"></div>
|
||||
|
||||
</body>
|
||||
<!-- ai 社区图标 -->
|
||||
<script type="text/javascript" src="https://cdn-static.gitcode.com/js/font_4976451_914etgmfzh8.js" defer></script>
|
||||
<script type="text/javascript" src="https://cdn-static.gitcode.com/js/font_4205092_4w2gnan46b9.js" defer></script>
|
||||
<script type="text/javascript" src="https://cdn-static.gitcode.com/js/lottie.min.js" defer></script>
|
||||
<script type="text/javascript" src="https://cdn-static.gitcode.com/js/tac/load.min.js" defer></script>
|
||||
<script type="text/javascript" src="https://cdn-static.gitcode.com/js/yunpian/riddler-sdk-0.2.2.js" defer></script>
|
||||
<script src="https://cdn-static.gitcode.com/js/yidun/yidun-captcha.js" defer></script>
|
||||
<script type="text/javascript" src="https://cdn-static.gitcode.com/js/furion.js" defer></script>
|
||||
<!-- baidu统计X -->
|
||||
<script>
|
||||
var _hmt = _hmt || [];
|
||||
_hmt.push(['_setAutoPageview', true]);
|
||||
(function() {
|
||||
var hm = document.createElement("script");
|
||||
hm.src = "https://hm.baidu.com/hm.js?62047c952451105d57bab2c4af9ce85b";
|
||||
var s = document.getElementsByTagName("script")[0];
|
||||
s.parentNode.insertBefore(hm, s);
|
||||
})();
|
||||
</script>
|
||||
</html>
|
||||
Loading…
Reference in New Issue