Onlife/pages/index/index.vue
2025-04-19 15:38:48 +08:00

1395 lines
35 KiB
Vue
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="container">
<canvas canvas-id="circuitCanvas" id="circuitCanvas" class="circuit-canvas"></canvas>
<web-view :webview-styles="webviewStyles" style="visibility: hidden; height: 1px; width: 100%;" src="/static/web3/transfer-web.html" @message="handleWebViewMessage"
:fullscreen="false" :update-title="false"></web-view>
<view class="content">
<view class="title-container">
<view class="main-title">元算力(香港)-Onlife</view>
<view class="sub-title">Web3分佈式隱私計算平臺</view>
<view class="description">Prover and Validator</view>
</view>
<view class="input-container">
<view class="wallet-card" style="
background: linear-gradient(to bottom, #393C84, #9193C6);
border-radius: 10px;
padding: 10px;
box-sizing: border-box;
">
<view class="wallet-header" style="height: 120rpx;border-bottom: #787ABA 2rpx solid;">
<view class="w_h_box">
<text class="titBold">BNB</text>
<text class="Bold">{{bnbMoney || 0}}</text>
</view>
<view class="w_h_box">
<text class="titBold">USDT</text>
<text class="Bold">{{userUsdtMoney || 0}}</text>
</view>
<view class="w_h_box">
<text class="titBold">ETH</text>
<text class="Bold">{{ethMoney || 0}}</text>
</view>
<view class="w_h_box">
<text class="titBold">BTC</text>
<text class="Bold">{{btcMoney || 0}}</text>
</view>
<u-icon name="arrow-right" color="#FFF" class="w_h_detail" size="16" @click="toDetail"></u-icon>
</view>
<view class="wallet-header wallet-header-money">
<text class="titBold">錢包地址</text><text
style="font-weight: 600; font-size: 28rpx;">{{userMoneyAdressOptions(userMoneyAdress)}}</text>
<image @tap="copyAdress(userMoneyAdress)" src="/static/fuzhi.png"
style="width: 40rpx;height: 40rpx;margin-left: 10px;"></image>
</view>
<view class="wallet-footer">
<button class="w_f_btn" @click="showUpgradeModal">轉賬</button>
<button @tap="showUpgradeModal1" class="w_f_btn">收款</button>
</view>
</view>
<view class="" style="
margin-top: 30rpx;
background: linear-gradient(to bottom, #393C84, #9193C6);
border-radius: 15px;
padding: 10px;
box-sizing: border-box;
">
<view class="label">購買算力服務器</view>
<view class="input-group">
<u--input type="number" color="#fff" placeholderStyle="color: #4B4C70;" class="input"
placeholder="請輸入購買數量340倍數" v-model="purchaseAmount"></u--input>
<button class="purchase-btn" @tap="handlePurchase">購買(340U/G)</button>
</view>
<view @click="payXieyiClick" class="label" style="margin-top: 30rpx;padding-left: 10rpx;">
<checkbox-group @change="payXieyiChange" v-model="xieChecked">
<checkbox :disabled="isDisable" style="font-size: 30rpx;" value="1">我已閱讀並同意</checkbox>
</checkbox-group>
</view>
<view style="
font-size: 27rpx;
color: rgba(255,255,255,0.8);
line-height: 40rpx;
">
<text @tap.stop="modalXieyiSee" style="color: #5A27DC;">眾籌採購算力服務器協議算力服務器租賃協議</text>
</view>
</view>
</view>
</view>
<!-- 協議書 -->
<view v-if="showModalXieyi" class="modal_xieyi">
<view class="xieyi_main">
<view class="xieyi_header">
<text @tap="showModalXieyi = false">×</text>
</view>
<scroll-view @scroll="checkScroll" scroll-y="true" class="xieyi_footer">
<view v-html="xieyiTxt"></view>
</scroll-view>
</view>
</view>
<!-- 購買算力密碼彈框 -->
<view class="modal" v-if="modalName">
<view class="modal-content">
<view class="modal-header">
<view class="zz_content">請輸入驗證信息</view>
</view>
<view class="modal-body">
<view class="modal-item">
<text class="modal-label">郵箱:</text>
<view class="">{{userInfos.email}}</view>
</view>
<view class="modal-item">
<text class="modal-label">支付密碼:</text>
<u--input color="#fff" style="width: 70%;" :value="zhifuMima" :password="showPassword1"
border="none" @input="handleInput"></u--input>
<img :src="!showPassword1 ? showpwdImg : hidepwdImg" @tap="changePassword(1)"
style="width: 50rpx;height: 50rpx;"></img>
</view>
<view class="modal-item">
<text class="modal-label">郵箱驗證碼:</text>
<u--input color="#fff" style="width: 70%;" v-model="emailCodeSl" border="none"></u--input>
<view class="sendcode" @click="tosendemailSl">{{emaiTipSl}}</view>
</view>
<view class="modal-item">
<text class="modal-label">谷歌驗證碼:</text>
<u--input color="#fff" style="width: 70%;" v-model="googleCodeSl" border="none"></u--input>
<view class="sendcode" @click="googleemailSl">{{googleTipSl}}</view>
</view>
</view>
<view class="modal-footer">
<button class="modal-button cancel" @tap="hideModal">取消</button>
<button class="modal-button confirm" @tap="modalBtn">確定</button>
</view>
</view>
</view>
<!-- 轉賬密碼彈框 -->
<view class="modal" v-if="modalNamezz">
<view class="modal-content">
<view class="modal-header">
<view class="zz_content">請輸入驗證信息</view>
</view>
<view class="modal-body">
<view class="modal-item">
<text class="modal-label">郵箱:</text>
<view class="">{{userInfos.email}}</view>
</view>
<view class="modal-item">
<text class="modal-label">支付密碼:</text>
<u--input color="#fff" style="width: 70%;" :value="zhifuMimaZz" :password="showPassword2"
border="none" @input="handleInput2"></u--input>
<img :src="!showPassword2 ? showpwdImg : hidepwdImg" @tap="changePassword(2)"
style="width: 50rpx;height: 50rpx;"></img>
</view>
<view class="modal-item">
<text class="modal-label">郵箱驗證碼:</text>
<u--input color="#fff" style="width: 70%;" v-model="emailCodeZz" border="none"></u--input>
<view class="sendcode" @click="tosendemailZz">{{emaiTipZz}}</view>
</view>
<view class="modal-item">
<text class="modal-label">谷歌驗證碼:</text>
<u--input color="#fff" style="width: 70%;" v-model="googleCodeZz" border="none"></u--input>
<view class="sendcode" @click="googleemailZz">{{googleTipZz}}</view>
</view>
</view>
<view class="modal-footer">
<button class="modal-button cancel" @tap="offModalBtnZz">取消</button>
<button class="modal-button confirm" @tap="modalBtnZz">確定</button>
</view>
</view>
</view>
<!-- 收款彈框 -->
<view class="modal1" v-if="modalintMoney">
<view class="modal1-content">
<view class="modal1-header">
<text class="modal1-close" @click="modalintMoney = false">×</text>
</view>
<view class="modal1-txt">
<canvas canvas-id="qrcodes" :style="{width: `${qrcodeSize}px`, height: `${qrcodeSize}px`}" />
</view>
<view class="modal1-footer">
錢包地址<text style="flex: 1;">{{userMoneyAdressOptions1(userMoneyAdress)}}</text>
<image @tap="copyAdress(userMoneyAdress)" src="/static/fuzhi.png"
style="width: 40rpx;height: 40rpx;"></image>
</view>
</view>
</view>
<!-- 轉賬彈窗 -->
<view class="modal" v-if="showModal" @click.self="cancelUpgrade">
<view class="modal-content">
<view class="modal-header">
<text class="modal-title">轉賬確認</text>
<text class="modal-close" @click="cancelUpgrade">×</text>
</view>
<view class="modal-body">
<view class="modal-item" style="display: flex;">
<text class="modal-label">轉賬地址:</text>
<text class="modal-value">{{userMoneyAdressOptions(userMoneyAdress)}}</text>
</view>
<view class="modal-item">
<text class="modal-label">收款地址:</text>
<text class="modal-value">
<input v-model="initAdress" type="text" style="color: #fff;" />
</text>
</view>
<view class="modal-item">
<text class="modal-label">轉賬金額:</text>
<view class="modal-value">
<input v-model="outMoney" type="number" style="color: #fff;" />
</view>
</view>
<view class="modal-item">
<text class="modal-label">付款方式:</text>
<view class="modal-value">
<radio-group @change="styleChange">
<radio :checked="payMoneyStyle == 'USDT'" value="USDT">USDT</radio>
<radio :checked="payMoneyStyle == 'BNB'" value="BNB">BNB</radio>
</radio-group>
</view>
</view>
<view class="modal-item">
<text class="modal-label">訂單號:</text>
<text class="modal-value">{{orderId}}</text>
</view>
</view>
<view class="modal-footer">
<button class="modal-button cancel" @click="cancelUpgrade">取消</button>
<button class="modal-button confirm" @click="confirmUpgrade">確定</button>
</view>
</view>
</view>
<!-- 熱更新 -->
<upVersion></upVersion>
</view>
</template>
<script>
import {
_createorder,
_walletinfo,
_sendcoin,
_paysord,
_payXieyi,
_userInfos,
_emailSend
} from "@/request/api.js";
import publicFn from '@/common/publicFunction.js'
import uQRCode from '@/common/uqrcode.js'
import upVersion from "@/components/am-upVersion/am-upVersion.vue";
import {
publicjiemi
} from "@/common/jiemi.js"
import MD5 from "blueimp-md5";
export default {
components: {
upVersion
},
data() {
return {
emailCodeZz:"",
googleCodeZz:"",
emaiTipZz:"發送",
googleTipZz:"發送",
emailCodeSl:"",
googleCodeSl:"",
emaiTipSl:"發送",
googleTipSl:"發送",
webviewStyles: {
progress: false,
width: "0px",
height: "0px"
},
webviewInstance: null,
xieChecked: [],
isDisable: true,
oneSee: false,
twoSee: false,
oneNum: 0,
twoNum: 0,
xieyiTxtList: {}, //協議內容
showPassword1: true,
showPassword2: true,
showpwdImg: "static/icon/eye_on.png",
hidepwdImg: "static/icon/eye_off.png",
xieyiTxt: "",
showModalXieyi: false,
zhifuMimaZz: "",
modalNamezz: false,
initAdress: "",
outMoney: "",
payMoneyStyle: 'USDT',
showModal: false,
orderId: "",
qrcodeSize: 200,
modalintMoney: false,
isCheckXieyi: false,
modalName: false, //密碼彈窗
zhifuMima: "",
ctx: null, // Canvas 上下文
canvasWidth: 300, // Canvas 寬度
canvasHeight: 300, // Canvas 高度
circuits: [], // 存儲電路數據的數組
chips: [], // 存儲芯片數據的數組
animationFrame: null, // 用於存儲動畫幀的引用
purchaseAmount: '', // 購買數量
payInfos: {}, //購買時支付信息
userUsdtMoney: "", //usdt餘額
bnbMoney: "", //bnb餘額
ethMoney:"",
btcMoney:"",
userMoneyAdress: "", //用戶錢包地址
userInfos: {}, //用戶信息
userPrivateKey: "", //用戶私鑰
}
},
watch: {
modalName: {
handler(val) {
if (val == false) {
this.zhifuMima = "";
}
}
},
modalNamezz: {
handler(val) {
if (val == false) {
this.zhifuMimaZz = "";
}
}
}
},
onReady() {
// #ifdef APP
// 獲取當前頁面
const currentWebview = this.$scope.$getAppWebview();
// 獲取web-view組件對象
this.webviewInstance = currentWebview.children()[0];
// #endif
},
onPullDownRefresh(){
this.getUserInfos();
},
created() {
this.initCanvas();
},
mounted() {
this.getUserInfos();
this.getXieyiBook();
},
methods: {
async tosendemailSl(){
if (this.emaiTipSl == "發送") {
let num = 60;
let emaiTimer = setInterval(() => {
this.emaiTipSl = num + 's';
num--;
if (num < 0) {
this.emaiTipSl = "發送";
clearInterval(emaiTimer)
}
}, 1000)
let res = await _emailSend({
email: this.userInfos.email,
event: "check"
});
if (res.code === 1) {
uni.showToast({
title: '發送成功',
icon: 'none'
});
}else{
uni.showToast({
title: res.msg,
icon: 'none'
});
}
} else {
return
}
},
googleemailSl() {
let num = 60;
let googleTimer = setInterval(() => {
this.googleTipSl = num + 's';
num--;
if (num < 0) {
this.googleTipSl = "發送";
clearInterval(googleTimer)
}
}, 1000)
},
async tosendemailZz(){
if (this.emaiTipZz == "發送") {
let num = 60;
let emaiTimer = setInterval(() => {
this.emaiTipZz = num + 's';
num--;
if (num < 0) {
this.emaiTipZz = "發送";
clearInterval(emaiTimer)
}
}, 1000);
const params = {
email: this.userInfos.email,
event: "check",
};
console.log(params,'參數')
let res = await _emailSend(params);
if (res.code === 1) {
uni.showToast({
title: '發送成功',
icon: 'none'
});
}else{
uni.showToast({
title: res.msg,
icon: 'none'
});
}
} else {
return
}
},
googleemailZz() {
let num = 60;
let googleTimer = setInterval(() => {
this.googleTipZz = num + 's';
num--;
if (num < 0) {
this.googleTipZz = "發送";
clearInterval(googleTimer)
}
}, 1000)
},
// 接收WebView消息
handleWebViewMessage(event) {
let _that = this;
let obj = event.detail.data;
console.log('收到WebView消息:', obj);
if (obj.length > 0) {
uni.hideLoading();
if (obj[0].type == 'USDT') {
if (obj[0].status == 'success') {
uni.showToast({
title: `USDT轉帳成功`,
icon: 'none'
})
} else {
uni.showToast({
title: `USDT轉帳失敗`,
icon: 'none'
})
}
}
if (obj[0].type == 'BNB') {
if (obj[0].status == 'success') {
uni.showToast({
title: `BNB轉帳成功`,
icon: 'none'
})
} else {
uni.showToast({
title: `BNB轉帳失敗`,
icon: 'none'
})
}
}
if (obj[0].type == 'paySuanLi') {
if (obj[0].status == 'success') {
uni.showToast({
title: "打款成功",
icon: "success",
duration: 1000
})
_that.toPaysord(obj[0].hash);
} else {
uni.showToast({
title: "打款失敗",
icon: "error",
duration: 1000
})
}
}
_that.zhifuMimaZz = "";
_that.payMoneyStyle = 'USDT';
_that.emailCodeZz = "";
_that.googleCodeZz = "";
_that.emaiTipZz = "發送";
_that.googleTipZz = "發送";
_that.emailCodeSl = "";
_that.googleCodeSl = "";
_that.emaiTipSl = "發送";
_that.googleTipSl = "發送";
_that.modalNamezz = false;
_that.modalName = false;
_that.getUserInfos();
}
},
handleInput(event) {
this.zhifuMima = event;
},
handleInput2(event) {
this.zhifuMimaZz = event;
},
checkScroll(event) {
const windowHeight = uni.getSystemInfoSync().windowHeight;
const element = event.target;
if (element.scrollHeight - element.scrollTop - windowHeight < 10) {
uni.showToast({
title: "協議閱讀完成",
icon: "none",
duration: 1000
})
this.oneSee = true;
}
},
modalXieyiSee(n) {
this.xieyiTxt = this.xieyiTxtList.miner_agreement
this.showModalXieyi = true;
},
async getUserInfos() {
let res = await _userInfos();
if (res.code === 1) {
this.userInfos = res.data.userinfo;
this.userPrivateKey = uni.getStorageSync(`user_privateKey_${this.userInfos.id}`)
this.userMoneyAdress = this.userInfos.wallet.address;
this.getYuMoney();
}
},
changePassword(n) {
switch (n) {
case 1:
this.showPassword1 = !this.showPassword1;
break;
case 2:
this.showPassword2 = !this.showPassword2;
break;
case 3:
this.showPassword3 = !this.showPassword3;
break;
}
},
styleChange(e) {
this.payMoneyStyle = e.detail.value;
},
async getXieyiBook(n) {
let res = await _payXieyi();
if (res.code === 1) {
this.xieyiTxtList = res.data;
}
},
//轉賬
offModalBtnZz() {
this.modalNamezz = false;
this.emailCodeZz = "";
this.googleCodeZz = "";
this.emaiTipZz = "發送";
this.googleTipZz = "發送";
},
async modalBtnZz() {
let _that = this;
if (!_that.zhifuMimaZz || !_that.emailCodeZz || !_that.googleCodeZz) return uni.showToast({
title: '請填寫正確資訊',
icon: 'none'
})
const params = {
code: _that.emailCodeZz,
googlecode: _that.googleCodeZz,
paykey: MD5(_that.zhifuMimaZz + (Math.floor(Date.now() / 1000))),
timestamp: Math.floor(Date.now() / 1000),
}
let res = await _walletinfo(params);
if (res.code === 1) {
uni.showLoading({
title: '打款中......'
});
if (_that.payMoneyStyle == 'USDT') {
let userSiyao = await publicjiemi(2, _that.zhifuMimaZz, _that.userMoneyAdress);
const params = {
type: 'USDT',
fromAdress: _that.userMoneyAdress,
toAdress: _that.initAdress,
coin: _that.outMoney,
privateKey: userSiyao
};
if (_that.webviewInstance) {
_that.webviewInstance.evalJS(`
usdtTransfer(${JSON.stringify(params)});
`);
}
} else if (_that.payMoneyStyle == 'BNB') {
let userSiyao = await publicjiemi(2, _that.zhifuMimaZz, _that.userMoneyAdress);
const params = {
type: 'BNB',
fromAdress: _that.userMoneyAdress,
toAdress: _that.initAdress,
coin: _that.outMoney,
privateKey: userSiyao
};
if (_that.webviewInstance) {
_that.webviewInstance.evalJS(`
bnbTransfer(${JSON.stringify(params)});
`);
}
}
}
},
cancelUpgrade() {
this.showModal = false;
},
confirmUpgrade() {
let usdts = this.userUsdtMoney;
usdts > 0 ? usdts = usdts : usdts = 0;
let bnbs = this.bnbMoney;
bnbs > 0 ? bnbs = bnbs : bnbs = 0;
if (!this.initAdress) {
uni.showToast({
title: '請輸入收款地址',
icon: 'none',
})
return
}
if (!this.outMoney) {
uni.showToast({
title: '請輸入轉賬金額',
icon: 'none',
})
return
}
if (this.payMoneyStyle == 'USDT' && usdts < this.outMoney) {
uni.showToast({
title: 'USDT不足',
icon: 'none',
})
return
}
if (this.payMoneyStyle == 'BNB' && bnbs < this.outMoney) {
uni.showToast({
title: 'BNB不足',
icon: 'none',
})
return
}
this.modalNamezz = true;
this.showModal = false;
},
toDetail() {
uni.navigateTo({
url: "/pages/mymoney/moneyDetail"
})
},
//轉賬
showUpgradeModal() {
this.showModal = true;
this.orderId = 'ORD-' + Math.random().toString(36).substr(2, 9);
},
//收款
async showUpgradeModal1() {
this.modalintMoney = true;
uni.showLoading({
title: '二維碼生成中',
mask: true
})
let qrcodeUrl = this.userMoneyAdress
await uQRCode.make({
canvasId: 'qrcodes',
text: qrcodeUrl,
size: this.qrcodeSize,
margin: 10,
success: res => {
this.erweimapath = res
console.log('qrcodeSrc = ' + this.erweimapath);
},
complete: () => {
uni.hideLoading()
}
})
},
payXieyiChange(e) {
if (e.target.value.length > 0) {
this.isCheckXieyi = true;
} else {
this.isCheckXieyi = false;
}
},
payXieyiClick() {
if (this.oneSee) {
this.isDisable = false;
} else {
uni.showToast({
title: "請先宣讀協議書",
icon: "none",
duration: 1000
})
}
},
//錢包地址顯示前6後4
userMoneyAdressOptions(data) {
let start = data.substring(0, 20);
let end = data.substring(data.length - 4);
let middle = "…";
let finalString = start + middle + end;
return finalString
},
userMoneyAdressOptions1(data) {
let start = data.substring(0, 14);
let end = data.substring(data.length - 4);
let middle = "…";
let finalString = start + middle + end;
return finalString
},
copyAdress(adress) {
uni.setClipboardData({
data: adress,
success: () => {
uni.showToast({
title: '複製成功',
icon: 'success'
})
}
})
},
handleProxy() {
uni.navigateTo({
url: "/pages/myProxy/myProxy"
})
},
getYuMoney() {
let _that = this;
uni.request({
url: "https://nfta.ikiry.com/getUserBalances?address=" + this.userMoneyAdress,
success(res) {
console.log(res,'ssss');
_that.userUsdtMoney = res.data.usdtBalance;
_that.bnbMoney = res.data.bnbBalance;
_that.ethMoney = res.data.ethBalance;
_that.btcMoney = res.data.btcBBalance;
uni.stopPullDownRefresh();
}
})
},
async modalBtn() {
let _that = this;
if (!_that.zhifuMima || !_that.emailCodeSl || !_that.googleCodeSl) return uni.showToast({
title: '請填寫正確資訊',
icon: 'none'
})
const params = {
code: _that.emailCodeSl,
googlecode: _that.googleCodeSl,
paykey: MD5(_that.zhifuMima + (Math.floor(Date.now() / 1000))),
timestamp: Math.floor(Date.now() / 1000),
}
let res = await _walletinfo(params);
if (res.code === 1) {
uni.showLoading({
title: "打款中..."
})
let item = _that.payInfos;
let userSiyao = await publicjiemi(2, _that.zhifuMima, _that.userMoneyAdress);
const params = {
type: 'paySuanLi',
fromAdress: _that.userMoneyAdress,
toAdress: item.pay_address,
coin: item.fee,
privateKey: userSiyao
};
if (_that.webviewInstance) {
_that.webviewInstance.evalJS(`
usdtTransfer(${JSON.stringify(params)});
`);
}
}else{
uni.showToast({
title: res.msg,
icon: 'none'
})
}
},
// 提交打款記錄
async toPaysord(hash) {
let res = await _paysord({
oid: this.payInfos.id,
tx: hash
});
},
hideModal() {
this.modalName = false;
this.emailCodeSl = "";
this.googleCodeSl = "";
this.emaiTipSl = "發送";
this.googleTipSl = "發送";
},
// 處理購買操作
async handlePurchase() {
if (!this.isCheckXieyi) {
uni.showToast({
title: '請勾選算力服務器購買及託管協議書',
icon: 'none'
});
return
}
if (!this.purchaseAmount) {
uni.showToast({
title: '請輸入購買數量',
icon: 'none'
});
return
}
const params = {
cnt: this.purchaseAmount,
area: "000000"
};
let res = await _createorder(params);
if (res.code === 1) {
this.payInfos = res.data;
if (this.userUsdtMoney >= this.payInfos.fee) {
this.modalName = true;
} else {
uni.showToast({
title: 'USDT不足',
icon: 'none'
});
return
}
} else {
uni.showToast({
title: res.msg,
icon: 'none'
});
if (res.msg == "請先綁定上級關係") {
setTimeout(() => {
uni.navigateTo({
url: "/pages/myuser/myuser"
})
}, 500)
}
}
},
// 初始化 Canvas
initCanvas() {
// 重置電路和芯片數組
this.circuits = [];
this.chips = [];
const sysInfo = uni.getSystemInfoSync(); // 獲取系統信息
this.canvasWidth = sysInfo.windowWidth; // 設置 Canvas 寬度為窗口寬度
this.canvasHeight = sysInfo.windowHeight; // 設置 Canvas 高度為窗口高度
this.ctx = uni.createCanvasContext('circuitCanvas', this); // 創建 Canvas 上下文
this.generateCircuits(); // 生成電路
this.generateChips(); // 生成芯片
// 清除之前的動畫幀
if (this.animationFrame) {
clearTimeout(this.animationFrame);
}
this.animate(); // 開始動畫
},
// 生成電路
generateCircuits() {
const circuitCount = 50; // 電路數量
for (let i = 0; i < circuitCount; i++) {
this.circuits.push(this.createCircuit()); // 創建並添加電路
}
},
// 創建單個電路
createCircuit() {
const startX = Math.random() * this.canvasWidth; // 隨機起始 X 座標
const startY = Math.random() * this.canvasHeight; // 隨機起始 Y 座標
return {
points: this.generatePoints(startX, startY), // 生成電路點
progress: 0, // 初始進度
speed: Math.random() * 0.002 + 0.001 // 隨機速度
};
},
// 為電路生成點
generatePoints(startX, startY) {
const points = [{
x: startX,
y: startY
}]; // 起始點
let currentX = startX;
let currentY = startY;
const steps = Math.floor(Math.random() * 10) + 3; // 隨機步數3-7
for (let i = 0; i < steps; i++) {
if (Math.random() < 0.5) {
currentX += (Math.random() - 0.5) * 200; // 隨機 X 方向移動
} else {
currentY += (Math.random() - 0.5) * 200; // 隨機 Y 方向移動
}
points.push({
x: currentX,
y: currentY
}); // 添加新點
}
return points;
},
// 生成芯片
generateChips() {
const chipCount = 15; // 芯片數量
for (let i = 0; i < chipCount; i++) {
this.chips.push({
x: Math.random() * this.canvasWidth, // 隨機 X 座標
y: Math.random() * this.canvasHeight, // 隨機 Y 座標
size: Math.random() * 30 + 20 // 隨機大小20-50
});
}
},
// 動畫循環
animate() {
this.ctx.clearRect(0, 0, this.canvasWidth, this.canvasHeight); // 清除畫布
// 繪製背景
this.ctx.setFillStyle('#000033');
this.ctx.fillRect(0, 0, this.canvasWidth, this.canvasHeight);
this.drawChips(); // 繪製芯片
this.drawCircuits(); // 繪製電路
this.ctx.draw(); // 執行繪製
// 使用 setTimeout 進行動畫循環
this.animationFrame = setTimeout(() => {
this.animate(); // 循環動畫
}, 10); // 約 60fps
},
// 繪製芯片
drawChips() {
this.chips.forEach(chip => {
// 繪製芯片主體
this.ctx.setFillStyle('#001144');
this.ctx.fillRect(chip.x, chip.y, chip.size, chip.size);
// 繪製芯片內部結構
this.ctx.setStrokeStyle('#0066cc');
this.ctx.strokeRect(chip.x + 2, chip.y + 2, chip.size - 4, chip.size - 4);
// 繪製芯片引腳
this.ctx.setFillStyle('#0099ff');
for (let i = 0; i < 4; i++) {
// 上下引腳
this.ctx.fillRect(chip.x + chip.size / 5 * i, chip.y + chip.size, 3, 5);
this.ctx.fillRect(chip.x + chip.size / 5 * i, chip.y - 5, 3, 5);
// 左右引腳
this.ctx.fillRect(chip.x - 5, chip.y + chip.size / 5 * i, 5, 3);
this.ctx.fillRect(chip.x + chip.size, chip.y + chip.size / 5 * i, 5, 3);
}
});
},
// 繪製電路
drawCircuits() {
this.circuits.forEach(circuit => {
circuit.progress += circuit.speed; // 更新進度
if (circuit.progress > 1) circuit.progress = 0; // 重置進度
// 繪製電路線
this.ctx.beginPath();
this.ctx.moveTo(circuit.points[0].x, circuit.points[0].y);
for (let i = 1; i < circuit.points.length; i++) {
this.ctx.lineTo(circuit.points[i].x, circuit.points[i].y);
}
this.ctx.setStrokeStyle('rgba(0, 153, 255, 0.5)');
this.ctx.setLineWidth(1);
this.ctx.stroke();
// 繪製移動的光點
const totalLength = this.getCircuitLength(circuit.points);
const currentDist = totalLength * circuit.progress;
let distanceSoFar = 0;
for (let i = 1; i < circuit.points.length; i++) {
const segmentLength = this.distance(circuit.points[i - 1], circuit.points[i]);
if (distanceSoFar + segmentLength >= currentDist) {
const ratio = (currentDist - distanceSoFar) / segmentLength;
const x = circuit.points[i - 1].x + (circuit.points[i].x - circuit.points[i - 1].x) *
ratio;
const y = circuit.points[i - 1].y + (circuit.points[i].y - circuit.points[i - 1].y) *
ratio;
// 繪製光點
this.ctx.setFillStyle('#00ffff');
this.ctx.beginPath();
this.ctx.arc(x, y, 5, 0, Math.PI * 2);
this.ctx.fill();
// 繪製光暈效果
const gradient = this.ctx.createCircularGradient(x, y, 10);
gradient.addColorStop(0, 'rgba(0, 255, 255, 0.8)');
gradient.addColorStop(1, 'rgba(0, 255, 255, 0)');
this.ctx.setFillStyle(gradient);
this.ctx.beginPath();
this.ctx.arc(x, y, 20, 0, Math.PI * 2);
this.ctx.fill();
break;
}
distanceSoFar += segmentLength;
}
});
},
// 計算電路總長度
getCircuitLength(points) {
let length = 0;
for (let i = 1; i < points.length; i++) {
length += this.distance(points[i - 1], points[i]);
}
return length;
},
// 計算兩點之間的距離
distance(p1, p2) {
return Math.sqrt(Math.pow(p2.x - p1.x, 2) + Math.pow(p2.y - p1.y, 2));
}
},
// 組件卸載時清除動畫
onUnload() {
if (this.animationFrame) {
clearTimeout(this.animationFrame);
}
this.ctx = null;
}
}
</script>
<style lang="scss">
.modal_xieyi {
position: fixed;
left: 0;
right: 0;
bottom: 0;
top: 0;
background-color: rgba(0, 0, 0, 0.6);
z-index: 999;
.xieyi_main {
width: 100vw;
height: 100vh;
background-color: #fff;
padding: 20px;
box-sizing: border-box;
.xieyi_header {
height: 30px;
line-height: 30px;
text-align: right;
}
.xieyi_footer {
height: calc(100% - 30px);
text-indent: 2rem;
overflow-y: scroll;
}
}
}
.modal1 {
width: 80vw;
height: 50vh;
position: fixed;
top: 62.7%;
left: 50%;
transform: translate(-50%, -50%);
background-color: rgba(0, 0, 0, 0.9);
z-index: 999;
.modal1-content {
width: 100%;
height: 100%;
position: relative;
padding: 20rpx;
box-sizing: border-box;
.modal1-header {
height: 10%;
width: 100%;
text-align: right;
color: #fff;
font-size: 50rpx;
}
.modal1-txt {
height: 75%;
display: flex;
justify-content: center;
align-items: center;
}
.modal1-footer {
width: 100%;
display: flex;
align-items: center;
height: 15%;
color: #fff;
font-size: 15px;
}
}
}
.container {
width: 100vw;
height: calc(100vh - 94px);
background-color: #000033;
}
.circuit-canvas {
width: 100%;
height: 100%;
position: absolute;
z-index: 1;
top: 0;
/* 添加這行 */
left: 0;
/* 添加這行 */
}
.content {
position: absolute;
top: 0;
left: 50%;
transform: translateX(-50%);
z-index: 2;
width: 90%;
height: 100%;
}
.title-container {
text-align: center;
color: #fff;
height: 30%;
}
.input-container {
width: 100%;
height: 70%;
}
.main-title {
font-size: 24px;
font-weight: bold;
height: 80px;
line-height: 80px;
}
.sub-title {
font-size: 18px;
margin-bottom: 20px;
}
.description {
font-size: 14px;
opacity: 0.8;
}
.wallet-card {
height: 360rpx;
width: 100%;
.wallet-header-money {
overflow: hidden;
/* 超出部分隱藏 */
text-overflow: ellipsis;
/* 超出部分顯示省略號 */
white-space: nowrap;
/* 不換行 */
margin-top: 20rpx;
}
.wallet-header {
color: white;
display: flex;
flex-wrap: wrap;
height: 80rpx;
align-items: center;
width: 100%;
font-size: 25rpx;
position: relative;
.w_h_box {
width: calc(50% - 20rpx);
height: 60rpx;
display: flex;
align-items: center;
// 加粗
.Bold {
font-weight: 600;
}
.w_h_b_btn {
height: 60rpx;
line-height: 60rpx;
// background-color: #f8f8f84f;
background-color: #4CAF50;
color: #fff;
// color: #4CAF50;
border: none;
cursor: pointer;
}
}
.w_h_detail{
position: absolute;
right: 0;
top: 14rpx;
}
}
.wallet-footer {
width: 100%;
height: calc(100% - 200rpx);
display: flex;
align-items: center;
.w_f_btn {
width: 35vw;
height: 70rpx;
line-height: 70rpx;
background-color: #4F5AD7;
color: #fff;
border-radius: 50rpx;
font-size: 24rpx;
// background-color: #f8f8f84f;
// color: #4CAF50;
}
}
}
.label {
color: #fff;
font-size: 18px;
margin-bottom: 10px;
margin-top: 3%;
}
.input-group {
color: #fff;
margin-top: 20px;
display: flex;
background-color: rgba(255, 255, 255, 0.1);
border-radius: 25px;
overflow: hidden;
}
.input {
flex: 1;
height: 50px;
padding: 0 20px;
box-sizing: border-box;
color: #fff !important;
background: #DADBF3;
// background-color: rgba(0,0,0,0.7);
border: none;
font-size: 14px;
}
.shengji-btn {
width: 275px;
height: 50px;
line-height: 50px;
text-align: center;
background-color: #4caf50;
color: #fff;
border: none;
font-size: 16px;
margin-top: 20px;
border-radius: 30px;
}
.purchase-btn {
width: 100px;
height: 50px;
line-height: 50px;
text-align: center;
background-color: #4F5AD7;
color: #fff;
border: none;
font-size: 14px;
padding: 0;
border-radius: 0;
}
.modal {
position: fixed;
left: 0;
right: 0;
bottom: 0;
top: 0;
background-color: rgba(0, 0, 0, 0.6);
display: flex;
align-items: flex-end;
z-index: 999;
}
.modal-content {
background-color: #b6b5c8;
border-radius: 20px 20px 0 0;
padding: 20px;
box-sizing: border-box;
width: 100%;
animation: slideUp 0.3s ease-out;
box-shadow: 0 -4px 10px rgba(0, 0, 0, 0.1);
}
@keyframes slideUp {
from {
transform: translateY(100%);
}
to {
transform: translateY(0);
}
}
.modal-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
}
.modal-title {
font-size: 20px;
font-weight: bold;
color: #333;
}
.modal-close {
font-size: 24px;
color: #999;
cursor: pointer;
}
.modal-body {
margin-bottom: 20px;
}
.modal-item {
display: flex;
margin-bottom: 15px;
padding-bottom: 10px;
border-bottom: 1px solid #f0f0f0;
}
.modal-label {
color: #666;
font-size: 14px;
margin-right: 20rpx;
}
.modal-value {
flex: 1;
font-weight: bold;
color: #333;
font-size: 14px;
word-break: break-all;
text-align: right;
overflow: hidden;
/* 超出部分隱藏 */
text-overflow: ellipsis;
/* 超出部分顯示省略號 */
white-space: nowrap;
/* 不換行 */
}
.modal-footer {
display: flex;
justify-content: space-between;
}
.modal-button {
width: 48%;
height: 44px;
border-radius: 22px;
font-size: 16px;
font-weight: bold;
border: none;
cursor: pointer;
transition: all 0.3s ease;
}
.modal-button.cancel {
background-color: #f0f0f0;
color: #333;
}
.modal-button.cancel:hover {
background-color: #e0e0e0;
}
.modal-button.confirm {
background-color: #4CAF50;
color: white;
}
.modal-button.confirm:hover {
background-color: #45a049;
}
.titBold {
color: #DADAF6;
}
</style>
<style lang="scss">
.container {
::v-deep .uni-checkbox-input {
width: 12px;
height: 12px;
}
}
</style>