first commit
This commit is contained in:
3
.env.development
Normal file
3
.env.development
Normal file
@@ -0,0 +1,3 @@
|
||||
|
||||
# 请求域名
|
||||
VITE_APP_BASE_URL='http://server.pronhub.sbs'
|
||||
3
.env.development.example
Normal file
3
.env.development.example
Normal file
@@ -0,0 +1,3 @@
|
||||
|
||||
# 请求域名
|
||||
VITE_APP_BASE_URL=''
|
||||
3
.env.production
Normal file
3
.env.production
Normal file
@@ -0,0 +1,3 @@
|
||||
|
||||
# 请求域名
|
||||
VITE_APP_BASE_URL='http://server.pronhub.sbs'
|
||||
3
.env.production.example
Normal file
3
.env.production.example
Normal file
@@ -0,0 +1,3 @@
|
||||
|
||||
# 请求域名
|
||||
VITE_APP_BASE_URL=''
|
||||
39
.eslintrc.js
Normal file
39
.eslintrc.js
Normal file
@@ -0,0 +1,39 @@
|
||||
/* eslint-env node */
|
||||
require('@rushstack/eslint-patch/modern-module-resolution')
|
||||
|
||||
module.exports = {
|
||||
root: true,
|
||||
ignorePatterns: ['src/uni_modules/'],
|
||||
extends: [
|
||||
'plugin:vue/vue3-essential',
|
||||
'eslint:recommended',
|
||||
'@vue/eslint-config-typescript/recommended',
|
||||
'@vue/eslint-config-prettier'
|
||||
],
|
||||
rules: {
|
||||
'prettier/prettier': [
|
||||
'warn',
|
||||
{
|
||||
semi: false,
|
||||
singleQuote: true,
|
||||
printWidth: 100,
|
||||
proseWrap: 'preserve',
|
||||
bracketSameLine: false,
|
||||
endOfLine: 'auto',
|
||||
tabWidth: 4,
|
||||
useTabs: false,
|
||||
trailingComma: 'none'
|
||||
}
|
||||
],
|
||||
'vue/multi-word-component-names': 'off',
|
||||
'@typescript-eslint/no-explicit-any': 'off',
|
||||
'@typescript-eslint/ban-ts-comment': 'off',
|
||||
'no-undef': 'off',
|
||||
'vue/prefer-import-from-vue': 'off',
|
||||
'no-prototype-builtins': 'off',
|
||||
'prefer-spread': 'off',
|
||||
'@typescript-eslint/no-non-null-assertion': 'off',
|
||||
'@typescript-eslint/no-non-null-asserted-optional-chain': 'off'
|
||||
},
|
||||
globals: {}
|
||||
}
|
||||
29
.gitignore
vendored
Normal file
29
.gitignore
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
lerna-debug.log*
|
||||
|
||||
node_modules
|
||||
.DS_Store
|
||||
dist
|
||||
dist-ssr
|
||||
coverage
|
||||
*.local
|
||||
|
||||
|
||||
/cypress/videos/
|
||||
/cypress/screenshots/
|
||||
|
||||
# Editor directories and files
|
||||
.idea
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
.hbuilderx
|
||||
|
||||
20
index.html
Normal file
20
index.html
Normal file
@@ -0,0 +1,20 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<script>
|
||||
var coverSupport = 'CSS' in window && typeof CSS.supports === 'function' && (CSS.supports('top: env(a)') ||
|
||||
CSS.supports('top: constant(a)'))
|
||||
document.write(
|
||||
'<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0' +
|
||||
(coverSupport ? ', viewport-fit=cover' : '') + '" />')
|
||||
</script>
|
||||
<title></title>
|
||||
<!--preload-links-->
|
||||
<!--app-context-->
|
||||
</head>
|
||||
<body>
|
||||
<div id="app" style="max-width: 750px;"><!--app-html--></div>
|
||||
<script type="module" src="/src/main.ts"></script>
|
||||
</body>
|
||||
</html>
|
||||
6191
package-lock.json
generated
Normal file
6191
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
82
package.json
Normal file
82
package.json
Normal file
@@ -0,0 +1,82 @@
|
||||
{
|
||||
"name": "uni-preset-vue",
|
||||
"version": "0.0.0",
|
||||
"scripts": {
|
||||
"dev:app": "uni -p app",
|
||||
"dev:custom": "uni -p",
|
||||
"dev:h5": "uni",
|
||||
"dev:h5:ssr": "uni --ssr",
|
||||
"dev:mp-alipay": "uni -p mp-alipay",
|
||||
"dev:mp-baidu": "uni -p mp-baidu",
|
||||
"dev:mp-kuaishou": "uni -p mp-kuaishou",
|
||||
"dev:mp-lark": "uni -p mp-lark",
|
||||
"dev:mp-qq": "uni -p mp-qq",
|
||||
"dev:mp-toutiao": "uni -p mp-toutiao",
|
||||
"dev:mp-weixin": "uni -p mp-weixin",
|
||||
"dev:quickapp-webview": "uni -p quickapp-webview",
|
||||
"dev:quickapp-webview-huawei": "uni -p quickapp-webview-huawei",
|
||||
"dev:quickapp-webview-union": "uni -p quickapp-webview-union",
|
||||
"build:app": "uni build -p app",
|
||||
"build:custom": "uni build -p",
|
||||
"build:h5": "uni build && node scripts/release.mjs",
|
||||
"build:h5:ssr": "uni build --ssr",
|
||||
"build:mp-alipay": "uni build -p mp-alipay",
|
||||
"build:mp-baidu": "uni build -p mp-baidu",
|
||||
"build:mp-kuaishou": "uni build -p mp-kuaishou",
|
||||
"build:mp-lark": "uni build -p mp-lark",
|
||||
"build:mp-qq": "uni build -p mp-qq",
|
||||
"build:mp-toutiao": "uni build -p mp-toutiao",
|
||||
"build:mp-weixin": "uni build -p mp-weixin",
|
||||
"build:quickapp-webview": "uni build -p quickapp-webview",
|
||||
"build:quickapp-webview-huawei": "uni build -p quickapp-webview-huawei",
|
||||
"build:quickapp-webview-union": "uni build -p quickapp-webview-union",
|
||||
"lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore"
|
||||
},
|
||||
"dependencies": {
|
||||
"@dcloudio/uni-app": "^3.0.0-alpha-3050520220824001",
|
||||
"@dcloudio/uni-app-plus": "^3.0.0-alpha-3050520220824001",
|
||||
"@dcloudio/uni-components": "^3.0.0-alpha-3050520220824001",
|
||||
"@dcloudio/uni-h5": "^3.0.0-alpha-3050520220824001",
|
||||
"@dcloudio/uni-mp-alipay": "^3.0.0-alpha-3050520220824001",
|
||||
"@dcloudio/uni-mp-baidu": "^3.0.0-alpha-3050520220824001",
|
||||
"@dcloudio/uni-mp-kuaishou": "^3.0.0-alpha-3050520220824001",
|
||||
"@dcloudio/uni-mp-lark": "^3.0.0-alpha-3050520220824001",
|
||||
"@dcloudio/uni-mp-qq": "^3.0.0-alpha-3050520220824001",
|
||||
"@dcloudio/uni-mp-toutiao": "^3.0.0-alpha-3050520220824001",
|
||||
"@dcloudio/uni-mp-weixin": "^3.0.0-alpha-3050520220824001",
|
||||
"@dcloudio/uni-quickapp-webview": "^3.0.0-alpha-3050520220824001",
|
||||
"lodash-es": "^4.17.21",
|
||||
"moment": "^2.30.1",
|
||||
"pinia": "^2.0.20",
|
||||
"vconsole": "^3.14.6",
|
||||
"vue": "^3.2.37",
|
||||
"vue-i18n": "^9.2.2",
|
||||
"weixin-js-sdk": "^1.6.0",
|
||||
"z-paging": "^2.3.8"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@dcloudio/types": "^3.0.13",
|
||||
"@dcloudio/uni-automator": "^3.0.0-alpha-3050520220824001",
|
||||
"@dcloudio/uni-cli-shared": "^3.0.0-alpha-3050520220824001",
|
||||
"@dcloudio/uni-stacktracey": "^3.0.0-alpha-3050520220824001",
|
||||
"@dcloudio/vite-plugin-uni": "^3.0.0-alpha-3050520220824001",
|
||||
"@rushstack/eslint-patch": "^1.1.4",
|
||||
"@types/lodash-es": "^4.17.6",
|
||||
"@types/node": "^18.7.16",
|
||||
"@vue/eslint-config-prettier": "^7.0.0",
|
||||
"@vue/eslint-config-typescript": "^11.0.0",
|
||||
"autoprefixer": "^10.4.8",
|
||||
"eslint": "^8.22.0",
|
||||
"eslint-plugin-vue": "^9.4.0",
|
||||
"execa": "^6.1.0",
|
||||
"fs-extra": "^10.1.0",
|
||||
"postcss": "^8.4.16",
|
||||
"postcss-rem-to-responsive-pixel": "^5.1.3",
|
||||
"prettier": "^2.7.1",
|
||||
"sass": "^1.54.5",
|
||||
"tailwindcss": "^3.1.8",
|
||||
"typescript": "^4.7.4",
|
||||
"vite": "^2.9.14",
|
||||
"weapp-tailwindcss-webpack-plugin": "^1.7.0"
|
||||
}
|
||||
}
|
||||
35
scripts/release.mjs
Normal file
35
scripts/release.mjs
Normal file
@@ -0,0 +1,35 @@
|
||||
import path from 'path'
|
||||
import fsExtra from 'fs-extra'
|
||||
const { existsSync, remove, copy } = fsExtra
|
||||
const cwd = process.cwd()
|
||||
//打包发布路径,谨慎改动
|
||||
const releaseRelativePath = '../server/public/mobile'
|
||||
const distPath = path.resolve(cwd, 'dist/build/h5')
|
||||
const releasePath = path.resolve(cwd, releaseRelativePath)
|
||||
|
||||
async function build() {
|
||||
if (existsSync(releasePath)) {
|
||||
await remove(releasePath)
|
||||
}
|
||||
console.log(`文件正在复制 ==> ${releaseRelativePath}`)
|
||||
try {
|
||||
await copyFile(distPath, releasePath)
|
||||
} catch (error) {
|
||||
console.log(`\n ${error}`)
|
||||
}
|
||||
console.log(`文件已复制 ==> ${releaseRelativePath}`)
|
||||
}
|
||||
|
||||
function copyFile(sourceDir, targetDir) {
|
||||
return new Promise((resolve, reject) => {
|
||||
copy(sourceDir, targetDir, (err) => {
|
||||
if (err) {
|
||||
reject(err)
|
||||
} else {
|
||||
resolve()
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
build()
|
||||
45
src/App.vue
Normal file
45
src/App.vue
Normal file
@@ -0,0 +1,45 @@
|
||||
<script setup lang="ts">
|
||||
import { onLaunch } from '@dcloudio/uni-app'
|
||||
import { useAppStore } from './stores/app'
|
||||
import { getLangPag } from '@/api/lang'
|
||||
const appStore = useAppStore()
|
||||
|
||||
onLaunch(async () => {
|
||||
await appStore.getConfig()
|
||||
|
||||
const pag = await getLangPag({ 'lang': uni.getStorageSync('lang') })
|
||||
await pag.forEach((item : any) => {
|
||||
//先销毁再重新赋值
|
||||
uni.removeStorageSync(item.type + '.' + item.name);
|
||||
uni.setStorageSync(item.type + '.' + item.name, item.value);
|
||||
});
|
||||
if (!uni.getStorageSync('langPag')) {
|
||||
uni.setStorageSync('langPag', 1);
|
||||
|
||||
const current = getCurrentPages();
|
||||
let pageRoute = "/pages/index/index";
|
||||
if (current) {
|
||||
let pageNow = current[current.length - 1]
|
||||
pageRoute = "/" + pageNow.route;
|
||||
|
||||
let params = pageNow.$page.options
|
||||
let keys = Object.keys(params); //获取对象的key 返回对象key的数组
|
||||
let query = '';
|
||||
if (keys.length > 0) {
|
||||
query = keys.reduce((pre, cur) => {
|
||||
return pre + cur + '=' + params[cur] + '&';
|
||||
}, '?').slice(0, -1);
|
||||
}
|
||||
pageRoute += query
|
||||
}
|
||||
uni.reLaunch({
|
||||
url: pageRoute
|
||||
});
|
||||
}
|
||||
})
|
||||
</script>
|
||||
<style lang="scss">
|
||||
.uni-simple-toast__text {
|
||||
word-break: break-word !important;
|
||||
}
|
||||
</style>
|
||||
12
src/api/account.ts
Normal file
12
src/api/account.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import { client } from '@/utils/client'
|
||||
import request from '@/utils/request'
|
||||
|
||||
// 登录
|
||||
export function login(data: Record<string, any>) {
|
||||
return request.post({ url: '/login/account', data: { ...data, terminal: client } })
|
||||
}
|
||||
|
||||
//注册
|
||||
export function register(data: Record<string, any>) {
|
||||
return request.post({ url: '/login/register', data: { ...data, channel: client } })
|
||||
}
|
||||
36
src/api/app.ts
Normal file
36
src/api/app.ts
Normal file
@@ -0,0 +1,36 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
//发送短信
|
||||
export function smsSend(data: any) {
|
||||
return request.post({ url: '/sms/sendCode', data: data })
|
||||
}
|
||||
|
||||
//发送邮件
|
||||
export function emailSend(data: any) {
|
||||
return request.post({ url: '/sms/sendEmail', data: data })
|
||||
}
|
||||
|
||||
//发送邮件
|
||||
export function sendEmailNoLogin(data: any) {
|
||||
return request.post({ url: '/sms/sendEmailNoLogin', data: data })
|
||||
}
|
||||
|
||||
export function getConfig() {
|
||||
return request.get({ url: '/index/config' })
|
||||
}
|
||||
|
||||
export function getCountryCode() {
|
||||
return request.get({ url: '/index/countryCode' })
|
||||
}
|
||||
|
||||
export function uploadImage(file: any, token?: string) {
|
||||
return request.uploadFile({
|
||||
url: '/upload/image',
|
||||
filePath: file,
|
||||
name: 'file',
|
||||
header: {
|
||||
token
|
||||
},
|
||||
fileType: 'image'
|
||||
})
|
||||
}
|
||||
99
src/api/finance.ts
Normal file
99
src/api/finance.ts
Normal file
@@ -0,0 +1,99 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
//资产数据
|
||||
export function fundIndex(data : any) {
|
||||
return request.get({ url: '/finance/index', data }, { isAuth: true })
|
||||
}
|
||||
//充值
|
||||
export function recharge(data : any) {
|
||||
return request.post({ url: '/recharge/recharge', data }, { isAuth: true })
|
||||
}
|
||||
// 充值方式
|
||||
export function rechargeMethod() {
|
||||
return request.get({ url: '/recharge/method' }, { isAuth: true })
|
||||
}
|
||||
// 充值方式详情
|
||||
export function rechargeMethodDetail(data : any) {
|
||||
return request.get({ url: '/recharge/methodDetail', data }, { isAuth: true })
|
||||
}
|
||||
// 充值配置
|
||||
export function rechargeConfig() {
|
||||
return request.get({ url: '/recharge/config' }, { isAuth: true })
|
||||
}
|
||||
// 常用充值金额
|
||||
export function commonMoney() {
|
||||
return request.get({ url: '/recharge/commonMoney' }, { isAuth: true })
|
||||
}
|
||||
//充值记录
|
||||
export function rechargeRecordLists(data : any) {
|
||||
return request.get({ url: '/finance/rechargeRecordLists', data }, { isAuth: true })
|
||||
}
|
||||
//充值记录详情
|
||||
export function rechargeRecordDetail(data : any) {
|
||||
return request.get({ url: '/finance/rechargeRecordDetail', data }, { isAuth: true })
|
||||
}
|
||||
// 充值方式详情
|
||||
export function rechargeMethodDetailUdun(data : any) {
|
||||
return request.get({ url: '/recharge/methodDetailUdun', data }, { isAuth: true })
|
||||
}
|
||||
// 充值方式详情
|
||||
export function rechargeMethodDetailTron(data : any) {
|
||||
return request.get({ url: '/recharge/methodDetailTron', data }, { isAuth: true })
|
||||
}
|
||||
// 充值方式详情
|
||||
export function rechargeMethodDetailAddress(data : any) {
|
||||
return request.get({ url: '/recharge/methodDetailAddress', data }, { isAuth: true })
|
||||
}
|
||||
//获取提现方式
|
||||
export function getWithdrawMethod() {
|
||||
return request.get({ url: '/finance/withdrawMethod' }, { isAuth: true })
|
||||
}
|
||||
//获取提现钱包
|
||||
export function getWithdrawWallet() {
|
||||
return request.get({ url: '/finance/withdrawWallet' }, { isAuth: true })
|
||||
}
|
||||
//绑定提现钱包
|
||||
export function withdrawWalletAdd(data : any) {
|
||||
return request.post({ url: '/finance/withdrawWalletAdd', data }, { isAuth: true })
|
||||
}
|
||||
//获取提现银行
|
||||
export function getWithdrawBanks() {
|
||||
return request.get({ url: '/finance/withdrawBanks' }, { isAuth: true })
|
||||
}
|
||||
//提现配置
|
||||
export function withdrawConfig(data : any) {
|
||||
return request.get({ url: '/finance/withdrawConfig', data }, { isAuth: true })
|
||||
}
|
||||
//提现
|
||||
export function withdraw(data : any) {
|
||||
return request.post({ url: '/finance/withdraw', data }, { isAuth: true })
|
||||
}
|
||||
//提现记录
|
||||
export function withdrawRecordLists(data : any) {
|
||||
return request.get({ url: '/finance/withdrawRecordLists', data }, { isAuth: true })
|
||||
}
|
||||
//提现记录详情
|
||||
export function withdrawRecordDetail(data : any) {
|
||||
return request.get({ url: '/finance/withdrawRecordDetail', data }, { isAuth: true })
|
||||
}
|
||||
|
||||
//资金明细
|
||||
export function financeLists(data : any) {
|
||||
return request.get({ url: '/finance/lists', data }, { isAuth: true })
|
||||
}
|
||||
//资金明细详情
|
||||
export function financeDetail(data : any) {
|
||||
return request.get({ url: '/finance/detail', data }, { isAuth: true })
|
||||
}
|
||||
//用户转账详情
|
||||
export function transferIndex() {
|
||||
return request.get({ url: '/finance/transferIndex' }, { isAuth: true })
|
||||
}
|
||||
//转账
|
||||
export function transfer(data : any) {
|
||||
return request.post({ url: '/finance/transfer', data }, { isAuth: true })
|
||||
}
|
||||
//转账明细
|
||||
export function transferRecordLists(data : any) {
|
||||
return request.get({ url: '/finance/transferRecordLists', data }, { isAuth: true })
|
||||
}
|
||||
26
src/api/item.ts
Normal file
26
src/api/item.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
// 首页数据
|
||||
export function getIndex() {
|
||||
return request.get({ url: '/item/index' }, { isAuth: true })
|
||||
}
|
||||
|
||||
// 详情
|
||||
export function getDetail(data : any) {
|
||||
return request.get({ url: '/item/detail', data }, { isAuth: true })
|
||||
}
|
||||
|
||||
// 合同
|
||||
export function getContract(data : any) {
|
||||
return request.get({ url: '/item/contract', data }, { isAuth: true })
|
||||
}
|
||||
|
||||
//投资
|
||||
export function invest(data : any) {
|
||||
return request.post({ url: '/item/invest', data }, { isAuth: true })
|
||||
}
|
||||
|
||||
//投资记录
|
||||
export function recordLists(data : any) {
|
||||
return request.get({ url: '/item/recordLists', data }, { isAuth: true })
|
||||
}
|
||||
6
src/api/kefu.ts
Normal file
6
src/api/kefu.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
//客服列表
|
||||
export function getKefuLists() {
|
||||
return request.get({ url: '/index/getKefuLists'})
|
||||
}
|
||||
19
src/api/lang.ts
Normal file
19
src/api/lang.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
//获取语言包
|
||||
export function getLangPag(data : any) {
|
||||
return request.get({ url: '/language/pagAll', data })
|
||||
}
|
||||
//获取所有语言
|
||||
export function getLangAll() {
|
||||
return request.get({ url: '/language/all'})
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 获取语言详情
|
||||
* @param { string } name
|
||||
* @return { Promise }
|
||||
*/
|
||||
export function getLangDetail(data: { name: string }) {
|
||||
return request.get({ url: '/language/detail', data: data })
|
||||
}
|
||||
31
src/api/mall.ts
Normal file
31
src/api/mall.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
// 首页数据
|
||||
export function getIndex() {
|
||||
return request.get({ url: '/mall/index' }, { isAuth: true })
|
||||
}
|
||||
|
||||
//兑换
|
||||
export function buy(data : any) {
|
||||
return request.post({ url: '/mall/buy', data }, { isAuth: true })
|
||||
}
|
||||
|
||||
//兑换记录
|
||||
export function recordLists(data : any) {
|
||||
return request.get({ url: '/mall/recordLists', data }, { isAuth: true })
|
||||
}
|
||||
|
||||
// 抽奖数据
|
||||
export function getDrawIndex() {
|
||||
return request.get({ url: '/mall/drawIndex' }, { isAuth: true })
|
||||
}
|
||||
|
||||
//抽奖
|
||||
export function draw(data : any) {
|
||||
return request.post({ url: '/mall/draw', data }, { isAuth: true })
|
||||
}
|
||||
|
||||
//抽奖记录
|
||||
export function drawLists(data : any) {
|
||||
return request.get({ url: '/mall/drawLists', data }, { isAuth: true })
|
||||
}
|
||||
35
src/api/news.ts
Normal file
35
src/api/news.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
/**
|
||||
* @description 获取文章分类
|
||||
* @return { Promise }
|
||||
*/
|
||||
export function getArticleCate() {
|
||||
return request.get({ url: '/article/cate' })
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 获取文章列表
|
||||
* @return { Promise }
|
||||
*/
|
||||
export function getArticleList(data: Record<string, any>) {
|
||||
return request.get({ url: '/article/lists', data: data })
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 获取文章详情
|
||||
* @param { number } id
|
||||
* @return { Promise }
|
||||
*/
|
||||
export function getArticleDetail(data: { id: number }) {
|
||||
return request.get({ url: '/article/detail', data: data })
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 获取提示内容
|
||||
* @param { number } id
|
||||
* @return { Promise }
|
||||
*/
|
||||
export function getHintDetail(data: { id: number }) {
|
||||
return request.get({ url: '/article/hintDetail', data: data })
|
||||
}
|
||||
29
src/api/robot.ts
Normal file
29
src/api/robot.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
// 首页数据
|
||||
export function getIndex(data : any) {
|
||||
return request.get({ url: '/robot/index', data }, { isAuth: true })
|
||||
}
|
||||
//量化买入
|
||||
export function buy(data : any) {
|
||||
return request.post({ url: '/robot/buy', data }, { isAuth: true })
|
||||
}
|
||||
//量化记录
|
||||
export function recordLists(data : any) {
|
||||
return request.get({ url: '/robot/recordLists', data }, { isAuth: true })
|
||||
}
|
||||
|
||||
|
||||
//抢单
|
||||
export function grab(data : any) {
|
||||
return request.post({ url: '/robot/grab', data }, { isAuth: true })
|
||||
}
|
||||
//获取进行中订单
|
||||
export function grabIngRecord() {
|
||||
return request.get({ url: '/robot/grabIngRecord' }, { isAuth: true })
|
||||
}
|
||||
|
||||
//订单支付
|
||||
export function grabPay(data : any) {
|
||||
return request.post({ url: '/robot/grabPay', data }, { isAuth: true })
|
||||
}
|
||||
11
src/api/shop.ts
Normal file
11
src/api/shop.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
//首页数据
|
||||
export function getIndex() {
|
||||
return request.get({ url: '/index/index' })
|
||||
}
|
||||
|
||||
//行情数据
|
||||
export function getMarket() {
|
||||
return request.get({ url: '/index/market' })
|
||||
}
|
||||
10
src/api/team.ts
Normal file
10
src/api/team.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
// 团队 首页数据
|
||||
export function getTeamIndex() {
|
||||
return request.get({ url: '/team/index'}, { isAuth: true })
|
||||
}
|
||||
// 团队列表
|
||||
export function teamLists(data : any) {
|
||||
return request.get({ url: '/team/lists', data }, { isAuth: true })
|
||||
}
|
||||
129
src/api/user.ts
Normal file
129
src/api/user.ts
Normal file
@@ -0,0 +1,129 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
//个人中心数据
|
||||
export function getUserIndex() {
|
||||
return request.get({ url: '/user/index' }, { isAuth: true })
|
||||
}
|
||||
// 分享 首页数据
|
||||
export function getShareIndex() {
|
||||
return request.get({ url: '/user/shareIndex' }, { isAuth: true })
|
||||
}
|
||||
// 个人信息
|
||||
export function getUserInfo() {
|
||||
return request.get({ url: '/user/info' }, { isAuth: true })
|
||||
}
|
||||
|
||||
// 个人编辑
|
||||
export function userEdit(data : any) {
|
||||
return request.post({ url: '/user/setInfo', data }, { isAuth: true })
|
||||
}
|
||||
|
||||
// 绑定手机
|
||||
export function userBindMobile(data : any, header ?: any) {
|
||||
return request.post({ url: '/user/bindMobile', data, header }, { isAuth: true })
|
||||
}
|
||||
|
||||
// 更改登录密码
|
||||
export function userChangePwd(data : any) {
|
||||
return request.post({ url: '/user/changePassword', data }, { isAuth: true })
|
||||
}
|
||||
|
||||
//忘记密码
|
||||
export function forgotPassword(data : Record<string, any>) {
|
||||
return request.post({ url: '/user/resetPassword', data })
|
||||
}
|
||||
|
||||
// 更改支付密码
|
||||
export function userChangePayPwd(data : any) {
|
||||
return request.post({ url: '/user/changePayPassword', data }, { isAuth: true })
|
||||
}
|
||||
|
||||
// 设置支付密码
|
||||
export function setPayPwd(data : any) {
|
||||
return request.post({ url: '/user/setPayPwd', data }, { isAuth: true })
|
||||
}
|
||||
|
||||
// 用户消息
|
||||
export function getUserNotice() {
|
||||
return request.get({ url: '/user/notice' }, { isAuth: true })
|
||||
}
|
||||
|
||||
//用户消息列表
|
||||
export function getUserNoticeLists(data : any) {
|
||||
return request.get({ url: '/user/noticeLists', data }, { isAuth: true })
|
||||
}
|
||||
|
||||
//用户消息详情
|
||||
export function getUserNoticeDetail(data : { id : number }) {
|
||||
return request.get({ url: '/user/noticeDetail', data: data })
|
||||
}
|
||||
|
||||
//奖励活动数据
|
||||
export function getActivityIndex() {
|
||||
return request.get({ url: '/user/activityIndex' }, { isAuth: true })
|
||||
}
|
||||
|
||||
//任务中心数据
|
||||
export function getMissionIndex() {
|
||||
return request.get({ url: '/user/missionIndex' }, { isAuth: true })
|
||||
}
|
||||
|
||||
//领取任务奖励
|
||||
export function missionReward(data : any) {
|
||||
return request.post({ url: '/user/missionReward', data: data })
|
||||
}
|
||||
|
||||
//意见反馈类型
|
||||
export function getFeedbackCate() {
|
||||
return request.get({ url: '/user/feedbackCate' }, { isAuth: true })
|
||||
}
|
||||
|
||||
//意见反馈
|
||||
export function feedback(data : any) {
|
||||
return request.post({ url: '/user/feedback', data }, { isAuth: true })
|
||||
}
|
||||
|
||||
//Google Authenticator校验
|
||||
export function verifyGoogle(data : any) {
|
||||
return request.post({ url: '/user/verifyGoogle', data }, { isAuth: true })
|
||||
}
|
||||
|
||||
//邮箱校验
|
||||
export function verifyEmail(data : any) {
|
||||
return request.post({ url: '/user/verifyEmail', data }, { isAuth: true })
|
||||
}
|
||||
|
||||
//实名认证
|
||||
export function verifyRealname(data : any) {
|
||||
return request.post({ url: '/user/verifyRealname', data }, { isAuth: true })
|
||||
}
|
||||
|
||||
//签到配置
|
||||
export function signinConfig() {
|
||||
return request.get({ url: '/user/signinConfig' }, { isAuth: true })
|
||||
}
|
||||
|
||||
//签到
|
||||
export function signin(data : any) {
|
||||
return request.post({ url: '/user/signin', data }, { isAuth: true })
|
||||
}
|
||||
|
||||
//挖矿 首页数据
|
||||
export function getMineIndex() {
|
||||
return request.get({ url: '/user/mineIndex' }, { isAuth: true })
|
||||
}
|
||||
|
||||
//挖矿记录
|
||||
export function getMineLists(data : any) {
|
||||
return request.get({ url: '/user/mineLists', data }, { isAuth: true })
|
||||
}
|
||||
|
||||
//矿机 启动
|
||||
export function mineStart(data : any) {
|
||||
return request.post({ url: '/user/mineStart', data }, { isAuth: true })
|
||||
}
|
||||
|
||||
//矿机 领取收益
|
||||
export function mineReceive(data : any) {
|
||||
return request.post({ url: '/user/mineReceive', data }, { isAuth: true })
|
||||
}
|
||||
15
src/api/vip.ts
Normal file
15
src/api/vip.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
//会员首页数据
|
||||
export function getIndex() {
|
||||
return request.get({ url: '/userMember/index' }, { isAuth: true })
|
||||
}
|
||||
//会员列表
|
||||
export function vipAll() {
|
||||
return request.get({ url: '/userMember/all' }, { isAuth: true })
|
||||
}
|
||||
|
||||
//加入会员
|
||||
export function vipJoin(data : any) {
|
||||
return request.post({ url: '/userMember/join', data }, { isAuth: true })
|
||||
}
|
||||
102
src/components/avatar-upload/avatar-upload.vue
Normal file
102
src/components/avatar-upload/avatar-upload.vue
Normal file
@@ -0,0 +1,102 @@
|
||||
<template>
|
||||
<button class="avatar-upload p-0 m-0 rounded" :style="styles" hover-class="none" open-type="chooseAvatar"
|
||||
@click="chooseAvatar" @chooseavatar="chooseAvatar">
|
||||
<image class="w-full h-full" mode="heightFix" :src="modelValue" v-if="modelValue" />
|
||||
<slot v-else>
|
||||
<div :style="styles"
|
||||
class="border border-dotted border-light flex w-full h-full flex-col items-center justify-center text-muted text-xs box-border rounded">
|
||||
<u-icon name="plus" :size="36" />
|
||||
{{t('user.avatarAddImg')}}
|
||||
</div>
|
||||
</slot>
|
||||
</button>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { uploadImage } from '@/api/app'
|
||||
import { useUserStore } from '@/stores/user'
|
||||
import { addUnit } from '@/utils/util'
|
||||
import { isBoolean } from 'lodash'
|
||||
import { computed, CSSProperties, onUnmounted } from 'vue'
|
||||
import { t } from '@/utils/util'
|
||||
|
||||
const props = defineProps({
|
||||
modelValue: {
|
||||
type: String
|
||||
},
|
||||
fileKey: {
|
||||
type: String,
|
||||
default: 'uri'
|
||||
},
|
||||
size: {
|
||||
type: [String, Number],
|
||||
default: 120
|
||||
},
|
||||
round: {
|
||||
type: [Boolean, String, Number],
|
||||
default: false
|
||||
},
|
||||
border: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
})
|
||||
const emit = defineEmits<{
|
||||
(event : 'update:modelValue', value : string) : void
|
||||
}>()
|
||||
const userStore = useUserStore()
|
||||
const styles = computed<CSSProperties>(() => {
|
||||
const size = addUnit(props.size)
|
||||
return {
|
||||
width: size,
|
||||
height: size,
|
||||
borderRadius: isBoolean(props.round) ? (props.round ? '50%' : '') : addUnit(props.round)
|
||||
}
|
||||
})
|
||||
|
||||
const chooseAvatar = (e : any) => {
|
||||
//// #ifndef MP-WEIXIN
|
||||
uni.navigateTo({
|
||||
url: '/uni_modules/vk-uview-ui/components/u-avatar-cropper/u-avatar-cropper?destWidth=300&rectWidth=200&fileType=jpg'
|
||||
})
|
||||
// // #endif
|
||||
// // #ifdef MP-WEIXIN
|
||||
// const path = e.detail?.avatarUrl
|
||||
// if (path) {
|
||||
// uploadImageIng(path)
|
||||
// }
|
||||
// // #endif
|
||||
}
|
||||
|
||||
const uploadImageIng = async (file : string) => {
|
||||
uni.showLoading({
|
||||
title: t('user.avatarUploading')
|
||||
})
|
||||
try {
|
||||
const res : any = await uploadImage(file, userStore.temToken!)
|
||||
uni.hideLoading()
|
||||
console.log(res)
|
||||
emit('update:modelValue', res[props.fileKey])
|
||||
} catch (error) {
|
||||
uni.hideLoading()
|
||||
uni.$u.toast(error)
|
||||
}
|
||||
}
|
||||
// 监听从裁剪页发布的事件,获得裁剪结果
|
||||
uni.$on('uAvatarCropper', (path) => {
|
||||
uploadImageIng(path)
|
||||
})
|
||||
onUnmounted(() => {
|
||||
uni.$off('uAvatarCropper')
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.avatar-upload {
|
||||
background: #fff;
|
||||
overflow: hidden;
|
||||
|
||||
&::after {
|
||||
border: none;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
88
src/components/country-code/country-code.vue
Normal file
88
src/components/country-code/country-code.vue
Normal file
@@ -0,0 +1,88 @@
|
||||
<template>
|
||||
<u-popup v-model="show" @close="handleClose" mode="bottom" height="60%" class="max-w-[750px]">
|
||||
<view class="fixed w-full bg-[#1B1F45] z-10 py-[16rpx]">
|
||||
<view class="text-center font-bold py-[16rpx]">
|
||||
{{t('login.countryCodeChoose')}}
|
||||
</view>
|
||||
<view class="px-[40rpx]">
|
||||
<u-search shape="square" :show-action="false" :placeholder="t('login.countryCodeSearch')" v-model="formData.keyword"></u-search>
|
||||
</view>
|
||||
|
||||
</view>
|
||||
<view class="pt-[200rpx]">
|
||||
<view v-for="item in keywordFliter" @click="handleChoose(item)" >
|
||||
<view class="flex justify-start items-center px-[40rpx] py-[10rpx]">
|
||||
<view class="mt-[16rpx]">
|
||||
<u-icon width="60rpx" height="40rpx" :name="item.logo"></u-icon>
|
||||
</view>
|
||||
<view class="ml-[20rpx] mr-[10rpx]">
|
||||
{{item.name}}
|
||||
</view>
|
||||
<view class="">
|
||||
( {{item.code}} )
|
||||
</view>
|
||||
</view>
|
||||
|
||||
</view>
|
||||
</view>
|
||||
|
||||
</u-popup>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { reactive, computed } from 'vue'
|
||||
import { t } from '@/utils/util'
|
||||
|
||||
const props = defineProps({
|
||||
list: {
|
||||
type: Array
|
||||
},
|
||||
show: {
|
||||
type: Boolean,
|
||||
}
|
||||
})
|
||||
const emit = defineEmits<{
|
||||
(event : 'update', value : any) : void
|
||||
}>()
|
||||
|
||||
const formData = reactive({
|
||||
keyword: '',
|
||||
})
|
||||
|
||||
//根据输入框内容塞选
|
||||
const keywordFliter = computed(() => {
|
||||
const lists = props.list??[]
|
||||
if (!formData.keyword) {
|
||||
return props.list
|
||||
}
|
||||
const inputValue = formData.keyword
|
||||
return lists.filter((item: any) => {
|
||||
if (item['code'].indexOf(inputValue) !== -1) {
|
||||
return item
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
const handleChoose = async (item:any) => {
|
||||
emit('update', {
|
||||
code: item['code'],
|
||||
show: false
|
||||
})
|
||||
}
|
||||
const handleClose = async () => {
|
||||
emit('update', {
|
||||
code: '',
|
||||
show: false
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.avatar-upload {
|
||||
background: #fff;
|
||||
overflow: hidden;
|
||||
|
||||
&::after {
|
||||
border: none;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
20
src/components/header/dark.vue
Normal file
20
src/components/header/dark.vue
Normal file
@@ -0,0 +1,20 @@
|
||||
<template>
|
||||
<view class="max-w-[750px]">
|
||||
<u-navbar :back-text="title" :back-text-style="{color: '#FFFFFF'}" :background="{backgroundColor: backgroundColor}" back-icon-color="#FFFFFF" title-color="#FFFFFF" height="50"></u-navbar>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
const props = withDefaults(
|
||||
defineProps < {
|
||||
title: String,
|
||||
backgroundColor: String,
|
||||
} > (), {
|
||||
title: '',
|
||||
backgroundColor: '#4E55AF',
|
||||
}
|
||||
)
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
</style>
|
||||
97
src/components/mplogin-popup/mplogin-popup.vue
Normal file
97
src/components/mplogin-popup/mplogin-popup.vue
Normal file
@@ -0,0 +1,97 @@
|
||||
<template>
|
||||
<view>
|
||||
<u-popup v-model="showPopup" mode="bottom" border-radius="14" :mask-close-able="false">
|
||||
<view class="h-[1000rpx] p-[40rpx]">
|
||||
<view class="flex items-center">
|
||||
<image
|
||||
class="w-[100rpx] h-[100rpx] rounded"
|
||||
mode="heightFix"
|
||||
:src="logo"
|
||||
></image>
|
||||
<text class="text-3xl ml-5 font-bold">{{ title }}</text>
|
||||
</view>
|
||||
<view class="mt-5 text-muted">
|
||||
建议使用您的微信头像和昵称,以便获得更好的体验
|
||||
</view>
|
||||
<view class="mt-[30rpx]">
|
||||
<form @submit="handleSubmit">
|
||||
<u-form-item required label="头像" :labelWidth="120">
|
||||
<view class="flex-1">
|
||||
<avatar-upload v-model="avatar"></avatar-upload>
|
||||
</view>
|
||||
</u-form-item>
|
||||
<u-form-item required label="昵称" :labelWidth="120">
|
||||
<input
|
||||
class="flex-1 h-[60rpx]"
|
||||
name="nickname"
|
||||
type="nickname"
|
||||
placeholder="请输入昵称"
|
||||
/>
|
||||
</u-form-item>
|
||||
<view class="mt-[80rpx]">
|
||||
<button
|
||||
class="bg-primary rounded-full text-white text-lg h-[80rpx] leading-[80rpx]"
|
||||
hover-class="none"
|
||||
form-type="submit"
|
||||
>
|
||||
确定
|
||||
</button>
|
||||
</view>
|
||||
|
||||
<view class="flex justify-center mt-[60rpx]">
|
||||
<view class="text-muted" @click="showPopup = false">暂不登录</view>
|
||||
</view>
|
||||
</form>
|
||||
</view>
|
||||
</view>
|
||||
</u-popup>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, ref } from 'vue'
|
||||
const props = defineProps({
|
||||
show: {
|
||||
type: Boolean
|
||||
},
|
||||
logo: {
|
||||
type: String
|
||||
},
|
||||
title: {
|
||||
type: String
|
||||
}
|
||||
})
|
||||
const emit = defineEmits<{
|
||||
(event: 'update:show', show: boolean): void
|
||||
(event: 'update', value: any): void
|
||||
}>()
|
||||
|
||||
const showPopup = computed({
|
||||
get() {
|
||||
return props.show
|
||||
},
|
||||
set(val) {
|
||||
emit('update:show', val)
|
||||
}
|
||||
})
|
||||
|
||||
const avatar = ref()
|
||||
|
||||
const handleSubmit = (e: any) => {
|
||||
const { nickname } = e.detail.value
|
||||
if (!avatar.value)
|
||||
return uni.$u.toast({
|
||||
title: '请添加头像'
|
||||
})
|
||||
if (!nickname)
|
||||
return uni.$u.toast({
|
||||
title: '请输入昵称'
|
||||
})
|
||||
emit('update', {
|
||||
avatar: avatar.value,
|
||||
nickname
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
44
src/components/news-card/news-card.vue
Normal file
44
src/components/news-card/news-card.vue
Normal file
@@ -0,0 +1,44 @@
|
||||
<template>
|
||||
<navigator :url="`/pages/news_detail/news_detail?id=${newsId}`">
|
||||
<view class="news-card flex px-[20rpx] py-[32rpx]">
|
||||
<view class="mr-[20rpx]" v-if="item.image">
|
||||
<u-image :src="item.image" width="240" height="180"></u-image>
|
||||
</view>
|
||||
<view class="news-card-content flex flex-col justify-between flex-1">
|
||||
<view class="news-card-content-title text-lg font-medium">{{ item.title }}</view>
|
||||
</view>
|
||||
<u-icon name="arrow-right" class="text-muted" size="28"></u-icon>
|
||||
</view>
|
||||
</navigator>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue'
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
item: any
|
||||
newsId: number
|
||||
}>(),
|
||||
{
|
||||
item: {},
|
||||
newsId: ''
|
||||
}
|
||||
)
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.news-card {
|
||||
border-bottom: 1px solid #f8f8f8;
|
||||
&-content {
|
||||
&-title {
|
||||
-webkit-line-clamp: 1;
|
||||
overflow: hidden;
|
||||
word-break: break-all;
|
||||
text-overflow: ellipsis;
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
62
src/components/page-status/page-status.vue
Normal file
62
src/components/page-status/page-status.vue
Normal file
@@ -0,0 +1,62 @@
|
||||
<template>
|
||||
<view
|
||||
class="page-status"
|
||||
v-if="status !== PageStatusEnum['NORMAL']"
|
||||
:class="{ 'page-status--fixed': fixed }"
|
||||
>
|
||||
<!-- Loading -->
|
||||
<template v-if="status === PageStatusEnum['LOADING']">
|
||||
<slot name="loading">
|
||||
<u-loading :size="60" mode="flower" />
|
||||
</slot>
|
||||
</template>
|
||||
<!-- Error -->
|
||||
<template v-if="status === PageStatusEnum['ERROR']">
|
||||
<slot name="error"></slot>
|
||||
</template>
|
||||
<!-- Empty -->
|
||||
<template v-if="status === PageStatusEnum['EMPTY']">
|
||||
<slot name="empty"></slot>
|
||||
</template>
|
||||
</view>
|
||||
<template v-else>
|
||||
<slot> </slot>
|
||||
</template>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { PageStatusEnum } from '@/enums/appEnums'
|
||||
|
||||
const props = defineProps({
|
||||
status: {
|
||||
type: String,
|
||||
default: PageStatusEnum['LOADING']
|
||||
},
|
||||
fixed: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.page-status {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
min-height: 100%;
|
||||
padding: 0;
|
||||
flex: 1;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
background-color: #ffffff;
|
||||
&--fixed {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
z-index: 900;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
322
src/components/payment/payment.vue
Normal file
322
src/components/payment/payment.vue
Normal file
@@ -0,0 +1,322 @@
|
||||
<template>
|
||||
<u-popup
|
||||
v-model="showPay"
|
||||
mode="bottom"
|
||||
safe-area-inset-bottom
|
||||
:mask-close-able="false"
|
||||
border-radius="14"
|
||||
closeable
|
||||
@close="handleClose"
|
||||
>
|
||||
<view class="h-[900rpx]">
|
||||
<page-status :status="popupStatus" :fixed="false">
|
||||
<template #error>
|
||||
<u-empty text="订单信息错误,无法查询到订单信息" mode="order"></u-empty>
|
||||
</template>
|
||||
<template #default>
|
||||
<view class="payment h-full w-full flex flex-col">
|
||||
<view class="header py-[50rpx] flex flex-col items-center">
|
||||
<price
|
||||
:content="payData.order_amount"
|
||||
mainSize="44rpx"
|
||||
minorSize="40rpx"
|
||||
fontWeight="500"
|
||||
color="#333"
|
||||
></price>
|
||||
</view>
|
||||
<view class="main flex-1 mx-[20rpx]">
|
||||
<view>
|
||||
<view class="payway-lists">
|
||||
<u-radio-group v-model="payWay" class="w-full">
|
||||
<view
|
||||
class="p-[20rpx] flex items-center w-full payway-item"
|
||||
v-for="(item, index) in payData.lists"
|
||||
:key="index"
|
||||
@click="selectPayWay(item.pay_way)"
|
||||
>
|
||||
<u-icon
|
||||
class="flex-none"
|
||||
:size="48"
|
||||
:name="item.icon"
|
||||
></u-icon>
|
||||
<view class="mx-[16rpx] flex-1">
|
||||
<view class="payway-item--name flex-1">
|
||||
{{ item.name }}
|
||||
</view>
|
||||
<view class="text-muted text-xs">{{
|
||||
item.extra
|
||||
}}</view>
|
||||
</view>
|
||||
|
||||
<u-radio class="mr-[-20rpx]" :name="item.pay_way">
|
||||
</u-radio>
|
||||
</view>
|
||||
</u-radio-group>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="submit-btn p-[20rpx]">
|
||||
<u-button
|
||||
@click="handlePay"
|
||||
shape="circle"
|
||||
type="primary"
|
||||
:loading="isLock"
|
||||
>
|
||||
立即支付
|
||||
</u-button>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
</page-status>
|
||||
</view>
|
||||
</u-popup>
|
||||
|
||||
<u-popup
|
||||
class="pay-popup"
|
||||
v-model="showCheckPay"
|
||||
round
|
||||
mode="center"
|
||||
borderRadius="10"
|
||||
:maskCloseAble="false"
|
||||
>
|
||||
<view class="content bg-white w-[560rpx] p-[40rpx]">
|
||||
<view class="text-2xl font-medium text-center"> 支付确认 </view>
|
||||
<view class="pt-[30rpx] pb-[40rpx]">
|
||||
<view> 请在微信内完成支付,如果您已支付成功,请点击`已完成支付`按钮 </view>
|
||||
</view>
|
||||
<view class="flex">
|
||||
<view class="flex-1 mr-[20rpx]">
|
||||
<u-button
|
||||
shape="circle"
|
||||
type="primary"
|
||||
plain
|
||||
size="medium"
|
||||
hover-class="none"
|
||||
:customStyle="{ width: '100%' }"
|
||||
@click="queryPayResult(false)"
|
||||
>
|
||||
重新支付
|
||||
</u-button>
|
||||
</view>
|
||||
<view class="flex-1">
|
||||
<u-button
|
||||
shape="circle"
|
||||
type="primary"
|
||||
size="medium"
|
||||
hover-class="none"
|
||||
:customStyle="{ width: '100%' }"
|
||||
@click="queryPayResult()"
|
||||
>
|
||||
已完成支付
|
||||
</u-button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</u-popup>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { pay, PayWayEnum } from '@/utils/pay'
|
||||
import { getPayWay, prepay, getPayResult } from '@/api/pay'
|
||||
import { computed, ref, watch } from 'vue'
|
||||
import { useLockFn } from '@/hooks/useLockFn'
|
||||
import { series } from '@/utils/util'
|
||||
import { ClientEnum, PageStatusEnum, PayStatusEnum } from '@/enums/appEnums'
|
||||
import { useUserStore } from '@/stores/user'
|
||||
import { client } from '@/utils/client'
|
||||
/*
|
||||
页面参数 orderId:订单id,from:订单来源
|
||||
*/
|
||||
|
||||
const props = defineProps({
|
||||
show: {
|
||||
type: Boolean,
|
||||
required: true
|
||||
},
|
||||
showCheck: {
|
||||
type: Boolean
|
||||
},
|
||||
// 订单id
|
||||
orderId: {
|
||||
type: Number,
|
||||
required: true
|
||||
},
|
||||
//订单来源
|
||||
from: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
//h5微信支付回跳路径,一般为拉起支付的页面路径
|
||||
redirect: {
|
||||
type: String
|
||||
}
|
||||
})
|
||||
|
||||
const emit = defineEmits(['update:showCheck', 'update:show', 'close', 'success', 'fail'])
|
||||
|
||||
const payWay = ref()
|
||||
const popupStatus = ref(PageStatusEnum.LOADING)
|
||||
const payData = ref<any>({
|
||||
order_amount: '',
|
||||
lists: []
|
||||
})
|
||||
|
||||
const showCheckPay = computed({
|
||||
get() {
|
||||
return props.showCheck
|
||||
},
|
||||
set(value) {
|
||||
emit('update:showCheck', value)
|
||||
}
|
||||
})
|
||||
|
||||
const showPay = computed({
|
||||
get() {
|
||||
return props.show
|
||||
},
|
||||
set(value) {
|
||||
emit('update:show', value)
|
||||
}
|
||||
})
|
||||
|
||||
const handleClose = () => {
|
||||
showPay.value = false
|
||||
emit('close')
|
||||
}
|
||||
const getPayData = async () => {
|
||||
popupStatus.value = PageStatusEnum.LOADING
|
||||
try {
|
||||
payData.value = await getPayWay({
|
||||
order_id: props.orderId,
|
||||
from: props.from
|
||||
})
|
||||
popupStatus.value = PageStatusEnum.NORMAL
|
||||
const checkPay =
|
||||
payData.value.lists.find((item: any) => item.is_default) || payData.value.lists[0]
|
||||
payWay.value = checkPay?.pay_way
|
||||
} catch (error) {
|
||||
popupStatus.value = PageStatusEnum.ERROR
|
||||
}
|
||||
}
|
||||
|
||||
const userStore = useUserStore()
|
||||
const selectPayWay = (pay: number) => {
|
||||
payWay.value = pay
|
||||
}
|
||||
const payment = (() => {
|
||||
// 查询是否绑定微信
|
||||
const checkIsBindWx = async () => {
|
||||
if (
|
||||
userStore.userInfo.is_auth == 0 &&
|
||||
[ClientEnum.OA_WEIXIN, ClientEnum.MP_WEIXIN].includes(client) &&
|
||||
payWay.value == PayWayEnum.WECHAT
|
||||
) {
|
||||
const res: any = await uni.showModal({
|
||||
title: '温馨提示',
|
||||
content: '当前账号未绑定微信,无法完成支付',
|
||||
confirmText: '去绑定'
|
||||
})
|
||||
if (res.confirm) {
|
||||
uni.navigateTo({
|
||||
url: '/pages/user_set/user_set'
|
||||
})
|
||||
}
|
||||
return Promise.reject()
|
||||
}
|
||||
}
|
||||
|
||||
// 调用预支付
|
||||
const prepayTask = async () => {
|
||||
uni.showLoading({
|
||||
title: '正在支付中'
|
||||
})
|
||||
const data = await prepay({
|
||||
order_id: props.orderId,
|
||||
from: props.from,
|
||||
pay_way: payWay.value,
|
||||
redirect: props.redirect
|
||||
})
|
||||
|
||||
return data
|
||||
}
|
||||
|
||||
//拉起支付
|
||||
const payTask = async (data: any) => {
|
||||
try {
|
||||
const res = await pay.payment(data.pay_way, data.config)
|
||||
return res
|
||||
} catch (error) {
|
||||
return Promise.reject(error)
|
||||
}
|
||||
}
|
||||
return series(checkIsBindWx, prepayTask, payTask)
|
||||
})()
|
||||
const { isLock, lockFn: handlePay } = useLockFn(async () => {
|
||||
try {
|
||||
const res: PayStatusEnum = await payment()
|
||||
handlePayResult(res)
|
||||
uni.hideLoading()
|
||||
} catch (error) {
|
||||
uni.hideLoading()
|
||||
console.log(error)
|
||||
}
|
||||
})
|
||||
|
||||
const handlePayResult = (status: PayStatusEnum) => {
|
||||
switch (status) {
|
||||
case PayStatusEnum.SUCCESS:
|
||||
emit('success')
|
||||
break
|
||||
case PayStatusEnum.FAIL:
|
||||
emit('fail')
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
const queryPayResult = async (confirm = true) => {
|
||||
const res = await getPayResult({
|
||||
order_id: props.orderId,
|
||||
from: props.from
|
||||
})
|
||||
|
||||
if (res.pay_status === 0) {
|
||||
if (confirm == true) {
|
||||
uni.$u.toast('您的订单还未支付,请重新支付')
|
||||
}
|
||||
showPay.value = true
|
||||
handlePayResult(PayStatusEnum.FAIL)
|
||||
} else {
|
||||
if (confirm == false) {
|
||||
uni.$u.toast('您的订单已经支付,请勿重新支付')
|
||||
}
|
||||
handlePayResult(PayStatusEnum.SUCCESS)
|
||||
}
|
||||
showCheckPay.value = false
|
||||
}
|
||||
|
||||
watch(
|
||||
() => props.show,
|
||||
(value) => {
|
||||
if (value) {
|
||||
if (!props.orderId) {
|
||||
popupStatus.value = PageStatusEnum.ERROR
|
||||
return
|
||||
}
|
||||
getPayData()
|
||||
}
|
||||
},
|
||||
{
|
||||
immediate: true
|
||||
}
|
||||
)
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.payway-lists {
|
||||
.payway-item {
|
||||
border-bottom: 1px solid;
|
||||
@apply border-page;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
126
src/components/price/price.vue
Normal file
126
src/components/price/price.vue
Normal file
@@ -0,0 +1,126 @@
|
||||
<template>
|
||||
<view class="price-container">
|
||||
<view
|
||||
:class="['price-wrap', { 'price-wrap--disabled': lineThrough }]"
|
||||
:style="{ color: color }"
|
||||
>
|
||||
<!-- Prefix -->
|
||||
<view class="fix-pre" :style="{ fontSize: minorSize }">
|
||||
<slot name="prefix">{{ prefix }}</slot>
|
||||
</view>
|
||||
|
||||
<!-- Content -->
|
||||
<view :style="{ 'font-weight': fontWeight }">
|
||||
<!-- Integer -->
|
||||
<text :style="{ fontSize: mainSize }">{{ integer }}</text>
|
||||
<!-- Decimals -->
|
||||
<text :style="{ fontSize: minorSize }">{{ decimals }}</text>
|
||||
</view>
|
||||
|
||||
<!-- Suffix -->
|
||||
<view class="fix-suf" :style="{ fontSize: minorSize }">
|
||||
<slot name="suffix">{{ suffix }}</slot>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
/**
|
||||
* @description 价格展示,适用于有前后缀,小数样式不一
|
||||
* @property {String|Number} content 价格 (必填项)
|
||||
* @property {Number} prec 小数位 (默认: 2)
|
||||
* @property {Boolean} autoPrec 自动小数位【注:以prec为最大小数位】 (默认: true)
|
||||
* @property {String} color 颜色 (默认: 'unset')
|
||||
* @property {String} mainSize 主要内容字体大小 (默认: 46rpx)
|
||||
* @property {String} minorSize 主要内容字体大小 (默认: 32rpx)
|
||||
* @property {Boolean} lineThrough 贯穿线 (默认: false)
|
||||
* @property {String|Number} fontWeight 字重 (默认: normal)
|
||||
* @property {String} prefix 前缀 (默认: ¥)
|
||||
* @property {String} suffix 后缀
|
||||
* @example <price content="100" suffix="\/元" />
|
||||
*/
|
||||
import { computed } from 'vue'
|
||||
import { formatPrice } from '@/utils/util'
|
||||
|
||||
/** Props Start **/
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
content: string | number // 标题
|
||||
prec?: number // 小数数量
|
||||
autoPrec?: boolean // 动态小数
|
||||
color?: string // 颜色
|
||||
mainSize?: string // 主要内容字体大小
|
||||
minorSize?: string // 次要内容字体大小
|
||||
lineThrough?: boolean // 贯穿线
|
||||
fontWeight?: string // 字重
|
||||
prefix?: string // 前缀
|
||||
suffix?: string // 后缀
|
||||
}>(),
|
||||
{
|
||||
content: '',
|
||||
prec: 2,
|
||||
autoPrec: true,
|
||||
color: '#FA8919',
|
||||
mainSize: '36rpx',
|
||||
minorSize: '28rpx',
|
||||
lineThrough: false,
|
||||
fontWeight: 'normal',
|
||||
prefix: '¥',
|
||||
suffix: ''
|
||||
}
|
||||
)
|
||||
/** Props End **/
|
||||
|
||||
/** Computed Start **/
|
||||
/**
|
||||
* @description 金额主体部分
|
||||
*/
|
||||
const integer = computed(() => {
|
||||
return formatPrice({
|
||||
price: props.content,
|
||||
take: 'int'
|
||||
})
|
||||
})
|
||||
/**
|
||||
* @description 金额小数部分
|
||||
*/
|
||||
const decimals = computed(() => {
|
||||
let decimals = formatPrice({
|
||||
price: props.content,
|
||||
take: 'dec',
|
||||
prec: props.prec
|
||||
})
|
||||
// 小数余十不能是 .10||.20||.30以此类推,
|
||||
decimals = decimals % 10 == 0 ? decimals.substr(0, decimals.length - 1) : decimals
|
||||
return props.autoPrec ? (decimals * 1 ? '.' + decimals : '') : props.prec ? '.' + decimals : ''
|
||||
})
|
||||
/** Computed End **/
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.price-container {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.price-wrap {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
|
||||
&--disabled {
|
||||
position: relative;
|
||||
|
||||
&::before {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 50%;
|
||||
right: 0;
|
||||
transform: translateY(-50%);
|
||||
display: block;
|
||||
content: '';
|
||||
height: 0.05em;
|
||||
background-color: currentColor;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
84
src/components/tab/tab.vue
Normal file
84
src/components/tab/tab.vue
Normal file
@@ -0,0 +1,84 @@
|
||||
<template>
|
||||
<view
|
||||
:class="{ active, inactive: !active, tab: true }"
|
||||
:style="shouldShow ? '' : 'display: none;'"
|
||||
>
|
||||
<slot v-if="shouldRender"></slot>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, provide, inject, watch, computed, onMounted, getCurrentInstance } from 'vue'
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
dot?: boolean | string
|
||||
name?: boolean | string
|
||||
info?: any
|
||||
}>(),
|
||||
{
|
||||
dot: false,
|
||||
name: ''
|
||||
}
|
||||
)
|
||||
|
||||
const active = ref<boolean>(false)
|
||||
const shouldShow = ref<boolean>(false)
|
||||
const shouldRender = ref<boolean>(false)
|
||||
const inited = ref(undefined)
|
||||
|
||||
const updateTabs: any = inject('updateTabs')
|
||||
const handleChange: any = inject('handleChange')
|
||||
|
||||
const updateRender = (value) => {
|
||||
inited.value = inited.value || value
|
||||
active.value = value
|
||||
shouldRender.value = inited.value!
|
||||
shouldShow.value = value
|
||||
}
|
||||
const update = () => {
|
||||
if (updateTabs) {
|
||||
updateTabs()
|
||||
}
|
||||
}
|
||||
|
||||
const instance = getCurrentInstance()
|
||||
console.log(instance)
|
||||
handleChange(instance?.props, updateRender)
|
||||
|
||||
onMounted(() => {
|
||||
update()
|
||||
})
|
||||
|
||||
const changeData = computed(() => {
|
||||
const { dot, info } = props
|
||||
return {
|
||||
dot,
|
||||
info
|
||||
}
|
||||
})
|
||||
|
||||
watch(
|
||||
() => changeData.value,
|
||||
() => {
|
||||
update()
|
||||
}
|
||||
)
|
||||
watch(
|
||||
() => props.name,
|
||||
(val) => {
|
||||
update()
|
||||
}
|
||||
)
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.tab.active {
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.tab.inactive {
|
||||
height: 0;
|
||||
overflow: visible;
|
||||
}
|
||||
</style>
|
||||
87
src/components/tabbar/tabbar.vue
Normal file
87
src/components/tabbar/tabbar.vue
Normal file
@@ -0,0 +1,87 @@
|
||||
<template>
|
||||
<u-tabbar v-if="showTabbar" height="120rpx" icon-size="50rpx" v-model="current" v-bind="tabbarStyle" :list="tabbarList"
|
||||
@change="handleChange" :hide-tab-bar="false" :border-top="false"></u-tabbar>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { onShow } from '@dcloudio/uni-app'
|
||||
import { navigateTo } from '@/utils/util'
|
||||
import { computed, ref } from 'vue'
|
||||
import { t } from '@/utils/util'
|
||||
|
||||
const current = ref()
|
||||
const tabbarList = ref([
|
||||
{
|
||||
iconPath: "../../static/images/tabs/home_off.png",
|
||||
selectedIconPath: "../../static/images/tabs/home_on.png",
|
||||
text: t('tabbar.index'),
|
||||
pagePath: "/pages/index/index",
|
||||
link: {
|
||||
path: "/pages/index/index",
|
||||
type: "shop"
|
||||
}
|
||||
},
|
||||
{
|
||||
iconPath: "../../static/images/tabs/item_off.png",
|
||||
selectedIconPath: "../../static/images/tabs/item_on.png",
|
||||
text: t('tabbar.mine'),
|
||||
pagePath: "/pages/item/index",
|
||||
link: {
|
||||
path: "/pages/item/index",
|
||||
type: "shop"
|
||||
}
|
||||
},
|
||||
{
|
||||
iconPath: "../../static/images/tabs/mine_on.gif",
|
||||
selectedIconPath: "../../static/images/tabs/mine_on.gif",
|
||||
text: '',
|
||||
pagePath: "/pages/mine/index",
|
||||
link: {
|
||||
path: "/pages/mine/index",
|
||||
type: "shop"
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
iconPath: "../../static/images/tabs/team_off.png",
|
||||
selectedIconPath: "../../static/images/tabs/team_on.png",
|
||||
text: t('tabbar.team'),
|
||||
pagePath: "/pages/team/index",
|
||||
link: {
|
||||
path: "/pages/team/index",
|
||||
type: "shop"
|
||||
}
|
||||
},
|
||||
{
|
||||
iconPath: "../../static/images/tabs/my_off.png",
|
||||
selectedIconPath: "../../static/images/tabs/my_on.png",
|
||||
text: t('tabbar.my'),
|
||||
pagePath: "/pages/user/user",
|
||||
link: {
|
||||
path: "/pages/user/user",
|
||||
type: "shop"
|
||||
}
|
||||
},
|
||||
])
|
||||
|
||||
const showTabbar = computed(() => {
|
||||
const currentPages = getCurrentPages()
|
||||
const currentPage = currentPages[currentPages.length - 1]
|
||||
const current = tabbarList.value.findIndex((item : any) => {
|
||||
return item.pagePath === '/' + currentPage.route
|
||||
})
|
||||
return current >= 0
|
||||
})
|
||||
|
||||
const tabbarStyle = computed(() => ({
|
||||
activeColor: "#A1DBF5",
|
||||
inactiveColor: "#FFFFFF"
|
||||
}))
|
||||
const handleChange = (index : number) => {
|
||||
const selectTab = tabbarList.value[index]
|
||||
navigateTo(selectTab.link, 'switchTab')
|
||||
}
|
||||
onShow(() => {
|
||||
uni.hideTabBar();
|
||||
})
|
||||
</script>
|
||||
437
src/components/tabs/tabs.vue
Normal file
437
src/components/tabs/tabs.vue
Normal file
@@ -0,0 +1,437 @@
|
||||
<template>
|
||||
<view class="tabs">
|
||||
<u-sticky :enable="isFixed" :bg-color="stickyBgColor" :offset-top="top" :h5-nav-height="0">
|
||||
<view
|
||||
:id="id"
|
||||
:style="{
|
||||
background: bgColor
|
||||
}"
|
||||
>
|
||||
<scroll-view
|
||||
:style="{ height: height + 'rpx' }"
|
||||
scroll-x
|
||||
class="scroll-view"
|
||||
:scroll-left="scrollLeft"
|
||||
scroll-with-animation
|
||||
>
|
||||
<view class="scroll-box" :class="{ 'tabs-scorll-flex': !isScroll }">
|
||||
<view
|
||||
class="tab-item line1"
|
||||
:id="'tab-item-' + index"
|
||||
v-for="(item, index) in list"
|
||||
:key="index"
|
||||
@tap="clickTab(index)"
|
||||
:style="[tabItemStyle(index)]"
|
||||
>
|
||||
<u-badge
|
||||
:count="item[count] || item['dot'] || 0"
|
||||
:offset="offset"
|
||||
size="mini"
|
||||
></u-badge>
|
||||
{{ item[name] || item['name'] }}
|
||||
</view>
|
||||
<view v-if="showBar" class="tab-bar" :style="[tabBarStyle]"></view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</u-sticky>
|
||||
<view
|
||||
class="tab-content"
|
||||
@touchstart="onTouchStart"
|
||||
@touchmove="onTouchMove"
|
||||
@touchcancel="onTouchEnd"
|
||||
@touchend="onTouchEnd"
|
||||
>
|
||||
<!-- <view class="tab-track" :class="{'tab-animated': animated}" :style="[trackStyle]"> -->
|
||||
<view>
|
||||
<slot></slot>
|
||||
</view>
|
||||
<!-- </view> -->
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { getRect } from '@/utils/util'
|
||||
import {
|
||||
ref,
|
||||
reactive,
|
||||
computed,
|
||||
watch,
|
||||
provide,
|
||||
nextTick,
|
||||
onMounted,
|
||||
getCurrentInstance
|
||||
} from 'vue'
|
||||
import { useTouch } from '@/hooks/useTouch'
|
||||
|
||||
// Touch 钩子
|
||||
const { touch, resetTouchStatus, touchStart, touchMove } = useTouch()
|
||||
|
||||
const emit = defineEmits<{
|
||||
(event: 'change', value: number): void
|
||||
}>()
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
isScroll?: boolean // 导航菜单是否需要滚动,如只有2或者3个的时候,就不需要滚动了,此时使用flex平分tab的宽度
|
||||
current?: number | string // 当前活动tab的索引
|
||||
height?: number | string // 导航栏的高度和行高
|
||||
fontSize?: number | string // 字体大小
|
||||
duration?: number | string // 过渡动画时长, 单位ms
|
||||
activeColor?: number | string // 选中项的主题颜色
|
||||
inactiveColor?: number | string // 未选中项的颜色
|
||||
barWidth?: number | string // 菜单底部移动的bar的宽度,单位rpx
|
||||
barHeight?: number // 移动bar的高度
|
||||
gutter?: number | string // 单个tab的左或有内边距(左右相同)
|
||||
bgColor?: number | string // 导航栏的背景颜色
|
||||
name?: string // 读取传入的数组对象的属性(tab名称)
|
||||
count?: string // 读取传入的数组对象的属性(徽标数)
|
||||
offset?: number[] // 徽标数位置偏移
|
||||
bold?: boolean // 活动tab字体是否加粗
|
||||
activeItemStyle?: any // 当前活动tab item的样式
|
||||
showBar?: boolean // 是否显示底部的滑块
|
||||
barStyle?: any // 底部滑块的自定义样式
|
||||
itemWidth?: string // 标签的宽度
|
||||
isFixed?: boolean // 吸顶是否固定
|
||||
top?: number | string // 吸顶顶部距离
|
||||
stickyBgColor?: string // 吸顶颜色
|
||||
|
||||
swipeable: boolean // 是否允许滑动切换
|
||||
// animated: boolean // 切换动画
|
||||
}>(),
|
||||
{
|
||||
isScroll: true,
|
||||
current: 0,
|
||||
height: 80,
|
||||
fontSize: 28,
|
||||
duration: 0.3,
|
||||
activeColor: '#2073F4',
|
||||
inactiveColor: '#333',
|
||||
barWidth: 40,
|
||||
barHeight: 4,
|
||||
gutter: 30,
|
||||
bgColor: '#FFFFFF',
|
||||
name: 'name',
|
||||
count: 'count',
|
||||
offset: [5, 20],
|
||||
bold: true,
|
||||
activeItemStyle: {},
|
||||
showBar: true,
|
||||
barStyle: {},
|
||||
itemWidth: 'auto',
|
||||
isFixed: false,
|
||||
top: 0,
|
||||
stickyBgColor: '#FFFFFF',
|
||||
|
||||
swipeable: true
|
||||
// animated: true
|
||||
}
|
||||
)
|
||||
|
||||
const list = ref<any>([])
|
||||
const childrens = ref<any>([])
|
||||
const scrollLeft = ref<number>(0) // 滚动scroll-view的左边滚动距离
|
||||
const tabQueryInfo = ref<any>([]) // 存放对tab菜单查询后的节点信息
|
||||
const componentWidth = ref<number>(0) // 屏幕宽度,单位为px
|
||||
const scrollBarLeft = ref<number>(0) // 移动bar需要通过translateX()移动的距离
|
||||
const parentLeft = ref<number>(0) // 父元素(tabs组件)到屏幕左边的距离
|
||||
const id = ref<string>('cu-tab') // id值
|
||||
const currentIndex = ref<any>(props.current)
|
||||
const barFirstTimeMove = ref<boolean>(true) // 滑块第一次移动时(页面刚生成时),无需动画,否则给人怪异的感觉
|
||||
const swiping = ref<boolean>(false)
|
||||
|
||||
//@ts-ignore
|
||||
const ctx = getCurrentInstance()
|
||||
|
||||
// 监听tab的变化,重新计算tab菜单的布局信息,因为实际使用中菜单可能是通过
|
||||
// 后台获取的(如新闻app顶部的菜单),获取返回需要一定时间,所以list变化时,重新获取布局信息
|
||||
watch(
|
||||
() => list.value,
|
||||
async (n, o) => {
|
||||
// list变动时,重制内部索引,否则可能导致超出数组边界的情况
|
||||
if (!barFirstTimeMove.value && n.length !== o.length) {
|
||||
currentIndex.value = 0
|
||||
}
|
||||
// 用$nextTick等待视图更新完毕后再计算tab的局部信息,否则可能因为tab还没生成就获取,就会有问题
|
||||
await nextTick()
|
||||
init()
|
||||
}
|
||||
)
|
||||
watch(
|
||||
() => props.current,
|
||||
(nVal, oVal) => {
|
||||
// 视图更新后再执行移动操作、
|
||||
nextTick(() => {
|
||||
currentIndex.value = nVal
|
||||
scrollByIndex()
|
||||
})
|
||||
},
|
||||
{ immediate: true }
|
||||
)
|
||||
|
||||
// 移动bar的样式
|
||||
const tabBarStyle = computed(() => {
|
||||
const style = {
|
||||
width: props.barWidth + 'rpx',
|
||||
transform: `translate(${scrollBarLeft.value}px, -100%)`,
|
||||
// 滑块在页面渲染后第一次滑动时,无需动画效果
|
||||
'transition-duration': `${barFirstTimeMove.value ? 0 : props.duration}s`,
|
||||
'background-color': props.activeColor,
|
||||
height: props.barHeight + 'rpx',
|
||||
opacity: barFirstTimeMove.value ? 0 : 1,
|
||||
// 设置一个很大的值,它会自动取能用的最大值,不用高度的一半,是因为高度可能是单数,会有小数出现
|
||||
'border-radius': `${props.barHeight / 2}px`
|
||||
}
|
||||
Object.assign(style, props.barStyle)
|
||||
return style
|
||||
})
|
||||
// tab的样式
|
||||
const tabItemStyle = computed(() => {
|
||||
return (index) => {
|
||||
let style: any = {
|
||||
height: props.height + 'rpx',
|
||||
'line-height': props.height + 'rpx',
|
||||
'font-size': props.fontSize + 'rpx',
|
||||
padding: props.isScroll ? `0 ${props.gutter}rpx` : '',
|
||||
flex: props.isScroll ? 'auto' : '1',
|
||||
width: `${props.itemWidth}rpx`
|
||||
}
|
||||
// 字体加粗
|
||||
if (index == currentIndex.value && props.bold) style.fontWeight = 'bold'
|
||||
if (index == currentIndex.value) {
|
||||
style.color = props.activeColor
|
||||
// 给选中的tab item添加外部自定义的样式
|
||||
style = Object.assign(style, props.activeItemStyle)
|
||||
} else {
|
||||
style.color = props.inactiveColor
|
||||
}
|
||||
return style
|
||||
}
|
||||
})
|
||||
|
||||
// const trackStyle = computed(() => {
|
||||
// if (!props.animated) return ''
|
||||
// return {
|
||||
// left: -100 * currentIndex.value + '%',
|
||||
// 'transition-duration': props.duration + 's',
|
||||
// '-webkit-transition-duration': props.duration + 's',
|
||||
// }
|
||||
// })
|
||||
|
||||
const updateTabs = () => {
|
||||
list.value = childrens.value.map((item) => {
|
||||
const { name, dot, active, inited } = item.event
|
||||
const { updateRender } = item
|
||||
return {
|
||||
name,
|
||||
dot,
|
||||
active,
|
||||
inited,
|
||||
updateRender
|
||||
}
|
||||
})
|
||||
// nextTick(() => {
|
||||
// init()
|
||||
// })
|
||||
}
|
||||
|
||||
// 设置一个init方法,方便多处调用
|
||||
const init = async () => {
|
||||
// 获取tabs组件的尺寸信息
|
||||
const tabRect = await getRect('#' + id.value, false, ctx)
|
||||
// tabs组件距离屏幕左边的宽度
|
||||
parentLeft.value = tabRect.left
|
||||
// tabs组件的宽度
|
||||
componentWidth.value = tabRect.width
|
||||
getTabRect()
|
||||
}
|
||||
|
||||
// 点击某一个tab菜单
|
||||
const clickTab = (index) => {
|
||||
// 点击当前活动tab,不触发事件
|
||||
if (index == currentIndex.value) return
|
||||
nextTick(() => {
|
||||
currentIndex.value = index
|
||||
scrollByIndex()
|
||||
})
|
||||
// 发送事件给父组件
|
||||
emit('change', index)
|
||||
}
|
||||
|
||||
// 查询tab的布局信息
|
||||
const getTabRect = () => {
|
||||
// 创建节点查询
|
||||
const query: any = uni.createSelectorQuery().in(ctx)
|
||||
// 历遍所有tab,这里是执行了查询,最终使用exec()会一次性返回查询的数组结果
|
||||
for (let i = 0; i < list.value.length; i++) {
|
||||
// 只要size和rect两个参数
|
||||
query.select(`#tab-item-${i}`).fields({
|
||||
size: true,
|
||||
rect: true
|
||||
})
|
||||
}
|
||||
// 执行查询,一次性获取多个结果
|
||||
query.exec((res) => {
|
||||
tabQueryInfo.value = res
|
||||
// 初始化滚动条和移动bar的位置
|
||||
scrollByIndex()
|
||||
})
|
||||
}
|
||||
|
||||
// 滚动scroll-view,让活动的tab处于屏幕的中间位置
|
||||
const scrollByIndex = () => {
|
||||
// 当前活动tab的布局信息,有tab菜单的width和left(为元素左边界到父元素左边界的距离)等信息
|
||||
const tabInfo = tabQueryInfo.value[currentIndex.value]
|
||||
if (!tabInfo) return
|
||||
// 活动tab的宽度
|
||||
const tabWidth = tabInfo.width
|
||||
// 活动item的左边到tabs组件左边的距离,用item的left减去tabs的left
|
||||
const offsetLeft = tabInfo.left - parentLeft.value
|
||||
// 将活动的tabs-item移动到屏幕正中间,实际上是对scroll-view的移动
|
||||
const scrollLefts = offsetLeft - (componentWidth.value - tabWidth) / 2
|
||||
scrollLeft.value = scrollLefts < 0 ? 0 : scrollLefts
|
||||
// 当前活动item的中点点到左边的距离减去滑块宽度的一半,即可得到滑块所需的移动距离
|
||||
const left = tabInfo.left + tabInfo.width / 2 - parentLeft.value
|
||||
// 计算当前活跃item到组件左边的距离
|
||||
scrollBarLeft.value = left - uni.upx2px(props.barWidth) / 2
|
||||
// 第一次移动滑块的时候,barFirstTimeMove为true,放到延时中将其设置false
|
||||
// 延时是因为scrollBarLeft作用于computed计算时,需要一个过程需,否则导致出错
|
||||
if (barFirstTimeMove.value == true) {
|
||||
setTimeout(() => {
|
||||
barFirstTimeMove.value = false
|
||||
}, 100)
|
||||
}
|
||||
|
||||
// 更新子组件的显示
|
||||
childrens.value.forEach((item, ind) => {
|
||||
const active = ind === currentIndex.value
|
||||
if (active !== item.event.active || !item.event.inited) {
|
||||
item.updateRender(active)
|
||||
}
|
||||
})
|
||||
}
|
||||
// 子组件调用此函数而产生的事件通信
|
||||
const handleChange = (event, updateRender) => {
|
||||
childrens.value.push({ event: event, updateRender })
|
||||
}
|
||||
// 手指触摸
|
||||
const onTouchStart = (event) => {
|
||||
if (!props.swipeable) return
|
||||
swiping.value = true
|
||||
touchStart(event)
|
||||
}
|
||||
// 手指滑动
|
||||
const onTouchMove = (event) => {
|
||||
if (!props.swipeable || !swiping.value) return
|
||||
touchMove(event)
|
||||
}
|
||||
// 手指滑动结束
|
||||
const onTouchEnd = () => {
|
||||
if (!props.swipeable || !swiping.value) return
|
||||
const minSwipeDistance = 50
|
||||
if (touch.direction === 'horizontal' && touch.offsetX >= minSwipeDistance) {
|
||||
let index,
|
||||
len = list.value.length,
|
||||
curIndex = currentIndex.value
|
||||
if (touch.deltaX <= 0) {
|
||||
curIndex >= len - 1 ? (index = 0) : (index = curIndex + 1)
|
||||
} else {
|
||||
curIndex <= 0 ? (index = len - 1) : (index = curIndex - 1)
|
||||
}
|
||||
nextTick(() => {
|
||||
currentIndex.value = index
|
||||
scrollByIndex()
|
||||
})
|
||||
// 发送事件给父组件
|
||||
emit('change', index)
|
||||
}
|
||||
swiping.value = false
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
updateTabs()
|
||||
})
|
||||
|
||||
provide('handleChange', handleChange)
|
||||
provide('updateTabs', updateTabs)
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
/* #ifndef APP-NVUE */
|
||||
::-webkit-scrollbar,
|
||||
::-webkit-scrollbar,
|
||||
::-webkit-scrollbar {
|
||||
display: none;
|
||||
width: 0 !important;
|
||||
height: 0 !important;
|
||||
-webkit-appearance: none;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
/* #endif */
|
||||
|
||||
.scroll-box {
|
||||
height: 100%;
|
||||
position: relative;
|
||||
/* #ifdef MP-TOUTIAO */
|
||||
white-space: nowrap;
|
||||
/* #endif */
|
||||
}
|
||||
|
||||
.tab-fixed {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* #ifdef H5 */
|
||||
// 通过样式穿透,隐藏H5下,scroll-view下的滚动条
|
||||
scroll-view ::v-deep ::-webkit-scrollbar {
|
||||
display: none;
|
||||
width: 0 !important;
|
||||
height: 0 !important;
|
||||
-webkit-appearance: none;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
/* #endif */
|
||||
|
||||
.scroll-view {
|
||||
width: 100%;
|
||||
white-space: nowrap;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.tab-item {
|
||||
position: relative;
|
||||
/* #ifndef APP-NVUE */
|
||||
display: inline-block;
|
||||
/* #endif */
|
||||
text-align: center;
|
||||
transition-property: background-color, color;
|
||||
}
|
||||
|
||||
.tab-bar {
|
||||
position: absolute;
|
||||
bottom: 6rpx;
|
||||
}
|
||||
|
||||
.tabs-scorll-flex {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
// .tab-content {
|
||||
// overflow: hidden;
|
||||
// .tab-track {
|
||||
// position: relative;
|
||||
// width: 100%;
|
||||
// height: 100%;
|
||||
// }
|
||||
// .tab-animated {
|
||||
// display: flex;
|
||||
// transition-property: left;
|
||||
// }
|
||||
// }
|
||||
</style>
|
||||
37
src/components/widgets/banner/banner.vue
Normal file
37
src/components/widgets/banner/banner.vue
Normal file
@@ -0,0 +1,37 @@
|
||||
<template>
|
||||
<view class="banner translate-y-0">
|
||||
<u-swiper borderRadius="16" height="auto" :list="banner" mode="none" @click="handleClick"></u-swiper>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { navigateTo, jumpTo } from '@/utils/util'
|
||||
|
||||
const props = defineProps({
|
||||
banner: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
},
|
||||
styles: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
}
|
||||
})
|
||||
const handleClick = (index : any) => {
|
||||
let linkArr = {}
|
||||
let link = props.banner[index]['link']
|
||||
if (link == "") return
|
||||
if (link.indexOf('http') == 0) {
|
||||
jumpTo(link)
|
||||
} else {
|
||||
linkArr = { path: link }
|
||||
}
|
||||
if (link.indexOf('/pages/team/index') == 0) {
|
||||
navigateTo(linkArr, 'switchTab')
|
||||
} else {
|
||||
navigateTo(linkArr)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style></style>
|
||||
56
src/components/widgets/customer-service/customer-service.vue
Normal file
56
src/components/widgets/customer-service/customer-service.vue
Normal file
@@ -0,0 +1,56 @@
|
||||
<template>
|
||||
<view
|
||||
class="customer-service bg-white flex flex-col justify-center items-center mx-[36rpx] mt-[20rpx] rounded-lg px-[110rpx] pt-[100rpx] pb-[160rpx]"
|
||||
>
|
||||
<u-image width="280" height="280" :src="getImageUrl(content.qrcode)" />
|
||||
<view v-if="content.title" class="text-lg mt-[14rpx] font-medium">{{ content.title }}</view>
|
||||
<view v-if="content.time" class="text-content mt-[40rpx]"
|
||||
>服务时间:{{ content.time }}</view
|
||||
>
|
||||
<view v-if="content.mobile" class="text-content mt-[14rpx] flex flex-wrap">
|
||||
客服电话:{{ content.mobile }}
|
||||
<!-- #ifdef H5 -->
|
||||
<a class="ml-[10rpx] phone text-muted underline" :href="'tel:' + content.mobile">
|
||||
拨打
|
||||
</a>
|
||||
<!-- #endif -->
|
||||
<!-- #ifndef H5 -->
|
||||
<view class="ml-[10rpx] phone text-muted underline" @click="handleCall">拨打</view>
|
||||
<!-- #endif -->
|
||||
</view>
|
||||
<view class="mt-[100rpx] w-full">
|
||||
<u-button
|
||||
type="primary"
|
||||
shape="circle"
|
||||
@click="saveImageToPhotosAlbum(getImageUrl(content.qrcode))"
|
||||
>
|
||||
保存二维码图片
|
||||
</u-button>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { useAppStore } from '@/stores/app'
|
||||
import { saveImageToPhotosAlbum } from '@/utils/file'
|
||||
|
||||
const props = defineProps({
|
||||
content: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
},
|
||||
styles: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
}
|
||||
})
|
||||
|
||||
const { getImageUrl } = useAppStore()
|
||||
|
||||
const handleCall = () => {
|
||||
uni.makePhoneCall({
|
||||
phoneNumber: String(props.content.mobile)
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss"></style>
|
||||
67
src/components/widgets/item/item.vue
Normal file
67
src/components/widgets/item/item.vue
Normal file
@@ -0,0 +1,67 @@
|
||||
<template>
|
||||
<view class="" v-if="items.length>0">
|
||||
<navigator v-for="(item, index) in items" :key="index" hover-class="none"
|
||||
:url="'/pages/item/detail?id='+item.id">
|
||||
<view class="bg-[#2C326B] rounded-lg mb-[30rpx] overflow-hidden">
|
||||
<view class="p-[20rpx] rounded-lg overflow-hidden">
|
||||
<u-image width="100%" mode="widthFix" :src="item.image" alt="" />
|
||||
</view>
|
||||
|
||||
<view class="p-[20rpx] pt-0">
|
||||
<view class="font-bold truncate">
|
||||
{{ item.title }}
|
||||
</view>
|
||||
<view class="flex justify-between items-center">
|
||||
<view class="">
|
||||
<view class="mt-[20rpx]">
|
||||
<text class="mr-[10rpx] text-[#00D2E0]">{{t('item.cycle')}}:</text><text
|
||||
class="mr-[10rpx] ">{{ item.cycle }}</text>
|
||||
<text v-if="item.type==1 || item.type==2" class="">{{t('item.days')}}</text>
|
||||
<text v-if="item.type==3 || item.type==4" class="">{{t('item.hour')}}</text>
|
||||
</view>
|
||||
<view class="mt-[10rpx]">
|
||||
<text class="mr-[10rpx] text-[#00D2E0]">
|
||||
<text v-if="item.type==1">{{t('item.dailyRate')}}:</text>
|
||||
<text v-if="item.type==4">{{t('item.hourRate')}}:</text>
|
||||
<text v-if="item.type==2 || item.type==3">{{t('item.totalRate')}}:</text>
|
||||
</text>
|
||||
|
||||
<text class="">{{ item.rate }}%</text>
|
||||
</view>
|
||||
<view class="mt-[10rpx]">
|
||||
<text class="mr-[10rpx] text-[#00D2E0]">{{t('item.limitVip')}}:</text>
|
||||
<text class="">{{ item.vip_name }}</text>
|
||||
</view>
|
||||
<!-- <view class="mt-[10rpx]">
|
||||
{{t("item.type" + item.type)}}
|
||||
</view> -->
|
||||
</view>
|
||||
<view class="mt-[20rpx]">
|
||||
<u-circle-progress width="180" bg-color="#2C326B" active-color="#4E55AF"
|
||||
:percent="item.progress">
|
||||
<view class="u-progress-content">
|
||||
<view class="u-progress-dot"></view>
|
||||
<text class='u-progress-info'>{{item.progress}}%</text>
|
||||
</view>
|
||||
</u-circle-progress>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</navigator>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useAppStore } from '@/stores/app'
|
||||
import { t } from '@/utils/util'
|
||||
|
||||
const props = defineProps({
|
||||
items: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
||||
<style></style>
|
||||
38
src/components/widgets/market/market.vue
Normal file
38
src/components/widgets/market/market.vue
Normal file
@@ -0,0 +1,38 @@
|
||||
<template>
|
||||
<view class="" v-if="market.length>0">
|
||||
<view class="float-left bg-[#2C326B] rounded-lg w-[49%] mb-[20rpx] p-[20rpx]" v-for="(item,key) in market"
|
||||
:key="item.id" :class="key%2==0?'mr-[2%]':''">
|
||||
<view class="flex justify-start items-center">
|
||||
<u-icon class="mr-[15rpx]" width="60rpx" height="60rpx" :name="item.logo"></u-icon>
|
||||
<text class="">{{item.name}}</text>
|
||||
</view>
|
||||
<view class="text-xl font-bold my-[10rpx]">
|
||||
<view v-if="item.rise>=0" class="text-[#17cdaf] mr-[20rpx]">
|
||||
+{{item.rise}}
|
||||
</view>
|
||||
<view v-if="item.rise<0" class="text-[#f85963] mr-[20rpx]">
|
||||
{{item.rise}}
|
||||
</view>
|
||||
</view>
|
||||
<view class="text-muted">
|
||||
<view v-if="item.rise>=0" class="text-[#17cdaf] mr-[20rpx]">
|
||||
{{item.price}}
|
||||
</view>
|
||||
<view v-if="item.rise<0" class="text-[#f85963] mr-[20rpx]">
|
||||
{{item.price}}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
const props = defineProps({
|
||||
market: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
||||
<style></style>
|
||||
54
src/components/widgets/my-order/my-order.vue
Normal file
54
src/components/widgets/my-order/my-order.vue
Normal file
@@ -0,0 +1,54 @@
|
||||
<template>
|
||||
<div class="my-service bg-white ">
|
||||
<div
|
||||
class="title px-[30rpx] py-[20rpx] font-medium text-xl border-light border-solid border-0 border-b">
|
||||
<div>{{t('robot.myOrder')}}</div>
|
||||
</div>
|
||||
<div class="flex flex-wrap pt-[40rpx] pb-[20rpx] px-[24rpx] ">
|
||||
<div v-for="(item, index) in data.menus1" :key="index" class="flex flex-col items-center w-1/3 mb-[15px] text-center"
|
||||
@click="handleClick(item.link)">
|
||||
<u-image width="64" height="64" :src="item.image" alt="" />
|
||||
<div class="mt-[7px]">{{ item.name }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { navigateTo } from '@/utils/util'
|
||||
import { reactive } from 'vue'
|
||||
import { t } from '@/utils/util'
|
||||
|
||||
const data = reactive({
|
||||
menus1: [
|
||||
{
|
||||
"image": "/static/images/robot/pending.png",
|
||||
"name": t('robot.orderStatus5'),
|
||||
"link": {
|
||||
"path": "/pages/robot/record?status=5",
|
||||
"type": "shop"
|
||||
}
|
||||
},
|
||||
{
|
||||
"image": "/static/images/robot/paying.png",
|
||||
"name": t('robot.orderStatus4'),
|
||||
"link": {
|
||||
"path": "/pages/robot/record?status=4",
|
||||
"type": "shop"
|
||||
}
|
||||
},
|
||||
{
|
||||
"image": "/static/images/robot/finish.png",
|
||||
"name": t('robot.orderStatus1'),
|
||||
"link": {
|
||||
"path": "/pages/robot/record?status=1",
|
||||
"type": "shop"
|
||||
}
|
||||
}
|
||||
]
|
||||
})
|
||||
const handleClick = (link : any) => {
|
||||
navigateTo(link)
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss"></style>
|
||||
38
src/components/widgets/my-service/my-service.vue
Normal file
38
src/components/widgets/my-service/my-service.vue
Normal file
@@ -0,0 +1,38 @@
|
||||
<template>
|
||||
<view class="bg-[#2C326B] rounded-lg mx-[30rpx] py-[30rpx] px-[30rpx]" v-if="navs.length>0">
|
||||
<view class="">
|
||||
<view v-for="(item, index) in navs" :key="index" class="flex justify-between items-center"
|
||||
:class="index<(navs.length-1)?'mb-[30rpx]':''" @click="handleClick(item.link)">
|
||||
<view class="flex justify-start items-center">
|
||||
<u-image width="26px" height="26px" :src="item.image" alt="" />
|
||||
<view class="ml-[30rpx]">{{ item.name }}</view>
|
||||
</view>
|
||||
<view class="">
|
||||
<u-icon color="#A1DBF5" size="32" name="arrow-right"></u-icon>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { navigateTo, jumpTo } from '@/utils/util'
|
||||
|
||||
const props = defineProps({
|
||||
navs: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
},
|
||||
})
|
||||
|
||||
const handleClick = (link : any) => {
|
||||
let linkArr = {}
|
||||
if (link.indexOf('http') == 0) {
|
||||
jumpTo(link)
|
||||
} else {
|
||||
linkArr = { path: link }
|
||||
}
|
||||
navigateTo(linkArr)
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss"></style>
|
||||
44
src/components/widgets/nav/nav.vue
Normal file
44
src/components/widgets/nav/nav.vue
Normal file
@@ -0,0 +1,44 @@
|
||||
<template>
|
||||
<view class="nav pt-[40rpx] " v-if="navs.length>0">
|
||||
<view class="nav-item flex flex-wrap">
|
||||
<view
|
||||
v-for="(item, index) in navs"
|
||||
:key="index"
|
||||
class="flex flex-col items-center w-1/4 mb-[40rpx]"
|
||||
@click="handleClick(item.link)"
|
||||
>
|
||||
<u-image width="46px" height="46px" :src="item.image" alt="" />
|
||||
<view class="mt-[14rpx] text-center text-[#F7F7F7]">{{ item.name }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useAppStore } from '@/stores/app'
|
||||
import { navigateTo,jumpTo } from '@/utils/util'
|
||||
|
||||
const props = defineProps({
|
||||
navs: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
},
|
||||
})
|
||||
|
||||
const handleClick = (link: any) => {
|
||||
let linkArr = {}
|
||||
if (link.indexOf('http') == 0) {
|
||||
jumpTo(link)
|
||||
} else {
|
||||
linkArr = { path: link }
|
||||
}
|
||||
if(link.indexOf('/pages/team/index') == 0){
|
||||
navigateTo(linkArr, 'switchTab')
|
||||
}else{
|
||||
navigateTo(linkArr)
|
||||
}
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
<style></style>
|
||||
13
src/components/widgets/search/search.vue
Normal file
13
src/components/widgets/search/search.vue
Normal file
@@ -0,0 +1,13 @@
|
||||
<template>
|
||||
<navigator
|
||||
url="/pages/search/search"
|
||||
class="search px-[24rpx] py-[14rpx] bg-white"
|
||||
hover-class="none"
|
||||
>
|
||||
<u-search placeholder="请输入关键词搜索" disabled :show-action="false"></u-search>
|
||||
</navigator>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts"></script>
|
||||
|
||||
<style></style>
|
||||
44
src/components/widgets/user-balance/user-balance.vue
Normal file
44
src/components/widgets/user-balance/user-balance.vue
Normal file
@@ -0,0 +1,44 @@
|
||||
<template>
|
||||
<view class="bg-[#2C326B] mx-[30rpx] px-[30rpx] py-[40rpx] rounded-lg">
|
||||
<view class="flex justify-between">
|
||||
<view class="w-1/2 text-center">
|
||||
<view class="text-2xl text-[#A1DBF5] mb-[10rpx]">
|
||||
{{getCurrency()}}{{formatMoney(user.user_money)}} {{getCurrency2()}}
|
||||
</view>
|
||||
<view class="">
|
||||
{{t('user.userBalance')}}
|
||||
</view>
|
||||
</view>
|
||||
<view class="">
|
||||
|
|
||||
</view>
|
||||
<view class="w-1/2 text-center">
|
||||
<view class="text-2xl text-[#A1DBF5] mb-[10rpx]">
|
||||
{{user.user_point}}
|
||||
</view>
|
||||
<view class="">
|
||||
{{t('user.userPoint')}}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { getCurrency,getCurrency2, formatMoney, t } from '@/utils/util'
|
||||
|
||||
const props = defineProps({
|
||||
user: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
},
|
||||
})
|
||||
const navigateTo = (url : string) => {
|
||||
uni.navigateTo({
|
||||
url
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
</style>
|
||||
42
src/components/widgets/user-banner/user-banner.vue
Normal file
42
src/components/widgets/user-banner/user-banner.vue
Normal file
@@ -0,0 +1,42 @@
|
||||
<template>
|
||||
<view class="banner h-[200rpx] mx-[30rpx] translate-y-0">
|
||||
<swiper class="swiper h-full" :indicator-dots="banner.length > 0" indicator-active-color="#4173ff"
|
||||
:autoplay="true">
|
||||
<swiper-item v-for="(item, index) in banner" :key="index" @click="handleClick(item.link)">
|
||||
<u-image mode="aspectFit" width="100%" height="100%" :src="item.image" />
|
||||
</swiper-item>
|
||||
</swiper>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useAppStore } from '@/stores/app'
|
||||
import { navigateTo,jumpTo } from '@/utils/util'
|
||||
|
||||
const props = defineProps({
|
||||
banner: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
},
|
||||
styles: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
}
|
||||
})
|
||||
const { getImageUrl } = useAppStore()
|
||||
const handleClick = (link : any) => {
|
||||
let linkArr = {}
|
||||
if (link.indexOf('http') == 0) {
|
||||
jumpTo(link)
|
||||
} else {
|
||||
linkArr = { path: link }
|
||||
}
|
||||
if(link.indexOf('/pages/team/index') == 0){
|
||||
navigateTo(linkArr, 'switchTab')
|
||||
}else{
|
||||
navigateTo(linkArr)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style></style>
|
||||
47
src/components/widgets/user-info/user-info.vue
Normal file
47
src/components/widgets/user-info/user-info.vue
Normal file
@@ -0,0 +1,47 @@
|
||||
<template>
|
||||
<view class="px-[30rpx] mb-[40rpx]">
|
||||
<view class="flex">
|
||||
<u-avatar :src="user.avatar" :size="120"></u-avatar>
|
||||
<view class="ml-[20rpx]">
|
||||
<view class="text-2xl font-bold mb-[20rpx]">{{ user.mobile }}</view>
|
||||
<view class="flex mb-[20rpx]">
|
||||
<view class="flex items-center justify-center" @click.stop="copyText(user.sn)">
|
||||
<text class="mr-[10rpx]">SN:</text>
|
||||
<text class="">{{ user.sn }}</text>
|
||||
<u-icon class="ml-[15rpx]" size="26" name="/static/images/common/copy.png"></u-icon>
|
||||
</view>
|
||||
</view>
|
||||
<view class="text-[#00D2E0] flex items-center">
|
||||
<u-icon class="mr-[10rpx]" size="42" :name="member.logo"></u-icon>
|
||||
<text class="">{{ member.name }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
</view>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { useCopy } from '@/hooks/useCopy'
|
||||
import { t } from '@/utils/util'
|
||||
|
||||
const props = defineProps({
|
||||
user: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
},
|
||||
member: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
}
|
||||
})
|
||||
const { copy } = useCopy()
|
||||
|
||||
const copyText = async (text : string) => {
|
||||
copy(text);
|
||||
uni.$u.toast(t('common.copySuccess'))
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
</style>
|
||||
46
src/components/widgets/user-member/user-member.vue
Normal file
46
src/components/widgets/user-member/user-member.vue
Normal file
@@ -0,0 +1,46 @@
|
||||
<template>
|
||||
<view class="mx-[30rpx] relative overflow-hidden rounded-lg">
|
||||
<view class="w-full h-[200rpx]">
|
||||
<u-image width="100%" height="200rpx" src="/static/images/user/vip_bg.png"></u-image>
|
||||
</view>
|
||||
<view class="absolute w-full top-0 flex items-center justify-between px-[30rpx] py-[40rpx]">
|
||||
<view class="">
|
||||
<view class="flex items-center justify-between text-[#FFE4BC] mb-[30rpx] ">
|
||||
<u-icon size="32" name="/static/images/user/viplogo.png"></u-icon>
|
||||
<view class="ml-[10rpx]">
|
||||
{{t('vip.unlocked')}}
|
||||
</view>
|
||||
</view>
|
||||
<view class="text-[#FFFFFF] text-2xl">
|
||||
{{ member.name }}
|
||||
</view>
|
||||
</view>
|
||||
<view class="">
|
||||
<navigator hover-class="none" url="/pages/user_vip/index">
|
||||
<view class="text-[#FFE4BC]">
|
||||
{{t('vip.upgrade')}}
|
||||
</view>
|
||||
</navigator>
|
||||
</view>
|
||||
|
||||
</view>
|
||||
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { t } from '@/utils/util'
|
||||
|
||||
const props = defineProps({
|
||||
member: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.vip-btn {
|
||||
background-color: #ffd200;
|
||||
}
|
||||
</style>
|
||||
5
src/enums/agreementEnums.ts
Normal file
5
src/enums/agreementEnums.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
//菜单主题类型
|
||||
export enum AgreementEnum {
|
||||
PRIVACY = 'privacy',
|
||||
SERVICE = 'service'
|
||||
}
|
||||
49
src/enums/appEnums.ts
Normal file
49
src/enums/appEnums.ts
Normal file
@@ -0,0 +1,49 @@
|
||||
//菜单主题类型
|
||||
export enum ThemeEnum {
|
||||
LIGHT = 'light',
|
||||
DARK = 'dark'
|
||||
}
|
||||
|
||||
// 客户端
|
||||
export enum ClientEnum {
|
||||
MP_WEIXIN = 1, // 微信-小程序
|
||||
OA_WEIXIN = 2, // 微信-公众号
|
||||
H5 = 3, // H5
|
||||
IOS = 5, //苹果
|
||||
ANDROID = 6 //安卓
|
||||
}
|
||||
|
||||
export enum SMSEnum {
|
||||
LOGIN = 'YZMDL',
|
||||
BIND_MOBILE = 'BDSJHM',
|
||||
CHANGE_MOBILE = 'BGSJHM',
|
||||
FIND_PASSWORD = 'ZHDLMM'
|
||||
}
|
||||
|
||||
export enum SearchTypeEnum {
|
||||
HISTORY = 'history'
|
||||
}
|
||||
|
||||
// 用户资料
|
||||
export enum FieldType {
|
||||
NONE = '',
|
||||
AVATAR = 'avatar',
|
||||
USERNAME = 'account',
|
||||
NICKNAME = 'nickname',
|
||||
SEX = 'sex'
|
||||
}
|
||||
|
||||
// 支付结果
|
||||
export enum PayStatusEnum {
|
||||
SUCCESS = 'success',
|
||||
FAIL = 'fail',
|
||||
PENDING = 'pending'
|
||||
}
|
||||
|
||||
// 页面状态
|
||||
export enum PageStatusEnum {
|
||||
LOADING = 'loading', // 加载中
|
||||
NORMAL = 'normal', // 正常
|
||||
ERROR = 'error', // 异常
|
||||
EMPTY = 'empty' // 为空
|
||||
}
|
||||
11
src/enums/constantEnums.ts
Normal file
11
src/enums/constantEnums.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
// 本地缓冲key
|
||||
|
||||
//token
|
||||
export const TOKEN_KEY = 'token'
|
||||
|
||||
// 搜索历史记录
|
||||
export const HISTORY = 'history'
|
||||
|
||||
export const BACK_URL = 'back_url'
|
||||
|
||||
export const PAY_STATUS_EVENT = 'event:payStatus'
|
||||
22
src/enums/requestEnums.ts
Normal file
22
src/enums/requestEnums.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
export enum ContentTypeEnum {
|
||||
// json
|
||||
JSON = 'application/json;charset=UTF-8',
|
||||
// form-data 上传资源(图片,视频)
|
||||
FORM_DATA = 'multipart/form-data;charset=UTF-8'
|
||||
}
|
||||
|
||||
export enum RequestMethodsEnum {
|
||||
GET = 'GET',
|
||||
POST = 'POST'
|
||||
}
|
||||
|
||||
export enum RequestCodeEnum {
|
||||
SUCCESS = 1, //成功
|
||||
FAILED = 0, // 失败
|
||||
TOKEN_INVALID = -1 // TOKEN参数无效
|
||||
}
|
||||
|
||||
export enum RequestErrMsgEnum {
|
||||
ABORT = 'request:fail abort',
|
||||
TIMEOUT = 'request:fail timeout'
|
||||
}
|
||||
25
src/hooks/useCopy.ts
Normal file
25
src/hooks/useCopy.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
export function useCopy() {
|
||||
const copy = (text: string) => {
|
||||
// #ifdef H5
|
||||
let transfer = document.createElement('input');
|
||||
document.body.appendChild(transfer);
|
||||
transfer.value = text;
|
||||
transfer.select();
|
||||
if (document.execCommand('copy')) {
|
||||
document.execCommand('copy');
|
||||
}
|
||||
transfer.blur();
|
||||
document.body.removeChild(transfer);
|
||||
// #endif
|
||||
// #ifndef H5
|
||||
uni.setClipboardData({
|
||||
data: String(text),
|
||||
showToast:false
|
||||
})
|
||||
// #endif
|
||||
|
||||
}
|
||||
return {
|
||||
copy
|
||||
}
|
||||
}
|
||||
21
src/hooks/useLockFn.ts
Normal file
21
src/hooks/useLockFn.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import { ref } from 'vue'
|
||||
|
||||
export function useLockFn(fn: (...args: any[]) => Promise<any>) {
|
||||
const isLock = ref(false)
|
||||
const lockFn = async (...args: any[]) => {
|
||||
if (isLock.value) return
|
||||
isLock.value = true
|
||||
try {
|
||||
const res = await fn(...args)
|
||||
isLock.value = false
|
||||
return res
|
||||
} catch (e) {
|
||||
isLock.value = false
|
||||
throw e
|
||||
}
|
||||
}
|
||||
return {
|
||||
isLock,
|
||||
lockFn
|
||||
}
|
||||
}
|
||||
72
src/hooks/useTouch.ts
Normal file
72
src/hooks/useTouch.ts
Normal file
@@ -0,0 +1,72 @@
|
||||
import { reactive } from 'vue'
|
||||
|
||||
/**
|
||||
* @description 触碰屏幕钩子函数
|
||||
* @return { Function } 暴露钩子
|
||||
*/
|
||||
export function useTouch() {
|
||||
// 最小移动距离
|
||||
const MIN_DISTANCE = 10
|
||||
|
||||
const touch = reactive({
|
||||
direction: '',
|
||||
deltaX: 0,
|
||||
deltaY: 0,
|
||||
offsetX: 0,
|
||||
offsetY: 0
|
||||
})
|
||||
|
||||
/**
|
||||
* @description 计算距离
|
||||
* @return { string } 空字符串
|
||||
*/
|
||||
const getDirection = (x: number, y: number) => {
|
||||
if (x > y && x > MIN_DISTANCE) {
|
||||
return 'horizontal'
|
||||
}
|
||||
if (y > x && y > MIN_DISTANCE) {
|
||||
return 'vertical'
|
||||
}
|
||||
return ''
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 重置参数
|
||||
*/
|
||||
const resetTouchStatus = () => {
|
||||
touch.direction = ''
|
||||
touch.deltaX = 0
|
||||
touch.deltaY = 0
|
||||
touch.offsetX = 0
|
||||
touch.offsetY = 0
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 触发
|
||||
*/
|
||||
const touchStart = (event: any) => {
|
||||
resetTouchStatus()
|
||||
const events = event.touches[0]
|
||||
touch.startX = events.clientX
|
||||
touch.startY = events.clientY
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 移动
|
||||
*/
|
||||
const touchMove = (event: any) => {
|
||||
const events = event.touches[0]
|
||||
touch.deltaX = events.clientX - touch.startX
|
||||
touch.deltaY = events.clientY - touch.startY
|
||||
touch.offsetX = Math.abs(touch.deltaX)
|
||||
touch.offsetY = Math.abs(touch.deltaY)
|
||||
touch.direction = touch.direction || getDirection(touch.offsetX, touch.offsetY)
|
||||
}
|
||||
|
||||
return {
|
||||
touch,
|
||||
resetTouchStatus,
|
||||
touchStart,
|
||||
touchMove
|
||||
}
|
||||
}
|
||||
16
src/main.ts
Normal file
16
src/main.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import { createSSRApp } from 'vue'
|
||||
import App from './App.vue'
|
||||
import plugins from './plugins'
|
||||
import { setupRouter } from './router'
|
||||
import './styles/index.scss'
|
||||
export function createApp() {
|
||||
const app = createSSRApp(App)
|
||||
|
||||
Promise.resolve().then(() => {
|
||||
setupRouter()
|
||||
})
|
||||
app.use(plugins)
|
||||
return {
|
||||
app
|
||||
}
|
||||
}
|
||||
92
src/manifest.json
Normal file
92
src/manifest.json
Normal file
@@ -0,0 +1,92 @@
|
||||
{
|
||||
"name" : "BD Market",
|
||||
"appid" : "__UNI__F98ABA2",
|
||||
"description" : "",
|
||||
"versionName" : "1.0.2",
|
||||
"versionCode" : "100",
|
||||
"transformPx" : false,
|
||||
/* 5+App特有相关 */
|
||||
"app-plus" : {
|
||||
"usingComponents" : true,
|
||||
"nvueStyleCompiler" : "uni-app",
|
||||
"compilerVersion" : 3,
|
||||
"compatible" : {
|
||||
"ignoreVersion" : true
|
||||
},
|
||||
"splashscreen" : {
|
||||
"alwaysShowBeforeRender" : true,
|
||||
"waiting" : true,
|
||||
"autoclose" : true,
|
||||
"delay" : 0
|
||||
},
|
||||
/* 模块配置 */
|
||||
"modules" : {
|
||||
"VideoPlayer" : {}
|
||||
},
|
||||
/* 应用发布信息 */
|
||||
"distribute" : {
|
||||
/* android打包配置 */
|
||||
"android" : {
|
||||
"permissions" : [
|
||||
"<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>",
|
||||
"<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>",
|
||||
"<uses-permission android:name=\"android.permission.VIBRATE\"/>",
|
||||
"<uses-permission android:name=\"android.permission.READ_LOGS\"/>",
|
||||
"<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>",
|
||||
"<uses-feature android:name=\"android.hardware.camera.autofocus\"/>",
|
||||
"<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>",
|
||||
"<uses-permission android:name=\"android.permission.CAMERA\"/>",
|
||||
"<uses-permission android:name=\"android.permission.GET_ACCOUNTS\"/>",
|
||||
"<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>",
|
||||
"<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>",
|
||||
"<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>",
|
||||
"<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>",
|
||||
"<uses-feature android:name=\"android.hardware.camera\"/>",
|
||||
"<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>"
|
||||
],
|
||||
"minSdkVersion" : 21,
|
||||
"abiFilters" : [ "armeabi-v7a", "arm64-v8a", "x86" ]
|
||||
},
|
||||
/* ios打包配置 */
|
||||
"ios" : {
|
||||
"dSYMs" : false
|
||||
},
|
||||
/* SDK配置 */
|
||||
"sdkConfigs" : {
|
||||
"ad" : {}
|
||||
}
|
||||
}
|
||||
},
|
||||
/* 快应用特有相关 */
|
||||
"quickapp" : {},
|
||||
/* 小程序特有相关 */
|
||||
"mp-weixin" : {
|
||||
"appid" : "wx386a75e518b38935",
|
||||
"setting" : {
|
||||
"urlCheck" : false,
|
||||
"es6" : true,
|
||||
"minified" : true
|
||||
},
|
||||
"usingComponents" : true
|
||||
},
|
||||
"mp-alipay" : {
|
||||
"usingComponents" : true
|
||||
},
|
||||
"mp-baidu" : {
|
||||
"usingComponents" : true
|
||||
},
|
||||
"mp-toutiao" : {
|
||||
"usingComponents" : true
|
||||
},
|
||||
"uniStatistics" : {
|
||||
"enable" : false
|
||||
},
|
||||
"vueVersion" : "3",
|
||||
"h5" : {
|
||||
"router" : {
|
||||
"mode" : "history",
|
||||
"base" : "/"
|
||||
},
|
||||
"title" : "Loading..."
|
||||
}
|
||||
}
|
||||
159
src/packages/pages/recharge/index.vue
Normal file
159
src/packages/pages/recharge/index.vue
Normal file
@@ -0,0 +1,159 @@
|
||||
<template>
|
||||
<view>
|
||||
<u-navbar :back-text="t('recharge.title')" :back-text-style="{color: '#FFFFFF'}" :background="{backgroundColor: '#4E55AF'}" back-icon-color="#FFFFFF" >
|
||||
<view class="flex justify-end w-full pr-[20rpx] relative">
|
||||
<navigator hover-class="none" url="/packages/pages/recharge/record">
|
||||
<u-icon size="40" name="/static/images/common/record.png"></u-icon>
|
||||
</navigator>
|
||||
</view>
|
||||
</u-navbar>
|
||||
<view class="bg-[#4E55AF] px-[30rpx] pt-[50rpx] pb-[15rpx]">
|
||||
<view class="flex flex-wrap">
|
||||
<view class="flex flex-col items-center w-1/5" v-for="(item, index) in data.money_list" :key="index"
|
||||
@click="moneyChange(item)">
|
||||
<view class="item rounded-md px-[20rpx] py-[10rpx] bg-[#2C326B] mb-[15px]">
|
||||
{{getCurrency()}}{{item}}
|
||||
</view>
|
||||
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="common-money my-[20rpx] mx-[30rpx] py-[20rpx] ">
|
||||
<view class=" mb-[30rpx]">
|
||||
{{t('recharge.rechargeMoney')}}
|
||||
</view>
|
||||
<view class="bg-[#3d4277] rounded-lg px-[20rpx] py-[10rpx]">
|
||||
<u-input v-model="data.money" type="number" :border="false"
|
||||
:placeholder="t('recharge.rechargeMoneyPlaceholder')" />
|
||||
</view>
|
||||
</view>
|
||||
<view class="common-money my-[20rpx] px-[30rpx] py-[20rpx] mb-[80px]">
|
||||
<view class=" mb-[30rpx]">
|
||||
{{t('recharge.rechargeMethod')}}
|
||||
</view>
|
||||
<view class="">
|
||||
<view class="flex justify-between items-center bg-[#2C326B] rounded-lg p-[20rpx] mb-[30rpx]" v-for="(item, index) in data.method_list"
|
||||
:key="index" @click="methodChange(item)">
|
||||
<view class="flex justify-start items-center">
|
||||
<view class="">
|
||||
<u-icon class="mr-[20rpx]" size="64" :name="item.logo"></u-icon>
|
||||
</view>
|
||||
<view class="">
|
||||
{{item.name}}
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="">
|
||||
<u-icon v-if="item.id==data.method_id" size="32" class="check-box"
|
||||
name="checkbox-mark"></u-icon>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="h-[10rpx]">
|
||||
</view>
|
||||
<view class="fixed flex bottom-0 w-full py-[30rpx] px-[50rpx] justify-between z-10 leading-loose max-w-[750px] bg-[#2C326B]">
|
||||
<view class="money-tips">
|
||||
{{t('recharge.money')}}
|
||||
<text class="money font-bold text-2xl">{{getCurrency()}}{{data.money}} {{getCurrency2()}}</text>
|
||||
</view>
|
||||
<view class="">
|
||||
<u-button type="primary" size="medium" shape="circle" :disabled="data.money == ''||data.method_type == 0"
|
||||
@click="submitHandle"> {{t('recharge.rechargeBtn')}} </u-button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { reactive, ref, nextTick } from 'vue'
|
||||
import { rechargeMethod, commonMoney, rechargeConfig } from '@/api/finance'
|
||||
import { getCurrency,getCurrency2, formatMoney, t } from '@/utils/util'
|
||||
|
||||
uni.setNavigationBarTitle({ title: t('recharge.title') })
|
||||
const data = reactive({
|
||||
money: '',
|
||||
method_id: 0,
|
||||
method_type: 0,//1USDT2扫码3银行卡6波场7自定义地址
|
||||
money_list: [],
|
||||
method_list: [],
|
||||
min: 0,
|
||||
})
|
||||
const methodChange = (item : any) => {
|
||||
data.method_type = item.type;
|
||||
data.method_id = item.id;
|
||||
}
|
||||
|
||||
const moneyChange = (money : string) => {
|
||||
data.money = money;
|
||||
}
|
||||
|
||||
const submitHandle = () => {
|
||||
|
||||
if (data.money == "") return uni.$u.toast(t('recharge.rechargeMoneyEmpty'))
|
||||
|
||||
//充值金额判断
|
||||
if (parseFloat(data.money) < data.min) return uni.$u.toast(t('recharge.minMoney') + getCurrency() + data.min + getCurrency2())
|
||||
|
||||
if (data.method_type == 0) {
|
||||
return uni.$u.toast(t('recharge.rechargeMethodEmpty'))
|
||||
}
|
||||
// 使用正则表达式匹配小数
|
||||
var decimalMatch = data.money.match(/\.(\d+)/);
|
||||
if (decimalMatch) {
|
||||
if (decimalMatch[1].length > 2) {
|
||||
data.money = formatMoney(data.money);
|
||||
}
|
||||
}
|
||||
|
||||
let params = '?id=' + data.method_id + '&money=' + data.money;
|
||||
if (data.method_type == 1 || data.method_type == 2) {
|
||||
uni.redirectTo({
|
||||
url: '/packages/pages/recharge/recharge_qrcode' + params
|
||||
})
|
||||
} else if (data.method_type == 3) {
|
||||
uni.redirectTo({
|
||||
url: '/packages/pages/recharge/recharge_bank' + params
|
||||
})
|
||||
} else if (data.method_type == 4) {
|
||||
uni.redirectTo({
|
||||
url: '/packages/pages/recharge/recharge_online' + params
|
||||
})
|
||||
} else if (data.method_type == 5) {
|
||||
uni.navigateTo({
|
||||
url: '/packages/pages/recharge/recharge_udun' + params
|
||||
})
|
||||
} else if (data.method_type == 6) {
|
||||
uni.navigateTo({
|
||||
url: '/packages/pages/recharge/recharge_tron' + params
|
||||
})
|
||||
} else if (data.method_type == 7) {
|
||||
uni.navigateTo({
|
||||
url: '/packages/pages/recharge/recharge_address' + params
|
||||
})
|
||||
}
|
||||
}
|
||||
const getData = async () => {
|
||||
const res = await rechargeConfig()
|
||||
if(res.need_bing_wallet == 1){
|
||||
uni.redirectTo({
|
||||
url: '/packages/pages/withdraw/account'
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
data.min = res.min;
|
||||
|
||||
data.money_list = await commonMoney()
|
||||
const apiData = await rechargeMethod()
|
||||
if (apiData.length > 0) {
|
||||
data.method_id = apiData[0]['id']
|
||||
data.method_type = apiData[0]['type']
|
||||
}
|
||||
data.method_list = apiData
|
||||
}
|
||||
getData()
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
</style>
|
||||
120
src/packages/pages/recharge/order_detail.vue
Normal file
120
src/packages/pages/recharge/order_detail.vue
Normal file
@@ -0,0 +1,120 @@
|
||||
<template>
|
||||
<view>
|
||||
<h-dark title=""></h-dark>
|
||||
<view class="bg-[#4E55AF] px-[30rpx] pt-[30rpx] pb-[300rpx]">
|
||||
<view class=" flex flex-col items-center">
|
||||
<u-image width="300" height="180" mode="widthFix"
|
||||
src="/static/images/withdraw/withdraw_bg.png"></u-image>
|
||||
</view>
|
||||
</view>
|
||||
<view class="bg-[#2C326B] rounded-lg p-[50rpx] mx-[30rpx] mt-[-260rpx]">
|
||||
<view class="flex justify-between mb-[40rpx]">
|
||||
<view class="w-1/4">
|
||||
{{t('recharge.rechargeMethod')}}
|
||||
</view>
|
||||
<view class="w-3/4 text-right ">
|
||||
{{orderData.method_name}}
|
||||
</view>
|
||||
</view>
|
||||
<view class="flex justify-between mb-[40rpx]">
|
||||
<view class="w-1/4">
|
||||
{{t('orderDetail.status')}}
|
||||
</view>
|
||||
<view v-if="orderData.status==1" class="w-3/4 text-right text-success ">
|
||||
{{t('tabs.finish')}}
|
||||
</view>
|
||||
<view v-if="orderData.status==0" class="w-3/4 text-right text-primary ">
|
||||
{{t('tabs.pending')}}
|
||||
</view>
|
||||
<view v-if="orderData.status==2" class="w-3/4 text-right text-error ">
|
||||
{{t('tabs.fail')}}
|
||||
</view>
|
||||
</view>
|
||||
<view class="flex justify-between mb-[40rpx]">
|
||||
<view class="w-1/4">
|
||||
{{t('orderDetail.orderSn')}}
|
||||
</view>
|
||||
<view class="w-3/4 text-right ">
|
||||
{{orderData.sn}}
|
||||
</view>
|
||||
</view>
|
||||
<view class="flex justify-between mb-[40rpx]">
|
||||
<view class="w-1/4">
|
||||
{{t('orderDetail.createTime')}}
|
||||
</view>
|
||||
<view class="w-3/4 text-right ">
|
||||
{{orderData.create_time}}
|
||||
</view>
|
||||
</view>
|
||||
<view class="flex justify-between mb-[40rpx]" v-if="orderData.status==2">
|
||||
<view class="w-1/4">
|
||||
{{t('orderDetail.remark')}}
|
||||
</view>
|
||||
<view class="w-3/4 text-error mt-[12rpx]">
|
||||
{{t('recharge.rechargeFailTips')}}
|
||||
</view>
|
||||
</view>
|
||||
<u-line class="text-info" margin="20rpx 0 40rpx 0" border-style="dashed" />
|
||||
<view class="flex justify-between">
|
||||
<view class="w-1/4">
|
||||
{{t('orderDetail.money')}}
|
||||
</view>
|
||||
<view class="w-3/4 text-right">
|
||||
<view v-if="orderData.status==1" class="text-lg font-bold text-success">
|
||||
{{getCurrency()}}{{formatMoney(orderData.amount)}} {{getCurrency2()}}
|
||||
</view>
|
||||
<view v-if="orderData.status==0" class="text-lg font-bold text-primary">
|
||||
{{getCurrency()}}{{formatMoney(orderData.amount)}} {{getCurrency2()}}
|
||||
</view>
|
||||
<view v-if="orderData.status==2" class="text-lg font-bold text-error">
|
||||
{{getCurrency()}}{{formatMoney(orderData.amount)}} {{getCurrency2()}}
|
||||
</view>
|
||||
<view class="mt-[10rpx]" v-if="orderData.rate && orderData.rate != 1">
|
||||
≈ {{orderData.amount_act}} {{orderData.symbol}}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="flex justify-between mt-[40rpx]" v-if="orderData.charge>0">
|
||||
<view class="w-1/4">
|
||||
{{t('orderDetail.charge')}}
|
||||
</view>
|
||||
<view class="w-3/4 text-right ">
|
||||
{{getCurrency()}}{{formatMoney(orderData.charge)}} {{getCurrency2()}}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="max-w-[750px] fixed bottom-[50rpx] w-4/5 ml-[10%]">
|
||||
<u-button type="primary" @click="handleBack"> {{t('common.back')}} </u-button>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue'
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
import { rechargeRecordDetail } from '@/api/finance'
|
||||
import { getCurrency,getCurrency2, formatDate, formatMoney,t } from '@/utils/util'
|
||||
uni.setNavigationBarTitle({ title: t('recharge.title') })
|
||||
const orderData = ref<any>({})
|
||||
let orderId = ''
|
||||
|
||||
const getData = async (id) => {
|
||||
orderData.value = await rechargeRecordDetail({ id, date: formatDate(Math.round(Date.now() / 1000)) })
|
||||
}
|
||||
const handleBack = async () => {
|
||||
let canNavBack = getCurrentPages()
|
||||
if (canNavBack && canNavBack.length > 1) {
|
||||
uni.navigateBack()
|
||||
} else {
|
||||
history.back();
|
||||
}
|
||||
}
|
||||
onLoad((options : any) => {
|
||||
orderId = options.id
|
||||
getData(orderId)
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
</style>
|
||||
149
src/packages/pages/recharge/recharge_address.vue
Normal file
149
src/packages/pages/recharge/recharge_address.vue
Normal file
@@ -0,0 +1,149 @@
|
||||
<template>
|
||||
<view>
|
||||
<h-dark :title="t('recharge.title')"></h-dark>
|
||||
<view class="mx-[30rpx] mt-[20rpx]">
|
||||
<view class="flex items-center bg-[#2C326B] rounded-lg px-[50rpx] py-[20rpx]">
|
||||
<u-icon size="80" :name="method.logo"></u-icon>
|
||||
<view class="ml-[16rpx]">{{method.name}}</view>
|
||||
</view>
|
||||
<view class="bg-[#2C326B] rounded-lg mt-[20rpx] p-[30rpx]">
|
||||
<view class="text-center">
|
||||
<view class="mb-[16rpx] text-[#00D2E0]">{{t('recharge.address')}}</view>
|
||||
<view class="bg-[#3d4277] rounded p-[20rpx] rounded-lg">
|
||||
<view class="flex break-all items-center justify-center" @click.stop="copyText(method.address)">
|
||||
<view class="mr-[10rpx]">{{method.address}}</view>
|
||||
<view>
|
||||
<u-icon size="26" name="/static/images/common/copy.png">
|
||||
</u-icon>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="bg-[#2C326B] rounded-lg mt-[20rpx] px-[30rpx] py-[30rpx]">
|
||||
<view class="text-[#00D2E0] mb-[10rpx]">
|
||||
{{t('recharge.rechargeMoney')}}
|
||||
</view>
|
||||
<view class="">
|
||||
<view class="font-bold text-lg py-[10rpx]">
|
||||
{{getCurrency()}}{{formData.money}} {{getCurrency2()}}
|
||||
<text class="text-[#00D2E0]" v-if="method.rate!=1">(≈
|
||||
{{formatMoney(formData.money,method.symbol,method.rate,method.precision)}})</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="text-[#00D2E0] my-[20rpx]" v-if="method.is_voucher">
|
||||
{{t('recharge.voucher')}}
|
||||
</view>
|
||||
<view class="" v-if="method.is_voucher">
|
||||
<view class="bg-[#3d4277] rounded w-full flex justify-center">
|
||||
<u-upload class="" ref="uploader" :custom-btn="true" :deletable="false" :auto-upload="false"
|
||||
max-count="1" :max-size="20*1024*1024" v-model="formData.voucher">
|
||||
<template v-slot:addBtn>
|
||||
<view class="flex items-center justify-center slot-btn w-[180rpx] h-[180rpx] "
|
||||
hover-class="slot-btn__hover" hover-stay-time="150">
|
||||
<u-icon name="photo" size="80" class="text-[#00D2E0]"></u-icon>
|
||||
</view>
|
||||
</template>
|
||||
</u-upload>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="my-[30rpx]">
|
||||
<u-button type="primary" @click="handleConfirm"> {{t('common.submit')}} </u-button>
|
||||
</view>
|
||||
<view class="leading-loose">
|
||||
<view class="">
|
||||
{{replaceStr(t('recharge.udunTips1'),'{code}',method.protocol)}}
|
||||
</view>
|
||||
<view class="">
|
||||
{{t('recharge.udunTips2')}}
|
||||
</view>
|
||||
<view class="">
|
||||
{{t('recharge.udunTips3')}}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, reactive } from 'vue'
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
import { rechargeMethodDetailAddress, recharge } from '@/api/finance'
|
||||
import { uploadImage } from '@/api/app'
|
||||
import { useUserStore } from '@/stores/user'
|
||||
import { formatDate, formatMoney, getCurrency,getCurrency2, replaceStr } from '@/utils/util'
|
||||
import { useCopy } from '@/hooks/useCopy'
|
||||
import { t } from '@/utils/util'
|
||||
|
||||
uni.setNavigationBarTitle({ title: t('recharge.title') })
|
||||
const { copy } = useCopy()
|
||||
const userStore = useUserStore()
|
||||
const uploader = ref();
|
||||
const method = ref<any>({})
|
||||
const formData = reactive({
|
||||
id: 0,
|
||||
money: '',
|
||||
address: '',
|
||||
voucher: '',
|
||||
date: formatDate(Math.round(Date.now() / 1000))
|
||||
})
|
||||
|
||||
const copyText = async (text : string) => {
|
||||
copy(text);
|
||||
uni.$u.toast(t('common.copySuccess'))
|
||||
}
|
||||
|
||||
const handleConfirm = async () => {
|
||||
if (method.value.is_voucher) {
|
||||
if (uploader.value.lists.length <= 0) return uni.$u.toast(t('recharge.voucherEmpty'))
|
||||
const res : any = await uploadImage(uploader.value.lists[0].url, userStore.temToken!)
|
||||
formData.voucher = res.url;
|
||||
}
|
||||
await recharge(formData)
|
||||
uni.redirectTo({
|
||||
url: '/pages/common/successful?type=0'
|
||||
})
|
||||
}
|
||||
|
||||
const getData = async (id : number) => {
|
||||
const res = await rechargeMethodDetailAddress({ id })
|
||||
|
||||
//计算每日获取次数
|
||||
if (!uni.getStorageSync('address_avail_num_' + formData.id)) {
|
||||
uni.setStorageSync('address_avail_num_' + formData.id, res.date + ',' + 1);
|
||||
} else {
|
||||
//对比时间
|
||||
var str = uni.getStorageSync('address_avail_num_' + formData.id);
|
||||
const str_arr = str.split(',');
|
||||
if (str_arr[0] == res.date) {
|
||||
if (parseInt(str_arr[1]) >= res.avail_num) {
|
||||
uni.$u.toast(t('recharge.addressNumTips'))
|
||||
let canNavBack = getCurrentPages()
|
||||
if (canNavBack && canNavBack.length > 1) {
|
||||
uni.navigateBack()
|
||||
} else {
|
||||
history.back();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
uni.setStorageSync('address_avail_num_' + formData.id, res.date + ',' + (parseInt(str_arr[1]) + 1));
|
||||
} else {
|
||||
uni.setStorageSync('address_avail_num_' + formData.id, res.date + ',' + 1);
|
||||
}
|
||||
}
|
||||
|
||||
method.value = res;
|
||||
formData.address = res.address;
|
||||
|
||||
}
|
||||
onLoad((options : any) => {
|
||||
formData.id = options.id
|
||||
formData.money = options.money
|
||||
getData(formData.id)
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
</style>
|
||||
126
src/packages/pages/recharge/recharge_bank.vue
Normal file
126
src/packages/pages/recharge/recharge_bank.vue
Normal file
@@ -0,0 +1,126 @@
|
||||
<template>
|
||||
<view>
|
||||
<h-dark :title="t('recharge.title')"></h-dark>
|
||||
<view class="flex items-center bg-white px-[50rpx] py-[20rpx] mt-[12rpx]">
|
||||
<u-icon size="80" :name="method.logo"></u-icon>
|
||||
<view class="ml-[16rpx]">{{method.name}}</view>
|
||||
</view>
|
||||
<view class="bg-white mt-[20rpx] p-[40rpx]">
|
||||
<view class="mb-[15rpx] mt-[30rpx]">
|
||||
<view class="mb-[16rpx] text-muted">{{t('recharge.bankName')}}</view>
|
||||
<view class="bg-[#f6f7fb] rounded p-[20rpx]">
|
||||
<view class="flex break-all items-center justify-between ">
|
||||
<view>{{method.bank_name}}</view>
|
||||
<view @click.stop="copyText(method.bank_name)"><u-icon size="26"
|
||||
name="/static/images/common/copy_1.png"></u-icon></view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="mb-[15rpx] mt-[30rpx]">
|
||||
<view class="mb-[16rpx] text-muted">{{t('recharge.bankUsername')}}</view>
|
||||
<view class="bg-[#f6f7fb] rounded p-[20rpx]">
|
||||
<view class="flex break-all items-center justify-between ">
|
||||
<view>{{method.bank_username}}</view>
|
||||
<view @click.stop="copyText(method.bank_username)"><u-icon size="26"
|
||||
name="/static/images/common/copy_1.png"></u-icon></view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="mb-[15rpx] mt-[30rpx]">
|
||||
<view class="mb-[16rpx] text-muted">{{t('recharge.bankAccount')}}</view>
|
||||
<view class="bg-[#f6f7fb] rounded p-[20rpx]">
|
||||
<view class="flex break-all items-center justify-between ">
|
||||
<view>{{method.account}}</view>
|
||||
<view @click.stop="copyText(method.account)"><u-icon size="26"
|
||||
name="/static/images/common/copy_1.png"></u-icon></view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="bg-white mt-[20rpx] px-[40rpx] py-[30rpx]">
|
||||
<view class="text-muted mb-[16rpx]">
|
||||
{{t('recharge.rechargeMoney')}}
|
||||
</view>
|
||||
<view class="font-bold text-lg mb-[50rpx]">
|
||||
{{getCurrency()}}{{formData.money}}
|
||||
<text class="text-muted" v-if="method.rate!=1">(≈
|
||||
{{formatMoney(formData.money,method.symbol,method.rate,method.precision)}})</text>
|
||||
</view>
|
||||
<view class="text-muted mb-[16rpx]">
|
||||
{{t('recharge.voucher')}}
|
||||
</view>
|
||||
<view class="">
|
||||
<view class="bg-[#f6f7fb] rounded w-full flex justify-center">
|
||||
<u-upload class="" ref="uploader" :custom-btn="true" :deletable="false" :auto-upload="false"
|
||||
max-count="1" :max-size="20*1024*1024" v-model="formData.voucher">
|
||||
<template v-slot:addBtn>
|
||||
<view class="flex items-center justify-center slot-btn w-[180rpx] h-[180rpx] "
|
||||
hover-class="slot-btn__hover" hover-stay-time="150">
|
||||
<u-icon name="photo" size="80" class="text-muted"></u-icon>
|
||||
</view>
|
||||
</template>
|
||||
</u-upload>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class=" px-[40rpx] my-[80rpx] pb-[50rpx]">
|
||||
<u-button type="primary" @click="handleConfirm"> {{t('common.submit')}} </u-button>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, reactive } from 'vue'
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
import { rechargeMethodDetail, recharge } from '@/api/finance'
|
||||
import { uploadImage } from '@/api/app'
|
||||
import { useUserStore } from '@/stores/user'
|
||||
import { formatDate, formatMoney, getCurrency } from '@/utils/util'
|
||||
import { useCopy } from '@/hooks/useCopy'
|
||||
import { t } from '@/utils/util'
|
||||
|
||||
uni.setNavigationBarTitle({ title: t('recharge.title') })
|
||||
const { copy } = useCopy()
|
||||
const userStore = useUserStore()
|
||||
const uploader = ref();
|
||||
const method = ref<any>({})
|
||||
const formData = reactive({
|
||||
id: 0,
|
||||
money: '',
|
||||
voucher: '',
|
||||
date: formatDate(Math.round(Date.now() / 1000))
|
||||
})
|
||||
|
||||
const copyText = async (text : string) => {
|
||||
copy(text);
|
||||
uni.$u.toast(t('common.copySuccess'))
|
||||
}
|
||||
|
||||
|
||||
const handleConfirm = async () => {
|
||||
if (uploader.value.lists.length <= 0) return uni.$u.toast(t('recharge.voucherEmpty'))
|
||||
const res : any = await uploadImage(uploader.value.lists[0].url, userStore.temToken!)
|
||||
formData.voucher = res.url;
|
||||
await recharge(formData)
|
||||
uni.redirectTo({
|
||||
url: '/pages/common/successful?type=0'
|
||||
})
|
||||
}
|
||||
|
||||
const getData = async (id : number) => {
|
||||
method.value = await rechargeMethodDetail({ id })
|
||||
}
|
||||
onLoad((options : any) => {
|
||||
formData.id = options.id
|
||||
formData.money = options.money
|
||||
getData(formData.id)
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.shadow-inner {
|
||||
border-radius: 10px;
|
||||
padding: 5px 10px;
|
||||
box-shadow: inset 0px 1px 4px 0px rgb(0 0 0 / 0.3);
|
||||
}
|
||||
</style>
|
||||
12
src/packages/pages/recharge/recharge_online.vue
Normal file
12
src/packages/pages/recharge/recharge_online.vue
Normal file
@@ -0,0 +1,12 @@
|
||||
<template>
|
||||
<view>
|
||||
<h-dark title=""></h-dark>
|
||||
<view></view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
</style>
|
||||
117
src/packages/pages/recharge/recharge_qrcode.vue
Normal file
117
src/packages/pages/recharge/recharge_qrcode.vue
Normal file
@@ -0,0 +1,117 @@
|
||||
<template>
|
||||
<view>
|
||||
<h-dark :title="t('recharge.title')"></h-dark>
|
||||
<view class="mx-[30rpx] mt-[20rpx]">
|
||||
<view class="flex items-center bg-[#2C326B] rounded-lg px-[50rpx] py-[20rpx]">
|
||||
<u-icon size="80" :name="method.logo"></u-icon>
|
||||
<view class="ml-[16rpx]">{{method.name}}</view>
|
||||
</view>
|
||||
<view class="bg-[#2C326B] rounded-lg mt-[20rpx] p-[30rpx]">
|
||||
<view class="flex justify-center">
|
||||
<view class="rounded-lg overflow-hidden">
|
||||
<u-image width="180px" height="180px" :src="method.qrcode"></u-image>
|
||||
</view>
|
||||
|
||||
</view>
|
||||
<view class="text-center text-[#00D2E0] mt-[30rpx]">
|
||||
<view class="mb-[16rpx]" v-if="method.type==1&&method.account!=''">{{t('recharge.address')}}</view>
|
||||
<view class="mb-[16rpx]" v-if="method.type==2 &&method.account!=''">{{t('recharge.account')}}</view>
|
||||
<view class="bg-[#3d4277] rounded p-[20rpx]">
|
||||
<view class="flex break-all items-center justify-center" v-if="method.account!=''"
|
||||
@click.stop="copyText(method.account)">
|
||||
<view class="mr-[10rpx]">{{method.account}}</view>
|
||||
<view>
|
||||
<u-icon size="26" name="/static/images/common/copy.png">
|
||||
</u-icon>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="bg-[#2C326B] rounded-lg mt-[20rpx] px-[30rpx] py-[30rpx]">
|
||||
<view class="text-[#00D2E0] mb-[10rpx]">
|
||||
{{t('recharge.rechargeMoney')}}
|
||||
</view>
|
||||
<view class="mb-[10rpx]">
|
||||
<view class="font-bold text-lg py-[10rpx]">
|
||||
{{getCurrency()}}{{formData.money}} {{getCurrency2()}}
|
||||
<text class="text-[#00D2E0]" v-if="method.rate!=1">(≈
|
||||
{{formatMoney(formData.money,method.symbol,method.rate,method.precision)}})</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="text-[#00D2E0] my-[20rpx]" v-if="method.is_voucher">
|
||||
{{t('recharge.voucher')}}
|
||||
</view>
|
||||
<view class="" v-if="method.is_voucher">
|
||||
<view class="bg-[#3d4277] rounded w-full flex justify-center">
|
||||
<u-upload class="" ref="uploader" :custom-btn="true" :deletable="false" :auto-upload="false"
|
||||
max-count="1" :max-size="20*1024*1024" v-model="formData.voucher">
|
||||
<template v-slot:addBtn>
|
||||
<view class="flex items-center justify-center slot-btn w-[180rpx] h-[180rpx] "
|
||||
hover-class="slot-btn__hover" hover-stay-time="150">
|
||||
<u-icon name="photo" size="80" class="text-[#00D2E0]"></u-icon>
|
||||
</view>
|
||||
</template>
|
||||
</u-upload>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class=" px-[40rpx] my-[80rpx] pb-[50rpx]">
|
||||
<u-button type="primary" @click="handleConfirm"> {{t('common.submit')}} </u-button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, reactive } from 'vue'
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
import { rechargeMethodDetail, recharge } from '@/api/finance'
|
||||
import { uploadImage } from '@/api/app'
|
||||
import { useUserStore } from '@/stores/user'
|
||||
import { formatDate, formatMoney, getCurrency,getCurrency2 } from '@/utils/util'
|
||||
import { useCopy } from '@/hooks/useCopy'
|
||||
import { t } from '@/utils/util'
|
||||
|
||||
uni.setNavigationBarTitle({ title: t('recharge.title') })
|
||||
const { copy } = useCopy()
|
||||
const userStore = useUserStore()
|
||||
const uploader = ref();
|
||||
const method = ref<any>({})
|
||||
const formData = reactive({
|
||||
id: 0,
|
||||
money: '',
|
||||
voucher: '',
|
||||
date: formatDate(Math.round(Date.now() / 1000))
|
||||
})
|
||||
|
||||
const copyText = async (text : string) => {
|
||||
copy(text);
|
||||
uni.$u.toast(t('common.copySuccess'))
|
||||
}
|
||||
|
||||
|
||||
const handleConfirm = async () => {
|
||||
if (method.value.is_voucher) {
|
||||
if (uploader.value.lists.length <= 0) return uni.$u.toast(t('recharge.voucherEmpty'))
|
||||
const res : any = await uploadImage(uploader.value.lists[0].url, userStore.temToken!)
|
||||
formData.voucher = res.url;
|
||||
}
|
||||
await recharge(formData)
|
||||
uni.redirectTo({
|
||||
url: '/pages/common/successful?type=0'
|
||||
})
|
||||
}
|
||||
|
||||
const getData = async (id : number) => {
|
||||
method.value = await rechargeMethodDetail({ id })
|
||||
}
|
||||
onLoad((options : any) => {
|
||||
formData.id = options.id
|
||||
formData.money = options.money
|
||||
getData(formData.id)
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
</style>
|
||||
69
src/packages/pages/recharge/recharge_tron.vue
Normal file
69
src/packages/pages/recharge/recharge_tron.vue
Normal file
@@ -0,0 +1,69 @@
|
||||
<template>
|
||||
<view>
|
||||
<h-dark :title="t('recharge.title')"></h-dark>
|
||||
<view class="flex items-center bg-white px-[50rpx] py-[20rpx] mt-[12rpx]">
|
||||
<u-icon size="80" :name="method.logo"></u-icon>
|
||||
<view class="ml-[16rpx]">{{method.name}}</view>
|
||||
</view>
|
||||
<view class="bg-white mt-[20rpx] p-[40rpx]">
|
||||
<view class="flex flex-col items-center">
|
||||
<u-image width="180px" height="180px" :src="method.qrcode"></u-image>
|
||||
</view>
|
||||
<view class="text-center text-muted mt-[30rpx]">
|
||||
<view class="mb-[16rpx]">{{t('recharge.address')}}</view>
|
||||
<view class="bg-[#f6f7fb] rounded p-[20rpx]">
|
||||
<view class="flex break-all items-center justify-center" v-if="method.address!=''"
|
||||
@click.stop="copyText(method.address)">
|
||||
<view>{{method.address}}</view>
|
||||
<view><u-icon size="26" name="/static/images/common/copy_1.png"></u-icon></view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="px-[40rpx] mt-[50rpx] leading-loose font-bold">
|
||||
<view class="text-error">
|
||||
{{replaceStr(t('recharge.udunTips1'),'{code}',method.protocol)}}
|
||||
</view>
|
||||
<view class="text-error">
|
||||
{{t('recharge.udunTips2')}}
|
||||
</view>
|
||||
<view class="text-error">
|
||||
{{t('recharge.udunTips3')}}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, reactive } from 'vue'
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
import { rechargeMethodDetailTron } from '@/api/finance'
|
||||
import { replaceStr } from '@/utils/util'
|
||||
import { useCopy } from '@/hooks/useCopy'
|
||||
import { t } from '@/utils/util'
|
||||
|
||||
uni.setNavigationBarTitle({ title: t('recharge.title') })
|
||||
const { copy } = useCopy()
|
||||
const method = ref<any>({})
|
||||
const formData = reactive({
|
||||
id: 0,
|
||||
money: '',
|
||||
})
|
||||
|
||||
const copyText = async (text : string) => {
|
||||
copy(text);
|
||||
uni.$u.toast(t('common.copySuccess'))
|
||||
}
|
||||
|
||||
const getData = async (id : number) => {
|
||||
method.value = await rechargeMethodDetailTron({ id })
|
||||
}
|
||||
onLoad((options : any) => {
|
||||
formData.id = options.id
|
||||
formData.money = options.money
|
||||
getData(formData.id)
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
</style>
|
||||
71
src/packages/pages/recharge/recharge_udun.vue
Normal file
71
src/packages/pages/recharge/recharge_udun.vue
Normal file
@@ -0,0 +1,71 @@
|
||||
<template>
|
||||
<view>
|
||||
<h-dark :title="t('recharge.title')"></h-dark>
|
||||
<view class="mx-[30rpx] mt-[20rpx]">
|
||||
<view class="flex items-center bg-[#2C326B] rounded-lg px-[50rpx] py-[20rpx]">
|
||||
<u-icon size="80" :name="method.logo"></u-icon>
|
||||
<view class="ml-[16rpx]">{{method.name}}</view>
|
||||
</view>
|
||||
<view class="bg-[#2C326B] rounded-lg mt-[20rpx] p-[30rpx]">
|
||||
<view class="flex flex-col items-center">
|
||||
<u-image width="180px" height="180px" :src="method.qrcode"></u-image>
|
||||
</view>
|
||||
<view class="text-center text-[#00D2E0] mt-[30rpx]">
|
||||
<view class="mb-[16rpx]">{{t('recharge.address')}}</view>
|
||||
<view class="bg-[#3d4277] rounded p-[20rpx]">
|
||||
<view class="flex break-all items-center justify-center" v-if="method.address!=''">
|
||||
<view>{{method.address}}</view>
|
||||
<view @click.stop="copyText(method.address)"><u-icon size="26"
|
||||
name="/static/images/common/copy.png"></u-icon></view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="mt-[50rpx] leading-loose">
|
||||
<view class="">
|
||||
{{replaceStr(t('recharge.udunTips1'),'{code}',method.protocol)}}
|
||||
</view>
|
||||
<view class="">
|
||||
{{t('recharge.udunTips2')}}
|
||||
</view>
|
||||
<view class="">
|
||||
{{t('recharge.udunTips3')}}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, reactive } from 'vue'
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
import { rechargeMethodDetailUdun } from '@/api/finance'
|
||||
import { replaceStr } from '@/utils/util'
|
||||
import { useCopy } from '@/hooks/useCopy'
|
||||
import { t } from '@/utils/util'
|
||||
|
||||
uni.setNavigationBarTitle({ title: t('recharge.title') })
|
||||
const { copy } = useCopy()
|
||||
const method = ref<any>({})
|
||||
const formData = reactive({
|
||||
id: 0,
|
||||
money: '',
|
||||
})
|
||||
|
||||
const copyText = async (text : string) => {
|
||||
copy(text);
|
||||
uni.$u.toast(t('common.copySuccess'))
|
||||
}
|
||||
|
||||
const getData = async (id : number) => {
|
||||
method.value = await rechargeMethodDetailUdun({ id })
|
||||
}
|
||||
onLoad((options : any) => {
|
||||
formData.id = options.id
|
||||
formData.money = options.money
|
||||
getData(formData.id)
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
</style>
|
||||
84
src/packages/pages/recharge/record.vue
Normal file
84
src/packages/pages/recharge/record.vue
Normal file
@@ -0,0 +1,84 @@
|
||||
<template>
|
||||
<z-paging :refresher-enabled="false" :show-loading-more-when-reload="true" loading-more-default-text=""
|
||||
loading-more-loading-text="" loading-more-fail-text="" :empty-view-text="t('common.noData')"
|
||||
:show-loading-more-no-more-view="false" ref="paging" v-model="dataList" @query="queryList"
|
||||
class="max-w-[750px]">
|
||||
<h-dark :title="t('recharge.titleRecord')"></h-dark>
|
||||
<view class="mx-[30rpx] mt-[20rpx]">
|
||||
<navigator v-for="item in dataList" :key="item.id" hover-class="none"
|
||||
:url="'/packages/pages/recharge/order_detail?id='+item.id">
|
||||
<view class="bg-[#2C326B] mb-[20rpx] rounded-lg px-[40rpx] py-[35rpx]">
|
||||
<view class="flex justify-between mb-[20rpx]">
|
||||
<view class="w-3/5">
|
||||
<view class="">{{item.create_time}}</view>
|
||||
</view>
|
||||
<view class="text-right w-2/5">
|
||||
<view class="font-bold ">
|
||||
{{item.amount}}
|
||||
</view>
|
||||
<view class="mt-[10rpx] text-xs" v-if="item.rate != 1">
|
||||
≈ {{item.amount_act}} {{item.symbol}}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="flex justify-between ">
|
||||
<view class="text-[#00D2E0]">
|
||||
<view class="">
|
||||
{{item.method_name}}
|
||||
</view>
|
||||
<view v-if="item.status==2" class="text-xs text-error mt-[12rpx]">
|
||||
{{tips.rechargeFailTips}}
|
||||
</view>
|
||||
</view>
|
||||
<view v-if="item.status==1" class="text-success">
|
||||
{{tips.finish}}
|
||||
</view>
|
||||
<view v-if="item.status==0" class="text-primary">
|
||||
{{tips.pending}}
|
||||
</view>
|
||||
<view v-if="item.status==2" class="text-error">
|
||||
{{tips.fail}}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</navigator>
|
||||
</view>
|
||||
</z-paging>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, shallowRef, reactive } from 'vue'
|
||||
import { rechargeRecordLists } from '@/api/finance'
|
||||
import { getCurrency,getCurrency2, formatDate, formatMoney } from '@/utils/util'
|
||||
import { t } from '@/utils/util'
|
||||
|
||||
//为了提高渲染速度
|
||||
const tips = reactive({
|
||||
rechargeFailTips: t('recharge.rechargeFailTips'),
|
||||
fail: t('tabs.fail'),
|
||||
pending: t('tabs.pending'),
|
||||
finish: t('tabs.finish'),
|
||||
})
|
||||
|
||||
uni.setNavigationBarTitle({ title: t('recharge.titleRecord') })
|
||||
const paging = shallowRef()
|
||||
const dataList = ref<any[]>([])
|
||||
const queryList = async (pageNo : number, pageSize : number) => {
|
||||
try {
|
||||
const data = await rechargeRecordLists({
|
||||
page_no: pageNo,
|
||||
page_size: pageSize,
|
||||
date: formatDate(Math.round(Date.now() / 1000))
|
||||
})
|
||||
Object.keys(data.lists).forEach(key => {
|
||||
data.lists[key]['amount'] = getCurrency() + formatMoney(data.lists[key]['amount']) + ' ' + getCurrency2()
|
||||
})
|
||||
paging.value.complete(data.lists)
|
||||
} catch (error) {
|
||||
paging.value.complete(false)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
</style>
|
||||
97
src/packages/pages/user_wallet/order_detail.vue
Normal file
97
src/packages/pages/user_wallet/order_detail.vue
Normal file
@@ -0,0 +1,97 @@
|
||||
<template>
|
||||
<view>
|
||||
<h-dark title=""></h-dark>
|
||||
<view class="bg-[#4E55AF] px-[30rpx] pt-[30rpx] pb-[300rpx]">
|
||||
<view class=" flex flex-col items-center">
|
||||
<u-image width="300" height="180" mode="widthFix"
|
||||
src="/static/images/withdraw/withdraw_bg.png"></u-image>
|
||||
</view>
|
||||
</view>
|
||||
<view class="bg-[#2C326B] rounded-lg p-[50rpx] mx-[30rpx] mt-[-260rpx]">
|
||||
<view class="flex justify-between mb-[40rpx]">
|
||||
<view class="w-1/4">
|
||||
{{t('orderDetail.money')}}
|
||||
</view>
|
||||
<view class="w-3/4 text-right">
|
||||
<text class=" font-bold " :class="orderData.action==1?'text-success':'text-error'">
|
||||
{{getCurrency()}}{{formatMoney(orderData.amount)}} {{getCurrency2()}}
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="flex justify-between mb-[40rpx]">
|
||||
<view class="w-1/4">
|
||||
{{t('orderDetail.name')}}
|
||||
</view>
|
||||
<view class="w-3/4 text-right ">
|
||||
{{t("finance.type"+orderData.type)}}
|
||||
</view>
|
||||
</view>
|
||||
<view class="flex justify-between mb-[40rpx]">
|
||||
<view class="w-1/4">
|
||||
{{t('orderDetail.type')}}
|
||||
</view>
|
||||
<view class="w-3/4 text-right " :class="orderData.action==1?'text-success':'text-error'">
|
||||
{{orderData.action==1?t('tabs.in'):t('tabs.out')}}
|
||||
</view>
|
||||
</view>
|
||||
<view class="flex justify-between mb-[40rpx]">
|
||||
<view class="w-1/4">
|
||||
{{t('orderDetail.orderSn')}}
|
||||
</view>
|
||||
<view class="w-3/4 text-right ">
|
||||
{{orderData.sn}}
|
||||
</view>
|
||||
</view>
|
||||
<view class="flex justify-between mb-[40rpx]">
|
||||
<view class="w-1/4">
|
||||
{{t('orderDetail.createTime')}}
|
||||
</view>
|
||||
<view class="w-3/4 text-right ">
|
||||
{{orderData.create_time}}
|
||||
</view>
|
||||
</view>
|
||||
<view class="flex justify-between mb-[40rpx]" v-if="orderData.remark && orderData.remark!=''">
|
||||
<view class="w-1/4">
|
||||
{{t('orderDetail.remark')}}
|
||||
</view>
|
||||
<view class="w-3/4 text-right text-error break-words">
|
||||
{{orderData.remark}}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="max-w-[750px] fixed bottom-[50rpx] w-4/5 ml-[10%]">
|
||||
<u-button type="primary" @click="handleBack"> {{t('common.back')}} </u-button>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue'
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
import { financeDetail } from '@/api/finance'
|
||||
import { getCurrency, getCurrency2,formatDate, formatMoney } from '@/utils/util'
|
||||
import { t } from '@/utils/util'
|
||||
uni.setNavigationBarTitle({ title: t('funds.assetDetails') })
|
||||
const orderData = ref<any>({})
|
||||
let orderId = ''
|
||||
|
||||
const getData = async (id) => {
|
||||
orderData.value = await financeDetail({ id, date: formatDate(Math.round(Date.now() / 1000)) })
|
||||
}
|
||||
const handleBack = async () => {
|
||||
let canNavBack = getCurrentPages()
|
||||
if (canNavBack && canNavBack.length > 1) {
|
||||
uni.navigateBack()
|
||||
} else {
|
||||
history.back();
|
||||
}
|
||||
}
|
||||
|
||||
onLoad((options : any) => {
|
||||
orderId = options.id
|
||||
getData(orderId)
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
</style>
|
||||
106
src/packages/pages/user_wallet/record.vue
Normal file
106
src/packages/pages/user_wallet/record.vue
Normal file
@@ -0,0 +1,106 @@
|
||||
<template>
|
||||
<z-paging :refresher-enabled="false" :show-loading-more-when-reload="true" loading-more-default-text=""
|
||||
loading-more-loading-text="" loading-more-fail-text="" :empty-view-text="t('common.noData')"
|
||||
:show-loading-more-no-more-view="false" ref="paging" v-model="dataList" @query="queryList"
|
||||
class="max-w-[750px]">
|
||||
<h-dark :title="t('funds.assetDetails')"></h-dark>
|
||||
<view class="user-wallet">
|
||||
<view class="bg-[#4E55AF] pb-[30rpx]">
|
||||
<u-tabs show-bar="false" bg-color="#4E55AF" active-color="#A1DBF5" inactive-color="#FFFFFF" :is-scroll="false" :list="tabList" v-model="current" @change="changeType"></u-tabs>
|
||||
</view>
|
||||
<view class="pt-2.5 mx-[30rpx]">
|
||||
<navigator v-for="item in dataList" :key="item.id" hover-class="none"
|
||||
:url="'/packages/pages/user_wallet/order_detail?id='+item.id">
|
||||
<view class="bg-[#2C326B] mb-[20rpx] rounded-lg px-[40rpx] py-[35rpx]">
|
||||
<view class="flex justify-between">
|
||||
<view class="w-3/5">
|
||||
<view class="">{{item.create_time}}</view>
|
||||
|
||||
</view>
|
||||
<view class="text-right w-2/5">
|
||||
<text class="font-bold">
|
||||
{{item.amount}}
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="flex justify-between mt-[16rpx]">
|
||||
<view class="text-[#00D2E0]">
|
||||
<view class="">
|
||||
{{item.type}}
|
||||
</view>
|
||||
<view class="text-error mt-[12rpx]" v-if="item.remark">
|
||||
{{item.remark}}
|
||||
</view>
|
||||
</view>
|
||||
<view class="text-success" v-if="item.action==1">
|
||||
{{tabList[1]['name']}}
|
||||
</view>
|
||||
<view class="text-error" v-if="item.action==2">
|
||||
{{tabList[2]['name']}}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</navigator>
|
||||
</view>
|
||||
</view>
|
||||
</z-paging>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, shallowRef } from 'vue'
|
||||
import { financeLists } from '@/api/finance'
|
||||
import { getUserInfo } from '@/api/user'
|
||||
import { getCurrency,getCurrency2, formatDate, formatMoney } from '@/utils/util'
|
||||
import { t } from '@/utils/util'
|
||||
uni.setNavigationBarTitle({ title: t('funds.assetDetails') })
|
||||
const tabList = ref([
|
||||
{
|
||||
name: t('tabs.all'),
|
||||
type: ''
|
||||
},
|
||||
{
|
||||
name: t('tabs.in'),
|
||||
type: 1
|
||||
},
|
||||
{
|
||||
name: t('tabs.out'),
|
||||
type: 2
|
||||
}
|
||||
])
|
||||
const paging = shallowRef()
|
||||
const dataList = ref<any[]>([])
|
||||
const current = ref(0)
|
||||
const user = ref([])
|
||||
|
||||
const changeType = (index : number) => {
|
||||
current.value = index
|
||||
paging.value.reload()
|
||||
}
|
||||
|
||||
const queryList = async (pageNo : number, pageSize : number) => {
|
||||
try {
|
||||
const action = tabList.value[current.value].type
|
||||
const data = await financeLists({
|
||||
frozen: '',
|
||||
action: action,
|
||||
page_no: pageNo,
|
||||
page_size: pageSize,
|
||||
date: formatDate(Math.round(Date.now() / 1000))
|
||||
})
|
||||
Object.keys(data.lists).forEach(key => {
|
||||
data.lists[key]['amount'] = getCurrency() + formatMoney(data.lists[key]['amount']) + ' ' + getCurrency2()
|
||||
data.lists[key]['type'] = t("finance.type" + data.lists[key]['type'])
|
||||
})
|
||||
paging.value.complete(data.lists)
|
||||
} catch (error) {
|
||||
paging.value.complete(false)
|
||||
}
|
||||
}
|
||||
const getData = async () => {
|
||||
user.value = await getUserInfo()
|
||||
}
|
||||
getData()
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
</style>
|
||||
70
src/packages/pages/user_wallet/record_freeze.vue
Normal file
70
src/packages/pages/user_wallet/record_freeze.vue
Normal file
@@ -0,0 +1,70 @@
|
||||
<template>
|
||||
<z-paging :refresher-enabled="false" :show-loading-more-when-reload="true" loading-more-default-text=""
|
||||
loading-more-loading-text="" loading-more-fail-text="" :empty-view-text="t('common.noData')"
|
||||
:show-loading-more-no-more-view="false" ref="paging" v-model="dataList" @query="queryList"
|
||||
class="max-w-[750px]">
|
||||
<h-dark :title="t('user.usedNoMoney')"></h-dark>
|
||||
<view class="user-wallet">
|
||||
<view class="pt-2.5">
|
||||
<view v-for="item in dataList" :key="item.id" class="bg-white mb-[8px] px-[40rpx] py-[20rpx] border-solid border-b border-0 border-light ">
|
||||
<view class="flex justify-between items-center">
|
||||
<view class="">
|
||||
<view class="">
|
||||
<view class="">
|
||||
{{item.type}}
|
||||
</view>
|
||||
<view class="text-error mt-[12rpx]" v-if="item.remark">
|
||||
{{item.remark}}
|
||||
</view>
|
||||
</view>
|
||||
<view class="flex justify-between mt-[16rpx]">
|
||||
<view class=" text-muted mr-1">{{item.create_time}}</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="text-right">
|
||||
<text class="font-bold">
|
||||
{{item.amount}}
|
||||
</text>
|
||||
</view>
|
||||
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</z-paging>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, shallowRef } from 'vue'
|
||||
import { financeLists } from '@/api/finance'
|
||||
import { getCurrency, formatDate, formatMoney } from '@/utils/util'
|
||||
import { t } from '@/utils/util'
|
||||
uni.setNavigationBarTitle({ title: t('user.usedNoMoney') })
|
||||
const paging = shallowRef()
|
||||
const dataList = ref<any[]>([])
|
||||
|
||||
const queryList = async (pageNo : number, pageSize : number) => {
|
||||
try {
|
||||
const data = await financeLists({
|
||||
action: '',
|
||||
frozen: 1,
|
||||
page_no: pageNo,
|
||||
page_size: pageSize,
|
||||
date: formatDate(Math.round(Date.now() / 1000))
|
||||
})
|
||||
Object.keys(data.lists).forEach(key => {
|
||||
data.lists[key]['amount'] = getCurrency() + formatMoney(data.lists[key]['amount'])
|
||||
data.lists[key]['type'] = t("finance.type" + data.lists[key]['type'])
|
||||
})
|
||||
paging.value.complete(data.lists)
|
||||
} catch (error) {
|
||||
paging.value.complete(false)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
page {
|
||||
background-color: #FFFFFF;
|
||||
}
|
||||
</style>
|
||||
82
src/packages/pages/withdraw/account.vue
Normal file
82
src/packages/pages/withdraw/account.vue
Normal file
@@ -0,0 +1,82 @@
|
||||
<template>
|
||||
<view>
|
||||
<h-dark :title="t('withdraw.withdrawAccountManage')"></h-dark>
|
||||
<view class="mt-[40rpx]">
|
||||
<u-cell-group>
|
||||
<u-cell-item v-for="(method, index) in data.methods" :title="method.name"
|
||||
:label="method.status?method.account:method.name" :arrow="false"
|
||||
hover-class="cell-hover-class">
|
||||
<template v-slot:icon>
|
||||
<u-icon class="mr-[15rpx]" size="100" :name="method.logo"></u-icon>
|
||||
</template>
|
||||
<template v-slot:right-icon>
|
||||
<view v-if="method.status" class="">
|
||||
{{t('withdraw.binded')}}
|
||||
</view>
|
||||
<navigator class="text-primary" v-if="!method.status&&method.type==1" hover-class="none"
|
||||
:url="'/packages/pages/withdraw/account_usdt?id='+method.id+'&name='+method.name+'&is_qrcode='+method.is_qrcode">
|
||||
{{t('withdraw.toBind')}}
|
||||
</navigator>
|
||||
<navigator class="text-primary" v-if="!method.status&&method.type==2" hover-class="none"
|
||||
:url="'/packages/pages/withdraw/account_qrcode?id='+method.id+'&name='+method.name">
|
||||
{{t('withdraw.toBind')}}
|
||||
</navigator>
|
||||
<navigator class="text-primary" v-if="!method.status&&method.type==3" hover-class="none"
|
||||
:url="'/packages/pages/withdraw/account_bank?id='+method.id+'&name='+method.name">
|
||||
{{t('withdraw.toBind')}}
|
||||
</navigator>
|
||||
</template>
|
||||
</u-cell-item>
|
||||
</u-cell-group>
|
||||
</view>
|
||||
<view class="mt-[50rpx] mx-[26rpx] ">
|
||||
<view class="font-bold flex justify-start items-center mb-[20rpx]">
|
||||
<u-icon size="32" name="info-circle-fill"></u-icon>
|
||||
<view class="ml-[10rpx]">
|
||||
{{t('withdraw.withdrawWarm')}}
|
||||
</view>
|
||||
</view>
|
||||
<view class="p-[20rpx] bg-[#F8F9FB] leading-loose rounded-lg" v-html="data.content"></view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { onShow } from '@dcloudio/uni-app'
|
||||
import { reactive } from 'vue'
|
||||
import { getWithdrawMethod, getWithdrawWallet } from '@/api/finance'
|
||||
import { getHintDetail } from '@/api/news'
|
||||
import { t } from '@/utils/util'
|
||||
|
||||
uni.setNavigationBarTitle({ title: t('withdraw.withdrawAccountManage') })
|
||||
const data = reactive({
|
||||
methods: [],
|
||||
wallets: [],
|
||||
content:''
|
||||
})
|
||||
const getData = async () => {
|
||||
data.wallets = await getWithdrawWallet()
|
||||
data.methods = await getWithdrawMethod()
|
||||
|
||||
data.methods.forEach((method : any) => {
|
||||
data.wallets.forEach((wallet : any) => {
|
||||
if (method['id'] - wallet['method_id'] == 0) {
|
||||
method['status'] = true;
|
||||
method['account'] = wallet['account'];
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
const res = await getHintDetail({id:12})
|
||||
data.content = res.content;
|
||||
}
|
||||
onShow(() => {
|
||||
getData()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
page{
|
||||
background-color: #FFFFFF;
|
||||
}
|
||||
</style>
|
||||
129
src/packages/pages/withdraw/account_bank.vue
Normal file
129
src/packages/pages/withdraw/account_bank.vue
Normal file
@@ -0,0 +1,129 @@
|
||||
<template>
|
||||
<view>
|
||||
<h-dark :title="title"></h-dark>
|
||||
<view class="mt-[40rpx]">
|
||||
<view class=" px-[40rpx] mb-[15rpx]">
|
||||
* {{t('withdraw.bankname')}}
|
||||
</view>
|
||||
<view class="account px-[40rpx] py-[30rpx]">
|
||||
<view class="bg-[#f6f7fb] rounded-lg px-[20rpx] py-[10rpx] ">
|
||||
<view class="py-[16rpx]">
|
||||
<u-picker class="max-w-[750px]" mode="selector" v-model="picker_show"
|
||||
:default-selector="[banks.default_select]" :range="banks.list" range-key="name"
|
||||
@confirm="handlePicker" :confirm-text="t('common.confirm')"
|
||||
:cancel-text="t('common.cancel')">
|
||||
</u-picker>
|
||||
<view class="mr-[20rpx]" @click="picker_show=true">
|
||||
<text class="mr-[10rpx]">{{formData.bank_name}}
|
||||
</text>
|
||||
<u-icon name="arrow-down" size="20"></u-icon>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class=" px-[40rpx] mb-[15rpx] mt-[30rpx]">
|
||||
* {{t('withdraw.bankUsername')}}
|
||||
</view>
|
||||
<view class="account px-[40rpx] py-[15rpx]">
|
||||
<view class="bg-[#f6f7fb] rounded-lg px-[20rpx] py-[10rpx] ">
|
||||
<u-input class="flex-1" v-model="formData.name" :border="false"
|
||||
:placeholder="t('withdraw.bankUsernamePlaceholder')" />
|
||||
</view>
|
||||
</view>
|
||||
<view class=" px-[40rpx] mb-[15rpx] mt-[30rpx]">
|
||||
* {{t('withdraw.bankAccount')}}
|
||||
</view>
|
||||
<view class="account px-[40rpx] py-[15rpx]">
|
||||
<view class="bg-[#f6f7fb] rounded-lg px-[20rpx] py-[10rpx] ">
|
||||
<u-input class="flex-1" v-model="formData.account" :border="false"
|
||||
:placeholder="t('withdraw.bankAccountPlaceholder')" />
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="px-[40rpx] mt-[50rpx] leading-loose font-bold">
|
||||
<view class="text-error ">
|
||||
{{t('withdraw.tips1')}}
|
||||
</view>
|
||||
<view class="text-error">
|
||||
{{t('withdraw.tips2')}}
|
||||
</view>
|
||||
</view>
|
||||
<view class=" px-[40rpx] my-[80rpx] pb-[50rpx]">
|
||||
<u-button type="primary" @click="handleConfirm"> {{t('withdraw.bindBtn')}} </u-button>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { reactive, ref } from 'vue'
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
import { t } from '@/utils/util'
|
||||
import { withdrawWalletAdd, getWithdrawBanks } from '@/api/finance'
|
||||
|
||||
uni.setNavigationBarTitle({ title: t('withdraw.withdrawAccountManage') })
|
||||
const title = ref('')
|
||||
|
||||
const picker_show = ref(false)
|
||||
|
||||
const banks = reactive<{
|
||||
list : any[]
|
||||
default_select : number
|
||||
}>({
|
||||
list: [],
|
||||
default_select: 0
|
||||
})
|
||||
const formData = reactive({
|
||||
bank_id: '',
|
||||
name: '',
|
||||
account: '',
|
||||
type: 3,//类型1USDT2扫码3银行卡
|
||||
method_id: '',
|
||||
bank_name: ''
|
||||
})
|
||||
|
||||
const getData = async () => {
|
||||
let data = await getWithdrawBanks()
|
||||
banks.list = data;
|
||||
formData.bank_id = data[0]['id']
|
||||
formData.bank_name = data[0]['name']
|
||||
}
|
||||
|
||||
const handlePicker = (index : number) => {
|
||||
banks.default_select = index;
|
||||
formData.bank_id = banks.list[index]['id'];
|
||||
formData.bank_name = banks.list[index]['name'];
|
||||
}
|
||||
|
||||
const handleConfirm = async () => {
|
||||
if (formData.bank_id == "") return uni.$u.toast(t('withdraw.banknameEmpty'))
|
||||
|
||||
if (!formData.name) return uni.$u.toast(t('withdraw.bankUsernameEmpty')
|
||||
)
|
||||
if (formData.name.length < 2 || formData.name.length > 30) return uni.$u.toast(t('withdraw.banknameError'))
|
||||
|
||||
if (!formData.account) return uni.$u.toast(t('withdraw.bankAccountEmpty'))
|
||||
if (formData.account.length < 6 || formData.account.length > 30) return uni.$u.toast(t('withdraw.bankAccountError'))
|
||||
|
||||
await withdrawWalletAdd(formData)
|
||||
uni.redirectTo({
|
||||
url: '/pages/common/successful?type=3'
|
||||
})
|
||||
}
|
||||
onLoad((options : any) => {
|
||||
formData.method_id = options.id
|
||||
title.value = options.name;
|
||||
getData()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
page {
|
||||
background-color: #FFFFFF;
|
||||
}
|
||||
|
||||
.shadow-inner {
|
||||
border-radius: 10px;
|
||||
padding: 5px 10px;
|
||||
box-shadow: inset 0px 1px 4px 0px rgb(0 0 0 / 0.3);
|
||||
}
|
||||
</style>
|
||||
91
src/packages/pages/withdraw/account_qrcode.vue
Normal file
91
src/packages/pages/withdraw/account_qrcode.vue
Normal file
@@ -0,0 +1,91 @@
|
||||
<template>
|
||||
<view>
|
||||
<h-dark :title="title"></h-dark>
|
||||
<view class="mt-[40rpx]">
|
||||
<view class=" px-[40rpx] mb-[15rpx]">
|
||||
* {{t('withdraw.qrcodeAccount')}}
|
||||
</view>
|
||||
<view class="account px-[40rpx] py-[15rpx]">
|
||||
<view class="bg-[#f6f7fb] rounded-lg px-[20rpx] py-[10rpx]">
|
||||
<u-input class="flex-1" v-model="formData.account" :border="false" :placeholder="t('withdraw.qrcodeAccountPlaceholder')" />
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class=" px-[40rpx] mb-[15rpx] mt-[30rpx]">
|
||||
* {{t('withdraw.qrcode')}}
|
||||
</view>
|
||||
<view class="px-[40rpx] py-[15rpx]">
|
||||
<view class="bg-[#f6f7fb] rounded-lg w-full flex justify-center">
|
||||
<u-upload class="" ref="uploader" :custom-btn="true" :deletable="false" :auto-upload="false"
|
||||
max-count="1" :max-size="20*1024*1024" v-model="formData.img">
|
||||
<template v-slot:addBtn>
|
||||
<view class="flex items-center justify-center slot-btn w-[180rpx] h-[180rpx] "
|
||||
hover-class="slot-btn__hover" hover-stay-time="150">
|
||||
<u-icon name="photo" size="80" class="text-muted"></u-icon>
|
||||
</view>
|
||||
</template>
|
||||
</u-upload>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="px-[40rpx] mt-[50rpx] leading-loose font-bold">
|
||||
<view class="text-error ">
|
||||
{{t('withdraw.tips1')}}
|
||||
</view>
|
||||
<view class="text-error">
|
||||
{{t('withdraw.tips2')}}
|
||||
</view>
|
||||
</view>
|
||||
<view class=" px-[40rpx] my-[80rpx] pb-[50rpx]">
|
||||
<u-button type="primary" @click="handleConfirm"> {{t('withdraw.bindBtn')}} </u-button>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { reactive, ref } from 'vue'
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
import { t } from '@/utils/util'
|
||||
import { uploadImage } from '@/api/app'
|
||||
import { useUserStore } from '@/stores/user'
|
||||
import { withdrawWalletAdd } from '@/api/finance'
|
||||
|
||||
uni.setNavigationBarTitle({ title: t('withdraw.withdrawAccountManage') })
|
||||
const title = ref('')
|
||||
const formData = reactive({
|
||||
account: '',
|
||||
img: '',
|
||||
type: 2,//类型1USDT2扫码3银行卡
|
||||
method_id: ''
|
||||
})
|
||||
const userStore = useUserStore()
|
||||
const uploader = ref();
|
||||
|
||||
const handleConfirm = async () => {
|
||||
if (!formData.account) return uni.$u.toast(t('withdraw.qrcodeAccountEmpty'))
|
||||
if (formData.account.length < 6 || formData.account.length > 30) return uni.$u.toast(t('withdraw.qrcodeAccountError'))
|
||||
|
||||
if (uploader.value.lists.length <= 0) return uni.$u.toast(t('withdraw.qrcodeEmpty'))
|
||||
const res : any = await uploadImage(uploader.value.lists[0].url, userStore.temToken!)
|
||||
formData.img = res.url;
|
||||
await withdrawWalletAdd(formData)
|
||||
uni.redirectTo({
|
||||
url: '/pages/common/successful?type=3'
|
||||
})
|
||||
}
|
||||
onLoad((options : any) => {
|
||||
formData.method_id = options.id
|
||||
title.value = options.name;
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
page{
|
||||
background-color: #FFFFFF;
|
||||
}
|
||||
.shadow-inner {
|
||||
border-radius: 10px;
|
||||
padding: 5px 10px;
|
||||
box-shadow: inset 0px 1px 4px 0px rgb(0 0 0 / 0.3);
|
||||
}
|
||||
</style>
|
||||
98
src/packages/pages/withdraw/account_usdt.vue
Normal file
98
src/packages/pages/withdraw/account_usdt.vue
Normal file
@@ -0,0 +1,98 @@
|
||||
<template>
|
||||
<view>
|
||||
<h-dark :title="title"></h-dark>
|
||||
<view class="mt-[40rpx]">
|
||||
<view class=" px-[40rpx] mb-[15rpx]">
|
||||
* {{t('withdraw.address')}}
|
||||
</view>
|
||||
<view class="account px-[40rpx] py-[15rpx] ">
|
||||
<view class="bg-[#f6f7fb] rounded-lg px-[20rpx] py-[10rpx]">
|
||||
<u-input class="flex-1" v-model="formData.account" :border="false"
|
||||
:placeholder="t('withdraw.addressPlaceholder')" />
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class=" px-[40rpx] mb-[15rpx] mt-[30rpx]" v-if="formData.is_qrcode==1">
|
||||
* {{t('withdraw.qrcode')}}
|
||||
</view>
|
||||
<view class="px-[40rpx] py-[15rpx]" v-if="formData.is_qrcode==1">
|
||||
<view class="bg-[#f6f7fb] rounded-lg w-full flex justify-center ">
|
||||
<u-upload class="" ref="uploader" :custom-btn="true" :deletable="false" :auto-upload="false"
|
||||
max-count="1" :max-size="20*1024*1024" v-model="formData.img">
|
||||
<template v-slot:addBtn>
|
||||
<view class="flex items-center justify-center slot-btn w-[180rpx] h-[180rpx] "
|
||||
hover-class="slot-btn__hover" hover-stay-time="150">
|
||||
<u-icon name="photo" size="80" class="text-muted"></u-icon>
|
||||
</view>
|
||||
</template>
|
||||
</u-upload>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="px-[40rpx] mt-[50rpx] leading-loose font-bold">
|
||||
<view class="text-error ">
|
||||
{{t('withdraw.tips1')}}
|
||||
</view>
|
||||
<view class="text-error">
|
||||
{{t('withdraw.tips2')}}
|
||||
</view>
|
||||
</view>
|
||||
<view class=" px-[40rpx] my-[80rpx] pb-[50rpx]">
|
||||
<u-button type="primary" @click="handleConfirm"> {{t('withdraw.bindBtn')}} </u-button>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { reactive, ref } from 'vue'
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
import { uploadImage } from '@/api/app'
|
||||
import { useUserStore } from '@/stores/user'
|
||||
import { withdrawWalletAdd } from '@/api/finance'
|
||||
import { t } from '@/utils/util'
|
||||
|
||||
uni.setNavigationBarTitle({ title: t('withdraw.withdrawAccountManage') })
|
||||
|
||||
const title = ref('')
|
||||
const formData = reactive({
|
||||
account: '',
|
||||
img: '',
|
||||
type: 1,//类型1USDT2扫码3银行卡
|
||||
method_id: '',
|
||||
is_qrcode: 0
|
||||
})
|
||||
const userStore = useUserStore()
|
||||
const uploader = ref();
|
||||
|
||||
const handleConfirm = async () => {
|
||||
if (!formData.account) return uni.$u.toast(t('withdraw.addressEmpty'))
|
||||
if (formData.account.length < 8 || formData.account.length > 128) return uni.$u.toast(t('withdraw.addressError'))
|
||||
|
||||
if(formData.is_qrcode==1){
|
||||
if (uploader.value.lists.length <= 0) return uni.$u.toast(t('withdraw.qrcodeEmpty'))
|
||||
const res : any = await uploadImage(uploader.value.lists[0].url, userStore.temToken!)
|
||||
formData.img = res.url;
|
||||
}
|
||||
await withdrawWalletAdd(formData)
|
||||
uni.redirectTo({
|
||||
url: '/pages/common/successful?type=3'
|
||||
})
|
||||
}
|
||||
onLoad((options : any) => {
|
||||
formData.method_id = options.id
|
||||
title.value = options.name;
|
||||
formData.is_qrcode = options.is_qrcode;
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
page {
|
||||
background-color: #FFFFFF;
|
||||
}
|
||||
|
||||
.shadow-inner {
|
||||
border-radius: 10px;
|
||||
padding: 5px 10px;
|
||||
box-shadow: inset 0px 1px 4px 0px rgb(0 0 0 / 0.3);
|
||||
}
|
||||
</style>
|
||||
226
src/packages/pages/withdraw/index.vue
Normal file
226
src/packages/pages/withdraw/index.vue
Normal file
@@ -0,0 +1,226 @@
|
||||
<template>
|
||||
<view>
|
||||
<u-navbar :back-text="t('withdraw.title')" :back-text-style="{color: '#FFFFFF'}"
|
||||
:background="{backgroundColor: '#4E55AF'}" back-icon-color="#FFFFFF">
|
||||
<view class="flex justify-end w-full pr-[20rpx] relative">
|
||||
<navigator hover-class="none" url="/packages/pages/withdraw/record">
|
||||
<u-icon size="40" name="/static/images/common/record.png"></u-icon>
|
||||
</navigator>
|
||||
</view>
|
||||
</u-navbar>
|
||||
<view class="mx-[30rpx] pt-[20rpx]">
|
||||
<u-form :border-bottom="false" :label-width="150" label-position="top">
|
||||
<u-form-item :itemStyle="{'background':'#3d4277'}" :border-bottom="false" :label="t('withdraw.mainNet')">
|
||||
<u-input v-model="formData.method_name" type="select" :placeholder="t('withdraw.mainNetPlaceholder')" @click="showAtionSheet" />
|
||||
</u-form-item>
|
||||
<u-form-item :itemStyle="{'background':'#3d4277'}" :border-bottom="false" :label="t('withdraw.waddress')">
|
||||
<u-input v-model="formData.address" :border="false" :placeholder="t('withdraw.waddressPlaceholder')" />
|
||||
</u-form-item>
|
||||
<u-form-item :itemStyle="{'background':'#3d4277'}" :border-bottom="false"
|
||||
:label="t('withdraw.withdrawMoney')">
|
||||
<u-input type="number" v-model="formData.money" @input="checkMoney" :border="false"
|
||||
:placeholder="t('withdraw.withdrawMoneyPlaceholder')" />
|
||||
</u-form-item>
|
||||
<view class="py-[25rpx]">
|
||||
<view class="text-[#00D2E0] mb-[10rpx]">
|
||||
{{t('withdraw.userMoney')}} {{getCurrency()}}{{formatMoney(data.config.balance)}} {{getCurrency2()}}
|
||||
</view>
|
||||
<view class="text-[#00D2E0]" v-if="formData.money >0">
|
||||
<view class=" mb-[10rpx]" v-if="data.method_rate !=1">
|
||||
{{t('withdraw.rate')}} {{data.method_rate}}
|
||||
</view>
|
||||
<view class=" mb-[10rpx]" v-if="data.charge > 0.01">
|
||||
{{t('withdraw.charge')}}
|
||||
{{formatMoney(data.charge,data.method_symbol,data.method_rate,data.method_precision)}}
|
||||
</view>
|
||||
<view class="">
|
||||
{{t('withdraw.actMoney')}}
|
||||
{{formatMoney(data.act_money,data.method_symbol,data.method_rate,data.method_precision)}}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</u-form>
|
||||
</view>
|
||||
|
||||
<view class="mt-[30rpx] mx-[30rpx] max-w-[750px]">
|
||||
<u-button type="primary" @click="submitHandle" :disabled="formData.method_id=='' || formData.address=='' || formData.money==''"> {{t('common.submit')}} </u-button>
|
||||
</view>
|
||||
|
||||
<view class="mt-[50rpx] mx-[30rpx] pb-[30rpx]">
|
||||
<view class="font-bold flex justify-start items-center mb-[20rpx]">
|
||||
<u-icon size="32" name="info-circle-fill"></u-icon>
|
||||
<view class="ml-[10rpx]">
|
||||
{{t('withdraw.withdrawWarm')}}
|
||||
</view>
|
||||
</view>
|
||||
<view class="p-[20rpx] bg-[#3d4277] leading-loose rounded-lg" v-html="data.content"></view>
|
||||
</view>
|
||||
|
||||
<u-keyboard class="max-w-[750px]" ref="uKeyboard1" mode="number" :dot-enabled="false" :tips="t('pwd.payPwd')"
|
||||
confirm-text="" cancel-text="" v-model="show_keyboard" @change="keyboardChange" @backspace="backspace"
|
||||
:show-input-val="true" :input-value="formData.pay_pwd"></u-keyboard>
|
||||
|
||||
<u-action-sheet class="max-w-[750px]" :list="data.methods" v-model="show" @click="handleClick"
|
||||
:safe-area-inset-bottom="true" :cancel-text="t('common.cancel')"></u-action-sheet>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { onShow } from '@dcloudio/uni-app'
|
||||
import { reactive, ref, nextTick } from 'vue'
|
||||
import { withdraw, withdrawConfig, getWithdrawMethod } from '@/api/finance'
|
||||
import { getHintDetail } from '@/api/news'
|
||||
import { formatDate, getCurrency,getCurrency2, formatMoney } from '@/utils/util'
|
||||
import { t } from '@/utils/util'
|
||||
|
||||
uni.setNavigationBarTitle({ title: t('withdraw.title') })
|
||||
const formData = reactive({
|
||||
address: '',
|
||||
money: '',
|
||||
method_id: 0,
|
||||
method_name: '',
|
||||
pay_pwd: '',
|
||||
date: formatDate(Math.round(Date.now() / 1000))
|
||||
})
|
||||
|
||||
const data = reactive<{
|
||||
config : any,
|
||||
methods : any,
|
||||
charge : number,
|
||||
act_money : number,
|
||||
method_charge : number,
|
||||
method_symbol : string,
|
||||
method_rate : number,
|
||||
method_precision : number,
|
||||
content : string
|
||||
}>({
|
||||
config: {
|
||||
balance: 0,
|
||||
noused_money: 0,
|
||||
min: 0,
|
||||
max: 0,
|
||||
num: 0,
|
||||
is_withdraw: false,
|
||||
need_realname: 0
|
||||
},
|
||||
methods: [],
|
||||
charge: 0,
|
||||
act_money: 0,
|
||||
method_charge: 0,
|
||||
method_symbol: '',
|
||||
method_rate: 0,
|
||||
method_precision: 2,
|
||||
content: ''
|
||||
})
|
||||
|
||||
const show_keyboard = ref(false)
|
||||
const show = ref(false)
|
||||
const getData = async () => {
|
||||
data.config = await withdrawConfig({ date: formatDate(Math.round(Date.now() / 1000)) })
|
||||
if (data.config.need_realname == 1) {
|
||||
uni.redirectTo({
|
||||
url: '/pages/auth/realname'
|
||||
})
|
||||
return
|
||||
}
|
||||
if (data.config.need_set_pwd == 1) {
|
||||
uni.$u.toast(t('pwd.pwdSetFirstTips'))
|
||||
uni.redirectTo({
|
||||
url: '/pages/change_password/set_password_pay'
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
data.methods = await getWithdrawMethod()
|
||||
if (data.methods.length > 0) {
|
||||
let index = 0
|
||||
//预输入
|
||||
if (data.config.ahead.method_id != 0) {
|
||||
index = data.methods.findIndex(item => item.id === data.config.ahead.method_id)
|
||||
formData.address = data.config.ahead.address
|
||||
console.log(index)
|
||||
}
|
||||
|
||||
formData.method_id = data.methods[index]['id']
|
||||
formData.method_name = data.methods[index]['text']
|
||||
data.method_charge = data.methods[index]['charge']
|
||||
data.method_symbol = data.methods[index]['symbol']
|
||||
data.method_rate = parseFloat(data.methods[index]['rate'])
|
||||
data.method_precision = data.methods[index]['precision']
|
||||
}
|
||||
|
||||
const res = await getHintDetail({ id: 12 })
|
||||
data.content = res.content;
|
||||
}
|
||||
|
||||
const keyboardChange = (val : string) => {
|
||||
formData.pay_pwd += val;
|
||||
if (formData.pay_pwd.length == 6) {
|
||||
show_keyboard.value = false;
|
||||
submit();
|
||||
}
|
||||
}
|
||||
const backspace = () => {
|
||||
// 删除value的最后一个字符
|
||||
if (formData.pay_pwd.length) formData.pay_pwd = (formData.pay_pwd).substr(0, (formData.pay_pwd.length) - 1);
|
||||
}
|
||||
|
||||
const showAtionSheet = () => {
|
||||
show.value = true;
|
||||
}
|
||||
|
||||
|
||||
const handleClick = (index : number) => {
|
||||
formData.method_id = data.methods[index]['id'];
|
||||
formData.method_name = data.methods[index]['text'];
|
||||
data.method_charge = data.methods[index]['charge'];
|
||||
data.method_symbol = data.methods[index]['symbol'];
|
||||
data.method_rate = parseFloat(data.methods[index]['rate']);
|
||||
data.method_precision = data.methods[index]['precision'];
|
||||
}
|
||||
|
||||
const checkMoney = (money : string) => {
|
||||
var precision = uni.getStorageSync('precision')
|
||||
// 使用正则表达式匹配小数
|
||||
var decimalMatch = money.match(/\.(\d+)/);
|
||||
if (decimalMatch) {
|
||||
if (decimalMatch[1].length >= precision) {
|
||||
nextTick(() => {
|
||||
formData.money = parseFloat(money).toFixed(precision);
|
||||
})
|
||||
}
|
||||
}
|
||||
money = parseFloat(money).toFixed(precision);
|
||||
data.charge = parseFloat(money) * data.method_charge / 100;
|
||||
|
||||
data.charge = parseFloat((data.charge).toFixed(precision));
|
||||
data.act_money = parseFloat((parseFloat(money) - data.charge).toFixed(precision));
|
||||
}
|
||||
|
||||
const submitHandle = async () => {
|
||||
//提现金额判断
|
||||
if (parseFloat(formData.money) - data.config.balance > 0) return uni.$u.toast(t('common.InsufficientBalance'));
|
||||
|
||||
if (parseFloat(formData.money) < data.config.min) return uni.$u.toast(t('withdraw.moneyMin') + getCurrency() + data.config.min + ' ' + getCurrency2())
|
||||
if (parseFloat(formData.money) > data.config.max) return uni.$u.toast(t('withdraw.moneyMax') + getCurrency() + data.config.max + ' ' + getCurrency2())
|
||||
//判断提现次数
|
||||
if (!data.config.is_withdraw) return uni.$u.toast(t('withdraw.withdrawNum') + data.config.num)
|
||||
|
||||
formData.pay_pwd = '';
|
||||
show_keyboard.value = true;
|
||||
}
|
||||
const submit = async () => {
|
||||
await withdraw(formData)
|
||||
|
||||
uni.redirectTo({
|
||||
url: '/pages/common/successful?type=1'
|
||||
})
|
||||
}
|
||||
getData()
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.u-tooltip-tips {
|
||||
flex: none !important;
|
||||
}
|
||||
</style>
|
||||
120
src/packages/pages/withdraw/order_detail.vue
Normal file
120
src/packages/pages/withdraw/order_detail.vue
Normal file
@@ -0,0 +1,120 @@
|
||||
<template>
|
||||
<view>
|
||||
<h-dark title=""></h-dark>
|
||||
<view class="bg-[#4E55AF] px-[30rpx] pt-[30rpx] pb-[300rpx]">
|
||||
<view class=" flex flex-col items-center">
|
||||
<u-image width="300" height="180" mode="widthFix"
|
||||
src="/static/images/withdraw/withdraw_bg.png"></u-image>
|
||||
</view>
|
||||
</view>
|
||||
<view class="bg-[#2C326B] rounded-lg p-[50rpx] mx-[30rpx] mt-[-260rpx]">
|
||||
<view class="flex justify-between mb-[40rpx]">
|
||||
<view class="w-1/4">
|
||||
{{t('withdraw.withdrawMethod')}}
|
||||
</view>
|
||||
<view class="w-3/4 text-right ">
|
||||
{{orderData.account}}
|
||||
</view>
|
||||
</view>
|
||||
<view class="flex justify-between mb-[40rpx]">
|
||||
<view class="w-1/4">
|
||||
{{t('orderDetail.status')}}
|
||||
</view>
|
||||
<view v-if="orderData.status==1" class="w-3/4 text-right text-success ">
|
||||
{{t('tabs.finish')}}
|
||||
</view>
|
||||
<view v-if="orderData.status==0" class="w-3/4 text-right text-primary ">
|
||||
{{t('tabs.pending')}}
|
||||
</view>
|
||||
<view v-if="orderData.status==2" class="w-3/4 text-right text-error ">
|
||||
{{t('tabs.fail')}}
|
||||
</view>
|
||||
</view>
|
||||
<view class="flex justify-between mb-[40rpx]">
|
||||
<view class="w-1/4">
|
||||
{{t('orderDetail.orderSn')}}
|
||||
</view>
|
||||
<view class="w-3/4 text-right ">
|
||||
{{orderData.sn}}
|
||||
</view>
|
||||
</view>
|
||||
<view class="flex justify-between mb-[40rpx]">
|
||||
<view class="w-1/4">
|
||||
{{t('orderDetail.createTime')}}
|
||||
</view>
|
||||
<view class="w-3/4 text-right ">
|
||||
{{orderData.create_time}}
|
||||
</view>
|
||||
</view>
|
||||
<view class="flex justify-between mb-[40rpx]" v-if="orderData.status==2">
|
||||
<view class="w-1/4">
|
||||
{{t('orderDetail.remark')}}
|
||||
</view>
|
||||
<view class="w-3/4 text-right text-error break-words">
|
||||
<text v-if="orderData.reamrk==''">{{t('withdraw.withdrawFailTips')}}</text>
|
||||
<text v-if="orderData.reamrk!=''">{{orderData.remark}}</text>
|
||||
</view>
|
||||
</view>
|
||||
<u-line class="text-info" margin="20rpx 0 40rpx 0" border-style="dashed" />
|
||||
<view class="flex justify-between">
|
||||
<view class="w-1/4">
|
||||
{{t('orderDetail.money')}}
|
||||
</view>
|
||||
<view class="w-3/4 text-right">
|
||||
<view v-if="orderData.status==1" class="text-lg font-bold text-success">
|
||||
{{getCurrency()}}{{formatMoney(orderData.amount)}} {{getCurrency2()}}
|
||||
</view>
|
||||
<view v-if="orderData.status==0" class="text-lg font-bold text-primary">
|
||||
{{getCurrency()}}{{formatMoney(orderData.amount)}} {{getCurrency2()}}
|
||||
</view>
|
||||
<view v-if="orderData.status==2" class="text-lg font-bold text-error">
|
||||
{{getCurrency()}}{{formatMoney(orderData.amount)}} {{getCurrency2()}}
|
||||
</view>
|
||||
<view class="mt-[10rpx]" v-if="orderData.rate && orderData.rate != 1">
|
||||
≈ {{orderData.amount_act}} {{orderData.symbol}}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="flex justify-between mt-[40rpx]" v-if="orderData.charge>0">
|
||||
<view class="w-1/4">
|
||||
{{t('orderDetail.charge')}}
|
||||
</view>
|
||||
<view class="w-3/4 text-right text-muted">
|
||||
{{getCurrency()}}{{formatMoney(orderData.charge)}} {{getCurrency2()}}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="max-w-[750px] fixed bottom-[50rpx] w-4/5 ml-[10%]">
|
||||
<u-button type="primary" @click="handleBack"> {{t('common.back')}} </u-button>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue'
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
import { withdrawRecordDetail } from '@/api/finance'
|
||||
import { getCurrency,getCurrency2, formatDate, formatMoney, t } from '@/utils/util'
|
||||
uni.setNavigationBarTitle({ title: t('withdraw.title') })
|
||||
const orderData = ref<any>({})
|
||||
let orderId = ''
|
||||
|
||||
const getData = async (id) => {
|
||||
orderData.value = await withdrawRecordDetail({ id, date: formatDate(Math.round(Date.now() / 1000)) })
|
||||
}
|
||||
const handleBack = async () => {
|
||||
let canNavBack = getCurrentPages()
|
||||
if (canNavBack && canNavBack.length > 1) {
|
||||
uni.navigateBack()
|
||||
} else {
|
||||
history.back();
|
||||
}
|
||||
}
|
||||
onLoad((options : any) => {
|
||||
orderId = options.id
|
||||
getData(orderId)
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
</style>
|
||||
86
src/packages/pages/withdraw/record.vue
Normal file
86
src/packages/pages/withdraw/record.vue
Normal file
@@ -0,0 +1,86 @@
|
||||
<template>
|
||||
<z-paging :refresher-enabled="false" :show-loading-more-when-reload="true" loading-more-default-text=""
|
||||
loading-more-loading-text="" loading-more-fail-text="" :empty-view-text="t('common.noData')"
|
||||
:show-loading-more-no-more-view="false" ref="paging" v-model="dataList" @query="queryList"
|
||||
class="max-w-[750px]">
|
||||
<h-dark :title="t('withdraw.titleRecord')"></h-dark>
|
||||
<view class="mx-[30rpx] mt-[20rpx]">
|
||||
<navigator v-for="item in dataList" :key="item.id" hover-class="none"
|
||||
:url="'/packages/pages/withdraw/order_detail?id='+item.id">
|
||||
<view class="bg-[#2C326B] mb-[20rpx] rounded-lg px-[40rpx] py-[35rpx]">
|
||||
<view class="flex justify-between mb-[20rpx]">
|
||||
<view class="w-3/5">
|
||||
<view class="">{{item.create_time}}</view>
|
||||
</view>
|
||||
<view class="text-right w-2/5">
|
||||
<view class=" font-bold ">
|
||||
{{item.amount}}
|
||||
</view>
|
||||
<view class="mt-[10rpx] text-xs" v-if="item.rate != 1">
|
||||
≈ {{item.amount_act}} {{item.symbol}}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="flex justify-between">
|
||||
<view class="text-[#00D2E0]">
|
||||
<view class="">
|
||||
{{item.account}}
|
||||
</view>
|
||||
<view v-if="item.status==2" class="text-xs text-error mt-[12rpx] break-words">
|
||||
<text v-if="item.reamrk==''">{{tips.withdrawFailTips}}</text>
|
||||
<text v-if="item.reamrk!=''">{{item.remark}}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view v-if="item.status==1" class="text-success">
|
||||
{{tips.finish}}
|
||||
</view>
|
||||
<view v-if="item.status==0" class="text-primary">
|
||||
{{tips.pending}}
|
||||
</view>
|
||||
<view v-if="item.status==2" class="text-error">
|
||||
{{tips.fail}}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</navigator>
|
||||
</view>
|
||||
</z-paging>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, reactive, shallowRef } from 'vue'
|
||||
import { withdrawRecordLists } from '@/api/finance'
|
||||
import { getCurrency,getCurrency2, formatDate, formatMoney } from '@/utils/util'
|
||||
import { t } from '@/utils/util'
|
||||
|
||||
//为了提高渲染速度
|
||||
const tips = reactive({
|
||||
charge: t('withdraw.charge'),
|
||||
withdrawFailTips: t('withdraw.withdrawFailTips'),
|
||||
fail: t('tabs.fail'),
|
||||
pending: t('tabs.pending'),
|
||||
finish: t('tabs.finish'),
|
||||
})
|
||||
uni.setNavigationBarTitle({ title: t('withdraw.titleRecord') })
|
||||
const paging = shallowRef()
|
||||
const dataList = ref<any[]>([])
|
||||
const queryList = async (pageNo : number, pageSize : number) => {
|
||||
try {
|
||||
const data = await withdrawRecordLists({
|
||||
page_no: pageNo,
|
||||
page_size: pageSize,
|
||||
date: formatDate(Math.round(Date.now() / 1000))
|
||||
})
|
||||
Object.keys(data.lists).forEach(key => {
|
||||
data.lists[key]['amount'] = getCurrency() + formatMoney(data.lists[key]['amount']) + ' ' + getCurrency2()
|
||||
})
|
||||
paging.value.complete(data.lists)
|
||||
} catch (error) {
|
||||
paging.value.complete(false)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
</style>
|
||||
329
src/pages.json
Normal file
329
src/pages.json
Normal file
@@ -0,0 +1,329 @@
|
||||
{
|
||||
"pages": [{
|
||||
"path": "pages/index/index"
|
||||
}, {
|
||||
"path": "pages/login/login"
|
||||
},
|
||||
{
|
||||
"path": "pages/team/index",
|
||||
"auth": true
|
||||
},
|
||||
{
|
||||
"path": "pages/robot/index",
|
||||
"auth": true
|
||||
},
|
||||
{
|
||||
"path": "pages/fund/index",
|
||||
"auth": true
|
||||
},
|
||||
{
|
||||
"path": "pages/user/user",
|
||||
"auth": true
|
||||
},
|
||||
{
|
||||
"path": "pages/register/register"
|
||||
},
|
||||
{
|
||||
"path": "pages/bind_mobile/bind_mobile"
|
||||
},
|
||||
{
|
||||
"path": "pages/forget_pwd/forget_pwd"
|
||||
},
|
||||
{
|
||||
"path": "pages/change_password/change_password",
|
||||
"auth": true
|
||||
},
|
||||
{
|
||||
"path": "pages/change_password/change_password_pay",
|
||||
"auth": true
|
||||
},
|
||||
{
|
||||
"path": "pages/change_password/set_password_pay",
|
||||
"auth": true
|
||||
},
|
||||
{
|
||||
"path": "pages/user_set/user_set",
|
||||
"auth": true
|
||||
},
|
||||
{
|
||||
"path": "pages/user_data/user_data",
|
||||
"auth": true
|
||||
},
|
||||
{
|
||||
"path": "pages/auth/google",
|
||||
"auth": true
|
||||
},
|
||||
{
|
||||
"path": "pages/auth/email",
|
||||
"auth": true
|
||||
},
|
||||
{
|
||||
"path": "pages/auth/realname",
|
||||
"auth": true
|
||||
},
|
||||
{
|
||||
"path": "pages/news/news",
|
||||
"style": {
|
||||
"disableScroll": true
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"path": "pages/kefu/index"
|
||||
},
|
||||
{
|
||||
"path": "pages/news_detail/news_detail"
|
||||
},
|
||||
{
|
||||
"path": "pages/news_detail/detail"
|
||||
},
|
||||
{
|
||||
"path": "pages/notice/index",
|
||||
"auth": true
|
||||
},
|
||||
{
|
||||
"path": "pages/notice/record",
|
||||
"auth": true
|
||||
},
|
||||
{
|
||||
"path": "pages/notice/detail",
|
||||
"auth": true
|
||||
},
|
||||
{
|
||||
"path": "pages/share/index",
|
||||
"auth": true
|
||||
},
|
||||
{
|
||||
"path": "pages/mission/index",
|
||||
"auth": true
|
||||
},
|
||||
{
|
||||
"path": "pages/activity/index",
|
||||
"auth": true
|
||||
},
|
||||
{
|
||||
"path": "pages/feedback/index",
|
||||
"auth": true
|
||||
},
|
||||
{
|
||||
"path": "pages/collection/collection",
|
||||
"auth": true
|
||||
},
|
||||
{
|
||||
"path": "pages/as_us/as_us"
|
||||
},
|
||||
{
|
||||
"path": "pages/agreement/agreement"
|
||||
},
|
||||
{
|
||||
"path": "pages/webview/webview"
|
||||
},
|
||||
|
||||
{
|
||||
"path": "pages/empty/empty",
|
||||
"style": {
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "uni_modules/vk-uview-ui/components/u-avatar-cropper/u-avatar-cropper",
|
||||
"style": {
|
||||
"navigationBarBackgroundColor": "#000000"
|
||||
},
|
||||
"auth": true
|
||||
},
|
||||
|
||||
{
|
||||
"path": "pages/robot/record",
|
||||
"auth": true
|
||||
},
|
||||
{
|
||||
"path": "pages/team/record",
|
||||
"auth": true
|
||||
},
|
||||
{
|
||||
"path": "pages/faq/index"
|
||||
},
|
||||
{
|
||||
"path": "pages/language/index"
|
||||
},
|
||||
{
|
||||
"path": "pages/signin/index"
|
||||
},
|
||||
|
||||
{
|
||||
"path": "pages/user_vip/index",
|
||||
"auth": true
|
||||
},
|
||||
{
|
||||
"path": "pages/common/successful"
|
||||
},
|
||||
{
|
||||
"path": "pages/item/index",
|
||||
"auth": true
|
||||
},
|
||||
{
|
||||
"path": "pages/item/detail",
|
||||
"auth": true
|
||||
},
|
||||
{
|
||||
"path": "pages/item/record",
|
||||
"auth": true
|
||||
},
|
||||
{
|
||||
"path": "pages/item/contract",
|
||||
"auth": true
|
||||
},
|
||||
{
|
||||
"path": "pages/transfer/index",
|
||||
"auth": true
|
||||
},
|
||||
{
|
||||
"path": "pages/transfer/record",
|
||||
"auth": true
|
||||
},
|
||||
{
|
||||
"path": "pages/mall/index",
|
||||
"auth": true
|
||||
},
|
||||
{
|
||||
"path": "pages/mall/record",
|
||||
"auth": true
|
||||
},
|
||||
{
|
||||
"path": "pages/mall/draw",
|
||||
"auth": true
|
||||
},
|
||||
{
|
||||
"path": "pages/mall/draw_record",
|
||||
"auth": true
|
||||
},
|
||||
{
|
||||
"path": "pages/mine/index",
|
||||
"auth": true
|
||||
},
|
||||
{
|
||||
"path": "pages/mine/record",
|
||||
"auth": true
|
||||
}
|
||||
],
|
||||
"subPackages": [{
|
||||
"root": "packages",
|
||||
"pages": [{
|
||||
"path": "pages/recharge/index",
|
||||
"auth": true
|
||||
},
|
||||
{
|
||||
"path": "pages/recharge/recharge_bank",
|
||||
"auth": true
|
||||
},
|
||||
{
|
||||
"path": "pages/recharge/recharge_qrcode",
|
||||
"auth": true
|
||||
},
|
||||
{
|
||||
"path": "pages/recharge/recharge_udun",
|
||||
"auth": true
|
||||
},
|
||||
{
|
||||
"path": "pages/recharge/recharge_tron",
|
||||
"auth": true
|
||||
},
|
||||
{
|
||||
"path": "pages/recharge/recharge_address",
|
||||
"auth": true
|
||||
},
|
||||
{
|
||||
"path": "pages/recharge/recharge_online",
|
||||
"auth": true
|
||||
},
|
||||
{
|
||||
"path": "pages/recharge/record",
|
||||
"auth": true
|
||||
},
|
||||
{
|
||||
"path": "pages/user_wallet/record",
|
||||
"auth": true
|
||||
},
|
||||
{
|
||||
"path": "pages/user_wallet/record_freeze",
|
||||
"auth": true
|
||||
},
|
||||
{
|
||||
"path": "pages/user_wallet/order_detail",
|
||||
"auth": true
|
||||
},
|
||||
{
|
||||
"path": "pages/withdraw/account",
|
||||
"auth": true
|
||||
},
|
||||
{
|
||||
"path": "pages/withdraw/account_usdt",
|
||||
"auth": true
|
||||
},
|
||||
{
|
||||
"path": "pages/withdraw/account_qrcode",
|
||||
"auth": true
|
||||
},
|
||||
{
|
||||
"path": "pages/withdraw/account_bank",
|
||||
"auth": true
|
||||
},
|
||||
|
||||
|
||||
{
|
||||
"path": "pages/recharge/order_detail",
|
||||
"auth": true
|
||||
},
|
||||
{
|
||||
"path": "pages/withdraw/index",
|
||||
"auth": true
|
||||
},
|
||||
{
|
||||
"path": "pages/withdraw/record",
|
||||
"auth": true
|
||||
},
|
||||
{
|
||||
"path": "pages/withdraw/order_detail",
|
||||
"auth": true
|
||||
}
|
||||
|
||||
]
|
||||
}],
|
||||
"globalStyle": {
|
||||
// "navigationBarTextStyle": "black",
|
||||
// "navigationBarBackgroundColor": "#FFFFFF",
|
||||
// "backgroundColor": "#F8F8F8",
|
||||
// "h5": {
|
||||
// "navigationStyle": "custom"
|
||||
// },
|
||||
"rpxCalcMaxDeviceWidth": 550,
|
||||
"navigationStyle": "custom"
|
||||
},
|
||||
"easycom": {
|
||||
"custom": {
|
||||
"^(?!z-paging-refresh|z-paging-load-more)z-paging(.*)": "z-paging/components/z-paging$1/z-paging$1.vue",
|
||||
"^w-(.*)": "@/components/widgets/$1/$1.vue",
|
||||
"^h-(.*)": "@/components/header/$1.vue"
|
||||
}
|
||||
},
|
||||
"tabBar": {
|
||||
"list": [{
|
||||
"pagePath": "pages/index/index"
|
||||
}, {
|
||||
"pagePath": "pages/team/index"
|
||||
},
|
||||
{
|
||||
"pagePath": "pages/mine/index"
|
||||
},
|
||||
{
|
||||
"pagePath": "pages/fund/index"
|
||||
}, {
|
||||
"pagePath": "pages/user/user"
|
||||
}, {
|
||||
"pagePath": "pages/item/index"
|
||||
}],
|
||||
"height": "0px"
|
||||
}
|
||||
|
||||
}
|
||||
77
src/pages/activity/index.vue
Normal file
77
src/pages/activity/index.vue
Normal file
@@ -0,0 +1,77 @@
|
||||
<template>
|
||||
<h-dark :title="t('activity.title')"></h-dark>
|
||||
<view class="mx-[30rpx]">
|
||||
<view class="ad flex items-center">
|
||||
<view class="flex justify-around items-center w-full text-white">
|
||||
<view class="text-center">
|
||||
<view class=" font-bold text-3xl mb-[10rpx]">
|
||||
{{data.report.today_income}}
|
||||
</view>
|
||||
<view class=" ">
|
||||
{{t('activity.todayIncome')}}
|
||||
</view>
|
||||
</view>
|
||||
<view class="text-center">
|
||||
<view class=" font-bold text-3xl mb-[10rpx]">
|
||||
{{data.report.total_income}}
|
||||
</view>
|
||||
<view class=" ">
|
||||
{{t('activity.totalIncome')}}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="mt-[20rpx] pb-[30rpx]">
|
||||
<view class="bg-[#2C326B] rounded-lg px-[24rpx] py-[40rpx] mb-[20rpx]"
|
||||
v-for="(item, index) in data.activities" :key="index">
|
||||
<view class="flex justify-between items-center">
|
||||
<view class="">
|
||||
<view class="font-bold">
|
||||
{{replaceStr(replaceStr(t('activity.itemTitle1'),'{money}',item.recharge_money),'{reward}',item.money)}}
|
||||
</view>
|
||||
<view class="text-[#00D2E0] mt-[10rpx]" v-if="item.count>0">
|
||||
<text class="mr-[10rpx]">{{t('activity.itemTips1')}}:</text>{{item.count}}
|
||||
</view>
|
||||
</view>
|
||||
<view class="ml-[30rpx]">
|
||||
<u-button type="primary" size="mini" shape="circle">{{t('tabs.pending')}}</u-button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { reactive, ref } from 'vue'
|
||||
import { getActivityIndex } from '@/api/user'
|
||||
import { t,replaceStr } from '@/utils/util'
|
||||
|
||||
uni.setNavigationBarTitle({ title: t('activity.title') })
|
||||
const data = reactive<{
|
||||
activities : any[]
|
||||
report : any
|
||||
}>({
|
||||
activities: [],
|
||||
report : []
|
||||
})
|
||||
|
||||
const getData = async () => {
|
||||
const res = await getActivityIndex()
|
||||
data.activities = res.activities
|
||||
data.report = res.report
|
||||
}
|
||||
getData()
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.ad {
|
||||
background-image: url('/static/images/activity/activitybg.png');
|
||||
background-size: 100% auto;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
width: 100%;
|
||||
height: 112px;
|
||||
border-radius: 30rpx;
|
||||
}
|
||||
</style>
|
||||
31
src/pages/agreement/agreement.vue
Normal file
31
src/pages/agreement/agreement.vue
Normal file
@@ -0,0 +1,31 @@
|
||||
<!-- <template>
|
||||
<view class="">
|
||||
<u-parse :html="agreementContent"></u-parse>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
import { getPolicy } from '@/api/app'
|
||||
|
||||
let agreementType = ref('') // 协议类型
|
||||
const agreementContent = ref('') // 协议内容
|
||||
|
||||
const getData = async (type) => {
|
||||
const res = await getPolicy({ type })
|
||||
agreementContent.value = res.content
|
||||
uni.setNavigationBarTitle({
|
||||
title: String(res.title)
|
||||
})
|
||||
}
|
||||
|
||||
onLoad((options: any) => {
|
||||
if (options.type) {
|
||||
agreementType = options.type
|
||||
getData(agreementType)
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style -->>
|
||||
23
src/pages/as_us/as_us.vue
Normal file
23
src/pages/as_us/as_us.vue
Normal file
@@ -0,0 +1,23 @@
|
||||
<template>
|
||||
<h-dark title="关于我们"></h-dark>
|
||||
<view class="as-us flex flex-1 flex-col items-center">
|
||||
<image :src="appStore.getWebsiteConfig.shop_logo" mode="" class="img"></image>
|
||||
<view class="text-content mt-[20rpx]">当前版本{{ appStore.config.version }}</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useAppStore } from '@/stores/app'
|
||||
const appStore = useAppStore()
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.as-us {
|
||||
.img {
|
||||
width: 160rpx;
|
||||
height: 160rpx;
|
||||
border-radius: 20rpx;
|
||||
margin-top: 96rpx;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
114
src/pages/auth/email.vue
Normal file
114
src/pages/auth/email.vue
Normal file
@@ -0,0 +1,114 @@
|
||||
<template>
|
||||
<h-dark :title="t('auth.emailTitle')"></h-dark>
|
||||
<view class="mx-[30rpx]" v-if="data.info.auth_email==1">
|
||||
<view class="flex justify-center mt-[60rpx]">
|
||||
<u-image width="180" height="180" mode="widthFix" src="/static/images/user/authemail.png"></u-image>
|
||||
</view>
|
||||
<view class="my-[30rpx] leading-loose">
|
||||
{{t('auth.emailTips')}}
|
||||
</view>
|
||||
<view class="flex justify-between mt-[100rpx]">
|
||||
<view class="">
|
||||
<view class="text-[#00D2E0] mt-[10rpx]">
|
||||
{{data.info.email}}
|
||||
</view>
|
||||
</view>
|
||||
<view class="">
|
||||
<text class="">{{t('tabs.Verified')}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="mx-[30rpx]" v-if="data.info.auth_email==0">
|
||||
<u-form :border-bottom="false" :label-width="150" label-position="top">
|
||||
<u-form-item :itemStyle="{'background':'#3d4277'}" :label="t('auth.email')" :border-bottom="false">
|
||||
<u-input class="flex-1" type="email" v-model="formData.email"
|
||||
:placeholder="t('auth.emailPlaceholder')" :border="false" />
|
||||
</u-form-item>
|
||||
<u-form-item :itemStyle="{'background':'#3d4277'}" :label="t('pwd.captcha')" :border-bottom="false">
|
||||
<u-input class="flex-1" v-model="formData.code" :placeholder="t('captcha.captchaPlaceholder')"
|
||||
:border="false" />
|
||||
<view class="border-l border-solid border-0 border-light pl-3 text-[#00D2E0] leading-4 ml-3 w-[180rpx]"
|
||||
@click="sendSms">
|
||||
<u-verification-code ref="uCodeRef" :seconds="60" @change="codeChange"
|
||||
:change-text="t('captcha.changeText')" :startText="t('captcha.startText')"
|
||||
:endText="t('captcha.endText')" />
|
||||
<text :class="formData.email ? 'text-primary' : 'text-[#00D2E0]'">
|
||||
{{ codeTips }}
|
||||
</text>
|
||||
</view>
|
||||
</u-form-item>
|
||||
</u-form>
|
||||
<view class="font-bold flex justify-start items-center mb-[20rpx] mt-[30rpx]">
|
||||
<u-icon size="32" name="info-circle-fill"></u-icon>
|
||||
<view class="ml-[10rpx]">
|
||||
{{t('auth.warm')}}
|
||||
</view>
|
||||
</view>
|
||||
<view class="p-[20rpx] bg-[#3d4277] text-[#00D2E0] leading-loose rounded-lg">
|
||||
{{t('auth.warmTips')}}
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view v-if="data.info.auth_email==0" class="max-w-[750px] fixed bottom-[50rpx] w-4/5 ml-[10%]">
|
||||
<u-button type="primary" :disabled="formData.code == ''||formData.code == ''" @click="submitHandle"> {{t('auth.bindBtn')}}
|
||||
</u-button>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { reactive, ref,shallowRef } from 'vue'
|
||||
import { emailSend } from '@/api/app'
|
||||
import { getUserInfo,verifyEmail } from '@/api/user'
|
||||
import { t } from '@/utils/util'
|
||||
|
||||
uni.setNavigationBarTitle({ title: t('auth.emailTitle') })
|
||||
|
||||
const uCodeRef = shallowRef()
|
||||
const codeTips = ref('')
|
||||
const data = ref<any>({
|
||||
info:{
|
||||
auth_email:2
|
||||
}
|
||||
})
|
||||
|
||||
const formData = reactive<any>({
|
||||
email:'',
|
||||
code: ''
|
||||
})
|
||||
|
||||
const getData = async () => {
|
||||
const res = await getUserInfo()
|
||||
data.value = res;
|
||||
}
|
||||
|
||||
const codeChange = (text : string) => {
|
||||
codeTips.value = text
|
||||
}
|
||||
|
||||
const sendSms = async () => {
|
||||
if (!formData.email) return
|
||||
var emailRegex = /^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,6}$/;
|
||||
if(!emailRegex.test(formData.email)){
|
||||
return uni.$u.toast(t('auth.emailEmpty'))
|
||||
}
|
||||
|
||||
if (uCodeRef.value?.canGetCode) {
|
||||
await emailSend({
|
||||
email: formData.email,
|
||||
})
|
||||
uni.$u.toast(t('captcha.sendSuccessfully'))
|
||||
uCodeRef.value?.start()
|
||||
}
|
||||
}
|
||||
|
||||
const submitHandle = async () => {
|
||||
await verifyEmail(formData)
|
||||
uni.$u.toast(t('network.bindingSuccessful'))
|
||||
getData();
|
||||
}
|
||||
getData()
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
</style>
|
||||
104
src/pages/auth/google.vue
Normal file
104
src/pages/auth/google.vue
Normal file
@@ -0,0 +1,104 @@
|
||||
<template>
|
||||
<h-dark :title="t('auth.googleTitle')"></h-dark>
|
||||
<view class="mx-[30rpx]" v-if="data.info.auth_google==1">
|
||||
<view class="flex justify-center mt-[60rpx]">
|
||||
<u-image width="180" height="180" mode="widthFix" src="/static/images/user/authgoogle.png"></u-image>
|
||||
</view>
|
||||
<view class="my-[30rpx] leading-loose">
|
||||
{{t('auth.googleTIps')}}
|
||||
</view>
|
||||
<view class="flex justify-between mt-[100rpx]">
|
||||
<view class="">
|
||||
<view class="text-[#00D2E0] mt-[10rpx]">
|
||||
{{data.info.google_key}}
|
||||
</view>
|
||||
</view>
|
||||
<view class="">
|
||||
<text class="">{{t('tabs.Verified')}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="mx-[30rpx]" v-if="data.info.auth_google==0">
|
||||
<view class="font-bold my-[30rpx]">
|
||||
{{t('auth.googleStep1')}}
|
||||
</view>
|
||||
<view class="text-[#00D2E0]">
|
||||
{{t('auth.googleStep1Tips')}}
|
||||
</view>
|
||||
<view class="font-bold my-[30rpx]">
|
||||
{{t('auth.googleStep2')}}
|
||||
</view>
|
||||
<view class="">
|
||||
<view class="">
|
||||
<view class="flex justify-center">
|
||||
<u-image width="330rpx" height="330rpx" :src="data.info.google_qrcode"></u-image>
|
||||
</view>
|
||||
</view>
|
||||
<view class="text-[#00D2E0] text-center my-[40rpx]">
|
||||
{{t('auth.googleStep2Tips')}}
|
||||
</view>
|
||||
<view class="bg-[#3d4277] rounded-lg px-[30rpx] py-[20rpx] mx-[100rpx]">
|
||||
<view class="flex justify-center items-center" @click.stop="copyText(data.info.google_key)">
|
||||
<view class="">
|
||||
{{data.info.google_key}}
|
||||
</view>
|
||||
<view class="ml-[10rpx]">
|
||||
<u-icon size="30" name="/static/images/common/copy.png"></u-icon>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="font-bold my-[30rpx]">
|
||||
{{t('auth.googleStep3')}}
|
||||
</view>
|
||||
<view class="bg-[#3d4277] rounded-lg px-[20rpx] py-[10rpx]">
|
||||
<u-input v-model="formData.code" type="number" :border="false"
|
||||
:placeholder="t('auth.googleCodePlaceholder')" />
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view v-if="data.info.auth_google==0" class="max-w-[750px] fixed bottom-[50rpx] w-4/5 ml-[10%]">
|
||||
<u-button type="primary" :disabled="formData.code == ''" @click="submitHandle"> {{t('auth.bindBtn')}}
|
||||
</u-button>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { reactive, ref } from 'vue'
|
||||
import { getUserInfo, verifyGoogle } from '@/api/user'
|
||||
import { useCopy } from '@/hooks/useCopy'
|
||||
import { t } from '@/utils/util'
|
||||
|
||||
uni.setNavigationBarTitle({ title: t('auth.googleTitle') })
|
||||
const { copy } = useCopy()
|
||||
const data = ref<any>({
|
||||
info: {
|
||||
auth_google: 2
|
||||
}
|
||||
})
|
||||
|
||||
const formData = reactive<any>({
|
||||
code: ''
|
||||
})
|
||||
|
||||
const getData = async () => {
|
||||
const res = await getUserInfo()
|
||||
data.value = res;
|
||||
}
|
||||
|
||||
const copyText = async (text : string) => {
|
||||
copy(text);
|
||||
uni.$u.toast(t('common.copySuccess'))
|
||||
}
|
||||
|
||||
const submitHandle = async () => {
|
||||
await verifyGoogle(formData)
|
||||
uni.$u.toast(t('network.bindingSuccessful'))
|
||||
getData();
|
||||
}
|
||||
getData()
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
</style>
|
||||
186
src/pages/auth/realname.vue
Normal file
186
src/pages/auth/realname.vue
Normal file
@@ -0,0 +1,186 @@
|
||||
<template>
|
||||
<h-dark :title="t('auth.realTitle')"></h-dark>
|
||||
<view class="mx-[30rpx]" v-if="data.info.auth_card==1||data.info.auth_card==2||data.info.auth_card==3">
|
||||
<view class="flex justify-center mt-[60rpx]">
|
||||
<u-image width="180" height="180" mode="widthFix" src="/static/images/user/authrealname.png"></u-image>
|
||||
</view>
|
||||
<view class="my-[30rpx]">
|
||||
{{t('auth.realTips')}}
|
||||
</view>
|
||||
<view class="flex justify-between items-center mt-[100rpx]">
|
||||
<view class="">
|
||||
<view class="text-[#00D2E0] mt-[10rpx]">
|
||||
{{data.info.card_name}}({{data.info.card_num}})
|
||||
</view>
|
||||
</view>
|
||||
<view class="">
|
||||
<text class="" v-if="data.info.auth_card==1">{{t('tabs.Verified')}}</text>
|
||||
<text class="" v-if="data.info.auth_card==2">{{t('tabs.auditing')}}</text>
|
||||
<view class="text-error" v-if="data.info.auth_card==3" @click="data.info.auth_card=0">
|
||||
{{t('tabs.authFailed')}}
|
||||
<u-icon name="arrow-right" size="22"></u-icon>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="text-error" v-if="data.info.auth_card==3">
|
||||
{{data.info.card_remark}}
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="mx-[30rpx]" v-if="data.info.auth_card==0">
|
||||
<u-form :border-bottom="false" :label-width="150" label-position="top">
|
||||
<u-form-item :itemStyle="{'background':'#3d4277'}" :label="t('auth.realName')" :border-bottom="false">
|
||||
<u-input class="flex-1" v-model="formData.card_name" maxlength="20"
|
||||
:placeholder="t('auth.realNamePlaceholder')" :border="false" />
|
||||
</u-form-item>
|
||||
<u-form-item :itemStyle="{'background':'#3d4277'}" :label="t('auth.realNum')" :border-bottom="false">
|
||||
<u-input class="flex-1" v-model="formData.card_num" maxlength="32"
|
||||
:placeholder="t('auth.realNumPlaceholder')" :border="false" />
|
||||
</u-form-item>
|
||||
<u-form-item :label="t('auth.realImg')" :border-bottom="false">
|
||||
<view class="w-full">
|
||||
<view class="flex justify-between w-full">
|
||||
<view class="w-[48%] flex justify-center img1">
|
||||
<u-upload class="" ref="uploader1" :custom-btn="true" :deletable="false"
|
||||
:auto-upload="false" max-count="1" :max-size="20*1024*1024" v-model="formData.card_img1">
|
||||
<template v-slot:addBtn>
|
||||
<view class="text-center items-center slot-btn" hover-class="slot-btn__hover"
|
||||
hover-stay-time="150">
|
||||
<u-icon name="/static/images/common/photo.png" size="80"></u-icon>
|
||||
<view class="text-[#000000]">
|
||||
{{t('auth.realImg1')}}
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
</u-upload>
|
||||
</view>
|
||||
<view class="w-[48%] flex justify-center img2">
|
||||
<u-upload class="" ref="uploader2" :custom-btn="true" :deletable="false"
|
||||
:auto-upload="false" max-count="1" :max-size="20*1024*1024" v-model="formData.card_img2">
|
||||
<template v-slot:addBtn>
|
||||
<view class="text-center items-center slot-btn" hover-class="slot-btn__hover"
|
||||
hover-stay-time="150">
|
||||
<u-icon name="/static/images/common/photo.png" size="80"></u-icon>
|
||||
<view class="text-[#000000]">
|
||||
{{t('auth.realImg2')}}
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
</u-upload>
|
||||
</view>
|
||||
</view>
|
||||
<view class="flex justify-start w-full mt-[20rpx]">
|
||||
<view class="w-[48%] flex justify-center img1">
|
||||
<u-upload class="" ref="uploader3" :custom-btn="true" :deletable="false"
|
||||
:auto-upload="false" max-count="1" :max-size="20*1024*1024" v-model="formData.card_img3">
|
||||
<template v-slot:addBtn>
|
||||
<view class="text-center items-center slot-btn" hover-class="slot-btn__hover"
|
||||
hover-stay-time="150">
|
||||
<u-icon name="/static/images/common/photo.png" size="80"></u-icon>
|
||||
<view class="text-[#000000]">
|
||||
{{t('auth.realImg3')}}
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
</u-upload>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</u-form-item>
|
||||
</u-form>
|
||||
</view>
|
||||
|
||||
<view v-if="data.info.auth_card==0" class="max-w-[750px] fixed bottom-[50rpx] w-4/5 ml-[10%]">
|
||||
<u-button type="primary" :loading="uploading" :disabled="formData.card_name == ''||formData.card_num == ''"
|
||||
@click="submitHandle"> {{t('common.submit')}}
|
||||
</u-button>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { reactive, ref } from 'vue'
|
||||
import { useUserStore } from '@/stores/user'
|
||||
import { getUserInfo, verifyRealname } from '@/api/user'
|
||||
import { uploadImage } from '@/api/app'
|
||||
import { t } from '@/utils/util'
|
||||
|
||||
uni.setNavigationBarTitle({ title: t('auth.realTitle') })
|
||||
const userStore = useUserStore()
|
||||
const uploader1 = ref()
|
||||
const uploader2 = ref()
|
||||
const uploader3 = ref()
|
||||
const uploading = ref(false)
|
||||
|
||||
const data = ref<any>({
|
||||
info: {
|
||||
auth_card: 4
|
||||
}
|
||||
})
|
||||
|
||||
const formData = reactive<any>({
|
||||
card_name: '',
|
||||
card_num: '',
|
||||
card_img1: '',
|
||||
card_img2: '',
|
||||
card_img3: ''
|
||||
})
|
||||
|
||||
const getData = async () => {
|
||||
const res = await getUserInfo()
|
||||
data.value = res;
|
||||
}
|
||||
|
||||
const submitHandle = async () => {
|
||||
if (uploading.value) return;
|
||||
uploading.value = true;
|
||||
|
||||
if (uploader1.value.lists.length <= 0) {
|
||||
uploading.value = false;
|
||||
return uni.$u.toast(t('auth.realImg1Empty'))
|
||||
}
|
||||
if (uploader2.value.lists.length <= 0) {
|
||||
uploading.value = false;
|
||||
return uni.$u.toast(t('auth.realImg2Empty'))
|
||||
}
|
||||
if (uploader3.value.lists.length <= 0) {
|
||||
uploading.value = false;
|
||||
return uni.$u.toast(t('auth.realImg3Empty'))
|
||||
}
|
||||
|
||||
if (formData.card_img1 == '') {
|
||||
const res1 : any = await uploadImage(uploader1.value.lists[0].url, userStore.temToken!)
|
||||
formData.card_img1 = res1.url;
|
||||
}
|
||||
if (formData.card_img2 == '') {
|
||||
const res2 : any = await uploadImage(uploader2.value.lists[0].url, userStore.temToken!)
|
||||
formData.card_img2 = res2.url;
|
||||
} if (formData.card_img3 == '') {
|
||||
const res3 : any = await uploadImage(uploader3.value.lists[0].url, userStore.temToken!)
|
||||
formData.card_img3 = res3.url;
|
||||
}
|
||||
|
||||
uploading.value = false;
|
||||
await verifyRealname(formData)
|
||||
uni.$u.toast(t('network.submittedSuccessfully'))
|
||||
getData();
|
||||
}
|
||||
getData()
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.img1 {
|
||||
background-image: url('/static/images/user/authrealnameimg1.png');
|
||||
background-size: 100% auto;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
height: 112px;
|
||||
}
|
||||
|
||||
.img2 {
|
||||
background-image: url('/static/images/user/authrealnameimg2.png');
|
||||
background-size: 100% auto;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
height: 112px;
|
||||
}
|
||||
</style>
|
||||
117
src/pages/bind_mobile/bind_mobile.vue
Normal file
117
src/pages/bind_mobile/bind_mobile.vue
Normal file
@@ -0,0 +1,117 @@
|
||||
<template>
|
||||
<h-dark :title="t('pwd.titleBind')"></h-dark>
|
||||
<view class="bg-white min-h-full flex flex-col items-center px-[40rpx] pt-[120rpx] box-border">
|
||||
<view>
|
||||
<u-image src="../../static/images/login/register-bg.png" mode="widthFix" height="260" width="260" />
|
||||
</view>
|
||||
<view class="w-full">
|
||||
<u-form :border-bottom="false" :label-width="150" label-position="top">
|
||||
<u-form-item :border-bottom="false" :label="t('pwd.mobile')" :required="true">
|
||||
<u-picker class="max-w-[750px]" mode="selector" v-model="picker_show"
|
||||
:default-selector="[country_code.default_select]" :range="country_code.list"
|
||||
@confirm="handlePicker" :confirm-text="t('common.confirm')" :cancel-text="t('common.cancel')">
|
||||
</u-picker>
|
||||
<view class="mr-[20rpx]" @click="picker_show=true">
|
||||
<text class="mr-[10rpx]">{{formData.country_code}}
|
||||
</text>
|
||||
<u-icon name="arrow-down" size="20"></u-icon>
|
||||
</view>
|
||||
<u-input class="flex-1" v-model="formData.mobile" :border="false"
|
||||
:placeholder="t('pwd.mobilePlaceholder')" />
|
||||
</u-form-item>
|
||||
<u-form-item :border-bottom="false" :label="t('captcha.captcha')" :required="true">
|
||||
<u-input class="flex-1" v-model="formData.code" :placeholder="t('captcha.captchaPlaceholder')"
|
||||
:border="false" />
|
||||
<view class="border-l border-solid border-0 border-light pl-3 text-muted leading-4 ml-3 w-[180rpx]"
|
||||
@click="sendSms">
|
||||
<u-verification-code ref="uCodeRef" :seconds="60" @change="codeChange"
|
||||
:change-text="t('captcha.changeText')" :startText="t('captcha.startText')"
|
||||
:endText="t('captcha.endText')" />
|
||||
<text :class="formData.mobile ? 'text-primary' : 'text-muted'">
|
||||
{{ codeTips }}
|
||||
</text>
|
||||
</view>
|
||||
</u-form-item>
|
||||
</u-form>
|
||||
<view class="mt-[40rpx]">
|
||||
<u-button type="primary" shape="circle" @click="handleConfirm"> {{t('common.confirm')}} </u-button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { userBindMobile } from '@/api/user'
|
||||
import { smsSend, getCountryCode } from '@/api/app'
|
||||
import { SMSEnum } from '@/enums/appEnums'
|
||||
import { reactive, ref, shallowRef } from 'vue'
|
||||
import { useUserStore } from '@/stores/user'
|
||||
import { t } from '@/utils/util'
|
||||
|
||||
uni.setNavigationBarTitle({ title: t('pwd.titleBind') })
|
||||
const uCodeRef = shallowRef()
|
||||
const codeTips = ref('')
|
||||
|
||||
const userStore = useUserStore()
|
||||
const codeChange = (text : string) => {
|
||||
codeTips.value = text
|
||||
}
|
||||
|
||||
const formData = reactive({
|
||||
type: 'bind',
|
||||
mobile: '',
|
||||
code: '',
|
||||
country_code: ''
|
||||
})
|
||||
|
||||
const picker_show = ref(false)
|
||||
const country_code = reactive<{
|
||||
list : any[]
|
||||
default_select : number
|
||||
}>({
|
||||
list: [],
|
||||
default_select: 0
|
||||
})
|
||||
const getData = async () => {
|
||||
let data = await getCountryCode()
|
||||
country_code.list = data;
|
||||
formData.country_code = data[0]
|
||||
}
|
||||
const handlePicker = (index : number) => {
|
||||
country_code.default_select = index;
|
||||
formData.country_code = country_code.list[index];
|
||||
}
|
||||
|
||||
const sendSms = async () => {
|
||||
if (!formData.mobile) return uni.$u.toast(t('captcha.mobileEmpty'))
|
||||
if (uCodeRef.value?.canGetCode) {
|
||||
await smsSend({
|
||||
scene: SMSEnum.BIND_MOBILE,
|
||||
mobile: formData.mobile,
|
||||
country_code: formData.country_code
|
||||
})
|
||||
uni.$u.toast(t('captcha.sendSuccessfully'))
|
||||
uCodeRef.value?.start()
|
||||
}
|
||||
}
|
||||
const handleConfirm = async () => {
|
||||
if (!formData.mobile) return uni.$u.toast(t('captcha.mobileEmpty'))
|
||||
if (!formData.code) return uni.$u.toast(t('captcha.captchaEmpty'))
|
||||
await userBindMobile(formData, { token: userStore.temToken })
|
||||
uni.$u.toast(t('pwd.bindSuccess'))
|
||||
userStore.login(userStore.temToken!)
|
||||
setTimeout(() => {
|
||||
uni.reLaunch({
|
||||
url: '/pages/index/index'
|
||||
})
|
||||
}, 1500)
|
||||
}
|
||||
|
||||
getData()
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
page {
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
51
src/pages/change_password/change_password.vue
Normal file
51
src/pages/change_password/change_password.vue
Normal file
@@ -0,0 +1,51 @@
|
||||
<template>
|
||||
<h-dark :title="t('pwd.chLoginPwd')"></h-dark>
|
||||
<view class="flex flex-col items-center px-[30rpx] box-border">
|
||||
<view class="w-full">
|
||||
<u-form :border-bottom="false" :label-width="150" label-position="top">
|
||||
<u-form-item :itemStyle="{'background':'#3d4277'}" :label="t('pwd.oldPwd')" :border-bottom="false">
|
||||
<u-input class="flex-1" type="password" v-model="formData.old_password" :border="false"
|
||||
:placeholder="t('pwd.oldPwdPlaceholder')" />
|
||||
</u-form-item>
|
||||
<u-form-item :itemStyle="{'background':'#3d4277'}" :label="t('pwd.newPwd')" :border-bottom="false">
|
||||
<u-input class="flex-1" type="password" v-model="formData.password" :placeholder="t('pwd.newPwdPlaceholder')"
|
||||
:border="false" />
|
||||
</u-form-item>
|
||||
<u-form-item :itemStyle="{'background':'#3d4277'}" :label="t('pwd.confirmPwd')" :border-bottom="false">
|
||||
<u-input class="flex-1" type="password" v-model="formData.password_confirm" :placeholder="t('pwd.confirmPwdPlaceholder')"
|
||||
:border="false" />
|
||||
</u-form-item>
|
||||
</u-form>
|
||||
<view class="mt-[100rpx]">
|
||||
<u-button type="primary" :disabled="formData.old_password==''||formData.password==''||formData.password_confirm==''" @click="handleConfirm"> {{t('common.submit')}} </u-button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { userChangePwd } from '@/api/user'
|
||||
import { reactive } from 'vue'
|
||||
import { t } from '@/utils/util'
|
||||
uni.setNavigationBarTitle({ title: t('pwd.titleChangePwd') })
|
||||
const formData = reactive<any>({
|
||||
old_password:'',
|
||||
password: '',
|
||||
password_confirm: ''
|
||||
})
|
||||
|
||||
const handleConfirm = async () => {
|
||||
if (!formData.old_password) return uni.$u.toast(t('pwd.oldPwdEmpty'))
|
||||
if (!formData.password) return uni.$u.toast(t('pwd.newPwdEmpty'))
|
||||
if (!formData.password_confirm) return uni.$u.toast(t('pwd.confirmPwdEmpty'))
|
||||
if (formData.password != formData.password_confirm) return uni.$u.toast(t('pwd.twoPwdError'))
|
||||
await userChangePwd(formData)
|
||||
uni.$u.toast(t('network.modifySuccessfully'))
|
||||
setTimeout(() => {
|
||||
uni.navigateBack()
|
||||
}, 1500)
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
</style>
|
||||
150
src/pages/change_password/change_password_pay.vue
Normal file
150
src/pages/change_password/change_password_pay.vue
Normal file
@@ -0,0 +1,150 @@
|
||||
<template>
|
||||
<h-dark :title="t('pwd.chPayPwd')"></h-dark>
|
||||
<view class="flex flex-col items-center px-[40rpx] box-border">
|
||||
<view class="w-full">
|
||||
<u-form :border-bottom="false" :label-width="150" label-position="top">
|
||||
<u-form-item :itemStyle="{'background':'#3d4277'}" :label="t('pwd.oldPwd')" :border-bottom="false"
|
||||
@click="inputClick(1)">
|
||||
<text v-if="formData.old_password_pay != ''">{{formData.old_password_pay}}</text>
|
||||
<text v-if="formData.old_password_pay == ''" class="text-muted">{{t('pwd.oldPwdEmpty')}}</text>
|
||||
</u-form-item>
|
||||
<u-form-item :itemStyle="{'background':'#3d4277'}" :label="t('pwd.newPwd')" :border-bottom="false"
|
||||
@click="inputClick(2)">
|
||||
<text v-if="formData.password_pay != ''">{{formData.password_pay}}</text>
|
||||
<text v-if="formData.password_pay == ''" class="text-muted">{{t('pwd.newPwdEmpty')}}</text>
|
||||
</u-form-item>
|
||||
<u-form-item :itemStyle="{'background':'#3d4277'}" :label="t('pwd.confirmPwd')" :border-bottom="false"
|
||||
@click="inputClick(3)">
|
||||
<text v-if="formData.password_pay_confirm != ''">{{formData.password_pay_confirm}}</text>
|
||||
<text v-if="formData.password_pay_confirm == ''"
|
||||
class="text-muted">{{t('pwd.confirmPwdEmpty')}}</text>
|
||||
</u-form-item>
|
||||
</u-form>
|
||||
<view class="mt-[100rpx]">
|
||||
<u-button type="primary" @click="handleConfirm"> {{t('common.submit')}} </u-button>
|
||||
</view>
|
||||
|
||||
<u-keyboard class="max-w-[750px]" ref="uKeyboard1" mode="number" :mask-close-able="false" :dot-enabled="false"
|
||||
tips=" " confirm-text="" cancel-text="" v-model="show_keyboard" @change="keyboardChange"
|
||||
@backspace="backspace" :show-input-val="true" :input-value="input.pwd"></u-keyboard>
|
||||
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { getUserInfo, userChangePayPwd } from '@/api/user'
|
||||
import { reactive, ref } from 'vue'
|
||||
import { t } from '@/utils/util'
|
||||
uni.setNavigationBarTitle({ title: t('pwd.titleChangePayPwd') })
|
||||
const formData = reactive<any>({
|
||||
old_password_pay: '',
|
||||
password_pay: '',
|
||||
password_pay_confirm: ''
|
||||
})
|
||||
const input = reactive<any>({
|
||||
pwd: '',
|
||||
})
|
||||
|
||||
const show_keyboard = ref(false)
|
||||
const show_type = ref(1)
|
||||
const loading_keyboard = ref(false)
|
||||
|
||||
const keyboardChange = (val : string) => {
|
||||
switch (show_type.value) {
|
||||
case 1:
|
||||
formData.old_password_pay += val;
|
||||
if (formData.old_password_pay.length == 6) {
|
||||
show_keyboard.value = false;
|
||||
//延时触发,防止误触
|
||||
setTimeout(() => {
|
||||
loading_keyboard.value = false;
|
||||
}, 500)
|
||||
}
|
||||
break
|
||||
case 2:
|
||||
formData.password_pay += val;
|
||||
if (formData.password_pay.length == 6) {
|
||||
show_keyboard.value = false;
|
||||
setTimeout(() => {
|
||||
loading_keyboard.value = false;
|
||||
}, 500)
|
||||
}
|
||||
break
|
||||
case 3:
|
||||
formData.password_pay_confirm += val;
|
||||
if (formData.password_pay_confirm.length == 6) {
|
||||
show_keyboard.value = false;
|
||||
setTimeout(() => {
|
||||
loading_keyboard.value = false;
|
||||
}, 500)
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
input.pwd += val
|
||||
}
|
||||
const backspace = () => {
|
||||
// 删除value的最后一个字符
|
||||
switch (show_type.value) {
|
||||
case 1:
|
||||
if (formData.old_password_pay.length) formData.old_password_pay = (formData.old_password_pay).substr(0, (formData.old_password_pay.length) - 1);
|
||||
break
|
||||
case 2:
|
||||
if (formData.password_pay.length) formData.password_pay = (formData.password_pay).substr(0, (formData.password_pay.length) - 1);
|
||||
break
|
||||
case 3:
|
||||
if (formData.password_pay_confirm.length) formData.password_pay_confirm = (formData.password_pay_confirm).substr(0, (formData.password_pay_confirm.length) - 1);
|
||||
break
|
||||
}
|
||||
|
||||
if (input.pwd.length) input.pwd = (input.pwd).substr(0, (input.pwd.length) - 1);
|
||||
}
|
||||
|
||||
const inputClick = (type : number) => {
|
||||
if (loading_keyboard.value) return
|
||||
show_type.value = type
|
||||
input.pwd = ''
|
||||
|
||||
switch (show_type.value) {
|
||||
case 1:
|
||||
formData.old_password_pay = '';
|
||||
break
|
||||
case 2:
|
||||
formData.password_pay = '';
|
||||
break
|
||||
case 3:
|
||||
formData.password_pay_confirm = '';
|
||||
break
|
||||
}
|
||||
show_keyboard.value = true;
|
||||
loading_keyboard.value = true;
|
||||
}
|
||||
|
||||
const handleConfirm = async () => {
|
||||
if (formData.old_password_pay.length != 6) return uni.$u.toast(t('pwd.oldPwdEmpty'))
|
||||
if (formData.password_pay.length != 6) return uni.$u.toast(t('pwd.newPwdEmpty'))
|
||||
if (formData.password_pay_confirm.length != 6) return uni.$u.toast(t('pwd.confirmPwdEmpty'))
|
||||
if (formData.password_pay != formData.password_pay_confirm) return uni.$u.toast(t('pwd.twoPwdError'))
|
||||
|
||||
await userChangePayPwd(formData)
|
||||
uni.$u.toast(t('network.modifySuccessfully'))
|
||||
setTimeout(() => {
|
||||
uni.navigateBack()
|
||||
}, 1500)
|
||||
}
|
||||
const getData = async () => {
|
||||
const res = await getUserInfo()
|
||||
if (res.need_set_pwd == 1) {
|
||||
uni.$u.toast(t('pwd.pwdSetFirstTips'))
|
||||
uni.redirectTo({
|
||||
url: '/pages/change_password/set_password_pay'
|
||||
})
|
||||
return
|
||||
}
|
||||
}
|
||||
getData()
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
</style>
|
||||
110
src/pages/change_password/set_password_pay.vue
Normal file
110
src/pages/change_password/set_password_pay.vue
Normal file
@@ -0,0 +1,110 @@
|
||||
<template>
|
||||
<h-dark :title="t('pwd.titleSetPwd')"></h-dark>
|
||||
<view class="flex flex-col items-center px-[40rpx] box-border">
|
||||
<view class="w-full">
|
||||
<u-form :border-bottom="false" :label-width="150" label-position="top">
|
||||
<u-form-item :itemStyle="{'background':'#3d4277'}" :label="t('pwd.pwd')" :border-bottom="false" @click="inputClick(2)">
|
||||
<text v-if="formData.password_pay != ''">{{formData.password_pay}}</text>
|
||||
<text v-if="formData.password_pay == ''" class="text-muted">{{t('pwd.pwdEmpty')}}</text>
|
||||
</u-form-item>
|
||||
<u-form-item :itemStyle="{'background':'#3d4277'}" :label="t('pwd.pwdConfirm')" :border-bottom="false" @click="inputClick(3)">
|
||||
<text v-if="formData.password_pay_confirm != ''">{{formData.password_pay_confirm}}</text>
|
||||
<text v-if="formData.password_pay_confirm == ''" class="text-muted">{{t('pwd.pwdConfirmEmpty')}}</text>
|
||||
</u-form-item>
|
||||
</u-form>
|
||||
<view class="mt-[100rpx]">
|
||||
<u-button type="primary" :disabled="formData.password_pay==''||formData.password_pay_confirm==''"
|
||||
@click="handleConfirm"> {{t('common.submit')}} </u-button>
|
||||
</view>
|
||||
|
||||
<u-keyboard class="max-w-[750px]" ref="uKeyboard1" mode="number" :mask-close-able="false" :dot-enabled="false"
|
||||
tips=" " confirm-text="" cancel-text="" v-model="show_keyboard" @change="keyboardChange"
|
||||
@backspace="backspace" :show-input-val="true" :input-value="input.pwd"></u-keyboard>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { setPayPwd } from '@/api/user'
|
||||
import { reactive, ref } from 'vue'
|
||||
import { t } from '@/utils/util'
|
||||
uni.setNavigationBarTitle({ title: t('pwd.titleSetPwd') })
|
||||
const formData = reactive<any>({
|
||||
password_pay: '',
|
||||
password_pay_confirm: ''
|
||||
})
|
||||
const input = reactive<any>({
|
||||
pwd: '',
|
||||
})
|
||||
|
||||
const show_keyboard = ref(false)
|
||||
const show_type = ref(1)
|
||||
const loading_keyboard = ref(false)
|
||||
|
||||
const keyboardChange = (val : string) => {
|
||||
switch (show_type.value) {
|
||||
case 2:
|
||||
formData.password_pay += val;
|
||||
if (formData.password_pay.length == 6) {
|
||||
show_keyboard.value = false;
|
||||
setTimeout(() => {
|
||||
loading_keyboard.value = false;
|
||||
}, 500)
|
||||
}
|
||||
break
|
||||
case 3:
|
||||
formData.password_pay_confirm += val;
|
||||
if (formData.password_pay_confirm.length == 6) {
|
||||
show_keyboard.value = false;
|
||||
setTimeout(() => {
|
||||
loading_keyboard.value = false;
|
||||
}, 500)
|
||||
}
|
||||
break
|
||||
}
|
||||
input.pwd += val
|
||||
}
|
||||
const backspace = () => {
|
||||
// 删除value的最后一个字符
|
||||
switch (show_type.value) {
|
||||
case 2:
|
||||
if (formData.password_pay.length) formData.password_pay = (formData.password_pay).substr(0, (formData.password_pay.length) - 1);
|
||||
break
|
||||
case 3:
|
||||
if (formData.password_pay_confirm.length) formData.password_pay_confirm = (formData.password_pay_confirm).substr(0, (formData.password_pay_confirm.length) - 1);
|
||||
break
|
||||
}
|
||||
if (input.pwd.length) input.pwd = (input.pwd).substr(0, (input.pwd.length) - 1);
|
||||
}
|
||||
|
||||
const inputClick = (type : number) => {
|
||||
if (loading_keyboard.value) return
|
||||
show_type.value = type
|
||||
input.pwd = ''
|
||||
switch (show_type.value) {
|
||||
case 2:
|
||||
formData.password_pay = '';
|
||||
break
|
||||
case 3:
|
||||
formData.password_pay_confirm = '';
|
||||
break
|
||||
}
|
||||
show_keyboard.value = true;
|
||||
loading_keyboard.value = true;
|
||||
}
|
||||
|
||||
const handleConfirm = async () => {
|
||||
if (formData.password_pay.length != 6) return uni.$u.toast(t('pwd.pwdEmpty'))
|
||||
if (formData.password_pay_confirm.length != 6) return uni.$u.toast(t('pwd.pwdConfirmEmpty'))
|
||||
if (formData.password_pay != formData.password_pay_confirm) return uni.$u.toast(t('pwd.twoPwdError'))
|
||||
|
||||
await setPayPwd(formData)
|
||||
uni.$u.toast(t('network.setSuccessful'))
|
||||
setTimeout(() => {
|
||||
uni.navigateBack()
|
||||
}, 1500)
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
</style>
|
||||
63
src/pages/collection/collection.vue
Normal file
63
src/pages/collection/collection.vue
Normal file
@@ -0,0 +1,63 @@
|
||||
<!-- <template>
|
||||
<h-dark title="我的收藏"></h-dark>
|
||||
<z-paging
|
||||
ref="paging"
|
||||
v-model="collectData"
|
||||
@query="queryList"
|
||||
:fixed="false"
|
||||
height="100%"
|
||||
use-page-scroll
|
||||
>
|
||||
<u-swipe-action
|
||||
:show="item.show"
|
||||
:index="index"
|
||||
v-for="(item, index) in collectData"
|
||||
:key="item.id"
|
||||
@click="handleCollect"
|
||||
:options="options"
|
||||
btn-width="120"
|
||||
>
|
||||
<news-card :item="item" :newsId="item.article_id"></news-card>
|
||||
</u-swipe-action>
|
||||
</z-paging>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, reactive, shallowRef } from 'vue'
|
||||
import { getCollect, cancelCollect } from '@/api/news'
|
||||
|
||||
const paging = shallowRef()
|
||||
const options = reactive([
|
||||
{
|
||||
text: '取消收藏',
|
||||
style: {
|
||||
color: '#FFFFFF',
|
||||
backgroundColor: '#FF2C3C'
|
||||
}
|
||||
}
|
||||
])
|
||||
const collectData: any = ref([])
|
||||
|
||||
const queryList = async (pageNo, pageSize) => {
|
||||
const { lists } = await getCollect()
|
||||
lists.forEach((item: any) => {
|
||||
item.show = false
|
||||
})
|
||||
collectData.value = lists
|
||||
paging.value.complete(lists)
|
||||
}
|
||||
|
||||
const handleCollect = async (index: number): Promise<void> => {
|
||||
try {
|
||||
const article_id: number = collectData.value[index].article_id
|
||||
await cancelCollect({ id: article_id })
|
||||
uni.$u.toast('已取消收藏')
|
||||
paging.value.reload()
|
||||
} catch (err) {
|
||||
//TODO handle the exception
|
||||
console.log('取消收藏报错=>', err)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped></style -->>
|
||||
66
src/pages/common/successful.vue
Normal file
66
src/pages/common/successful.vue
Normal file
@@ -0,0 +1,66 @@
|
||||
<template>
|
||||
<view class="absolute w-full h-full bg-[#4E55AF]">
|
||||
<!-- <u-navbar :background="background" title=""></u-navbar> -->
|
||||
<view class=" flex flex-col items-center mt-[180rpx]">
|
||||
<u-image width="500" height="300" mode="widthFix" src="/static/images/withdraw/withdraw_bg.png"></u-image>
|
||||
</view>
|
||||
<view class="my-[100rpx] text-center px-[50rpx]">
|
||||
<view class="type-primary font-bold mb-[50rpx]">
|
||||
{{text1}}
|
||||
</view>
|
||||
<view class="leading-loose">
|
||||
{{text2}}
|
||||
</view>
|
||||
</view>
|
||||
<view class="max-w-[750px] fixed bottom-[50rpx] w-4/5 ml-[10%]">
|
||||
<u-button type="primary" @click="submitHandle"> {{t('common.confirm')}} </u-button>
|
||||
</view>
|
||||
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { reactive, ref } from 'vue'
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
import { t } from '@/utils/util'
|
||||
|
||||
const text1 = ref('')
|
||||
const text2 = ref('')
|
||||
|
||||
|
||||
let type_arr = [{
|
||||
text1: t('orderDetail.rechargeSuccess'),
|
||||
text2: t('orderDetail.rechargeSuccessTips')
|
||||
}, {
|
||||
text1: t('orderDetail.withdrawSuccess'),
|
||||
text2: t('orderDetail.withdrawSuccessTips')
|
||||
}, {
|
||||
text1: t('orderDetail.vipOpenSuccess'),
|
||||
text2: ""
|
||||
}, {
|
||||
text1: t('orderDetail.bindSuccess'),
|
||||
text2: ""
|
||||
}]
|
||||
|
||||
|
||||
const submitHandle = () => {
|
||||
let canNavBack = getCurrentPages()
|
||||
if( canNavBack && canNavBack.length>1) {
|
||||
uni.navigateBack({
|
||||
delta: 2
|
||||
});
|
||||
} else {
|
||||
history.back();
|
||||
}
|
||||
}
|
||||
onLoad((options : any) => {
|
||||
text1.value = type_arr[options.type]['text1'];
|
||||
text2.value = type_arr[options.type]['text2'];
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.type-primary {
|
||||
color: $u-type-primary;
|
||||
}
|
||||
</style>
|
||||
7
src/pages/empty/empty.vue
Normal file
7
src/pages/empty/empty.vue
Normal file
@@ -0,0 +1,7 @@
|
||||
<template>
|
||||
<div></div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts"></script>
|
||||
|
||||
<style></style>
|
||||
60
src/pages/faq/index.vue
Normal file
60
src/pages/faq/index.vue
Normal file
@@ -0,0 +1,60 @@
|
||||
<template>
|
||||
<z-paging :refresher-enabled="false" :show-loading-more-when-reload="true" loading-more-default-text=""
|
||||
loading-more-loading-text="" loading-more-fail-text="" :empty-view-text="t('common.noData')"
|
||||
:show-loading-more-no-more-view="false" ref="paging" v-model="dataList" @query="queryList"
|
||||
class="max-w-[750px]">
|
||||
<h-dark :title="t('article.titleHelp')"></h-dark>
|
||||
<view class="mx-[30rpx] mt-[20rpx]">
|
||||
<view class="team-item p-[30rpx] mb-[20rpx] bg-[#2C326B] rounded-lg" v-for="(item, index) in dataList"
|
||||
:key="index">
|
||||
<navigator :url="'/pages/news_detail/news_detail?id='+item.id">
|
||||
<view class="news-card flex">
|
||||
<view class="news-card-content flex flex-col justify-between flex-1">
|
||||
<view class="news-card-content-title text-lg font-medium">{{ item.title }}</view>
|
||||
</view>
|
||||
<u-icon name="arrow-right" class="text-muted" size="28"></u-icon>
|
||||
</view>
|
||||
</navigator>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
</z-paging>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, shallowRef } from 'vue'
|
||||
import { getArticleList } from '@/api/news'
|
||||
import { t } from '@/utils/util'
|
||||
|
||||
uni.setNavigationBarTitle({ title: t('article.titleHelp') })
|
||||
const paging = shallowRef()
|
||||
const dataList = ref<any[]>([])
|
||||
|
||||
const queryList = async (pageNo : number, pageSize : number) => {
|
||||
try {
|
||||
const data = await getArticleList({
|
||||
page_no: pageNo,
|
||||
page_size: pageSize,
|
||||
cid: 3
|
||||
})
|
||||
paging.value.complete(data.lists)
|
||||
} catch (error) {
|
||||
paging.value.complete(false)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.news-card {
|
||||
&-content {
|
||||
&-title {
|
||||
-webkit-line-clamp: 1;
|
||||
overflow: hidden;
|
||||
word-break: break-all;
|
||||
text-overflow: ellipsis;
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
80
src/pages/feedback/index.vue
Normal file
80
src/pages/feedback/index.vue
Normal file
@@ -0,0 +1,80 @@
|
||||
<template>
|
||||
<h-dark :title="t('feedback.title')"></h-dark>
|
||||
<view class="mx-[30rpx]">
|
||||
<view class="py-[20rpx]">
|
||||
{{t('feedback.type')}}
|
||||
</view>
|
||||
<view class="bg-[#2C326B] rounded-lg p-[24rpx] mb-[20rpx]">
|
||||
<u-radio-group v-model="formData.cid" :wrap="true">
|
||||
<u-radio v-for="(item, index) in data.cates" :key="index" :name="item.id" @change="handelChange(item)">
|
||||
{{item.name}}
|
||||
</u-radio>
|
||||
</u-radio-group>
|
||||
</view>
|
||||
<view class="py-[20rpx]">
|
||||
{{t('feedback.opinion')}}
|
||||
</view>
|
||||
<view class="bg-[#2C326B] rounded-lg p-[24rpx]">
|
||||
<u-input v-model="formData.content" type="textarea" height="200" maxlength="256"
|
||||
:placeholder="t('feedback.opinionPlaceholder')" />
|
||||
</view>
|
||||
|
||||
</view>
|
||||
<view class="max-w-[750px] fixed bottom-[50rpx] w-4/5 ml-[10%]">
|
||||
<u-button type="primary" @click="handleSubmit"> {{t('common.submit')}} </u-button>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { reactive } from 'vue'
|
||||
import { feedback, getFeedbackCate } from '@/api/user'
|
||||
import { t } from '@/utils/util'
|
||||
|
||||
uni.setNavigationBarTitle({ title: t('feedback.title') })
|
||||
|
||||
const data = reactive<{
|
||||
cates : any[]
|
||||
}>({
|
||||
cates: [],
|
||||
})
|
||||
|
||||
const formData = reactive({
|
||||
cid: '',
|
||||
content: '',
|
||||
})
|
||||
|
||||
const getData = async () => {
|
||||
const res = await getFeedbackCate()
|
||||
data.cates = res.cates
|
||||
if (data.cates.length > 0) {
|
||||
formData.cid = data.cates[0]['id']
|
||||
}
|
||||
}
|
||||
const handelChange = async (item : any) => {
|
||||
formData.cid = item.id
|
||||
}
|
||||
|
||||
const handleSubmit = async () => {
|
||||
if (!formData.cid) return uni.$u.toast(t('feedback.typeEmpty'))
|
||||
if (!formData.content) return uni.$u.toast(t('feedback.opinionEmpty'))
|
||||
await feedback(formData)
|
||||
formData.content = ''
|
||||
uni.$u.toast(t('feedback.feedbackSuccess'))
|
||||
setTimeout(() => {
|
||||
handleBack()
|
||||
}, 1500)
|
||||
}
|
||||
|
||||
const handleBack = async () => {
|
||||
let canNavBack = getCurrentPages()
|
||||
if (canNavBack && canNavBack.length > 1) {
|
||||
uni.navigateBack()
|
||||
} else {
|
||||
history.back();
|
||||
}
|
||||
}
|
||||
getData()
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
</style>
|
||||
184
src/pages/forget_pwd/forget_pwd.vue
Normal file
184
src/pages/forget_pwd/forget_pwd.vue
Normal file
@@ -0,0 +1,184 @@
|
||||
<template>
|
||||
<u-navbar :title="t('pwd.fgLoginPwd')" :background="{backgroundColor: '#0066ff'}" back-icon-color="#FFFFFF"
|
||||
title-color="#FFFFFF">
|
||||
<view class="flex justify-end w-full pr-[20rpx]">
|
||||
<navigator hover-class="none" url="/pages/kefu/index">
|
||||
<u-icon size="40" name="/static/images/common/kefu.png"></u-icon>
|
||||
</navigator>
|
||||
</view>
|
||||
</u-navbar>
|
||||
<view class="flex flex-col items-center px-[40rpx] box-border">
|
||||
<view class="w-full">
|
||||
<u-form :border-bottom="false" :label-width="150" label-position="top">
|
||||
<u-form-item :itemStyle="{'background':'#f6f7fb'}" :label="t('pwd.mobile')" :border-bottom="false"
|
||||
:required="true">
|
||||
<country-code :list="country_code.list" :show="picker_show" @update="handleCountryCode">
|
||||
</country-code>
|
||||
<view class="mr-[20rpx]" @click="picker_show=true">
|
||||
<text class="mr-[10rpx]">{{formData.country_code}}
|
||||
</text>
|
||||
<u-icon name="arrow-down" size="20"></u-icon>
|
||||
</view>
|
||||
<u-input class="flex-1" v-model="formData.mobile" type="number" :border="false"
|
||||
:placeholder="t('pwd.mobilePlaceholder')" />
|
||||
</u-form-item>
|
||||
<view class="rounded-lg overflow-hidden mt-[20rpx] p-[7rpx] bg-[#F0F2F6]">
|
||||
<u-tabs :list="tabList" v-model="formData.type" @change="changeType" :is-scroll="false" height="60"
|
||||
:show-bar="false" bg-color="#F0F2F6"
|
||||
:active-item-style="{'background-color':'#FFFFFF','border-radius':'5px'}"></u-tabs>
|
||||
</view>
|
||||
<u-form-item :itemStyle="{'background':'#f6f7fb'}" :label="t('auth.email')" :border-bottom="false"
|
||||
:required="true" v-if="formData.type==1">
|
||||
<u-input class="flex-1" type="email" v-model="formData.email"
|
||||
:placeholder="t('auth.emailPlaceholder')" :border="false" />
|
||||
</u-form-item>
|
||||
<u-form-item :itemStyle="{'background':'#f6f7fb'}" :label="t('pwd.captcha')" :border-bottom="false"
|
||||
:required="true" v-if="formData.type==1">
|
||||
<u-input class="flex-1" v-model="formData.code" :placeholder="t('captcha.captchaPlaceholder')"
|
||||
:border="false" />
|
||||
<view class="border-l border-solid border-0 border-light pl-3 text-muted leading-4 ml-3 w-[180rpx]"
|
||||
@click="sendSms">
|
||||
<u-verification-code ref="uCodeRef" :seconds="60" @change="codeChange"
|
||||
:change-text="t('captcha.changeText')" :startText="t('captcha.startText')"
|
||||
:endText="t('captcha.endText')" />
|
||||
<text :class="formData.email ? 'text-primary' : 'text-muted'">
|
||||
{{ codeTips }}
|
||||
</text>
|
||||
</view>
|
||||
</u-form-item>
|
||||
<u-form-item :itemStyle="{'background':'#f6f7fb'}" :label="t('pwd.captcha')" :border-bottom="false" :required="true"
|
||||
v-if="formData.type==0">
|
||||
<u-input class="flex-1" v-model="formData.code" :placeholder="t('captcha.captchaPlaceholder')"
|
||||
:border="false" />
|
||||
</u-form-item>
|
||||
<u-form-item :itemStyle="{'background':'#f6f7fb'}" :label="t('pwd.newPwd')" :border-bottom="false"
|
||||
:required="true">
|
||||
<u-input class="flex-1" type="password" v-model="formData.password"
|
||||
:placeholder="t('pwd.newPwdPlaceholder')" :border="false" />
|
||||
</u-form-item>
|
||||
<u-form-item :itemStyle="{'background':'#f6f7fb'}" :label="t('pwd.confirmPwd')" :border-bottom="false"
|
||||
:required="true">
|
||||
<u-input class="flex-1" type="password" v-model="formData.password_confirm"
|
||||
:placeholder="t('pwd.confirmPwdPlaceholder')" :border="false" />
|
||||
</u-form-item>
|
||||
</u-form>
|
||||
<view class="mt-[100rpx] pb-[60rpx]">
|
||||
<u-button type="primary" v-if="formData.type==0"
|
||||
:disabled="formData.mobile==''||formData.code==''||formData.password==''||formData.password_confirm==''"
|
||||
@click="handleConfirm"> {{t('common.submit')}} </u-button>
|
||||
|
||||
<u-button type="primary" v-if="formData.type==1"
|
||||
:disabled="formData.mobile==''||formData.email==''||formData.code==''||formData.password==''||formData.password_confirm==''"
|
||||
@click="handleConfirm"> {{t('common.submit')}} </u-button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { sendEmailNoLogin, getCountryCode } from '@/api/app'
|
||||
import { useAppStore } from '@/stores/app'
|
||||
import { forgotPassword } from '@/api/user'
|
||||
import { SMSEnum } from '@/enums/appEnums'
|
||||
import { reactive, ref, shallowRef } from 'vue'
|
||||
import { t, isEmpty } from '@/utils/util'
|
||||
|
||||
uni.setNavigationBarTitle({ title: t('pwd.titleForgetPwd') })
|
||||
|
||||
const appStore = useAppStore()
|
||||
const uCodeRef = shallowRef()
|
||||
const codeTips = ref('')
|
||||
|
||||
const picker_show = ref(false)
|
||||
const country_code = reactive<{
|
||||
list : any[]
|
||||
default_select : number
|
||||
}>({
|
||||
list: [],
|
||||
default_select: 0
|
||||
})
|
||||
const tabList = ref([
|
||||
{
|
||||
name: t('pwd.authGoogle'),
|
||||
},
|
||||
{
|
||||
name: t('pwd.authEmail'),
|
||||
}
|
||||
])
|
||||
|
||||
const changeType = (index : number) => {
|
||||
formData.type = index
|
||||
}
|
||||
const formData = reactive({
|
||||
mobile: '',
|
||||
email: '',
|
||||
code: '',
|
||||
password: '',
|
||||
password_confirm: '',
|
||||
country_code: '',
|
||||
type: 0
|
||||
})
|
||||
|
||||
const getData = async () => {
|
||||
let data = appStore.getLoginConfig.region_code
|
||||
if (isEmpty(data)) data = await getCountryCode()
|
||||
country_code.list = data;
|
||||
formData.country_code = data[0]['code']
|
||||
}
|
||||
const handlePicker = (index : number) => {
|
||||
country_code.default_select = index;
|
||||
formData.country_code = country_code.list[index];
|
||||
}
|
||||
const handleCountryCode = (data : any) => {
|
||||
picker_show.value = data['show']
|
||||
if (data['code'] != '') {
|
||||
formData.country_code = data['code'];
|
||||
}
|
||||
}
|
||||
|
||||
const codeChange = (text : string) => {
|
||||
codeTips.value = text
|
||||
}
|
||||
|
||||
const sendSms = async () => {
|
||||
if (!formData.email) return
|
||||
var emailRegex = /^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,6}$/;
|
||||
if (!emailRegex.test(formData.email)) {
|
||||
return uni.$u.toast(t('auth.emailEmpty'))
|
||||
}
|
||||
|
||||
if (uCodeRef.value?.canGetCode) {
|
||||
await sendEmailNoLogin({
|
||||
country_code: formData.country_code,
|
||||
mobile: formData.mobile,
|
||||
email: formData.email,
|
||||
})
|
||||
uni.$u.toast(t('captcha.sendSuccessfully'))
|
||||
uCodeRef.value?.start()
|
||||
}
|
||||
}
|
||||
|
||||
const handleConfirm = async () => {
|
||||
if (!formData.mobile) return uni.$u.toast(t('pwd.mobileEmpty'))
|
||||
if (!formData.code) return uni.$u.toast(t('captcha.captchaEmpty'))
|
||||
if (!formData.password) return uni.$u.toast(t('pwd.newPwdEmpty'))
|
||||
if (!formData.password_confirm) return uni.$u.toast(t('pwd.confirmPwdEmpty'))
|
||||
if (formData.password != formData.password_confirm) return uni.$u.toast(t('pwd.twoPwdError'))
|
||||
await forgotPassword(formData)
|
||||
setTimeout(() => {
|
||||
uni.navigateBack()
|
||||
}, 1500)
|
||||
}
|
||||
getData()
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
page {
|
||||
background-color: #FFFFFF;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.register {
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
161
src/pages/fund/index.vue
Normal file
161
src/pages/fund/index.vue
Normal file
@@ -0,0 +1,161 @@
|
||||
<template>
|
||||
<view>
|
||||
<u-navbar :is-back="false" title="" :background="{backgroundColor: '#FFFFFF'}" title-color="#000000">
|
||||
<view class="slot-wrap w-full pl-[30rpx]">
|
||||
<view class="">
|
||||
{{t('funds.title')}}
|
||||
</view>
|
||||
</view>
|
||||
<view class="flex justify-end w-full pr-[30rpx] relative">
|
||||
<navigator hover-class="none" url="/packages/pages/user_wallet/record">
|
||||
<u-icon size="42" name="/static/images/common/record_b.png"></u-icon>
|
||||
</navigator>
|
||||
</view>
|
||||
</u-navbar>
|
||||
<view class="px-[30rpx] pt-[30rpx] mb-[30rpx]">
|
||||
<navigator hover-class="none" url="/pages/news_detail/detail?id=11">
|
||||
<view class="flex justify-between items-center mb-[30rpx] py-[20rpx] px-[30rpx] rounded-lg bg-white">
|
||||
<view class="flex justify-start items-center">
|
||||
<view class="mr-[20rpx]">
|
||||
<u-icon size="40" name="/static/images/fund/fund_desc.png"></u-icon>
|
||||
</view>
|
||||
<view class="">
|
||||
{{t('funds.introduction')}}
|
||||
</view>
|
||||
</view>
|
||||
<view class="">
|
||||
<u-icon size="26" name="arrow-right"></u-icon>
|
||||
</view>
|
||||
</view>
|
||||
</navigator>
|
||||
<view class="bg-white rounded-lg py-[50rpx] px-[50rpx]">
|
||||
<view class="flex justify-around items-center mb-[30rpx]">
|
||||
<view class="text-center w-1/2">
|
||||
<view class="text-muted mb-[10rpx]">
|
||||
{{t('funds.totalAssets')}}
|
||||
</view>
|
||||
<view class="font-bold text-[#0066FF]">
|
||||
{{getCurrency()}}{{formatMoney(state.report.user_money)}}
|
||||
</view>
|
||||
</view>
|
||||
<view class="text-center w-1/2">
|
||||
<view class="text-muted mb-[10rpx]">
|
||||
{{t('funds.userPoint')}}
|
||||
</view>
|
||||
<view class="font-bold">
|
||||
{{state.report.user_point}}
|
||||
</view>
|
||||
</view>
|
||||
<!-- <view class="text-center w-1/3">
|
||||
<view class="text-muted mb-[10rpx]">
|
||||
{{t('funds.usedNoMoney')}}
|
||||
</view>
|
||||
<view class="font-bold">
|
||||
{{getCurrency()}}{{formatMoney(state.report.noused_money)}}
|
||||
</view>
|
||||
</view> -->
|
||||
|
||||
</view>
|
||||
<view class="flex justify-between py-[20rpx]">
|
||||
<view @click="handleJump('/packages/pages/recharge/index')"
|
||||
class="text-center w-[48%] flex items-center justify-center rounded-lg py-[20rpx]"
|
||||
style="border: 1px solid #0066ff;">
|
||||
<u-icon class="mr-[20rpx]" size="44" name="/static/images/fund/recharge.png"></u-icon>
|
||||
{{t('funds.recharge')}}
|
||||
</view>
|
||||
<view @click="handleJump('/packages/pages/withdraw/index')"
|
||||
class="text-center w-[48%] flex items-center justify-center rounded-lg py-[20rpx] text-white"
|
||||
style="background: linear-gradient(114.5deg, #00A3FF 16.6%, #0066FF 85.41%);">
|
||||
<u-icon class="mr-[20rpx]" size="44" name="/static/images/fund/withdraw.png"></u-icon>
|
||||
{{t('funds.withdraw')}}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="mx-[30rpx] mb-[30rpx] font-bold flex justify-between">
|
||||
<view class=" ">
|
||||
{{t('funds.assetDetails')}}
|
||||
</view>
|
||||
<view class="text-[#0066FF]" @click="handleJump('/packages/pages/user_wallet/record')">
|
||||
{{t('funds.viewAll')}}
|
||||
</view>
|
||||
</view>
|
||||
<view class="mx-[30rpx] ">
|
||||
<view class="mt-[100rpx]" v-if="state.fund_list.length == 0">
|
||||
<u-empty :text="t('common.noData')" mode="data"></u-empty>
|
||||
</view>
|
||||
<navigator v-for="item in state.fund_list" :key="item.id" hover-class="none"
|
||||
:url="'/packages/pages/user_wallet/order_detail?id='+item.id">
|
||||
<view class="bg-white mb-[8px] px-[40rpx] py-[40rpx] rounded-lg">
|
||||
<view
|
||||
class="flex justify-between mb-[30rpx] pb-[20rpx] border-solid border-b border-0 border-light ">
|
||||
<view class=" text-muted mr-1">{{item.create_time}}</view>
|
||||
<view class="text-success" v-if="item.action==1">
|
||||
{{t('tabs.in')}}
|
||||
</view>
|
||||
<view class="text-error" v-if="item.action==2">
|
||||
{{t('tabs.out')}}
|
||||
</view>
|
||||
</view>
|
||||
<view class="flex justify-between">
|
||||
<view class="w-[70%]">
|
||||
<view class="">
|
||||
{{t("finance.type" + item.type)}}
|
||||
</view>
|
||||
<view class="text-error mt-[12rpx]" v-if="item.remark">
|
||||
{{item.remark}}
|
||||
</view>
|
||||
</view>
|
||||
<view class="text-right w-[30%]">
|
||||
<text class="font-bold" :class="item.action==1?'text-success':'text-error'">
|
||||
{{getCurrency() }}{{formatMoney(item.amount)}}
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</navigator>
|
||||
</view>
|
||||
|
||||
</view>
|
||||
<tabbar />
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { onShow } from '@dcloudio/uni-app'
|
||||
import { useAppStore } from '@/stores/app'
|
||||
import { reactive } from 'vue'
|
||||
import { fundIndex } from '@/api/finance'
|
||||
import { t, formatDate, getCurrency, formatMoney } from '@/utils/util'
|
||||
uni.setNavigationBarTitle({ title: t('funds.title') })
|
||||
const appStore = useAppStore()
|
||||
|
||||
const state = reactive<{
|
||||
fund_list : any[]
|
||||
report : any[]
|
||||
}>({
|
||||
fund_list: [],
|
||||
report: {
|
||||
user_money:0,
|
||||
user_point: 0
|
||||
}
|
||||
})
|
||||
|
||||
const handleJump = async (val : string) => {
|
||||
uni.navigateTo({
|
||||
url: val
|
||||
})
|
||||
}
|
||||
|
||||
const getData = async () => {
|
||||
const data = await fundIndex({ date: formatDate(Math.round(Date.now() / 1000)) })
|
||||
state.fund_list = data.fund_list
|
||||
state.report = data.report
|
||||
}
|
||||
|
||||
onShow(() => {
|
||||
getData()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
</style>
|
||||
169
src/pages/index/index.vue
Normal file
169
src/pages/index/index.vue
Normal file
@@ -0,0 +1,169 @@
|
||||
<template>
|
||||
<view class="">
|
||||
<u-navbar :is-back="false" :background="{backgroundColor: '#4E55AF'}" height="50">
|
||||
<view class="flex justify-between items-center w-full">
|
||||
<view class="flex justify-start items-center">
|
||||
<view class="rounded-lg ml-[30rpx] bg-white p-[10rpx] mr-[12rpx]">
|
||||
<u-image width="40rpx" height="40rpx" :src="appStore.getWebsiteConfig.shop_logo"></u-image>
|
||||
</view>
|
||||
<view class="">
|
||||
{{appStore.getWebsiteConfig.shop_name}}
|
||||
</view>
|
||||
</view>
|
||||
<view class="flex justify-end pr-[30rpx]">
|
||||
<navigator hover-class="none" url="/pages/language/index">
|
||||
<u-icon size="50" name="/static/images/common/change_lang_w.png"></u-icon>
|
||||
</navigator>
|
||||
</view>
|
||||
</view>
|
||||
</u-navbar>
|
||||
<view class="bg-[#4E55AF] pb-[200rpx] pt-[30rpx]">
|
||||
<view class="pb-[20rpx] mb-[50rpx] mx-[30rpx] bg-[#5C62B5] rounded-lg" v-if="state.notice.is_show">
|
||||
<navigator hover-class="none" :url="'/pages/news_detail/news_detail?id='+state.notice.id">
|
||||
<u-notice-bar class="h-[60rpx]" mode="horizontal" bg-color="unset" color="#FFFFFF"
|
||||
:list="state.notice.text" />
|
||||
</navigator>
|
||||
</view>
|
||||
</view>
|
||||
<view class="mb-[20rpx] bg-[#2C326B] mx-[30rpx] rounded-lg mt-[-200rpx]" v-if="state.banner.length>0">
|
||||
<w-banner :banner="state.banner" />
|
||||
</view>
|
||||
|
||||
<view class="mb-[20rpx]" v-if="state.navs.length>0">
|
||||
<view class="px-[30rpx]">
|
||||
<w-nav :navs="state.navs" />
|
||||
</view>
|
||||
</view>
|
||||
<view class="px-[30rpx] mb-[20rpx] inline-block" v-if="show_market">
|
||||
<w-market :market="state.market" />
|
||||
</view>
|
||||
<view class="mb-[20rpx] rounded-xl overflow-hidden" v-if="state.video.is_show">
|
||||
<view class="mx-[30rpx]">
|
||||
<video class="w-full rounded-xl" :src="state.video.url" controls :poster="state.video.image"></video>
|
||||
</view>
|
||||
</view>
|
||||
<view class="px-[30rpx] mb-[20rpx] inline-block " v-if="state.partner.is_show">
|
||||
<view class="mb-[20rpx]">
|
||||
{{t('index.partner')}}
|
||||
</view>
|
||||
<view class="" v-html="state.partner.content"></view>
|
||||
</view>
|
||||
<u-popup class="max-w-[750px]" v-model="state.popup.is_show" mode="center" border-radius="30" width="90%"
|
||||
height="880rpx" :closeable="true" close-icon-color="#ECECEC" close-icon-size="36" @close="modalHandle">
|
||||
<view class="">
|
||||
<view class="notice text-center">
|
||||
<view class="flex justify-center items-center py-[15px]">
|
||||
<view class="bg-[#2C326B] rounded-full p-[15rpx]">
|
||||
<u-image width="80rpx" height="80rpx" :src="appStore.getWebsiteConfig.shop_logo"></u-image>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<scroll-view scroll-y="true" style="height: 650rpx;">
|
||||
<view class="leading-loose pb-[24rpx] px-[24rpx]" v-html="state.popup.content">
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</u-popup>
|
||||
<!-- 客服 -->
|
||||
<view class="fixed right-[30rpx] bottom-[150rpx]" v-if="state.show_kefu" @click="jumpTo(state.kefu_link)">
|
||||
<u-icon size="100" :name="state.kefu_logo"></u-icon>
|
||||
</view>
|
||||
</view>
|
||||
<tabbar />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { onLoad, onUnload, onHide, onShow } from '@dcloudio/uni-app'
|
||||
import { getIndex, getMarket } from '@/api/shop'
|
||||
import { reactive, ref } from 'vue'
|
||||
import { useAppStore } from '@/stores/app'
|
||||
import { t, jumpTo } from '@/utils/util'
|
||||
uni.setNavigationBarTitle({ title: t('index.title') })
|
||||
const appStore = useAppStore()
|
||||
|
||||
let timer : any = null
|
||||
const show_market = ref(false)
|
||||
const state = reactive<{
|
||||
banner : any[]
|
||||
notice : any
|
||||
navs : any[]
|
||||
partner : any[]
|
||||
video : any[]
|
||||
popup : any
|
||||
market : any[]
|
||||
kefu_logo : string
|
||||
show_kefu : number
|
||||
kefu_link : string
|
||||
}>({
|
||||
banner: [],
|
||||
notice: {
|
||||
text: '',
|
||||
is_show: false
|
||||
},
|
||||
navs: [],
|
||||
partner: [],
|
||||
video: [],
|
||||
popup: {
|
||||
content: '',
|
||||
is_show: false
|
||||
},
|
||||
market: [],
|
||||
kefu_logo: '',
|
||||
show_kefu: 0,
|
||||
kefu_link: '',
|
||||
})
|
||||
|
||||
const modalHandle = async () => {
|
||||
state.popup.is_show = false;
|
||||
}
|
||||
const getData = async () => {
|
||||
const data = await getIndex()
|
||||
state.banner = data.banner
|
||||
state.navs = data.navs
|
||||
state.notice = data.notice
|
||||
state.notice.text = [data.notice.text]
|
||||
state.partner = data.partner
|
||||
state.video = data.video
|
||||
state.popup = data.popup
|
||||
state.market = data.market
|
||||
if (state.market.length > 0) show_market.value = true;
|
||||
|
||||
state.kefu_logo = data.kefu_logo;
|
||||
state.show_kefu = data.show_kefu;
|
||||
state.kefu_link = data.kefu_link;
|
||||
}
|
||||
|
||||
const getTimer = async () => {
|
||||
timer = setInterval(() => {
|
||||
getMarketData();
|
||||
}, 3000)
|
||||
}
|
||||
|
||||
const getMarketData = async () => {
|
||||
const res = await getMarket()
|
||||
state.market = res;
|
||||
if (state.market.length > 0) show_market.value = true;
|
||||
}
|
||||
onUnload(() => {
|
||||
timer && clearInterval(timer)
|
||||
})
|
||||
onLoad(() => {
|
||||
getData();
|
||||
})
|
||||
onShow(() => {
|
||||
getTimer();
|
||||
})
|
||||
onHide(() => {
|
||||
timer && clearInterval(timer)
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.nva-bg {
|
||||
background-image: url('/static/images/index/noticebarbg.png');
|
||||
background-size: 100% auto;
|
||||
background-repeat: no-repeat;
|
||||
background-position: bottom;
|
||||
height: 80px;
|
||||
}
|
||||
</style>
|
||||
58
src/pages/item/contract.vue
Normal file
58
src/pages/item/contract.vue
Normal file
@@ -0,0 +1,58 @@
|
||||
<template>
|
||||
<view class="">
|
||||
<h-dark :title="t('item.titleContract')"></h-dark>
|
||||
<view class="my-[30rpx] mx-[30rpx]">
|
||||
<view class="content leading-loose" v-html="data.content"></view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { reactive } from 'vue'
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
import { getContract } from '@/api/item'
|
||||
import { t, replaceStr } from '@/utils/util'
|
||||
|
||||
uni.setNavigationBarTitle({ title: t('item.titleContract') })
|
||||
const data = reactive({
|
||||
content: ''
|
||||
})
|
||||
const getData = async (id : number) => {
|
||||
const res = await getContract({ id: id })
|
||||
data.content = res.content;
|
||||
|
||||
let cycle = res.cycle + ' ' + t('item.hour');
|
||||
if (res.type == 1 || res.type == 2) {
|
||||
cycle = res.cycle + ' ' + t('item.days');
|
||||
}
|
||||
|
||||
let y_img = '<img src="' + res.contract_y_logo + '" style="width:120px;position: absolute;left: 30px;margin-top: -30px;">'
|
||||
let b_img = '<img src="' + res.contract_b_logo + '" style="width:120px;position: absolute;left: 30px;margin-top: -30px;">'
|
||||
|
||||
data.content = replaceStr(data.content, '{type}', t("item.type" + res.type))
|
||||
data.content = replaceStr(data.content, '{cycle}', cycle)
|
||||
|
||||
data.content = replaceStr(data.content, '{y_img}', y_img)
|
||||
data.content = replaceStr(data.content, '{b_img}', b_img)
|
||||
}
|
||||
onLoad((options : any) => {
|
||||
getData(options.id)
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
page {
|
||||
background-color: #4E55AF;
|
||||
}
|
||||
|
||||
.content {
|
||||
::v-deep table {
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
::v-deep td {
|
||||
padding: 0 5px;
|
||||
border: 1px solid #EAEAEA;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
240
src/pages/item/detail.vue
Normal file
240
src/pages/item/detail.vue
Normal file
@@ -0,0 +1,240 @@
|
||||
<template>
|
||||
<u-navbar :background="{backgroundColor: '#4E55AF'}" back-icon-color="#FFFFFF" height="50">
|
||||
<view class="flex justify-end items-center w-full">
|
||||
<view class="flex justify-end pr-[30rpx] ">
|
||||
<navigator hover-class="none" url="/pages/item/record">
|
||||
<u-icon size="40" name="/static/images/common/record.png"></u-icon>
|
||||
</navigator>
|
||||
</view>
|
||||
</view>
|
||||
</u-navbar>
|
||||
<view class="bg-[#4E55AF] pt-[10rpx] px-[30rpx] mb-[30rpx] pb-[50rpx]">
|
||||
<view class="mb-[30rpx]">
|
||||
<text class="font-bold text-xl">{{data.item.title}}</text>
|
||||
</view>
|
||||
<view class="">
|
||||
{{t("item.type" + data.item.type)}}
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="mt-[20rpx] pb-[30rpx]">
|
||||
<view class="bg-[#2C326B] mx-[30rpx] mb-[20rpx] rounded-lg">
|
||||
<view class=" rounded-lg p-[30rpx]">
|
||||
<view class="flex justify-between mb-[20rpx]">
|
||||
<view class="text-[#00D2E0]">
|
||||
{{t('item.moneyRange')}}
|
||||
</view>
|
||||
<view class="">
|
||||
{{getCurrency() }}{{formatMoney(data.item.min_money)}} -
|
||||
{{getCurrency() }}{{formatMoney(data.item.max_money)}} {{getCurrency2()}}
|
||||
</view>
|
||||
</view>
|
||||
<view class="flex justify-between mb-[20rpx]">
|
||||
<view class="text-[#00D2E0]">
|
||||
{{t('item.cycle')}}
|
||||
</view>
|
||||
<view class="">
|
||||
<text class="mr-[5rpx]">{{ data.item.cycle }}</text>
|
||||
<text v-if="data.item.type==1 || data.item.type==2">{{t('item.days')}}</text>
|
||||
<text v-if="data.item.type==3 || data.item.type==4">{{t('item.hour')}}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="flex justify-between mb-[20rpx]">
|
||||
<view class="text-[#00D2E0]">
|
||||
<text v-if="data.item.type==1">{{t('item.dailyRate')}}</text>
|
||||
<text v-if="data.item.type==4">{{t('item.hourRate')}}</text>
|
||||
<text v-if="data.item.type==2 || data.item.type==3">{{t('item.totalRate')}}</text>
|
||||
</view>
|
||||
<view class="">
|
||||
{{data.item.rate}}%
|
||||
</view>
|
||||
</view>
|
||||
<view class="flex justify-between mb-[20rpx]" v-if="data.user.member.item_add_rate > 0">
|
||||
<view class="text-[#00D2E0]">
|
||||
{{t('item.vipAddRate')}}
|
||||
</view>
|
||||
<view class="">
|
||||
{{data.user.member.item_add_rate}}%
|
||||
</view>
|
||||
</view>
|
||||
<view class="flex justify-between mb-[20rpx]" v-if="data.item.point > 0">
|
||||
<view class="text-[#00D2E0]">
|
||||
{{t('item.point')}}
|
||||
</view>
|
||||
<view class="w-3/5 text-right ">
|
||||
{{data.item.point}}
|
||||
</view>
|
||||
</view>
|
||||
<view class="flex justify-between mb-[40rpx]">
|
||||
<view class="text-[#00D2E0]">
|
||||
{{t('item.limitVip')}}
|
||||
</view>
|
||||
<view class="">
|
||||
{{data.item.vip_name}}
|
||||
</view>
|
||||
</view>
|
||||
<view class="flex justify-between">
|
||||
<u-line-progress :striped="true" :percent="data.item.progress" :striped-active="true"
|
||||
active-color="#4E55AF"></u-line-progress>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="bg-[#2C326B] mx-[30rpx] mb-[20rpx] rounded-lg p-[30rpx]">
|
||||
<view class="flex justify-between mb-[40rpx]">
|
||||
<view class="text-[#00D2E0]">
|
||||
{{t('item.myFunds')}}
|
||||
</view>
|
||||
<view class="">
|
||||
{{getCurrency() }}{{formatMoney(data.user.balance)}} {{getCurrency2()}}
|
||||
</view>
|
||||
</view>
|
||||
<view class="">
|
||||
<view class="bg-[#3d4277] rounded-lg px-[20rpx] py-[10rpx] mb-[30rpx]">
|
||||
<u-input v-model="formData.money" type="number" @input="checkMoney"
|
||||
:placeholder="t('item.moneyPlaceholder')" :border="false" />
|
||||
</view>
|
||||
<view class="text-right mb-[30rpx]" v-if="data.income > 0">
|
||||
<text
|
||||
class="mr-[10rpx]">{{t('item.expIncome')}}:</text>{{getCurrency() }}{{formatMoney(data.income)}} {{getCurrency2()}}
|
||||
</view>
|
||||
<u-button type="primary" :disabled="formData.money==''" @click="handleInvest()">
|
||||
{{t('item.investBtn')}}
|
||||
</u-button>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="bg-[#2C326B] mx-[30rpx] mb-[20rpx] rounded-lg">
|
||||
<view class="leading-loose rounded-lg p-[30rpx]">
|
||||
<view class="" v-html="data.item.content"></view>
|
||||
</view>
|
||||
</view>
|
||||
<u-keyboard class="max-w-[750px]" ref="uKeyboard1" mode="number" :dot-enabled="false" :tips="t('pwd.payPwd')"
|
||||
confirm-text="" cancel-text="" v-model="show_keyboard" @change="keyboardChange" @backspace="backspace"
|
||||
:show-input-val="true" :input-value="formData.pay_pwd"></u-keyboard>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { reactive, ref, nextTick } from 'vue'
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
import { getDetail, invest } from '@/api/item'
|
||||
import { t, formatMoney, getCurrency, getCurrency2,replaceStr } from '@/utils/util'
|
||||
|
||||
uni.setNavigationBarTitle({ title: t('item.titleDetail') })
|
||||
const show_keyboard = ref(false)
|
||||
const data = reactive({
|
||||
item: {
|
||||
min_money: 0,
|
||||
max_money: 0,
|
||||
member_id: 0,
|
||||
progress: 0,
|
||||
point: 0
|
||||
},
|
||||
user: {
|
||||
today_order: 0,
|
||||
balance: 0,
|
||||
member: {
|
||||
id: 0,
|
||||
item_num: 0,
|
||||
item_add_rate: 0
|
||||
}
|
||||
},
|
||||
income: 0
|
||||
})
|
||||
|
||||
const formData = reactive({
|
||||
id: 0,
|
||||
money: '',
|
||||
pay_pwd: '',
|
||||
invest: 1//验证器标识
|
||||
})
|
||||
|
||||
const handleInvest = async () => {
|
||||
if (!formData.money) {
|
||||
return uni.$u.toast(t('item.moneyEmpty'))
|
||||
}
|
||||
if (parseFloat(formData.money) < data.item.min_money || parseFloat(formData.money) > data.item.max_money) {
|
||||
return uni.$u.toast(t('item.moneyError'))
|
||||
}
|
||||
if (parseFloat(formData.money) - data.user.balance > 0) {
|
||||
return uni.$u.toast(t('common.InsufficientBalance'))
|
||||
}
|
||||
if (data.item.member_id - data.user.member.id > 0) {
|
||||
return uni.$u.toast(replaceStr(t('item.limitVIpTips'), '{vip_name}', data.item.vip_name))
|
||||
}
|
||||
if (data.item.progress >= 100) {
|
||||
return uni.$u.toast(t('item.progressFull'))
|
||||
}
|
||||
if (data.user.today_order - data.user.member.item_num >= 0) {
|
||||
return uni.$u.toast(t('item.itemNumInsufficient'))
|
||||
}
|
||||
formData.pay_pwd = '';
|
||||
show_keyboard.value = true;
|
||||
}
|
||||
|
||||
const submit = async () => {
|
||||
await invest(formData)
|
||||
uni.redirectTo({
|
||||
url: '/pages/item/record'
|
||||
})
|
||||
}
|
||||
|
||||
const keyboardChange = (val : string) => {
|
||||
formData.pay_pwd += val;
|
||||
if (formData.pay_pwd.length == 6) {
|
||||
show_keyboard.value = false;
|
||||
submit();
|
||||
}
|
||||
}
|
||||
const backspace = () => {
|
||||
// 删除value的最后一个字符
|
||||
if (formData.pay_pwd.length) formData.pay_pwd = (formData.pay_pwd).substr(0, (formData.pay_pwd.length) - 1);
|
||||
}
|
||||
|
||||
const getData = async (id : number) => {
|
||||
formData.id = id;
|
||||
const res = await getDetail({ id: id })
|
||||
if (res.need_set_pwd == 1) {
|
||||
uni.$u.toast(t('pwd.pwdSetFirstTips'))
|
||||
uni.redirectTo({
|
||||
url: '/pages/change_password/set_password_pay'
|
||||
})
|
||||
return
|
||||
}
|
||||
data.item = res.item;
|
||||
data.user = res.user;
|
||||
}
|
||||
|
||||
const checkMoney = (money : string) => {
|
||||
var precision = uni.getStorageSync('precision')
|
||||
// 使用正则表达式匹配小数
|
||||
var decimalMatch = money.match(/\.(\d+)/);
|
||||
if (decimalMatch) {
|
||||
if (decimalMatch[1].length >= precision) {
|
||||
nextTick(() => {
|
||||
formData.money = parseFloat(money).toFixed(precision);
|
||||
})
|
||||
}
|
||||
}
|
||||
money = parseFloat(money).toFixed(precision);
|
||||
var rate = parseFloat(data.item.rate);
|
||||
|
||||
if (data.user.member.item_add_rate > 0) rate += parseFloat(data.user.member.item_add_rate);
|
||||
|
||||
if (data.item.type == 1 || data.item.type == 4) {
|
||||
data.income = parseFloat(money) * rate * data.item.cycle / 100;
|
||||
} else {
|
||||
data.income = parseFloat(money) * rate / 100;
|
||||
}
|
||||
|
||||
|
||||
data.income = parseFloat((data.income).toFixed(precision));
|
||||
}
|
||||
|
||||
onLoad((options : any) => {
|
||||
getData(options.id)
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
</style>
|
||||
135
src/pages/item/index.vue
Normal file
135
src/pages/item/index.vue
Normal file
@@ -0,0 +1,135 @@
|
||||
<template>
|
||||
<view>
|
||||
<u-navbar :is-back="false" :background="{backgroundColor: '#4E55AF'}" height="50">
|
||||
<view class="flex justify-between items-center w-full">
|
||||
<view class="flex justify-start items-center">
|
||||
<view class="rounded-lg ml-[30rpx] bg-white p-[10rpx] mr-[12rpx]">
|
||||
<u-image width="40rpx" height="40rpx" :src="appStore.getWebsiteConfig.shop_logo"></u-image>
|
||||
</view>
|
||||
<view class="">
|
||||
{{t('item.titleIndex')}}
|
||||
</view>
|
||||
</view>
|
||||
<view class="flex justify-end pr-[30rpx] ">
|
||||
<navigator hover-class="none" url="/pages/item/record">
|
||||
<u-icon size="40" name="/static/images/common/record.png"></u-icon>
|
||||
</navigator>
|
||||
</view>
|
||||
</view>
|
||||
</u-navbar>
|
||||
<view class="bg-[#4E55AF] pt-[30rpx] mb-[30rpx] pb-[150rpx]">
|
||||
<view class="vipbg mx-[30rpx] relative items-center flex">
|
||||
<view class="text-white text-left mx-[30rpx]">{{t('robot.currentLevel')}}: {{data.user.member.name}}
|
||||
</view>
|
||||
<view class="absolute right-[30rpx] top-[-30rpx]">
|
||||
<u-image width="200rpx" mode="widthFix" :src="data.user.member.logo"></u-image>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="mb-[30rpx] mt-[-150rpx]">
|
||||
<view class="bg-[#2C326B] mx-[30rpx] px-[30rpx] py-[40rpx] rounded-lg">
|
||||
<view class="flex justify-between items-center">
|
||||
<view class="w-1/2 text-center">
|
||||
<view class="text-2xl text-[#A1DBF5] mb-[10rpx]">
|
||||
{{formatMoney(data.user.totalMoney)}}
|
||||
</view>
|
||||
<view class="">
|
||||
{{t('item.myItems')}}
|
||||
</view>
|
||||
</view>
|
||||
<view class="">
|
||||
|
|
||||
</view>
|
||||
<view class="w-1/2 text-center">
|
||||
<view class="text-2xl text-[#A1DBF5] mb-[10rpx]">
|
||||
{{formatMoney(data.user.totalIncome)}}
|
||||
</view>
|
||||
<view class="">
|
||||
{{t('item.totalIncome')}}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="mx-[30rpx]">
|
||||
<view class="flex mb-[30rpx]">
|
||||
<u-icon size="38" name="clock-fill"></u-icon>
|
||||
<text class="ml-[6rpx]">{{date}}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="mx-[30rpx] mb-[20rpx]">
|
||||
<view class="">
|
||||
<w-item :items="data.items" />
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<tabbar />
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { reactive, ref } from 'vue'
|
||||
import { useAppStore } from '@/stores/app'
|
||||
import { onUnload, onHide, onShow } from '@dcloudio/uni-app'
|
||||
import { formatDate, formatMoney, t } from '@/utils/util'
|
||||
import { getIndex } from '@/api/item'
|
||||
|
||||
uni.setNavigationBarTitle({ title: t('item.titleIndex') })
|
||||
const appStore = useAppStore()
|
||||
|
||||
let timer : any = null
|
||||
|
||||
const date = ref('')
|
||||
const data = reactive({
|
||||
user: {
|
||||
totalMoney: 0,
|
||||
todayIncome: 0,
|
||||
totalIncome: 0,
|
||||
balance: 0,
|
||||
member: []
|
||||
},
|
||||
items: [],
|
||||
date: ''
|
||||
})
|
||||
|
||||
const getTimer = async () => {
|
||||
timer && clearInterval(timer)
|
||||
|
||||
timer = setInterval(() => {
|
||||
let serverDateTime = new Date(data.date)
|
||||
serverDateTime.setSeconds(serverDateTime.getSeconds() + 1)
|
||||
date.value = formatDate(new Date(serverDateTime).getTime() / 1000, uni.getStorageSync('formatTime'));
|
||||
data.date = date.value;
|
||||
}, 1000)
|
||||
}
|
||||
|
||||
const getData = async () => {
|
||||
const res = await getIndex()
|
||||
data.date = res.server_date
|
||||
getTimer();
|
||||
|
||||
data.user = res.user;
|
||||
data.items = res.items;
|
||||
}
|
||||
|
||||
onUnload(() => {
|
||||
timer && clearInterval(timer)
|
||||
})
|
||||
onShow(() => {
|
||||
getData()
|
||||
})
|
||||
onHide(() => {
|
||||
timer && clearInterval(timer)
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.vipbg {
|
||||
background-image: url('/static/images/quantify/vipbg.png');
|
||||
background-size: 100% auto;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
height: 68px;
|
||||
}
|
||||
</style>
|
||||
155
src/pages/item/record.vue
Normal file
155
src/pages/item/record.vue
Normal file
@@ -0,0 +1,155 @@
|
||||
<template>
|
||||
<z-paging :refresher-enabled="false" :show-loading-more-when-reload="true" loading-more-default-text=""
|
||||
loading-more-loading-text="" loading-more-fail-text="" :empty-view-text="t('common.noData')"
|
||||
:show-loading-more-no-more-view="false" ref="paging" v-model="dataList" @query="queryList"
|
||||
class="max-w-[750px]">
|
||||
<h-dark :title="t('item.titleRecord')"></h-dark>
|
||||
<view class="bg-[#2C326B] rounded-lg p-[30rpx] mt-[20rpx] mx-[30rpx]" v-for="item in dataList" :key="item.id">
|
||||
<view class="">
|
||||
<view class="font-bold mb-[30rpx]">
|
||||
{{item.item_title}}
|
||||
</view>
|
||||
<view class="flex justify-between mb-[20rpx]">
|
||||
<view class="text-[#00D2E0]">
|
||||
{{t('item.money')}}
|
||||
</view>
|
||||
<view class="">
|
||||
{{item.money}}
|
||||
</view>
|
||||
</view>
|
||||
<view class="flex justify-between mb-[20rpx]">
|
||||
<view class="text-[#00D2E0]">
|
||||
{{t('item.cycle')}}
|
||||
</view>
|
||||
<view class="">
|
||||
<text class="">{{ item.cycle }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="flex justify-between mb-[20rpx]">
|
||||
<view class="text-[#00D2E0]">
|
||||
{{item.rateName}}
|
||||
</view>
|
||||
<view class="">
|
||||
{{item.rate}}%
|
||||
</view>
|
||||
</view>
|
||||
<view class="flex justify-between mb-[20rpx]">
|
||||
<view class="text-[#00D2E0]">
|
||||
{{t('item.toIncome')}}
|
||||
</view>
|
||||
<view class="">
|
||||
{{item.total_income}}
|
||||
</view>
|
||||
</view>
|
||||
<view class="flex justify-between mb-[20rpx]" v-if="item.point > 0">
|
||||
<view class="text-[#00D2E0]">
|
||||
{{t('item.point')}}
|
||||
</view>
|
||||
<view class="">
|
||||
{{item.point}}
|
||||
</view>
|
||||
</view>
|
||||
<view class="flex justify-between mb-[20rpx]">
|
||||
<view class="text-[#00D2E0]">
|
||||
{{t('item.status')}}
|
||||
</view>
|
||||
<view class="">
|
||||
<view v-if="item.status==2" class="text-success">
|
||||
{{tips.finish}}
|
||||
</view>
|
||||
<view v-if="item.status==1" class="">
|
||||
{{tips.pending}}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="flex justify-between mb-[20rpx]">
|
||||
<view class="text-[#00D2E0]">
|
||||
{{t('item.contractNo')}}
|
||||
</view>
|
||||
<view class="text-[#6EA2FF] font-bold underline">
|
||||
<navigator hover-class="none" :url="'/pages/item/contract?id='+item.id">
|
||||
{{item.contract_no}}
|
||||
</navigator>
|
||||
</view>
|
||||
</view>
|
||||
<view class="flex justify-between mb-[20rpx]">
|
||||
<view class="text-[#00D2E0]">
|
||||
{{t('item.timeInvest')}}
|
||||
</view>
|
||||
<view class="">
|
||||
{{item.create_time}}
|
||||
</view>
|
||||
</view>
|
||||
<view class="flex justify-between mb-[20rpx]">
|
||||
<view class="text-[#00D2E0]">
|
||||
{{t('item.timeExp')}}
|
||||
</view>
|
||||
<view class="">
|
||||
{{item.end_time}}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</z-paging>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, reactive, shallowRef } from 'vue'
|
||||
import { recordLists } from '@/api/item'
|
||||
import { getCurrency, getCurrency2,formatMoney } from '@/utils/util'
|
||||
import { t } from '@/utils/util'
|
||||
|
||||
uni.setNavigationBarTitle({ title: t('item.titleRecord') })
|
||||
|
||||
//为了提高渲染速度
|
||||
const tips = reactive({
|
||||
pending: t('tabs.pending'),
|
||||
finish: t('tabs.finish'),
|
||||
hour: t('item.hour'),
|
||||
days: t('item.days'),
|
||||
totalRate: t('item.totalRate'),
|
||||
dailyRate: t('item.dailyRate'),
|
||||
hourRate: t('item.hourRate')
|
||||
})
|
||||
|
||||
const paging = shallowRef()
|
||||
const dataList = ref<any[]>([])
|
||||
const queryList = async (pageNo : number, pageSize : number) => {
|
||||
try {
|
||||
const data = await recordLists({
|
||||
page_no: pageNo,
|
||||
page_size: pageSize
|
||||
})
|
||||
Object.keys(data.lists).forEach(key => {
|
||||
data.lists[key]['money'] = getCurrency() + formatMoney(data.lists[key]['money']) + ' ' + getCurrency2()
|
||||
data.lists[key]['total_income'] = getCurrency() + formatMoney(data.lists[key]['total_income']) + ' ' + getCurrency2()
|
||||
var type = data.lists[key]['type'];
|
||||
var cycleTime = tips.hour;
|
||||
var rateName = tips.totalRate;
|
||||
|
||||
switch (type) {
|
||||
case 1:
|
||||
cycleTime = tips.days;
|
||||
rateName = tips.dailyRate;
|
||||
break;
|
||||
case 2:
|
||||
cycleTime = tips.days;
|
||||
break;
|
||||
case 3:
|
||||
break;
|
||||
case 4:
|
||||
rateName = tips.hourRate;
|
||||
break;
|
||||
}
|
||||
data.lists[key]['cycle'] = data.lists[key]['cycle'] + ' ' + cycleTime;
|
||||
data.lists[key]['rateName'] = rateName;
|
||||
})
|
||||
paging.value.complete(data.lists)
|
||||
} catch (error) {
|
||||
paging.value.complete(false)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
</style>
|
||||
42
src/pages/kefu/index.vue
Normal file
42
src/pages/kefu/index.vue
Normal file
@@ -0,0 +1,42 @@
|
||||
<template>
|
||||
<view>
|
||||
<h-dark :title="t('kefu.title')"></h-dark>
|
||||
<view class="mx-[30rpx] mt-[20rpx]">
|
||||
<view v-for="(item, index) in data.list" :key="index"
|
||||
class="flex items-center bg-[#2C326B] rounded-lg p-[30rpx] mb-[20rpx]" @click="handleClick(item.link)">
|
||||
<u-image width="64" height="64" :src="item.logo" alt="" />
|
||||
<view class="ml-[20rpx] flex-1">{{ item.name }}</view>
|
||||
<view class="text-muted">
|
||||
<u-icon name="arrow-right" />
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
import { reactive } from 'vue'
|
||||
import { getKefuLists } from '@/api/kefu'
|
||||
import { jumpTo, t } from '@/utils/util'
|
||||
uni.setNavigationBarTitle({ title: t('kefu.title') })
|
||||
|
||||
const data = reactive({
|
||||
list: []
|
||||
})
|
||||
const handleClick = (link : any) => {
|
||||
jumpTo(link)
|
||||
}
|
||||
|
||||
const getData = async () => {
|
||||
const res = await getKefuLists()
|
||||
data.list = res;
|
||||
}
|
||||
onLoad(() => {
|
||||
|
||||
getData()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
</style>
|
||||
88
src/pages/language/index.vue
Normal file
88
src/pages/language/index.vue
Normal file
@@ -0,0 +1,88 @@
|
||||
<template>
|
||||
<view>
|
||||
<h-dark :title="t('language.language')" backgroundColor="#1B1F45"></h-dark>
|
||||
<view class="mx-[120rpx] my-[30rpx]">
|
||||
<u-image width="100%" mode="widthFix" src="/static/images/common/country.png" alt="" />
|
||||
</view>
|
||||
|
||||
<view class="py-[20rpx] mx-[30rpx]">
|
||||
<view class="flex justify-around px-[40rpx] py-[35rpx] bg-[#2C326B] rounded-lg mb-[20rpx]" v-for="(item, index) in data.list" @click="langChange(item)">
|
||||
<view class="w-4/5">
|
||||
{{item.name}}
|
||||
</view>
|
||||
<view class="w-1/5 text-right">
|
||||
<u-icon v-if="!loading && item.symbol==data.lang_name" name="checkbox-mark"></u-icon>
|
||||
<u-loading v-if="loading && item.symbol==data.lang_name" mode="flower"></u-loading>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
import { reactive, ref } from 'vue'
|
||||
import { getLangAll, getLangPag } from '@/api/lang'
|
||||
import { t } from '@/utils/util'
|
||||
uni.setNavigationBarTitle({ title: t('language.language') })
|
||||
|
||||
const loading = ref(false)
|
||||
const data = reactive({
|
||||
lang_name: uni.getStorageSync('lang'),
|
||||
list: []
|
||||
})
|
||||
const langChange = (item : any) => {
|
||||
loading.value = true;
|
||||
data.lang_name = item.symbol;
|
||||
uni.setStorageSync('lang', item.symbol)
|
||||
uni.setStorageSync('formatTime', item.time_format)
|
||||
|
||||
getPags()
|
||||
const current = getCurrentPages();
|
||||
let prevPageRoute = '';
|
||||
|
||||
if (current.length >= 2) {
|
||||
let prevPage = current[current.length - 2];
|
||||
prevPageRoute = "/" + prevPage.route; // 上一个页面的路由
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
/*#ifdef H5*/
|
||||
if (current && current.length > 1) {
|
||||
uni.reLaunch({
|
||||
url: prevPageRoute// 替换为你的页面路径
|
||||
});
|
||||
} else {
|
||||
history.back();
|
||||
}
|
||||
/*#endif*/
|
||||
|
||||
/*#ifdef APP-PLUS*/
|
||||
uni.reLaunch({
|
||||
url: prevPageRoute// 替换为你的页面路径
|
||||
});
|
||||
/*#endif*/
|
||||
}, 3000);
|
||||
|
||||
|
||||
}
|
||||
const getPags = async () => {
|
||||
const pag = await getLangPag({ 'lang': uni.getStorageSync('lang') })
|
||||
pag.forEach((item : any) => {
|
||||
//先销毁再重新赋值
|
||||
uni.removeStorageSync(item.type + '.' + item.name);
|
||||
uni.setStorageSync(item.type + '.' + item.name, item.value);
|
||||
});
|
||||
}
|
||||
|
||||
const getData = async () => {
|
||||
const apiData = await getLangAll()
|
||||
data.list = apiData;
|
||||
}
|
||||
onLoad(() => {
|
||||
getData()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
</style>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user