1189 lines
29 KiB
Vue
1189 lines
29 KiB
Vue
<template>
|
||
<view class="asset-page asset-theme home-page">
|
||
<view class="home-topbar">
|
||
<view class="home-topbar__side"></view>
|
||
<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>
|
||
</view>
|
||
<text class="home-wallet-btn__text" style="margin-top: 4rpx;">钱包</text>
|
||
</view>
|
||
</view>
|
||
|
||
<view class="asset-scroll home-scroll">
|
||
<view v-if="isHomeLoading" class="home-skeleton">
|
||
<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 class="home-skeleton__line home-skeleton__line--label skeleton-block"></view>
|
||
<view class="home-skeleton__line home-skeleton__line--value skeleton-block"></view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<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 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>
|
||
</view>
|
||
</view>
|
||
|
||
<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 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>
|
||
</view>
|
||
<view class="home-skeleton__feature-arrow skeleton-block"></view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<view class="home-skeleton__notice">
|
||
<view class="home-skeleton__notice-icon skeleton-block"></view>
|
||
<view class="home-skeleton__notice-lines">
|
||
<view class="home-skeleton__line home-skeleton__line--notice skeleton-block"></view>
|
||
<view class="home-skeleton__line home-skeleton__line--notice-short skeleton-block"></view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<view v-show="!isHomeLoading">
|
||
<view class="home-hero">
|
||
<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 class="stat-card__body">
|
||
<text class="stat-card__label">{{ item.title }}</text>
|
||
<view class="stat-card__value-row">
|
||
<text class="stat-card__value asset-number-font">{{ item.value }}</text>
|
||
<text class="stat-card__unit">{{ item.unit }}</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<view class="home-section">
|
||
<view class="home-section__head">
|
||
<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 class="asset-mini-card__head">
|
||
<text class="asset-mini-card__label">{{ item.title }}</text>
|
||
</view>
|
||
<text class="asset-mini-card__value asset-number-font">{{
|
||
item.key === "bmtr"
|
||
? formatBmtrValue(item.value)
|
||
: formatAssetValue(item.value)
|
||
}}</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<view class="home-section">
|
||
<view class="home-section__head">
|
||
<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 class="feature-list__main">
|
||
<view class="feature-list__icon">
|
||
<image class="feature-list__icon-image" :src="featureIcon(feature.key)" mode="aspectFit"></image>
|
||
</view>
|
||
<text class="feature-list__title">{{ feature.title }}</text>
|
||
</view>
|
||
<image class="feature-list__arrow" src="https://imgs.agrimedia.cn/bm-bmt/more.png"></image>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<view class="notice-bar">
|
||
<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>
|
||
</view>
|
||
</view>
|
||
|
||
<asset-confirm-popup :visible="signPopupVisible" :title="signPopupTitle" :message="signPopupMessage"
|
||
:confirm-text="signPopupConfirmText" cancel-text="取消" @cancel="handleSignPopupCancel"
|
||
@confirm="handleSignPopupConfirm" />
|
||
</view>
|
||
</template>
|
||
|
||
<script>
|
||
import {
|
||
fetchAssetHome,
|
||
fetchCouponRedeemLinkData,
|
||
} from "../../api/assets";
|
||
import {
|
||
fetchBmtContractStatus,
|
||
checkBmtSignCondition,
|
||
startBmtSigning,
|
||
} from "../../api/bmt";
|
||
import AssetConfirmPopup from "../../components/asset-confirm-popup.vue";
|
||
import serviceConfig from "../../config/service";
|
||
import { truncateToTwo } from "../../utils/index.js";
|
||
|
||
// H5 下点击弹框「取消」后固定跳转的推广页
|
||
const BMT_CANCEL_REDIRECT_URL =
|
||
`${window.location.origin}/JXH5/pages/users/user_spread_user/index`;
|
||
|
||
/** personal_auth_status 可能是对象或标量,统一取出 status 值(1 表示需要先走协议签约) */
|
||
function resolvePersonalAuthStatus(source) {
|
||
const raw = source && source.personal_auth_status;
|
||
|
||
if (raw && typeof raw === "object") {
|
||
return Number(raw.status) === 1 ? 1 : 0;
|
||
}
|
||
|
||
return Number(raw) === 1 ? 1 : 0;
|
||
}
|
||
|
||
export default {
|
||
components: {
|
||
AssetConfirmPopup,
|
||
},
|
||
data() {
|
||
return {
|
||
isHomeLoading: true,
|
||
hasLoadedOnce: false,
|
||
isFetchingHome: false,
|
||
isOpeningCouponRedeem: false,
|
||
signPopupVisible: false,
|
||
signPopupMode: "",
|
||
signPopupTitle: "BMT签约",
|
||
signPopupMessage: "",
|
||
signPopupConfirmText: "确认",
|
||
signContractType: 0,
|
||
signContractId: "",
|
||
signRecordId: "",
|
||
signPersonalAuthStatus: 0,
|
||
signInfoData: {},
|
||
isSigning: false,
|
||
overview: {
|
||
title: "数字资产",
|
||
heroTitle: "BM数字资产管理",
|
||
topStats: [],
|
||
quickAssets: [],
|
||
features: [],
|
||
notice: "",
|
||
},
|
||
};
|
||
},
|
||
onLoad() {
|
||
this.loadPage({
|
||
showSkeleton: true,
|
||
});
|
||
},
|
||
onShow() {
|
||
// 首次进入首页校验 BMT 签约状态,命中条件时弹框引导,不自动跳页
|
||
this.checkBmtContract();
|
||
this.loadPage({
|
||
showSkeleton: !this.hasLoadedOnce,
|
||
});
|
||
},
|
||
methods: {
|
||
async checkBmtContract() {
|
||
try {
|
||
const status = (await fetchBmtContractStatus()) || {};
|
||
|
||
// status === 2:无需签约提示,不再做后续判断与接口请求
|
||
if (Number(status.status) === 2) {
|
||
return;
|
||
}
|
||
|
||
const rawComplete = status.sign_info_complete;
|
||
const signInfoComplete =
|
||
rawComplete === undefined || rawComplete === null || rawComplete === ""
|
||
? 1
|
||
: Number(rawComplete);
|
||
const contractStatus = Number(status.contract_status || 0);
|
||
|
||
// 签约信息未完善:弹框引导,用户点击后再进认证页
|
||
if (signInfoComplete !== 1) {
|
||
this.openSignInfoPopup(status);
|
||
return;
|
||
}
|
||
|
||
// 未签约:弹框引导,点击后直接发起签约
|
||
if (contractStatus === 0) {
|
||
await this.openSigningPopup(status);
|
||
}
|
||
} catch (error) {
|
||
// 签约状态查询失败不阻断首页加载
|
||
}
|
||
},
|
||
openSignInfoPopup(status) {
|
||
this.signPopupMode = "info";
|
||
this.signPopupTitle = "BMT签约";
|
||
this.signPopupMessage =
|
||
"您的签约信息尚未完善,请先补充签约信息后再进行签约。";
|
||
this.signPopupConfirmText = "去补充信息";
|
||
this.signInfoData = status || {};
|
||
this.signPopupVisible = true;
|
||
},
|
||
async openSigningPopup(status) {
|
||
let tips = String((status && status.tips) || "");
|
||
let contractType = Number((status && status.contract_type) || 0);
|
||
let checkData = {};
|
||
|
||
// 提示签约时先请求前置校验接口,取 tips / contract_type / c_id
|
||
try {
|
||
checkData =
|
||
(await checkBmtSignCondition(
|
||
{},
|
||
{
|
||
showLoading: true,
|
||
loadingText: "校验中",
|
||
},
|
||
)) || {};
|
||
} catch (error) {
|
||
checkData = {};
|
||
}
|
||
|
||
const checkTips = String(checkData.tips || "");
|
||
const checkType = checkData.contract_type;
|
||
|
||
if (checkTips) {
|
||
tips = checkTips;
|
||
}
|
||
|
||
if (checkType !== undefined && checkType !== null && checkType !== "") {
|
||
contractType = Number(checkType) === 1 ? 1 : 0;
|
||
}
|
||
|
||
// c_id / id 来自前置校验接口,点击「去签约」时随请求一并带上
|
||
this.signContractId = String(checkData.c_id || "");
|
||
this.signRecordId = String(checkData.id || (status && status.id) || "");
|
||
this.signPersonalAuthStatus = resolvePersonalAuthStatus(checkData);
|
||
this.signPopupMode = "sign";
|
||
this.signPopupTitle = "BMT签约";
|
||
this.signPopupMessage =
|
||
tips || "您尚未签署 BMT 相关协议,请完成签约后继续使用。";
|
||
this.signPopupConfirmText = contractType === 1 ? "更新协议" : "签约新协议";
|
||
this.signContractType = contractType;
|
||
this.signPopupVisible = true;
|
||
},
|
||
handleSignPopupConfirm() {
|
||
if (this.signPopupMode === "info") {
|
||
const data = encodeURIComponent(
|
||
JSON.stringify(this.signInfoData || {}),
|
||
);
|
||
|
||
this.signPopupVisible = false;
|
||
uni.navigateTo({
|
||
url: "/pages/assets/bmt-sign-info?data=" + data,
|
||
});
|
||
return;
|
||
}
|
||
|
||
this.handleGoSigning();
|
||
},
|
||
handleSignPopupCancel() {
|
||
this.signPopupVisible = false;
|
||
this.exitToHostPage();
|
||
},
|
||
/** 退出当前页:H5 固定跳转推广页;其它端返回上一页 / 关闭 webview */
|
||
exitToHostPage() {
|
||
const ua = navigator.userAgent.toLowerCase();
|
||
const isAppWebview = ua.indexOf('html5plus') > -1 || window.plus;
|
||
|
||
// App内嵌webview:跳约定的uniwebview协议,外层拦截
|
||
if (isAppWebview) {
|
||
window.location.href = "uniwebview://redirectTo?url=/pages/users/user_spread_user/index";
|
||
return;
|
||
}
|
||
|
||
// 普通浏览器H5,跳转推广页
|
||
if (typeof window !== "undefined") {
|
||
window.location.href = BMT_CANCEL_REDIRECT_URL;
|
||
return;
|
||
}
|
||
|
||
// uni-app原生App页面(非webview)
|
||
if (typeof getCurrentPages === "function" && getCurrentPages().length > 1) {
|
||
uni.navigateBack();
|
||
return;
|
||
}
|
||
if (typeof plus !== "undefined") {
|
||
const currentWebview = plus.webview.currentWebview();
|
||
currentWebview?.close?.();
|
||
}
|
||
},
|
||
|
||
|
||
async handleGoSigning() {
|
||
if (this.isSigning) {
|
||
return;
|
||
}
|
||
|
||
// personal_auth_status.status === 1:先到协议页阅读并签约(协议页用 id 签约)
|
||
if (this.signPersonalAuthStatus === 1) {
|
||
this.isSigning = true;
|
||
|
||
try {
|
||
this.signPopupVisible = false;
|
||
uni.navigateTo({
|
||
url: "/pages/assets/bmt-sign-agreement",
|
||
});
|
||
} finally {
|
||
this.isSigning = false;
|
||
}
|
||
|
||
return;
|
||
}
|
||
|
||
if (!this.signContractId) {
|
||
uni.showToast({
|
||
title: "签约信息获取失败,请稍后重试",
|
||
icon: "none",
|
||
});
|
||
return;
|
||
}
|
||
|
||
this.isSigning = true;
|
||
|
||
try {
|
||
const result = await startBmtSigning(
|
||
{
|
||
contract_type: this.signContractType,
|
||
c_id: this.signContractId,
|
||
id: this.signRecordId,
|
||
},
|
||
{
|
||
showLoading: true,
|
||
loadingText: "发起签约",
|
||
},
|
||
);
|
||
|
||
// 输出原始返回,便于确认字段实际层级(排查完可删)
|
||
console.log("[BMT签约] start_signing_bmt_v2 返回:", result.raw);
|
||
|
||
// status 为 0:直接跳转 saasShortLink 去认证
|
||
if (Number(result.status) === 0 && result.saasShortLink) {
|
||
this.signPopupVisible = false;
|
||
this.navigateToExternalUrl(result.saasShortLink);
|
||
return;
|
||
}
|
||
|
||
uni.showToast({
|
||
title: result.message || "发起签约失败,请稍后重试",
|
||
icon: "none",
|
||
});
|
||
} catch (error) {
|
||
uni.showToast({
|
||
title: error.message || "发起签约失败",
|
||
icon: "none",
|
||
});
|
||
} finally {
|
||
this.isSigning = false;
|
||
}
|
||
},
|
||
formatAssetValue(value) {
|
||
return truncateToTwo(value);
|
||
},
|
||
formatBmtrValue(value) {
|
||
const number = Number(value || 0);
|
||
return Number.isFinite(number) ? number.toFixed(2) : "0.00";
|
||
},
|
||
async loadPage(options = {}) {
|
||
if (this.isFetchingHome) {
|
||
return;
|
||
}
|
||
|
||
const shouldShowSkeleton =
|
||
Boolean(options.showSkeleton) || !this.hasLoadedOnce;
|
||
if (shouldShowSkeleton) {
|
||
this.isHomeLoading = true;
|
||
}
|
||
this.isFetchingHome = true;
|
||
|
||
try {
|
||
const nextOverview = await fetchAssetHome();
|
||
|
||
this.overview = nextOverview;
|
||
this.hasLoadedOnce = true;
|
||
} catch (error) {
|
||
uni.showToast({
|
||
title: error.message || "首页加载失败",
|
||
icon: "none",
|
||
});
|
||
} finally {
|
||
if (shouldShowSkeleton || !this.hasLoadedOnce) {
|
||
this.isHomeLoading = false;
|
||
}
|
||
this.isFetchingHome = false;
|
||
}
|
||
},
|
||
quickAssetIcon(key) {
|
||
const iconMap = {
|
||
points: "https://imgs.agrimedia.cn/bm-bmt/jifen-icon.png",
|
||
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] || "";
|
||
},
|
||
quickAssetBg(key) {
|
||
const bgMap = {
|
||
balance: "https://imgs.agrimedia.cn/bm-bmt/brokerage-icon.png",
|
||
points: "https://imgs.agrimedia.cn/bm-bmt/jifen-bg.png",
|
||
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] || "";
|
||
},
|
||
featureIcon(key) {
|
||
const iconMap = {
|
||
"bmt-exchange": "https://imgs.agrimedia.cn/bm-bmt/b.png",
|
||
"bmt-flash": "https://imgs.agrimedia.cn/bm-bmt/shandui.png",
|
||
"power-exchange": "https://imgs.agrimedia.cn/bm-bmt/s.png",
|
||
transfer: "https://imgs.agrimedia.cn/bm-bmt/z.png",
|
||
withdraw: "https://imgs.agrimedia.cn/bm-bmt/t.png",
|
||
"points-convert": "https://imgs.agrimedia.cn/bm-bmt/j.png",
|
||
};
|
||
|
||
return iconMap[key] || "";
|
||
},
|
||
openFeature(key) {
|
||
const urlMap = {
|
||
transfer: "/pages/assets/transfer",
|
||
"power-exchange": "/pages/assets/power-exchange",
|
||
"bmt-exchange": "/pages/assets/bmt-exchange",
|
||
"bmt-flash": "/pages/assets/bmt-flash",
|
||
withdraw: "/pages/assets/withdraw",
|
||
"points-convert": "/pages/assets/points-convert",
|
||
};
|
||
|
||
const targetUrl = urlMap[key];
|
||
if (!targetUrl) {
|
||
uni.showToast({
|
||
title: "功能开发中",
|
||
icon: "none",
|
||
});
|
||
return;
|
||
}
|
||
|
||
uni.navigateTo({
|
||
url: targetUrl,
|
||
});
|
||
},
|
||
openTopStat(item) {
|
||
const key = item && item.key ? item.key : "";
|
||
const urlMap = {
|
||
"wallet-bmt": "/pages/assets/ledger?type=withdraw",
|
||
};
|
||
|
||
const targetUrl = urlMap[key];
|
||
if (!targetUrl) {
|
||
return;
|
||
}
|
||
|
||
uni.navigateTo({
|
||
url: targetUrl,
|
||
});
|
||
},
|
||
openQuickAsset(item) {
|
||
if (item && item.key === "balance") {
|
||
this.openBalanceSpread();
|
||
return;
|
||
}
|
||
|
||
if (item && item.key === "voucher") {
|
||
this.openVoucherBroker();
|
||
return;
|
||
}
|
||
|
||
if (item && item.key === "coupon") {
|
||
this.openCouponRedeem();
|
||
return;
|
||
}
|
||
|
||
const urlMap = {
|
||
points: "/pages/assets/ledger?type=points",
|
||
power: "/pages/assets/ledger?type=power-flow",
|
||
bmtr: "/pages/assets/bmtr",
|
||
};
|
||
|
||
const targetUrl = urlMap[item.key];
|
||
if (!targetUrl) {
|
||
return;
|
||
}
|
||
|
||
uni.navigateTo({
|
||
url: targetUrl,
|
||
});
|
||
},
|
||
navigateToExternalUrl(targetUrl) {
|
||
if (!targetUrl) {
|
||
return;
|
||
}
|
||
|
||
if (typeof window !== "undefined" && window.location) {
|
||
window.location.href = targetUrl;
|
||
return;
|
||
}
|
||
|
||
if (
|
||
typeof plus !== "undefined" &&
|
||
plus.webview &&
|
||
plus.webview.currentWebview
|
||
) {
|
||
const currentWebview = plus.webview.currentWebview();
|
||
if (currentWebview && typeof currentWebview.loadURL === "function") {
|
||
currentWebview.loadURL(targetUrl);
|
||
return;
|
||
}
|
||
}
|
||
|
||
uni.navigateTo({
|
||
url: targetUrl,
|
||
});
|
||
},
|
||
async openVoucherBroker() {
|
||
uni.navigateTo({
|
||
url: "/pages/assets/voucher-center",
|
||
});
|
||
},
|
||
async openCouponRedeem() {
|
||
if (this.isOpeningCouponRedeem) {
|
||
return;
|
||
}
|
||
|
||
this.isOpeningCouponRedeem = true;
|
||
|
||
try {
|
||
const result = await fetchCouponRedeemLinkData({
|
||
showLoading: true,
|
||
loadingText: "加载中",
|
||
});
|
||
|
||
this.navigateToExternalUrl(result.targetUrl);
|
||
} catch (error) {
|
||
uni.showToast({
|
||
title: error.message || "跳转失败",
|
||
icon: "none",
|
||
});
|
||
} finally {
|
||
this.isOpeningCouponRedeem = false;
|
||
}
|
||
},
|
||
openBalanceSpread() {
|
||
uni.navigateTo({
|
||
url: "/pages/assets/balance-center",
|
||
});
|
||
},
|
||
openWallet() {
|
||
uni.navigateTo({
|
||
url: "/pages/assets/wallet",
|
||
});
|
||
},
|
||
},
|
||
};
|
||
</script>
|
||
|
||
<style lang="scss" scoped>
|
||
@import "../../styles/tokens.scss";
|
||
@import "../../styles/common.scss";
|
||
|
||
.home-page {
|
||
background: #191e32;
|
||
}
|
||
|
||
.home-topbar {
|
||
display: grid;
|
||
grid-template-columns: 136rpx 1fr 136rpx;
|
||
align-items: center;
|
||
padding: calc(env(safe-area-inset-top) + 20rpx) 16rpx 8rpx;
|
||
}
|
||
|
||
.home-topbar__side {
|
||
width: 136rpx;
|
||
height: 1rpx;
|
||
}
|
||
|
||
.home-topbar__title {
|
||
text-align: center;
|
||
font-size: 36rpx;
|
||
font-weight: 700;
|
||
color: #ffffff;
|
||
letter-spacing: 1rpx;
|
||
}
|
||
|
||
.home-wallet-btn {
|
||
justify-self: end;
|
||
display: flex;
|
||
align-items: center;
|
||
height: 52rpx;
|
||
color: rgba(229, 235, 255, 0.82);
|
||
padding-right: 10rpx;
|
||
}
|
||
|
||
.home-wallet-btn__icon {
|
||
width: 30rpx;
|
||
height: 32rpx;
|
||
margin-right: 8rpx;
|
||
|
||
image {
|
||
width: 30rpx;
|
||
height: 32rpx;
|
||
}
|
||
}
|
||
|
||
.home-wallet-btn__text {
|
||
font-size: 28rpx;
|
||
line-height: 1;
|
||
color: rgba(229, 235, 255, 0.82);
|
||
}
|
||
|
||
.home-scroll {
|
||
padding: 12rpx 20rpx 24rpx;
|
||
}
|
||
|
||
.home-skeleton {
|
||
padding-bottom: 6rpx;
|
||
}
|
||
|
||
.skeleton-block {
|
||
position: relative;
|
||
overflow: hidden;
|
||
background: rgba(86, 98, 135, 0.32);
|
||
}
|
||
|
||
.skeleton-block::after {
|
||
content: "";
|
||
position: absolute;
|
||
top: 0;
|
||
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%);
|
||
animation: home-skeleton-shimmer 1.35s linear infinite;
|
||
}
|
||
|
||
.skeleton-card {
|
||
border-radius: 12rpx;
|
||
background: rgba(36, 41, 68, 0.92);
|
||
border: 1px solid rgba(129, 141, 183, 0.16);
|
||
}
|
||
|
||
.home-skeleton__hero {
|
||
position: relative;
|
||
margin-bottom: 26rpx;
|
||
}
|
||
|
||
.home-skeleton__banner {
|
||
height: 380rpx;
|
||
border-radius: 28rpx;
|
||
}
|
||
|
||
.home-skeleton__stat-panel {
|
||
position: absolute;
|
||
left: 20rpx;
|
||
right: 20rpx;
|
||
bottom: 24rpx;
|
||
display: grid;
|
||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||
gap: 20rpx;
|
||
}
|
||
|
||
.home-skeleton__stat-card {
|
||
padding: 22rpx 22rpx 20rpx;
|
||
min-height: 126rpx;
|
||
}
|
||
|
||
.home-skeleton__section {
|
||
margin-top: 28rpx;
|
||
}
|
||
|
||
.home-skeleton__title {
|
||
width: 154rpx;
|
||
height: 34rpx;
|
||
border-radius: 8rpx;
|
||
margin-bottom: 16rpx;
|
||
}
|
||
|
||
.home-skeleton__asset-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||
gap: 16rpx;
|
||
}
|
||
|
||
.home-skeleton__asset-card {
|
||
height: 80rpx;
|
||
padding: 14rpx 20rpx;
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
}
|
||
|
||
.home-skeleton__feature-list {
|
||
display: grid;
|
||
gap: 16rpx;
|
||
}
|
||
|
||
.home-skeleton__feature-item {
|
||
min-height: 100rpx;
|
||
padding: 0 22rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
}
|
||
|
||
.home-skeleton__feature-main {
|
||
display: flex;
|
||
align-items: center;
|
||
min-width: 0;
|
||
flex: 1;
|
||
}
|
||
|
||
.home-skeleton__feature-icon {
|
||
width: 36rpx;
|
||
height: 36rpx;
|
||
border-radius: 8rpx;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.home-skeleton__feature-arrow {
|
||
width: 24rpx;
|
||
height: 24rpx;
|
||
border-radius: 999rpx;
|
||
margin-left: 20rpx;
|
||
}
|
||
|
||
.home-skeleton__notice {
|
||
display: flex;
|
||
align-items: flex-start;
|
||
margin-top: 20rpx;
|
||
padding: 0 2rpx;
|
||
}
|
||
|
||
.home-skeleton__notice-icon {
|
||
width: 28rpx;
|
||
height: 28rpx;
|
||
border-radius: 50%;
|
||
margin-right: 8rpx;
|
||
margin-top: 4rpx;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.home-skeleton__notice-lines {
|
||
flex: 1;
|
||
}
|
||
|
||
.home-skeleton__line {
|
||
border-radius: 8rpx;
|
||
}
|
||
|
||
.home-skeleton__line--label {
|
||
width: 150rpx;
|
||
height: 24rpx;
|
||
}
|
||
|
||
.home-skeleton__line--value {
|
||
width: 200rpx;
|
||
height: 34rpx;
|
||
margin-top: 16rpx;
|
||
}
|
||
|
||
.home-skeleton__line--asset-label {
|
||
width: 86rpx;
|
||
height: 24rpx;
|
||
}
|
||
|
||
.home-skeleton__line--asset-value {
|
||
width: 118rpx;
|
||
height: 30rpx;
|
||
}
|
||
|
||
.home-skeleton__line--feature {
|
||
width: 200rpx;
|
||
height: 28rpx;
|
||
margin-left: 20rpx;
|
||
}
|
||
|
||
.home-skeleton__line--notice {
|
||
width: 100%;
|
||
height: 24rpx;
|
||
}
|
||
|
||
.home-skeleton__line--notice-short {
|
||
width: 72%;
|
||
height: 24rpx;
|
||
margin-top: 10rpx;
|
||
}
|
||
|
||
@keyframes home-skeleton-shimmer {
|
||
0% {
|
||
transform: translateX(0);
|
||
}
|
||
|
||
100% {
|
||
transform: translateX(900rpx);
|
||
}
|
||
}
|
||
|
||
.home-hero {
|
||
position: relative;
|
||
margin-bottom: 26rpx;
|
||
}
|
||
|
||
.brand-banner {
|
||
position: relative;
|
||
overflow: hidden;
|
||
height: 380rpx;
|
||
border-radius: 28rpx;
|
||
background:
|
||
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;
|
||
border: 1px solid rgba(112, 135, 196, 0.18);
|
||
background-size: cover;
|
||
box-shadow: 0 24rpx 48rpx rgba(7, 12, 32, 0.28);
|
||
}
|
||
|
||
.brand-banner::before {
|
||
content: "";
|
||
position: absolute;
|
||
inset: 0;
|
||
background: linear-gradient(180deg, rgba(255, 255, 255, 0.02), transparent 26%);
|
||
pointer-events: none;
|
||
}
|
||
|
||
.brand-banner::after {
|
||
content: "";
|
||
position: absolute;
|
||
left: 0;
|
||
right: 0;
|
||
bottom: 0;
|
||
height: 120rpx;
|
||
background: linear-gradient(180deg, rgba(4, 10, 24, 0), rgba(4, 10, 24, 0.18));
|
||
pointer-events: none;
|
||
}
|
||
|
||
.stat-panel {
|
||
position: absolute;
|
||
z-index: 2;
|
||
left: 20rpx;
|
||
right: 20rpx;
|
||
bottom: 24rpx;
|
||
display: grid;
|
||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||
gap: 20rpx;
|
||
padding: 0;
|
||
background: transparent;
|
||
}
|
||
|
||
.stat-card {
|
||
position: relative;
|
||
overflow: hidden;
|
||
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%);
|
||
border: 1px solid rgba(121, 139, 190, 0.16);
|
||
box-shadow: 0 14rpx 24rpx rgba(5, 11, 29, 0.2);
|
||
}
|
||
|
||
.stat-card::before {
|
||
content: "";
|
||
position: absolute;
|
||
inset: 0;
|
||
background: linear-gradient(180deg, rgba(255, 255, 255, 0.05), transparent 34%);
|
||
pointer-events: none;
|
||
}
|
||
|
||
.stat-card__icon-box {
|
||
position: absolute;
|
||
right: 16rpx;
|
||
top: 16rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
width: 56rpx;
|
||
height: 56rpx;
|
||
border-radius: 8rpx;
|
||
border: 1px solid rgba(255, 255, 255, 0.08);
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.stat-card__icon-box--gold {
|
||
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%);
|
||
}
|
||
|
||
.stat-card__body {
|
||
position: relative;
|
||
z-index: 1;
|
||
display: flex;
|
||
flex-direction: column;
|
||
justify-content: flex-end;
|
||
flex: 1;
|
||
min-width: 0;
|
||
min-height: 84rpx;
|
||
margin-left: 0;
|
||
padding-right: 56rpx;
|
||
}
|
||
|
||
.stat-card__label {
|
||
display: block;
|
||
font-size: 26rpx;
|
||
font-weight: 500;
|
||
line-height: 1.25;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.stat-card--gold .stat-card__label {
|
||
color: #19b9ff;
|
||
}
|
||
|
||
.stat-card--green .stat-card__label {
|
||
color: #28e0a6;
|
||
}
|
||
|
||
.stat-card__value-row {
|
||
display: flex;
|
||
align-items: baseline;
|
||
flex-wrap: wrap;
|
||
margin-top: 16rpx;
|
||
min-width: 0;
|
||
}
|
||
|
||
.stat-card__value {
|
||
font-size: 32rpx;
|
||
font-weight: 800;
|
||
color: #ffffff;
|
||
line-height: 1;
|
||
}
|
||
|
||
.stat-card__unit {
|
||
margin-left: 8rpx;
|
||
font-size: 22rpx;
|
||
line-height: 1.2;
|
||
color: rgba(170, 181, 208, 0.92);
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.home-section {
|
||
margin-top: 28rpx;
|
||
}
|
||
|
||
.home-section__head {
|
||
margin-bottom: 16rpx;
|
||
}
|
||
|
||
.home-section__title {
|
||
font-size: 28rpx;
|
||
font-weight: 500;
|
||
color: #ffffff;
|
||
}
|
||
|
||
.asset-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||
gap: 16rpx;
|
||
}
|
||
|
||
.asset-mini-card {
|
||
position: relative;
|
||
overflow: hidden;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
min-width: 0;
|
||
height: 80rpx;
|
||
line-height: 80rpx;
|
||
padding: 0rpx 20rpx;
|
||
border-radius: 12rpx;
|
||
box-shadow: 0 12rpx 24rpx rgba(10, 16, 37, 0.16);
|
||
background: rgba(35, 45, 79, 0.9);
|
||
}
|
||
|
||
// .asset-mini-card--full {
|
||
// grid-column: 1 / -1;
|
||
// }
|
||
|
||
.asset-mini-card__bg {
|
||
position: absolute;
|
||
inset: 0;
|
||
width: 100%;
|
||
height: 100%;
|
||
}
|
||
|
||
.asset-mini-card--blue {
|
||
background: linear-gradient(135deg, #10acee 0%, #1aa4ff 100%);
|
||
}
|
||
|
||
.asset-mini-card--green {
|
||
background: linear-gradient(135deg, #25d8a4 0%, #36e08f 100%);
|
||
}
|
||
|
||
.asset-mini-card--orange {
|
||
background: linear-gradient(135deg, #ff8d58 0%, #ff7d7d 100%);
|
||
}
|
||
|
||
.asset-mini-card--violet {
|
||
background: linear-gradient(135deg, #a667f3 0%, #b27cff 100%);
|
||
}
|
||
|
||
.asset-mini-card__head,
|
||
.asset-mini-card__value {
|
||
position: relative;
|
||
z-index: 1;
|
||
}
|
||
|
||
.asset-mini-card__head {
|
||
display: flex;
|
||
font-size: 26rpx;
|
||
align-items: center;
|
||
}
|
||
|
||
.asset-mini-card__icon {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
width: 38rpx;
|
||
height: 38rpx;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.asset-mini-card__icon-image {
|
||
width: 32rpx;
|
||
height: 32rpx;
|
||
}
|
||
|
||
.asset-mini-card__label {
|
||
margin-left: 14rpx;
|
||
font-size: 26rpx;
|
||
font-weight: 500;
|
||
color: rgba(255, 255, 255, 0.94);
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.asset-mini-card__value {
|
||
display: block;
|
||
font-size: 32rpx;
|
||
font-weight: 800;
|
||
text-align: right;
|
||
color: #ffffff;
|
||
}
|
||
|
||
.feature-list {
|
||
display: grid;
|
||
gap: 16rpx;
|
||
}
|
||
|
||
.feature-list__item {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
min-height: 100rpx;
|
||
padding: 0 22rpx;
|
||
border-radius: 12rpx;
|
||
background: #242944;
|
||
box-shadow: 0 12rpx 22rpx rgba(8, 13, 30, 0.14);
|
||
}
|
||
|
||
.feature-list__main {
|
||
display: flex;
|
||
align-items: center;
|
||
min-width: 0;
|
||
}
|
||
|
||
.feature-list__icon {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
width: 36rpx;
|
||
height: 36rpx;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.feature-list__icon-image {
|
||
width: 32rpx;
|
||
height: 32rpx;
|
||
}
|
||
|
||
.feature-list__title {
|
||
margin-left: 20rpx;
|
||
font-size: 28rpx;
|
||
font-weight: 400;
|
||
color: #f3f6ff;
|
||
}
|
||
|
||
.feature-list__arrow {
|
||
margin-left: 16rpx;
|
||
width: 26rpx;
|
||
height: 26rpx;
|
||
line-height: 1;
|
||
}
|
||
|
||
.notice-bar {
|
||
display: flex;
|
||
align-items: flex-start;
|
||
margin-top: 20rpx;
|
||
padding: 0 2rpx;
|
||
}
|
||
|
||
.notice-bar__icon {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
width: 28rpx;
|
||
height: 28rpx;
|
||
margin-right: 8rpx;
|
||
margin-top: 4rpx;
|
||
background: linear-gradient(180deg, #ffd764 0%, #ffbb2e 100%);
|
||
font-size: 16rpx;
|
||
font-weight: 700;
|
||
color: #ffffff;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.notice-bar__text {
|
||
font-size: 24rpx;
|
||
line-height: 1.65;
|
||
color: rgba(200, 207, 227, 0.82);
|
||
}
|
||
</style>
|