This commit is contained in:
parent
514c153745
commit
fe641618e1
|
|
@ -0,0 +1,6 @@
|
|||
import { request } from '@/api';
|
||||
|
||||
//获取资金明细列表
|
||||
export const getFundDetailListApi = (params: any) => {
|
||||
return request.get('/user/FundFlowRecords', {...params})
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
import { request } from '@/api';
|
||||
|
||||
//获取历史交易列表
|
||||
export const getHistoryTradeListApi = (params: any) => {
|
||||
return request.get('orderRecords/getList', {...params})
|
||||
}
|
||||
|
|
@ -38,6 +38,7 @@ body,
|
|||
padding: 20px;
|
||||
overflow: auto;
|
||||
max-height: calc(1080px - 200px);
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ import type { FormInstance, FormRules } from 'element-plus'
|
|||
import type { Component } from 'vue'
|
||||
|
||||
interface FormItem {
|
||||
type: 'input' | 'select' | 'number' | 'radio' | 'slot' | 'checkbox' | 'date' | 'switch' | 'edit' | 'password' | 'time'
|
||||
type: 'input' | 'select' | 'number' | 'radio' | 'slot' | 'checkbox' | 'date' | 'switch' | 'edit' | 'password' | 'time' | 'upload'
|
||||
label: string
|
||||
prop: string
|
||||
placeholder?: string
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ const handleChangePassword = () => {
|
|||
const handleLogout = () => {
|
||||
// 示例:退出登录逻辑
|
||||
const deviceNo = getStorage('device_no') as string
|
||||
userStore.logout({ device_no: deviceNo })
|
||||
userStore.logout({ device_no: String(deviceNo) })
|
||||
}
|
||||
|
||||
// 处理菜单项点击
|
||||
|
|
|
|||
|
|
@ -123,7 +123,19 @@ const staticMenuList = ref<ElMenuItem[]>(
|
|||
label: '做市商管理',
|
||||
path: '/account/market-maker', // index="3-3"
|
||||
icon: ''
|
||||
}
|
||||
},
|
||||
{
|
||||
id: 34,
|
||||
label: '档案管理',
|
||||
path: '/account/archives', // index="3-4"
|
||||
icon: ''
|
||||
},
|
||||
{
|
||||
id: 35,
|
||||
label: '账号管理',
|
||||
path: '/account/accountDetail', // index="3-5"
|
||||
icon: ''
|
||||
},
|
||||
]
|
||||
},
|
||||
// 交易管理(子菜单)
|
||||
|
|
@ -145,6 +157,24 @@ const staticMenuList = ref<ElMenuItem[]>(
|
|||
path: '/trade/group', // index="4-2"
|
||||
icon: ''
|
||||
},
|
||||
{
|
||||
id: 43,
|
||||
label: '持仓统计',
|
||||
path: '/trade/positionStat', // index="4-3"
|
||||
icon: ''
|
||||
},
|
||||
{
|
||||
id: 44,
|
||||
label: '历史交易',
|
||||
path: '/trade/historyTrade', // index="4-4"
|
||||
icon: ''
|
||||
},
|
||||
{
|
||||
id: 45,
|
||||
label: '交易软件',
|
||||
path: '/trade/tradeSoftware', // index="4-5"
|
||||
icon: ''
|
||||
},
|
||||
// {
|
||||
// id: 43,
|
||||
// label: '交易时间',
|
||||
|
|
@ -197,6 +227,12 @@ const staticMenuList = ref<ElMenuItem[]>(
|
|||
path: '/funding/transferDetail', // index="6-5"
|
||||
icon: ''
|
||||
},
|
||||
{
|
||||
id: 66,
|
||||
label: '资金明细',
|
||||
path: '/funding/fundDetail', // index="6-6"
|
||||
icon: ''
|
||||
},
|
||||
// {
|
||||
// id: 66,
|
||||
// label: '资金流水',
|
||||
|
|
@ -248,52 +284,62 @@ const staticMenuList = ref<ElMenuItem[]>(
|
|||
|
||||
|
||||
// 资金管理(子菜单)
|
||||
{
|
||||
id: 9,
|
||||
label: '资金管理',
|
||||
path: 'funding', // index="funding"
|
||||
icon: 'GoodsFilled', // 对应 <GoodsFilled /> 图标
|
||||
children: [
|
||||
//存款/取款暂时没有
|
||||
//资金明细
|
||||
// 审核记录
|
||||
// 提现记录
|
||||
// 充值记录
|
||||
]
|
||||
},
|
||||
// {
|
||||
// id: 9,
|
||||
// label: '资金管理',
|
||||
// path: 'funding', // index="funding"
|
||||
// icon: 'GoodsFilled', // 对应 <GoodsFilled /> 图标
|
||||
// children: [
|
||||
// //存款/取款/审核记录/ 提现记录/ 充值记录暂时没有
|
||||
// //资金明细
|
||||
|
||||
// ]
|
||||
// },
|
||||
// 交易统计(子菜单)
|
||||
{
|
||||
id: 10,
|
||||
label: '交易统计',
|
||||
path: 'trade', // index="trade"
|
||||
icon: 'ChartBarFilled', // 对应 <ChartBarFilled /> 图标
|
||||
children: [
|
||||
// 持仓统计
|
||||
//历史交易
|
||||
//交易软件
|
||||
]
|
||||
},
|
||||
// {
|
||||
// id: 10,
|
||||
// label: '交易统计归交易管理',
|
||||
// path: 'trade', // index="trade"
|
||||
// icon: 'ChartBarFilled', // 对应 <ChartBarFilled /> 图标
|
||||
// children: [
|
||||
// // 持仓统计是辉哥
|
||||
// //历史交易
|
||||
// //交易软件
|
||||
// ]
|
||||
// },
|
||||
// 账户管理(子菜单)
|
||||
{
|
||||
id: 11,
|
||||
label: '账户管理',
|
||||
path: 'account', // index="account"
|
||||
icon: 'UserFilled', // 对应 <UserFilled /> 图标
|
||||
children: [
|
||||
// 档案管理
|
||||
// 账户管理
|
||||
]
|
||||
},
|
||||
// {
|
||||
// id: 11,
|
||||
// label: '账户管理',
|
||||
// path: 'account', // index="account"
|
||||
// icon: 'UserFilled', // 对应 <UserFilled /> 图标
|
||||
// children: [
|
||||
// // 档案管理
|
||||
// // 账户管理
|
||||
// ]
|
||||
// },
|
||||
// 个性化交易(子菜单)
|
||||
{
|
||||
id: 12,
|
||||
label: '个性化交易',
|
||||
path: 'customTrade', // index="customTrade"
|
||||
path: 'personalized', // index="personalized"
|
||||
icon: 'SettingFilled', // 对应 <SettingFilled /> 图标
|
||||
children: [
|
||||
// 排行榜
|
||||
// 排行榜放在了app中
|
||||
// 跟单记录
|
||||
{
|
||||
id: 121,
|
||||
label: '跟单记录',
|
||||
path: '/personalized/followRecord', // index="12-1"
|
||||
icon: ''
|
||||
},
|
||||
// 带单记录
|
||||
{
|
||||
id: 122,
|
||||
label: '带单记录',
|
||||
path: '/personalized/leadRecord', // index="12-2"
|
||||
icon: ''
|
||||
},
|
||||
]
|
||||
},
|
||||
// 代理管理(子菜单)
|
||||
|
|
|
|||
|
|
@ -33,6 +33,18 @@ const routes = [
|
|||
name: 'ChangePassword',
|
||||
component: () => import('@/views/user/ChangePassword.vue'),
|
||||
meta: { requiresAuth: true, title: '修改密码' }
|
||||
},
|
||||
{
|
||||
path: 'bind-email',
|
||||
name: 'BindEmail',
|
||||
component: () => import('@/views/user/bindEmail.vue'),
|
||||
meta: { requiresAuth: true, title: '绑定邮箱' }
|
||||
},
|
||||
{
|
||||
path: 'bind-phone',
|
||||
name: 'BindPhone',
|
||||
component: () => import('@/views/user/bindPhone.vue'),
|
||||
meta: { requiresAuth: true, title: '绑定手机号' }
|
||||
}
|
||||
]
|
||||
},
|
||||
|
|
@ -118,7 +130,23 @@ const routes = [
|
|||
meta: {
|
||||
title: '做市商管理', // 左侧菜单显示的标题
|
||||
}
|
||||
},
|
||||
{
|
||||
path: 'archives',
|
||||
name: 'Archives',
|
||||
component: () => import('@/views/account/archives/index.vue'),
|
||||
meta: {
|
||||
title: '档案管理', // 左侧菜单显示的标题
|
||||
}
|
||||
},
|
||||
{
|
||||
path: 'accountDetail',
|
||||
name: 'AccountDetail',
|
||||
component: () => import('@/views/account/accountDetail/index.vue'),
|
||||
meta: {
|
||||
title: '账号管理', // 左侧菜单显示的标题
|
||||
}
|
||||
},
|
||||
]
|
||||
},
|
||||
//交易管理
|
||||
|
|
@ -152,7 +180,31 @@ const routes = [
|
|||
// meta: {
|
||||
// title: '交易时间', // 左侧菜单显示的标题
|
||||
// }
|
||||
// }
|
||||
// },
|
||||
{
|
||||
path: 'positionStat',
|
||||
name: 'PositionStat',
|
||||
component: () => import('@/views/trade/positionStat/index.vue'),
|
||||
meta: {
|
||||
title: '持仓统计', // 左侧菜单显示的标题
|
||||
}
|
||||
},
|
||||
{
|
||||
path: 'historyTrade',
|
||||
name: 'HistoryTrade',
|
||||
component: () => import('@/views/trade/historyTrade/index.vue'),
|
||||
meta: {
|
||||
title: '历史交易', // 左侧菜单显示的标题
|
||||
}
|
||||
},
|
||||
{
|
||||
path: 'tradeSoftware',
|
||||
name: 'TradeSoftware',
|
||||
component: () => import('@/views/trade/tradeSoftware/index.vue'),
|
||||
meta: {
|
||||
title: '交易软件', // 左侧菜单显示的标题
|
||||
}
|
||||
},
|
||||
]
|
||||
},
|
||||
//公告管理
|
||||
|
|
@ -236,6 +288,14 @@ const routes = [
|
|||
title: '存款渠道列表', // 左侧菜单显示的标题
|
||||
}
|
||||
},
|
||||
{
|
||||
path: 'fundDetail',
|
||||
name: 'FundDetail',
|
||||
component: () => import('@/views/funding/fundDetail/index.vue'),
|
||||
meta: {
|
||||
title: '资金明细', // 左侧菜单显示的标题
|
||||
}
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -245,7 +305,35 @@ const routes = [
|
|||
title: '风控管理', // 左侧菜单显示的标题
|
||||
},
|
||||
component: () => import('@/views/risk/index.vue'),
|
||||
},
|
||||
// 个性化交易
|
||||
{
|
||||
path: 'personalized',
|
||||
name: 'Personalized',
|
||||
meta: {
|
||||
title: '个性化交易', // 左侧菜单显示的标题
|
||||
},
|
||||
children: [
|
||||
// 跟单记录
|
||||
{
|
||||
path: 'followRecord',
|
||||
name: 'FollowRecord',
|
||||
component: () => import('@/views/personalized/followRecord/index.vue'),
|
||||
meta: {
|
||||
title: '跟单记录', // 左侧菜单显示的标题
|
||||
}
|
||||
},
|
||||
// 带单记录
|
||||
{
|
||||
path: 'leadRecord',
|
||||
name: 'LeadRecord',
|
||||
component: () => import('@/views/personalized/leadRecord/index.vue'),
|
||||
meta: {
|
||||
title: '带单记录', // 左侧菜单显示的标题
|
||||
}
|
||||
},
|
||||
]
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
|
|||
|
|
@ -0,0 +1,194 @@
|
|||
<template>
|
||||
<div class="account-detail">
|
||||
<h4>账户信息</h4>
|
||||
<el-card class="account-info">
|
||||
<el-icon>
|
||||
<UserFilled />
|
||||
</el-icon>
|
||||
<div class="item">
|
||||
<div class="item-content">
|
||||
<div class="item-label" v-if="!isChangeName">
|
||||
<span>账号名称:</span>
|
||||
<span>{{ accountName }}</span>
|
||||
</div>
|
||||
<div class="item-changeName" v-else>
|
||||
<span>账号名称:</span>
|
||||
<el-input v-model="newAccountName" placeholder="请输入新账号名称" size="small" ref="inputRef" @blur="handleSave" @keyup.enter="handleSave"/>
|
||||
</div>
|
||||
<el-button type="default" @click="changeName" size="small">修改名称</el-button>
|
||||
</div>
|
||||
<span>用户最后登录时间:2026.02.02 07:00:00</span>
|
||||
</div>
|
||||
</el-card>
|
||||
<div class="security">
|
||||
<h4>安全信息</h4>
|
||||
<div class="card-group">
|
||||
<el-card>
|
||||
<span>邮箱</span>
|
||||
<span>已绑定邮箱:{{ userInfo?.email || '未绑定' }}</span>
|
||||
<el-button :type="accountStatus === true ? 'primary' : 'danger'" @click="handleEmail">{{ accountStatus === true ? '已验证' :
|
||||
'未验证' }}</el-button>
|
||||
</el-card>
|
||||
<el-card>
|
||||
<span>手机号</span>
|
||||
<span>已绑定手机号:{{ userInfo?.phone || '未绑定' }}</span>
|
||||
<el-button :type="phoneStatus === true ? 'primary' : 'danger'" @click="handlePhone">{{ phoneStatus === true ? '已绑定' :
|
||||
'未绑定' }}</el-button>
|
||||
</el-card>
|
||||
<el-card>
|
||||
<span>密码</span>
|
||||
<span>************</span>
|
||||
<el-button type="primary" @click="changePassword">修改</el-button>
|
||||
</el-card>
|
||||
<el-card>
|
||||
<span>默认语言</span>
|
||||
<span>选择您的语言偏好</span>
|
||||
<LanguageSelect v-model="languageStore.lang" @change="languageStore.changeLang" />
|
||||
</el-card>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { UserFilled } from '@element-plus/icons-vue'
|
||||
|
||||
//组件
|
||||
import LanguageSelect from '@/components/LanguageSelect/index.vue'
|
||||
|
||||
// 导入Pinia状态
|
||||
import { useLanguageStore } from '@/stores/modules/language'
|
||||
import { getStorage, setStorage } from '@/utils/storage'
|
||||
|
||||
//接口
|
||||
import { editAgentNameApi } from '@/api/modules/agent'
|
||||
|
||||
// 语言选择配置
|
||||
const router = useRouter()
|
||||
const languageStore = useLanguageStore()
|
||||
|
||||
// 账户状态
|
||||
const accountStatus = ref(true)
|
||||
// 手机号状态
|
||||
const phoneStatus = ref(true)
|
||||
|
||||
/**
|
||||
* @description 账户信息数据
|
||||
*/
|
||||
|
||||
// 从本地存储获取账户名称
|
||||
const userInfo = getStorage<any>('userInfo')
|
||||
const accountName = ref(userInfo?.username || '')
|
||||
const newAccountName = ref(accountName.value)
|
||||
//判断是否修改名称
|
||||
const isChangeName = ref(false)
|
||||
// 输入框引用
|
||||
const inputRef = ref<HTMLInputElement>()
|
||||
|
||||
/**
|
||||
* @description 绑定邮箱
|
||||
*/
|
||||
const handleEmail = ()=>{
|
||||
accountStatus.value === false ? router.push('/user/bind-email') : ''
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 绑定手机号
|
||||
*/
|
||||
const handlePhone = ()=>{
|
||||
phoneStatus.value === false ? router.push('/user/bind-phone') : ''
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 修改密码
|
||||
*/
|
||||
const changePassword = () => {
|
||||
router.push('/user/change-password')
|
||||
}
|
||||
|
||||
|
||||
// 修改用户名
|
||||
const changeName = async () => {
|
||||
isChangeName.value = true
|
||||
// 等待 DOM 更新后自动聚焦输入框
|
||||
await nextTick()
|
||||
inputRef.value?.focus()
|
||||
}
|
||||
|
||||
//修改用户名提交
|
||||
const handleSave = async () => {
|
||||
if (newAccountName.value.trim()) {
|
||||
await editAgentNameApi({
|
||||
account_id: userInfo?.id || '',
|
||||
account_name: newAccountName.value
|
||||
})
|
||||
accountName.value = newAccountName.value.trim()
|
||||
setStorage('userInfo', {
|
||||
...userInfo,
|
||||
username: accountName.value
|
||||
})
|
||||
} else {
|
||||
newAccountName.value = accountName.value // 若为空则恢复原值
|
||||
}
|
||||
isChangeName.value = false
|
||||
}
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
.account-detail {
|
||||
h4 {
|
||||
margin-bottom: 10px;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.account-info {
|
||||
box-shadow: none;
|
||||
|
||||
:deep(.el-card__body) {
|
||||
display: flex;
|
||||
padding: 10px;
|
||||
|
||||
.el-icon {
|
||||
font-size: 48px;
|
||||
}
|
||||
}
|
||||
|
||||
.item {
|
||||
.item-content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.item-changeName {
|
||||
display: flex;
|
||||
|
||||
span {
|
||||
width: 70px;
|
||||
}
|
||||
|
||||
.el-input {
|
||||
margin-right: 10px;
|
||||
width: 140px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.security {
|
||||
margin-top: 20px;
|
||||
|
||||
.card-group {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 20px;
|
||||
|
||||
.el-card {
|
||||
:deep(.el-card__body) {
|
||||
padding: 20px 10px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,206 @@
|
|||
<template>
|
||||
<div class="archives">
|
||||
<div class="bar">
|
||||
<h4>档案管理</h4>
|
||||
<span :class="['status', isActive === true ? 'active' : '']">未认证</span>
|
||||
<span class="info">资料审核包含身份信息/联络信息/实名认证/合规文件,需要管理员审核</span>
|
||||
</div>
|
||||
<div class="content">
|
||||
<div class="tab">
|
||||
<div class="tab-item">
|
||||
<el-button :type="tabType === 'identity' ? 'primary' : 'default'" @click="tabType = 'identity'">身份信息</el-button>
|
||||
</div>
|
||||
<div class="tab-item">
|
||||
<el-button :type="tabType === 'contact' ? 'primary' : 'default'" @click="tabType = 'contact'">联系信息</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<article>
|
||||
<p class="warn">
|
||||
<el-icon>
|
||||
<WarnTriangleFilled />
|
||||
</el-icon>
|
||||
请填写正确的个人身份信息,以确保所有功能正常使用
|
||||
</p>
|
||||
<ArchivesForm ref="archivesFormRef" :form-data="archivesForm" :form-rules="archivesFormRules"
|
||||
:form-items="formOptions" :options-map="archivesFormOptionsMap" :row-gutter="rowGutter"
|
||||
:col-span="colSpan">
|
||||
<template #upload>
|
||||
<div class="upload">
|
||||
<div>
|
||||
<p class="warn">请上传证件正面</p>
|
||||
<el-upload class="avatar-uploader" action="" :show-file-list="true"
|
||||
:on-success="handleAvatarSuccess" :before-upload="beforeAvatarUpload">
|
||||
<img v-if="imageUrl" :src="imageUrl" class="avatar" />
|
||||
<el-icon v-else class="avatar-uploader-icon">
|
||||
<Plus />
|
||||
</el-icon>
|
||||
</el-upload>
|
||||
</div>
|
||||
<div>
|
||||
<p class="warn">请上传证件反面</p>
|
||||
<el-upload class="avatar-uploader" action="" :show-file-list="true"
|
||||
:on-success="handleAvatarSuccess" :before-upload="beforeAvatarUpload">
|
||||
<img v-if="imageUrl" :src="imageUrl" class="avatar" />
|
||||
<el-icon v-else class="avatar-uploader-icon">
|
||||
<Plus />
|
||||
</el-icon>
|
||||
</el-upload>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</ArchivesForm>
|
||||
</article>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { UploadProps } from 'element-plus'
|
||||
import { WarnTriangleFilled, Plus } from '@element-plus/icons-vue'
|
||||
|
||||
//组件
|
||||
import ArchivesForm from '@/components/common/Form.vue'
|
||||
|
||||
// 表单配置
|
||||
import { identityFormItems, contactFormItems } from './options'
|
||||
import { ref } from 'vue'
|
||||
// 判断是否认证
|
||||
const isActive = ref(false)
|
||||
// 判断信息类型
|
||||
const tabType = ref('identity')
|
||||
|
||||
/**
|
||||
* @description: 档案管理表单
|
||||
*/
|
||||
const archivesForm = ref({
|
||||
nationality: 'CN',
|
||||
idType: 'ID',
|
||||
idNumber: '',
|
||||
phone: '',
|
||||
email: '',
|
||||
address: '',
|
||||
})
|
||||
const archivesFormRules = ref()
|
||||
const archivesFormOptionsMap = ref({
|
||||
nationality: [
|
||||
{ label: '中国', value: 'CN' },
|
||||
{ label: '美国', value: 'US' },
|
||||
{ label: '英国', value: 'GB' },
|
||||
{ label: '法国', value: 'FR' },
|
||||
],
|
||||
idType: [
|
||||
{ label: '身份证', value: 'ID' },
|
||||
{ label: '护照', value: 'PASSPORT' },
|
||||
{ label: '其他', value: 'OTHER' },
|
||||
]
|
||||
})
|
||||
const formOptions = computed(() => tabType.value === 'identity' ? identityFormItems : contactFormItems)
|
||||
const rowGutter = ref(20)
|
||||
const colSpan = ref(12)
|
||||
|
||||
|
||||
const imageUrl = ref('')
|
||||
|
||||
const handleAvatarSuccess: UploadProps['onSuccess'] = (
|
||||
response,
|
||||
uploadFile
|
||||
) => {
|
||||
imageUrl.value = URL.createObjectURL(uploadFile.raw!)
|
||||
}
|
||||
|
||||
const beforeAvatarUpload: UploadProps['beforeUpload'] = (rawFile) => {
|
||||
if (rawFile.type !== 'image/jpeg') {
|
||||
ElMessage.error('Avatar picture must be JPG format!')
|
||||
return false
|
||||
} else if (rawFile.size / 1024 / 1024 > 2) {
|
||||
ElMessage.error('Avatar picture size can not exceed 2MB!')
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.archives {
|
||||
height: 100%;
|
||||
|
||||
.bar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 20px;
|
||||
|
||||
.status {
|
||||
background: #f56c6c;
|
||||
border-radius: 5px;
|
||||
padding: 4px;
|
||||
margin: 0 10px;
|
||||
}
|
||||
|
||||
.active {
|
||||
background: var(--el-color-primary);
|
||||
}
|
||||
|
||||
.info {
|
||||
background: var(--el-color-primary-light-5);
|
||||
padding: 4px;
|
||||
border-radius: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
.content {
|
||||
display: flex;
|
||||
gap: 20px;
|
||||
height: calc(100% - 55px);
|
||||
|
||||
.tab {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
article {
|
||||
flex: 1;
|
||||
height: 100%;
|
||||
border: 1px solid #e4e7ed;
|
||||
border-radius: 5px;
|
||||
padding: 20px;
|
||||
|
||||
.warn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
margin-bottom: 10px;
|
||||
|
||||
.el-icon {
|
||||
font-size: 20px;
|
||||
color: #f56c6c;
|
||||
}
|
||||
}
|
||||
|
||||
.el-form {
|
||||
.upload {
|
||||
display: flex;
|
||||
gap: 20px;
|
||||
|
||||
.avatar-uploader {
|
||||
width: 178px;
|
||||
height: 178px;
|
||||
border: 1px dashed var(--el-border-color);
|
||||
border-radius: 6px;
|
||||
|
||||
:deep(.el-upload) {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
.el-icon {
|
||||
font-size: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
export const identityFormItems = [
|
||||
// 国籍
|
||||
{ prop: 'nationality', label: '国籍', type: 'select' as const ,width: "200px"},
|
||||
// 证件类型
|
||||
{ prop: 'idType', label: '证件类型', type: 'select' as const ,width: "200px"},
|
||||
// 上传证件
|
||||
{ prop: 'idCard', slotName: 'upload', label: '上传证件' ,type: 'upload' as const},
|
||||
]
|
||||
|
||||
export const contactFormItems = [
|
||||
// 联系电话
|
||||
{ prop: 'phone', label: '联系电话', type: 'input' as const ,width: "200px"},
|
||||
]
|
||||
|
||||
|
|
@ -0,0 +1,128 @@
|
|||
<template>
|
||||
<div>
|
||||
<!-- 搜索 -->
|
||||
<FundDetailSearch :search-form="searchForm" :search-options="searchOptions" @search="handleSearch"
|
||||
@reset="handleReset">
|
||||
<template #button="{ form }">
|
||||
<el-button type="primary" @click="handleExport()">
|
||||
导出
|
||||
</el-button>
|
||||
</template>
|
||||
</FundDetailSearch>
|
||||
<!-- 表格 -->
|
||||
<FundDetailTable :table-data="tableTree" :columns="tableColumnsOptions" row-key="id" />
|
||||
<!-- 分页 -->
|
||||
<FundDetailPagination v-model="currentPage" v-model:pageSizeValue="pageSize" :total="total"
|
||||
@pagination-change="handlePaginationChange" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
// 组件
|
||||
import FundDetailSearch from '@/components/common/Search.vue'
|
||||
import FundDetailTable from '@/components/common/Table.vue'
|
||||
import FundDetailPagination from '@/components/common/Pagination.vue'
|
||||
// 配置以及表单验证
|
||||
import { search, tableColumns } from './options'
|
||||
// 接口
|
||||
import { getFundDetailListApi } from '@/api/modules/funding/fundDetail'
|
||||
|
||||
// 导出表格
|
||||
import {exportToExcel} from '@/utils/exportToExcel'
|
||||
/**
|
||||
* @description: 定义搜索数据
|
||||
*/
|
||||
const searchOptions = ref(search)
|
||||
const searchForm = ref({
|
||||
username: '',
|
||||
subAccountId: '',
|
||||
startTime: '',
|
||||
endTime: '',
|
||||
})
|
||||
/**
|
||||
* @description: 定义表格数据
|
||||
*/
|
||||
const tableTree = ref([])
|
||||
const tableColumnsOptions = ref(tableColumns)
|
||||
/**
|
||||
* @description: 定义分页数据
|
||||
*/
|
||||
const currentPage = ref(1)
|
||||
const pageSize = ref(10)
|
||||
const total = ref(0)
|
||||
|
||||
/**
|
||||
* @description: 定义公共请求数据方法
|
||||
*/
|
||||
//获取资金明细列表
|
||||
const getFundDetailList = async () => {
|
||||
const params = {
|
||||
page: currentPage.value,
|
||||
page_size: pageSize.value,
|
||||
start_time: searchForm.value.startTime.length > 0 ? `${searchForm.value.startTime} 0:00:00` : '2026-01-01 0:00:00',
|
||||
end_time: searchForm.value.endTime.length > 0 ? `${searchForm.value.endTime} 23:59:59` : '2026-03-15 23:59:59',
|
||||
user_name: searchForm.value.username,
|
||||
account_id: searchForm.value.subAccountId,
|
||||
}
|
||||
// 调用接口获取数据
|
||||
const data: any = await getFundDetailListApi(params)
|
||||
console.log(data)
|
||||
tableTree.value = data.data.map((item: any) => ({
|
||||
// 用户名
|
||||
username: item.user.username,
|
||||
//单号
|
||||
orderNo: item.trade_id,
|
||||
//操作类型
|
||||
type: item.enum_dic.value,
|
||||
//原有金额
|
||||
originalAmount: item.amount,
|
||||
//余额变动
|
||||
balanceChange: item.balance,
|
||||
//创建时间
|
||||
createTime: item.created_at,
|
||||
//钱包类型
|
||||
walletType: item.wallet_type === "1" ? '主钱包' : '子钱包',
|
||||
}))
|
||||
//分页数据
|
||||
total.value = data.total
|
||||
currentPage.value = data.current_page
|
||||
pageSize.value = Number(data.per_page)
|
||||
}
|
||||
|
||||
/**
|
||||
* @description: 页面加载完成需要请求的数据
|
||||
*/
|
||||
onMounted(() => {
|
||||
getFundDetailList()
|
||||
})
|
||||
/**
|
||||
* @description: 定义搜索方法
|
||||
*/
|
||||
const handleSearch = () => {
|
||||
getFundDetailList()
|
||||
}
|
||||
const handleReset = () => {
|
||||
searchForm.value = {
|
||||
username: '',
|
||||
subAccountId: '',
|
||||
startTime: '',
|
||||
endTime: '',
|
||||
}
|
||||
getFundDetailList()
|
||||
}
|
||||
const handleExport = () => {
|
||||
exportToExcel({
|
||||
tableData: tableTree.value,
|
||||
columns: tableColumnsOptions.value,
|
||||
title: '导出资金明细',
|
||||
defaultFileNamePrefix: '资金明细',
|
||||
})
|
||||
}
|
||||
/**
|
||||
* @description: 定义分页方法
|
||||
*/
|
||||
const handlePaginationChange = (page: any) => {
|
||||
currentPage.value = page.currentPage
|
||||
getFundDetailList()
|
||||
}
|
||||
</script>
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
/**
|
||||
* @description: 搜索配置
|
||||
*/
|
||||
export const search = [
|
||||
//单号
|
||||
// { prop: 'orderNo', label: '单号', type: 'input' as const, placeholder: '请输入流水单号', width: '140px' },
|
||||
//用户名
|
||||
{ prop: 'username', label: '用户名', type: 'input' as const, placeholder: '请输入用户名', width: '140px' },
|
||||
// 子账号
|
||||
{ prop: 'subAccountId', label: '子账号ID', type: 'input' as const, placeholder: '请输入子账号ID', width: '140px' },
|
||||
//操作类型
|
||||
// { prop: 'type', label: '操作类型', type: 'select' as const, placeholder: '请选择操作类型', width: '140px', options: [
|
||||
// {label:"充值",value:"1"},
|
||||
// {label:"提现",value:"2"},
|
||||
// ] },
|
||||
//钱包
|
||||
// { prop: 'wallet', label: '钱包', type: 'select' as const, placeholder: '请选择钱包', width: '140px', options: [
|
||||
// {label:"主钱包",value:"1"},
|
||||
// {label:"子钱包",value:"2"},
|
||||
// ] },
|
||||
//开始时间
|
||||
{
|
||||
prop: 'startTime', label: '开始时间', type: 'date' as const, dateType: 'date' as const, // 时间范围选择器
|
||||
valueFormat: 'YYYY-MM-DD', placeholder: '请选择开始时间', width: '150px'
|
||||
},
|
||||
//结束时间
|
||||
{
|
||||
prop: 'endTime', label: '结束时间', type: 'date' as const, dateType: 'date' as const, // 时间范围选择器
|
||||
valueFormat: 'YYYY-MM-DD', placeholder: '请选择结束时间', width: '150px'
|
||||
},
|
||||
|
||||
|
||||
]
|
||||
export const tableColumns = [
|
||||
// 用户名
|
||||
{ prop: 'username', label: '用户名' },
|
||||
//单号
|
||||
{ prop: 'orderNo', label: '单号' },
|
||||
//操作类型
|
||||
{ prop: 'type', label: '操作类型' },
|
||||
//资金流向
|
||||
// { prop: 'fundDirection', label: '资金流向' },
|
||||
//原有金额
|
||||
{ prop: 'originalAmount', label: '原有金额' },
|
||||
//余额变动
|
||||
{ prop: 'balanceChange', label: '余额变动' },
|
||||
//现有余额
|
||||
// { prop: 'currentBalance', label: '现有余额' },
|
||||
//状态
|
||||
// { prop: 'status', label: '状态' },
|
||||
//创建时间
|
||||
{ prop: 'createTime', label: '创建时间' },
|
||||
//钱包类型
|
||||
{ prop: 'walletType', label: '钱包类型' },
|
||||
]
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
<template>
|
||||
<div>
|
||||
跟单记录
|
||||
</div>
|
||||
</template>
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
<template>
|
||||
<div>
|
||||
带单记录
|
||||
</div>
|
||||
</template>
|
||||
|
|
@ -0,0 +1,131 @@
|
|||
<template>
|
||||
<div class="history-trade">
|
||||
<HistoryTradeSearch :search-form="searchForm" :search-options="searchOptions" @search="handleSearch"
|
||||
@reset="handleReset">
|
||||
|
||||
<template #button="{ form }">
|
||||
<el-button type="primary" @click="handleExport()">
|
||||
导出
|
||||
</el-button>
|
||||
</template>
|
||||
</HistoryTradeSearch>
|
||||
<!-- 表格 -->
|
||||
<HistoryTradeTable :table-data="tableTree" :columns="tableColumnsOptions" row-key="id" />
|
||||
<!-- 分页 -->
|
||||
<HistoryTradePagination v-model="currentPage" v-model:pageSizeValue="pageSize" :total="total"
|
||||
@pagination-change="handlePaginationChange" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
// 组件
|
||||
import HistoryTradeSearch from '@/components/common/Search.vue'
|
||||
import HistoryTradeTable from '@/components/common/Table.vue'
|
||||
import HistoryTradePagination from '@/components/common/Pagination.vue'
|
||||
// 配置以及表单验证
|
||||
import { search, tableColumns } from './options'
|
||||
// 接口
|
||||
import { getHistoryTradeListApi } from '@/api/modules/trade/historyTrade'
|
||||
|
||||
// 调用接口
|
||||
// 导出表格
|
||||
import { exportToExcel } from '@/utils/exportToExcel'
|
||||
/**
|
||||
* @description: 定义搜索数据
|
||||
*/
|
||||
const searchOptions = ref(search)
|
||||
const searchForm = ref({
|
||||
username: '',
|
||||
orderNo: '',
|
||||
subAccountId: '',
|
||||
tradeType: '',
|
||||
startTime: '',
|
||||
endTime: '',
|
||||
})
|
||||
/**
|
||||
* @description: 定义表格数据
|
||||
*/
|
||||
const tableTree = ref([])
|
||||
const tableColumnsOptions = ref(tableColumns)
|
||||
/**
|
||||
* @description: 定义分页数据
|
||||
*/
|
||||
const currentPage = ref(1)
|
||||
const pageSize = ref(10)
|
||||
const total = ref(0)
|
||||
|
||||
/**
|
||||
* @description: 定义公共请求数据方法
|
||||
*/
|
||||
const getHistoryTradeList = async () => {
|
||||
const params = {
|
||||
page: currentPage.value,
|
||||
page_size: pageSize.value,
|
||||
user_name: searchForm.value.username,
|
||||
account_id: searchForm.value.subAccountId,
|
||||
order_no: searchForm.value.orderNo,
|
||||
type: searchForm.value.tradeType,
|
||||
start_time: searchForm.value.startTime.length > 0 ? `${searchForm.value.startTime} 0:00:00` : '2026-01-01 0:00:00',
|
||||
end_time: searchForm.value.endTime.length > 0 ? `${searchForm.value.endTime} 23:59:59` : '2026-03-01 23:59:59',
|
||||
}
|
||||
const data: any = await getHistoryTradeListApi(params)
|
||||
tableTree.value = data.data.map((item: any) => ({
|
||||
orderNo: item.order_id,
|
||||
tradeType: item.type === '1' ? '买入' : '卖出',
|
||||
amount: item.amount,
|
||||
tradeQty: item.num,
|
||||
tradeTime: item.created_at,
|
||||
floatProfit: '后续添加'
|
||||
}))
|
||||
|
||||
//分页数据
|
||||
total.value = data.total
|
||||
currentPage.value = data.current_page
|
||||
pageSize.value = Number(data.per_page)
|
||||
}
|
||||
/**
|
||||
* @description: 页面加载完成需要请求的数据
|
||||
*/
|
||||
onMounted(() => {
|
||||
getHistoryTradeList()
|
||||
})
|
||||
|
||||
/**
|
||||
* @description: 定义搜索方法
|
||||
*/
|
||||
const handleSearch = () => {
|
||||
getHistoryTradeList()
|
||||
}
|
||||
/**
|
||||
* @description: 定义重置方法
|
||||
*/
|
||||
const handleReset = () => {
|
||||
searchForm.value = {
|
||||
username: '',
|
||||
orderNo: '',
|
||||
subAccountId: '',
|
||||
tradeType: '',
|
||||
startTime: '',
|
||||
endTime: '',
|
||||
}
|
||||
getHistoryTradeList()
|
||||
}
|
||||
/**
|
||||
* @description: 定义导出方法
|
||||
*/
|
||||
const handleExport = () => {
|
||||
exportToExcel({
|
||||
tableData: tableTree.value,
|
||||
columns: tableColumnsOptions.value,
|
||||
title: '导出交易记录',
|
||||
defaultFileNamePrefix: '交易记录',
|
||||
})
|
||||
}
|
||||
/**
|
||||
* @description: 定义分页方法
|
||||
*/
|
||||
const handlePaginationChange = (page: any) => {
|
||||
currentPage.value = page.currentPage
|
||||
getHistoryTradeList()
|
||||
}
|
||||
</script>
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
export const search = [
|
||||
// 用户名
|
||||
{ prop: 'username', label: '用户名', type: 'input' as const, placeholder: '请输入用户名',width: '150px' },
|
||||
// 订单号
|
||||
{ prop: 'orderNo', label: '订单号', type: 'input' as const, placeholder: '请输入订单号',width: '150px' },
|
||||
// 交易账户ID
|
||||
{ prop: 'subAccountId', label: '交易账户ID', type: 'input' as const, placeholder: '请输入交易账户ID',width: '150px' },
|
||||
// 交易类型
|
||||
{ prop: 'tradeType', label: '交易类型', type: 'select' as const, placeholder: '请选择交易类型',width: '140px', options: [
|
||||
{ label: '买入', value: '1' },
|
||||
{ label: '卖出', value: '2' },
|
||||
] },
|
||||
//开始时间
|
||||
{
|
||||
prop: 'startTime', label: '开始时间', type: 'date' as const, dateType: 'date' as const, // 时间范围选择器
|
||||
valueFormat: 'YYYY-MM-DD', placeholder: '请选择开始时间', width: '150px'
|
||||
},
|
||||
//结束时间
|
||||
{
|
||||
prop: 'endTime', label: '结束时间', type: 'date' as const, dateType: 'date' as const, // 时间范围选择器
|
||||
valueFormat: 'YYYY-MM-DD', placeholder: '请选择结束时间', width: '150px'
|
||||
},
|
||||
]
|
||||
|
||||
export const tableColumns = [
|
||||
// 订单号
|
||||
{ prop: 'orderNo', label: '订单号' },
|
||||
// 操作类型
|
||||
{ prop: 'tradeType', label: '操作类型' },
|
||||
// 金额
|
||||
{ prop: 'amount', label: '金额' },
|
||||
// 交易数量
|
||||
{ prop: 'tradeQty', label: '交易数量' },
|
||||
// 交易时间
|
||||
{ prop: 'tradeTime', label: '交易时间' },
|
||||
// 浮动盈亏
|
||||
{ prop: 'floatProfit', label: '浮动盈亏' },
|
||||
]
|
||||
|
|
@ -0,0 +1,88 @@
|
|||
<template>
|
||||
<div class="position-stat">
|
||||
<!-- 搜索 -->
|
||||
<PositionStatSearch :search-form="searchForm" :search-options="searchOptions" @search="handleSearch"
|
||||
@reset="handleReset">
|
||||
<template #button="{ form }">
|
||||
<el-button type="primary" @click="handleExport()">
|
||||
导出
|
||||
</el-button>
|
||||
</template>
|
||||
</PositionStatSearch>
|
||||
<!-- 表格 -->
|
||||
<PositionStatTable :table-data="tableTree" :columns="tableColumnsOptions" row-key="id" />
|
||||
|
||||
<!-- 分页 -->
|
||||
<PositionStatPagination :current-page="currentPage" :page-size="pageSize" :total="total" @change="handleChange" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
// 组件
|
||||
import PositionStatSearch from '@/components/common/Search.vue'
|
||||
import PositionStatTable from '@/components/common/Table.vue'
|
||||
import PositionStatPagination from '@/components/common/Pagination.vue'
|
||||
// 配置以及表单验证
|
||||
import { search, tableColumns } from './options'
|
||||
|
||||
// 接口
|
||||
|
||||
|
||||
// 导出表格
|
||||
import {exportToExcel} from '@/utils/exportToExcel'
|
||||
/**
|
||||
* @description: 定义搜索数据
|
||||
*/
|
||||
const searchOptions = ref(search)
|
||||
const searchForm = ref({
|
||||
orderNo: '',
|
||||
tradeType: '',
|
||||
account: '',
|
||||
startTime: '',
|
||||
endTime: '',
|
||||
})
|
||||
/**
|
||||
* @description: 定义表格数据
|
||||
*/
|
||||
const tableTree = ref([])
|
||||
const tableColumnsOptions = ref(tableColumns)
|
||||
/**
|
||||
* @description: 定义分页数据
|
||||
*/
|
||||
const currentPage = ref(1)
|
||||
const pageSize = ref(10)
|
||||
const total = ref(0)
|
||||
/**
|
||||
* @description: 定义公共数据处理方法
|
||||
*/
|
||||
/**
|
||||
* @description: 定义公共请求数据方法
|
||||
*/
|
||||
/**
|
||||
* @description: 页面加载完成需要请求的数据
|
||||
*/
|
||||
/**
|
||||
* @description: 定义搜索方法
|
||||
*/
|
||||
const handleSearch = async () => {
|
||||
console.log("搜索");
|
||||
|
||||
}
|
||||
const handleReset = () => {
|
||||
console.log('重置搜索')
|
||||
}
|
||||
const handleExport = () => {
|
||||
exportToExcel({
|
||||
tableData: tableTree.value,
|
||||
columns: tableColumnsOptions.value,
|
||||
title: '导出资金明细',
|
||||
defaultFileNamePrefix: '资金明细',
|
||||
})
|
||||
}
|
||||
/**
|
||||
* @description: 定义分页方法
|
||||
*/
|
||||
const handleChange = (page: {currentPage: number, size: number}) => {
|
||||
currentPage.value = page.currentPage
|
||||
}
|
||||
</script>
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
export const search = [
|
||||
// 订单号
|
||||
{ prop: 'orderNo', label: '订单号', type: 'input' as const, placeholder: '请输入订单号',width: '200px' },
|
||||
// 交易类型
|
||||
{ prop: 'tradeType', label: '交易类型', type: 'select' as const, placeholder: '请选择交易类型',width: '150px', options: [
|
||||
{ label: '买入', value: '1' },
|
||||
{ label: '卖出', value: '2' },
|
||||
] },
|
||||
//账号
|
||||
{ prop: 'account', label: '账号', type: 'select' as const, placeholder: '请选择账号',width: '150px' },
|
||||
//开始时间
|
||||
{
|
||||
prop: 'startTime', label: '开始时间', type: 'date' as const, dateType: 'date' as const, // 时间范围选择器
|
||||
valueFormat: 'YYYY-MM-DD', placeholder: '请选择开始时间', width: '150px'
|
||||
},
|
||||
//结束时间
|
||||
{
|
||||
prop: 'endTime', label: '结束时间', type: 'date' as const, dateType: 'date' as const, // 时间范围选择器
|
||||
valueFormat: 'YYYY-MM-DD', placeholder: '请选择结束时间', width: '150px'
|
||||
},
|
||||
]
|
||||
|
||||
export const tableColumns = [
|
||||
// 订单号
|
||||
{ prop: 'orderNo', label: '订单号' },
|
||||
// 操作类型
|
||||
{ prop: 'tradeType', label: '操作类型' },
|
||||
// 金额
|
||||
{ prop: 'amount', label: '金额' },
|
||||
// 交易数量
|
||||
{ prop: 'tradeQty', label: '交易数量' },
|
||||
// 交易时间
|
||||
{ prop: 'tradeTime', label: '交易时间' },
|
||||
// 浮动盈亏
|
||||
{ prop: 'floatProfit', label: '浮动盈亏' },
|
||||
]
|
||||
|
|
@ -0,0 +1,113 @@
|
|||
<template>
|
||||
<div class="trade-software">
|
||||
<el-card>
|
||||
<div class="left">
|
||||
<el-icon>
|
||||
<Monitor />
|
||||
</el-icon>
|
||||
<span class="title">PC端</span>
|
||||
<el-icon class="download">
|
||||
<Bottom />
|
||||
</el-icon>
|
||||
</div>
|
||||
<div class="right">
|
||||
<span class="text">系统要求:适用于windows 2008/7/8/10操作系统,网络速度为56kbps或更高</span>
|
||||
</div>
|
||||
</el-card>
|
||||
<el-card>
|
||||
<div class="left">
|
||||
<el-icon>
|
||||
<svg t="1774244659320" class="icon" viewBox="0 0 1024 1024" version="1.1"
|
||||
xmlns="http://www.w3.org/2000/svg" p-id="2548" width="200" height="200">
|
||||
<path
|
||||
d="M839.562 344.72c-30.082 0-54.476 24.771-54.476 55.326l0 216.209c0 30.558 24.393 55.328 54.476 55.328 30.087 0 54.476-24.771 54.476-55.328l0-216.209c0.001-30.555-24.387-55.326-54.476-55.326zM182.482 344.72c-30.085 0-54.476 24.771-54.476 55.326l0 216.209c0 30.558 24.391 55.328 54.476 55.328s54.476-24.771 54.476-55.328l0-216.209c0-30.555-24.391-55.326-54.476-55.326zM269.74 346.395l0 395.014c0 23.462 19.02 42.481 42.483 42.481l48.533 0 0 120.293c0 30.558 24.391 55.328 54.476 55.328 30.087 0 54.478-24.771 54.478-55.328l0-120.294 84.786 0 0 120.293c0 30.558 24.393 55.328 54.476 55.328 30.087 0 54.481-24.771 54.481-55.328l0-120.293 48.528 0c23.467 0 42.485-19.018 42.485-42.481l0-395.013-484.725 0zM625.92 141.706l44.777-64.999c2.657-3.861 1.997-8.932-1.478-11.326-3.475-2.392-8.447-1.204-11.104 2.659l-46.512 67.518c-30.65-12.075-64.707-18.805-100.581-18.805-35.874 0-69.929 6.729-100.579 18.805l-46.512-67.518c-2.659-3.863-7.631-5.05-11.106-2.659-3.475 2.395-4.134 7.466-1.476 11.326l44.777 64.999c-71.188 33.117-121.113 96.042-127.467 169.487l484.727 0c-6.355-73.445-56.28-136.37-127.466-169.487zM408.772 244.144c-14.811 0-26.819-12.005-26.819-26.819 0-14.811 12.007-26.819 26.819-26.819 14.813 0 26.819 12.007 26.819 26.819 0 14.813-12.005 26.819-26.819 26.819zM616.625 244.144c-14.811 0-26.816-12.005-26.816-26.819 0-14.811 12.004-26.819 26.816-26.819 14.816 0 26.821 12.007 26.821 26.819 0 14.813-12.004 26.819-26.821 26.819z"
|
||||
fill="#272636" p-id="2549"></path>
|
||||
</svg>
|
||||
</el-icon>
|
||||
<span class="title">Android APK</span>
|
||||
<el-icon class="download">
|
||||
<Bottom />
|
||||
</el-icon>
|
||||
</div>
|
||||
<div class="right">
|
||||
<span class="text">下载说明:下载后可以通过手机安装APK</span>
|
||||
</div>
|
||||
</el-card>
|
||||
<el-card>
|
||||
<div class="left">
|
||||
<el-icon>
|
||||
<svg t="1774244690948" class="icon" viewBox="0 0 1024 1024" version="1.1"
|
||||
xmlns="http://www.w3.org/2000/svg" p-id="3750" width="200" height="200">
|
||||
<path
|
||||
d="M836.608 675.84q41.984 59.392 96.256 76.8-23.552 72.704-74.752 151.552-78.848 118.784-155.648 118.784-28.672 0-84.992-19.456-52.224-19.456-91.136-19.456t-86.016 20.48q-49.152 19.456-80.896 19.456-92.16 0-181.248-156.672-89.088-154.624-89.088-304.128 0-138.24 67.584-226.304 69.632-88.064 172.032-88.064 22.528 0 50.176 5.632t57.344 20.992q31.744 17.408 52.224 24.064t31.744 6.656q13.312 0 40.96-6.144t55.296-22.528q29.696-16.384 51.2-24.576t44.032-8.192q71.68 0 129.024 38.912 30.72 20.48 62.464 60.416-47.104 40.96-68.608 71.68-39.936 57.344-39.936 124.928 0 74.752 41.984 135.168z m-205.824-478.208q-35.84 33.792-65.536 44.032-10.24 3.072-26.112 5.632t-36.352 4.608q1.024-90.112 47.104-155.648T701.44 6.144q2.048 10.24 3.072 14.336v11.264q0 36.864-17.408 82.944-18.432 45.056-56.32 82.944z"
|
||||
fill="#272636" p-id="3751"></path>
|
||||
</svg>
|
||||
</el-icon>
|
||||
<span class="title">IOS</span>
|
||||
<el-icon class="download">
|
||||
<Bottom />
|
||||
</el-icon>
|
||||
</div>
|
||||
<div class="right">
|
||||
<span class="text">下载说明:iPhone和iPad用户可以通过 Apple App Store搜索InTrade安装</span>
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { Monitor, Bottom } from '@element-plus/icons-vue'
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.trade-software {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 20px;
|
||||
|
||||
.el-card {
|
||||
:deep(.el-card__body) {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.left {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
|
||||
.title {
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
|
||||
.right {
|
||||
.text {
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
.left,
|
||||
.right {
|
||||
.el-icon{
|
||||
font-size: 30px;
|
||||
}
|
||||
.download {
|
||||
font-size: 20px;
|
||||
cursor: pointer;
|
||||
|
||||
&:before {
|
||||
content: "";
|
||||
display: block;
|
||||
height: 2px;
|
||||
width: 16px;
|
||||
background: var(--el-text-color-primary);
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,140 @@
|
|||
<template>
|
||||
<div class="user-card">
|
||||
<UserHeader />
|
||||
<UserText :user-text="userText" @back="handleBack" />
|
||||
<el-form class="user-form" ref="bindEmailFormRef" :model="bindEmailForm" :rules="bindEmailRules">
|
||||
<el-form-item prop="email">
|
||||
<el-input v-model="bindEmailForm.email" placeholder="请输入邮箱" type="email" clearable
|
||||
size="large" />
|
||||
</el-form-item>
|
||||
<UserCaptcha v-model="bindEmailForm.code" @sendCode="handleSendCode" :show-send-button="showSendButton"
|
||||
:send-state="sendState" />
|
||||
<el-form-item class="form-submit">
|
||||
<el-button type="primary" @click="handleSubmit">确认绑定</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
// alert('绑定邮箱')
|
||||
// type类型
|
||||
import type { FormInstance, FormRules } from 'element-plus'
|
||||
// 组件
|
||||
import UserHeader from './components/Header.vue'
|
||||
import UserText from './components/Text.vue'
|
||||
import UserCaptcha from './components/Captcha.vue'
|
||||
//用户校验规则
|
||||
import { emailRules, codeRules } from './config/rules'
|
||||
import { useUserStore } from '@/stores/modules/user'
|
||||
import { sendCaptcha, initCaptchaState, clearCaptchaTimer } from '@/utils/sendCaptcha'
|
||||
|
||||
const userStore = useUserStore()
|
||||
const router = useRouter()
|
||||
|
||||
//userText 实例
|
||||
const userText = ref({
|
||||
backText: '返回',
|
||||
account: ''
|
||||
})
|
||||
|
||||
// bindEmail 表单实例
|
||||
const bindEmailFormRef = ref<FormInstance>()
|
||||
const bindEmailForm = ref({
|
||||
email: '',
|
||||
code: '',
|
||||
})
|
||||
const bindEmailRules = ref<FormRules>({
|
||||
email: emailRules().email,
|
||||
code: codeRules().code,
|
||||
})
|
||||
|
||||
|
||||
// 验证码实例
|
||||
const showSendButton = ref<boolean>(true)
|
||||
const sendState = ref<object>({
|
||||
isCounting: false,
|
||||
countdown: 0,
|
||||
})
|
||||
//初始化验证码倒计时状态
|
||||
const emailCaptchaState = initCaptchaState('email');
|
||||
// 邮箱验证码状态
|
||||
const { isCounting: emailIsCounting, countdown: emailCountdown } = emailCaptchaState
|
||||
|
||||
//方法
|
||||
// 统一更新sendState的方法
|
||||
const updateSendState = (type: string) => {
|
||||
sendState.value = {
|
||||
isCounting: emailIsCounting,
|
||||
countdown: emailCountdown
|
||||
}
|
||||
}
|
||||
// 初始化时根据当前activeTab更新sendState(避免刷新后丢失)
|
||||
const initSendState = () => {
|
||||
const currentType = 'email'
|
||||
updateSendState(currentType)
|
||||
}
|
||||
onMounted(() => {
|
||||
// 页面加载时立即执行,恢复倒计时
|
||||
initSendState()
|
||||
})
|
||||
|
||||
|
||||
// 定义发送验证码接口
|
||||
const sendCodeApi = async () => {
|
||||
// 发送验证码参数
|
||||
const sendParams = {
|
||||
email: bindEmailForm.value.email,
|
||||
reg_type: 1,
|
||||
type:'resetPass_code'
|
||||
}
|
||||
return userStore.sendCode(sendParams)
|
||||
}
|
||||
|
||||
//发送验证码
|
||||
const handleSendCode = async () => {
|
||||
const currentType = 'email'
|
||||
// 第二步:确定类型、接收方、对应的倒计时状态和发送函数
|
||||
const type: string = currentType || 'email'
|
||||
const receiver = bindEmailForm.value.email;
|
||||
const currentCaptchaState = emailCaptchaState;
|
||||
|
||||
// 第三步:调用封装的发送函数(传正确的函数,而非字符串)
|
||||
await sendCaptcha(
|
||||
type,
|
||||
receiver,
|
||||
currentCaptchaState, // 只更新当前类型的倒计时状态
|
||||
() => sendCodeApi() // 传入返回Promise的函数
|
||||
);
|
||||
|
||||
//把状态同步给子组件
|
||||
updateSendState(type)
|
||||
}
|
||||
// 组件卸载时清除定时器(关键:防止内存泄漏)
|
||||
onUnmounted(() => {
|
||||
clearCaptchaTimer(emailCaptchaState);
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @description: 返回
|
||||
*/
|
||||
const handleBack = () => {
|
||||
router.back()
|
||||
}
|
||||
|
||||
// 提交表单
|
||||
const handleSubmit = async () => {
|
||||
if (!bindEmailFormRef.value) return;
|
||||
await bindEmailFormRef.value.validate();
|
||||
}
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
.user-card{
|
||||
.user-text{
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,187 @@
|
|||
<template>
|
||||
<div class="user-card">
|
||||
<UserHeader />
|
||||
<UserText :user-text="userText" @back="handleBack" />
|
||||
<el-form class="user-form" ref="bindPhoneFormRef" :model="bindPhoneForm" :rules="bindPhoneRules">
|
||||
<el-form-item class="phone-item" prop="phone">
|
||||
<el-select v-model="bindPhoneForm.countryCode" :teleported="false" value-key="code" placeholder="国家"
|
||||
size="large">
|
||||
<el-option v-for="item in countryOptions" :key="item.code" :label="item.code" :value="item.code">
|
||||
<div class="country-option">
|
||||
<span class="country-name">{{ item.name }}</span>
|
||||
<span class="country-code">{{ item.code }}</span>
|
||||
</div>
|
||||
</el-option>
|
||||
</el-select>
|
||||
<el-input v-model="bindPhoneForm.phone" placeholder="请输入手机号" clearable size="large" />
|
||||
</el-form-item>
|
||||
<UserCaptcha v-model="bindPhoneForm.code" @sendCode="handleSendCode" :show-send-button="showSendButton"
|
||||
:send-state="sendState" />
|
||||
<el-form-item class="form-submit">
|
||||
<el-button type="primary" @click="handleSubmit">确认绑定</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
// alert('绑定邮箱')
|
||||
// type类型
|
||||
import type { FormInstance, FormRules } from 'element-plus'
|
||||
// 组件
|
||||
import UserHeader from './components/Header.vue'
|
||||
import UserText from './components/Text.vue'
|
||||
import UserCaptcha from './components/Captcha.vue'
|
||||
//用户校验规则
|
||||
import { emailRules, codeRules } from './config/rules'
|
||||
import { useUserStore } from '@/stores/modules/user'
|
||||
import { sendCaptcha, initCaptchaState, clearCaptchaTimer } from '@/utils/sendCaptcha'
|
||||
import { countryOptions } from '@/views/user/config/mock'
|
||||
|
||||
const userStore = useUserStore()
|
||||
const router = useRouter()
|
||||
|
||||
//userText 实例
|
||||
const userText = ref({
|
||||
backText: '返回',
|
||||
account: ''
|
||||
})
|
||||
|
||||
// bindPhone 表单实例
|
||||
const bindPhoneFormRef = ref<FormInstance>()
|
||||
const bindPhoneForm = ref({
|
||||
phone: '',
|
||||
code: '',
|
||||
countryCode: '+86',
|
||||
})
|
||||
const bindPhoneRules = ref<FormRules>({
|
||||
phone: emailRules().phone,
|
||||
code: codeRules().code,
|
||||
})
|
||||
|
||||
|
||||
// 验证码实例
|
||||
const showSendButton = ref<boolean>(true)
|
||||
const sendState = ref<object>({
|
||||
isCounting: false,
|
||||
countdown: 0,
|
||||
})
|
||||
//初始化验证码倒计时状态
|
||||
const phoneCaptchaState = initCaptchaState('phone');
|
||||
// 邮箱验证码状态
|
||||
const { isCounting: phoneIsCounting, countdown: phoneCountdown } = phoneCaptchaState
|
||||
|
||||
//方法
|
||||
// 统一更新sendState的方法
|
||||
const updateSendState = (type: string) => {
|
||||
sendState.value = {
|
||||
isCounting: phoneIsCounting,
|
||||
countdown: phoneCountdown
|
||||
}
|
||||
}
|
||||
// 初始化时根据当前activeTab更新sendState(避免刷新后丢失)
|
||||
const initSendState = () => {
|
||||
const currentType = 'phone'
|
||||
updateSendState(currentType)
|
||||
}
|
||||
onMounted(() => {
|
||||
// 页面加载时立即执行,恢复倒计时
|
||||
initSendState()
|
||||
})
|
||||
|
||||
|
||||
// 定义发送验证码接口
|
||||
const sendCodeApi = async () => {
|
||||
// 发送验证码参数
|
||||
const sendParams = {
|
||||
mobile: bindPhoneForm.value.phone,
|
||||
reg_type: 2,
|
||||
type: 'resetPass_code'
|
||||
}
|
||||
return userStore.sendCode(sendParams)
|
||||
}
|
||||
|
||||
//发送验证码
|
||||
const handleSendCode = async () => {
|
||||
const currentType = 'phone'
|
||||
// 第二步:确定类型、接收方、对应的倒计时状态和发送函数
|
||||
const type: string = currentType || 'phone'
|
||||
const receiver = bindPhoneForm.value.phone;
|
||||
const currentCaptchaState = phoneCaptchaState;
|
||||
|
||||
// 第三步:调用封装的发送函数(传正确的函数,而非字符串)
|
||||
await sendCaptcha(
|
||||
type,
|
||||
receiver,
|
||||
currentCaptchaState, // 只更新当前类型的倒计时状态
|
||||
() => sendCodeApi() // 传入返回Promise的函数
|
||||
);
|
||||
|
||||
//把状态同步给子组件
|
||||
updateSendState(type)
|
||||
}
|
||||
// 组件卸载时清除定时器(关键:防止内存泄漏)
|
||||
onUnmounted(() => {
|
||||
clearCaptchaTimer(phoneCaptchaState);
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @description: 返回
|
||||
*/
|
||||
const handleBack = () => {
|
||||
router.back()
|
||||
}
|
||||
|
||||
// 提交表单
|
||||
const handleSubmit = async () => {
|
||||
if (!bindPhoneFormRef.value) return;
|
||||
await bindPhoneFormRef.value.validate();
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.user-card{
|
||||
.user-text{
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
.user-form {
|
||||
.phone-item {
|
||||
:deep(.el-form-item__content) {
|
||||
flex-wrap: nowrap;
|
||||
}
|
||||
|
||||
.el-select {
|
||||
width: 120px;
|
||||
margin-right: 10px;
|
||||
|
||||
.country-option {
|
||||
width: 120px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
:deep(.el-select-dropdown__item) {
|
||||
padding: 0 16px 0 16px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.forgot-password {
|
||||
font-size: 14px;
|
||||
color: #409eff;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.form-submit {
|
||||
margin-top: 18px;
|
||||
|
||||
:deep(.el-form-item__content) {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Loading…
Reference in New Issue