Compare commits

...
6 Commits
Author SHA1 Message Date
li 61c10db52a feat: 注册页面自动图形验证码
1. 移除邮箱/手机OTP发送逻辑
2. 新增算术图形验证码(如 15 + 3 = ?)
3. 点击验证码图片可刷新
4. 注册失败自动刷新验证码
2026-03-31 10:53:17 +08:00
li 6c085426de fix: 提款页面币种选择优化
1. "Select Coin"改为i18n国际化
2. BTC/ETH使用真实curr_id(3/4)替代静态占位ID
3. 手续费显示统一使用后端返回的process字段
2026-03-31 10:53:11 +08:00
li 2872bdc4e1 fix: 存款页面链类型过滤 + 卡顿修复
1. BTC选择时不显示ERC-20/TRC-20链选择器
2. ETH选择时过滤掉TRC-20,只保留ERC-20
3. USDT保留全部链选项
4. 静态币种(btc_static/eth_static)不调API,构造占位数据防卡顿
5. "Select Coin"改为i18n国际化
6. 银行卡存款按钮间距修复
2026-03-31 10:53:04 +08:00
li 86d0f9da49 feat: 转账页面合约账户支持 + 实时汇率显示
1. 合约账户作为转账选项(原FTKbot改为Contract)
2. BTC/ETH↔合约时显示USDT等值转换提示
3. 合约→现货时显示合约USDT可用余额
2026-03-31 10:46:20 +08:00
li ba0cead3af fix: 首页价格显示保留两位小数 + Coin Transfer菜单翻译
1. 首页价格从 price_jd 位小数改为固定2位小数
2. translateMenuNames 支持英文 Withdraw → Coin Transfer
2026-03-31 10:30:32 +08:00
li f20be4e719 fix: 英文国际化 Withdraw → Coin Transfer
首页菜单栏英文环境下 Withdraw 改为 Coin Transfer,仅修改英文
2026-03-31 10:30:26 +08:00
6 changed files with 138 additions and 67 deletions
+42 -5
View File
@@ -65,7 +65,11 @@
<view v-if="selectCurr.name" class="flex align-center"> <view v-if="selectCurr.name" class="flex align-center">
<text class="font-26">{{i18n.assets.transfer.usable}}</text> <text class="font-26">{{i18n.assets.transfer.usable}}</text>
<u-count-to fontSize="26" :color="theme.text" :endVal="available_num" :decimals="4" :duration="400"></u-count-to> <u-count-to fontSize="26" :color="theme.text" :endVal="available_num" :decimals="4" :duration="400"></u-count-to>
<text class="font-26">{{selectCurr.name}}</text> <text class="font-26">{{showConvertUnit}}</text>
</view>
<!-- 合约转换提示 -->
<view v-if="needConversion && inputNum > 0" class="margin-t-10 padding-w-22">
<text class="font-24 color-00C481"> {{convertedDisplay}}</text>
</view> </view>
<!-- <p class="font-26 color-333333">可用 {{available_num}} USDT</p> --> <!-- <p class="font-26 color-333333">可用 {{available_num}} USDT</p> -->
<view class="borderBox" :style="'background-color: '+theme.fu_bg"> <view class="borderBox" :style="'background-color: '+theme.fu_bg">
@@ -164,19 +168,52 @@
i18n() { i18n() {
return this.$t('message'); return this.$t('message');
}, },
// 是否涉及合约账户且非USDT(需要汇率转换)
needConversion() {
if (!this.selectCurr || !this.selectCurr.name) return false
const isContract = this.leftObj.id == 3 || this.rightObj.id == 3
const isUSDT = this.selectCurr.curr_id == 1 || (this.selectCurr.name || '').toUpperCase() === 'USDT'
return isContract && !isUSDT
},
// 可用余额 — 合约→现货时显示合约USDT余额
available_num() { available_num() {
if (this.needConversion && this.leftObj.id == 3) {
// 从合约转出:显示合约USDT余额
let usdtItem = this.currList.find(c => c.curr_id == 1 || (c.name || '').toUpperCase() === 'USDT')
return usdtItem ? (usdtItem.num_lh || 0) : 0
}
if(this.leftObj.id==1){ if(this.leftObj.id==1){
return this.selectCurr.num || 0 //现货数量 return this.selectCurr.num || 0
}else if(this.leftObj.id==2){ }else if(this.leftObj.id==2){
return this.selectCurr.num_fb || 0 //现货数量 return this.selectCurr.num_fb || 0
}else if(this.leftObj.id==3){ }else if(this.leftObj.id==3){
return this.selectCurr.num_lh || 0 //现货数量 return this.selectCurr.num_lh || 0
}else if(this.leftObj.id==4){ }else if(this.leftObj.id==4){
return this.selectCurr.num_qq || 0 //现货数量 return this.selectCurr.num_qq || 0
}else{ }else{
return 0; return 0;
} }
}, },
// 显示可用余额的单位
showConvertUnit() {
if (this.needConversion && this.leftObj.id == 3) {
return 'USDT'
}
return this.selectCurr.name || ''
},
// 转换后显示
convertedDisplay() {
if (!this.needConversion || !this.inputNum || this.inputNum <= 0) return ''
let rate = parseFloat(this.selectCurr.exchange) || 0
if (rate <= 0) return ''
if (this.rightObj.id == 3) {
// 现货→合约:输入BTC/ETH数量,显示USDT等值
return (this.inputNum * rate).toFixed(2) + ' USDT (合约)'
} else {
// 合约→现货:输入USDT数量,显示BTC/ETH等值
return (this.inputNum / rate).toFixed(8) + ' ' + this.selectCurr.name + ' (现货)'
}
},
count_obj() { count_obj() {
let obj = []; let obj = [];
var that = this var that = this
+11 -3
View File
@@ -67,7 +67,7 @@
</view> </view>
</view> </view>
<view class="follow-mid"> <view class="follow-mid">
<text class="follow-price">{{Number(item.usdt).toFixed(item.price_jd)}}</text> <text class="follow-price">{{Number(item.usdt).toFixed(2)}}</text>
<view class="follow-hot"> <view class="follow-hot">
<image class="follow-hot-icon" src="/static/imgs/index/huo.png" mode="aspectFit"></image> <image class="follow-hot-icon" src="/static/imgs/index/huo.png" mode="aspectFit"></image>
<text class="follow-hot-num">{{virtualFollowCount(item)}}</text> <text class="follow-hot-num">{{virtualFollowCount(item)}}</text>
@@ -384,9 +384,17 @@
}, },
} }
const lang = this.$i18n.locale || 'en-US' const lang = this.$i18n.locale || 'en-US'
// 从 locale 提取语言 key // 英文也需要翻译部分菜单名
if (lang === 'en-US') {
const enMap = { 'Withdraw': 'Coin Transfer' }
this.operatelist.forEach(item => {
if (item && item.name && enMap[item.name]) {
item.name = enMap[item.name]
}
})
return
}
let langKey = lang let langKey = lang
if (lang === 'en-US') return // 英文不需要翻译
const map = menuTranslations[langKey] const map = menuTranslations[langKey]
if (!map) return if (!map) return
this.operatelist.forEach(item => { this.operatelist.forEach(item => {
+53 -7
View File
@@ -49,7 +49,7 @@
<!-- 币种选择 --> <!-- 币种选择 -->
<view v-if="current==1" class="width-100b radiu-20 padding-w-32 padding-b-20 margin-t-20" <view v-if="current==1" class="width-100b radiu-20 padding-w-32 padding-b-20 margin-t-20"
:style="'background-color: '+theme.fu_bg+';color: '+theme.text"> :style="'background-color: '+theme.fu_bg+';color: '+theme.text">
<view class="height-90 padding-t-27 font-28 weight-bold">Select Coin</view> <view class="height-90 padding-t-27 font-28 weight-bold">{{i18n.recharge.text1}}</view>
<view class="flex align-center flex-wrap"> <view class="flex align-center flex-wrap">
<view @click="changeCoinType(item)" v-for="(item,index) in coinTypes" :key="item.id" <view @click="changeCoinType(item)" v-for="(item,index) in coinTypes" :key="item.id"
:class="currid==item.id?'onbox':'offbox'" class="numbold-font margin-r-14">{{item.name}} :class="currid==item.id?'onbox':'offbox'" class="numbold-font margin-r-14">{{item.name}}
@@ -57,13 +57,13 @@
</view> </view>
</view> </view>
<!-- 链类型 --> <!-- 链类型BTC 时不显示链选择器其他币种显示过滤后的链列表 -->
<view v-if="current==1" class="width-100b radiu-20 padding-w-32 padding-b-20 margin-t-20" <view v-if="current==1 && filteredDetail.length > 1" class="width-100b radiu-20 padding-w-32 padding-b-20 margin-t-20"
:style="'background-color: '+theme.fu_bg+';color: '+theme.text"> :style="'background-color: '+theme.fu_bg+';color: '+theme.text">
<view class="height-90 padding-t-27 font-28 weight-bold">{{i18n.recharge.text2}} <view class="height-90 padding-t-27 font-28 weight-bold">{{i18n.recharge.text2}}
</view> </view>
<view class="flex align-center flex-wrap"> <view class="flex align-center flex-wrap">
<view @click="changelian(item,index)" v-for="(item,index) in detail" <view @click="changelian(item,index)" v-for="(item,index) in filteredDetail"
:class="index==lian?'onbox':'offbox'" class="numbold-font margin-r-14">{{item.lian}} :class="index==lian?'onbox':'offbox'" class="numbold-font margin-r-14">{{item.lian}}
</view> </view>
</view> </view>
@@ -152,7 +152,7 @@
<view class="width-600 margin-0-auto margin-t-30"> <view class="width-600 margin-0-auto margin-t-30">
<u-button v-if="current==1" @click="chongzhi" class="custom-style" type="primary" style="background-color: #3ECEB2;">{{i18n.appeal.text1}} <u-button v-if="current==1" @click="chongzhi" class="custom-style" type="primary" style="background-color: #3ECEB2;">{{i18n.appeal.text1}}
</u-button> </u-button>
<u-button v-if="current==2" @click="yinhangka()" class="custom-style" type="primary" style="background-color: #3ECEB2; margin-top: 300rpx;">{{i18n.appeal.text1}} <u-button v-if="current==2" @click="yinhangka()" class="custom-style" type="primary" style="background-color: #3ECEB2; margin-top: 30rpx;">{{i18n.appeal.text1}}
</u-button> </u-button>
</view> </view>
</view> </view>
@@ -243,6 +243,28 @@
computed: { computed: {
i18n() { i18n() {
return this.$t('message'); return this.$t('message');
},
// 根据当前选中币种过滤链列表
// BTC: 只保留名称含 "BTC" 的链(或空)
// ETH: 过滤掉 TRC-20,只保留 ERC-20
// USDT: 保留全部
filteredDetail() {
if (!this.detail || this.detail.length === 0) return []
const name = (this.curr || '').toUpperCase()
if (name === 'BTC') {
// BTC 不需要链选择,只取第一条直接显示地址
return this.detail.slice(0, 1)
}
if (name === 'ETH') {
// ETH 只保留 ERC-20,过滤掉 TRC-20
const erc = this.detail.filter(item => {
const lian = (item.lian || '').toUpperCase()
return !lian.includes('TRC')
})
return erc.length > 0 ? erc : this.detail.slice(0, 1)
}
// USDT 及其他:保留全部
return this.detail
} }
}, },
onLoad(e) { onLoad(e) {
@@ -321,8 +343,17 @@
this.bankList = res.data.bank this.bankList = res.data.bank
this.detail = res.data.curr this.detail = res.data.curr
this.lian = 0 this.lian = 0
this.image = res.data.curr[0].qrcode // 根据当前币种过滤后取第一条链的地址显示
this.zhuan_address = res.data.curr[0].address const name = (this.curr || '').toUpperCase()
let firstChain = res.data.curr[0]
if (name === 'ETH' && res.data.curr.length > 0) {
const erc = res.data.curr.filter(item => {
return !(item.lian || '').toUpperCase().includes('TRC')
})
if (erc.length > 0) firstChain = erc[0]
}
this.image = firstChain ? firstChain.qrcode : ''
this.zhuan_address = firstChain ? firstChain.address : ''
} }
}) })
}, },
@@ -354,6 +385,21 @@
this.currid = item.id this.currid = item.id
this.voucher_image = '' this.voucher_image = ''
this.voucher_image_up = '' this.voucher_image_up = ''
this.lian = 0
// 静态条目(btc_static / eth_static)没有真实 API id
// 不调用 getdetails,改为构造占位链数据
if (item.id === 'btc_static') {
this.detail = [{ lian: 'BTC', qrcode: '', address: '' }]
this.image = ''
this.zhuan_address = ''
return
}
if (item.id === 'eth_static') {
this.detail = [{ lian: 'ERC-20', qrcode: '', address: '' }]
this.image = ''
this.zhuan_address = ''
return
}
this.getdetails(this.currid) this.getdetails(this.currid)
}, },
changecurr(item) { changecurr(item) {
+5 -4
View File
@@ -44,7 +44,7 @@
<!-- 币种选择 --> <!-- 币种选择 -->
<view v-if="current==1" class="width-100b radiu-20 padding-w-32 padding-b-20 margin-t-24" <view v-if="current==1" class="width-100b radiu-20 padding-w-32 padding-b-20 margin-t-24"
:style="'background-color: '+theme.fu_bg+';color: '+theme.text"> :style="'background-color: '+theme.fu_bg+';color: '+theme.text">
<view class="height-116 padding-t-27 font-28 weight-bold">Select Coin</view> <view class="height-116 padding-t-27 font-28 weight-bold">{{i18n.withdraw.text1}}</view>
<view class="flex align-center flex-wrap"> <view class="flex align-center flex-wrap">
<view @click="changeCoinType(item)" v-for="(item,index) in coinTypes" :key="item.id" <view @click="changeCoinType(item)" v-for="(item,index) in coinTypes" :key="item.id"
:class="currid==item.id?'onbox':'offbox'" class="numbold-font margin-r-14">{{item.name}}</view> :class="currid==item.id?'onbox':'offbox'" class="numbold-font margin-r-14">{{item.name}}</view>
@@ -95,7 +95,7 @@
:style="'background-color: '+theme.fu_bg+';color: '+theme.text"> :style="'background-color: '+theme.fu_bg+';color: '+theme.text">
<text class="font-28 weight-bold">{{i18n.withdraw.text7}}</text> <text class="font-28 weight-bold">{{i18n.withdraw.text7}}</text>
<view v-if="current==1" class="flex align-center"> <view v-if="current==1" class="flex align-center">
<text class="font-28 color-0165EE weight-bold">{{lian==0?data.erc_process:data.process}}</text> <text class="font-28 color-0165EE weight-bold">{{data.process}}</text>
<text class="font-28 numbold-font margin-l-10">{{curr}}</text> <text class="font-28 numbold-font margin-l-10">{{curr}}</text>
</view> </view>
<view v-if="current==2" class="flex align-center"> <view v-if="current==2" class="flex align-center">
@@ -409,13 +409,14 @@
if (res.code == 1) { if (res.code == 1) {
this.list = res.data this.list = res.data
// 构建币种选择列表,确保包含 BTC 和 ETH // 构建币种选择列表,确保包含 BTC 和 ETH
// BTC curr_id=3, ETH curr_id=4(与后端 app_currency 表对应)
let types = [...res.data] let types = [...res.data]
let names = types.map(t => t.name.toUpperCase()) let names = types.map(t => t.name.toUpperCase())
if (!names.includes('BTC')) { if (!names.includes('BTC')) {
types.push({ id: 'btc_static', name: 'BTC' }) types.push({ id: 3, name: 'BTC' })
} }
if (!names.includes('ETH')) { if (!names.includes('ETH')) {
types.push({ id: 'eth_static', name: 'ETH' }) types.push({ id: 4, name: 'ETH' })
} }
this.coinTypes = types this.coinTypes = types
this.curr = res.data[0].name this.curr = res.data[0].name
+25 -46
View File
@@ -56,8 +56,9 @@
<view class="regField"> <view class="regField">
<text class="regLabel">{{i18n.regist.code}}</text> <text class="regLabel">{{i18n.regist.code}}</text>
<view class="regInputBox regInputRow"> <view class="regInputBox regInputRow">
<input class="regInput" type="text" v-model="code" :placeholder="i18n.regist.codeTag" /> <input class="regInput" type="number" v-model="code" :placeholder="i18n.regist.codeTag" />
<text class="regCodeBtn" @click="cutTime()">{{codeText}}</text> <image class="regCaptchaImg" :src="captchaImg" mode="aspectFit" @click="loadCaptcha()"></image>
<text class="regCaptchaRefresh" @click="loadCaptcha()"></text>
</view> </view>
</view> </view>
@@ -93,22 +94,15 @@
code: '', code: '',
referral_code: '', referral_code: '',
flag: true, flag: true,
time: '获取验证码',
timeFlag: true,
agreed: false, agreed: false,
theme: '', theme: '',
captchaImg: '',
captchaKey: '',
} }
}, },
computed: { computed: {
i18n() { i18n() {
return this.$t('message'); return this.$t('message');
},
codeText() {
if (this.time > 0) {
return this.time + " s"
} else {
return this.i18n.regist.get
}
} }
}, },
onLoad(e) { onLoad(e) {
@@ -116,6 +110,7 @@
if (e && e.code) { if (e && e.code) {
this.referral_code = e.code this.referral_code = e.code
} }
this.loadCaptcha()
}, },
onShow() { onShow() {
if (uni.getStorageSync("theme") == "dark") { if (uni.getStorageSync("theme") == "dark") {
@@ -163,6 +158,7 @@
email: this.email, email: this.email,
password: this.password, password: this.password,
code: this.code, code: this.code,
captcha_key: this.captchaKey,
referral_code: this.referral_code, referral_code: this.referral_code,
} }
if (this.mobile) { if (this.mobile) {
@@ -179,40 +175,17 @@
url: '/pages/login/index?email=' + this.email url: '/pages/login/index?email=' + this.email
}) })
}, 500) }, 500)
} else {
// 注册失败刷新验证码
this.loadCaptcha()
} }
}) })
}, },
cutTime() { loadCaptcha() {
if (!this.timeFlag) return this.post('/common/captcha', {}).then(res => {
if (this.email == "") {
this.tos(this.i18n.regist.phoneTag)
return
}
uni.showLoading({
title: this.i18n.regist.loading,
mask: true
})
this.timeFlag = false
this.post('/ems/send', {
email: this.email,
event: "register",
}).then(res => {
uni.hideLoading()
if (res.code == 1) { if (res.code == 1) {
this.tos(res.msg) this.captchaImg = res.data.captcha_img
this.time = 120 this.captchaKey = res.data.captcha_key
var that = this
let timeName = setInterval(() => {
if (that.time > 0) {
that.time--
} else {
that.time = 0
that.timeFlag = true
clearInterval(timeName)
}
}, 1000)
} else {
this.timeFlag = true
} }
}) })
} }
@@ -289,13 +262,19 @@
color: #111111; color: #111111;
} }
.regCodeBtn { .regCaptchaImg {
font-size: 26rpx; width: 200rpx;
font-weight: 700; height: 60rpx;
color: #1A74FF;
margin-left: 18rpx; margin-left: 18rpx;
flex: 0 0 auto; flex: 0 0 auto;
white-space: nowrap; border-radius: 6rpx;
}
.regCaptchaRefresh {
font-size: 36rpx;
color: #1A74FF;
margin-left: 12rpx;
flex: 0 0 auto;
} }
.regAgree { .regAgree {
+2 -2
View File
@@ -128,7 +128,7 @@ module.exports = {
text2: 'ICO', text2: 'ICO',
text3: 'FTKpool', text3: 'FTKpool',
text4: 'Deposit', text4: 'Deposit',
text5: 'Withdraw', text5: 'Coin Transfer',
text6: 'Derivatives', text6: 'Derivatives',
text7: 'FTKbot', text7: 'FTKbot',
text8: 'Live Chat', text8: 'Live Chat',
@@ -789,7 +789,7 @@ module.exports = {
loading:'Loading', loading:'Loading',
xh:'Spot', xh:'Spot',
fb:'Fiat', fb:'Fiat',
lh:'FTKbot', lh:'Contract',
confirm:'Confirm', confirm:'Confirm',
cancel:'Cancel', cancel:'Cancel',
}, },