foreign-admin-ui/src/views/profile/agent/index.vue

654 lines
20 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

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

<template>
<div class="table_form-container">
<!-- 搜索 -->
<CustomerListSearch :buttonLoading="loading" :search-form="searchForm" :search-options="searchOptions" @search="handleSearch"
@reset="handleReset"></CustomerListSearch>
<!-- 表格 -->
<CustomerListTable :table-data="tableTree" :columns="tableColumnsOptions" row-key="userId"
:default-sort="{ prop: 'createTime', order: 'descending' }" :loading="loading" @expand-change="handleGetSubList">
<template #marginRatio="{ row }">
<el-button v-if="row.role_id === 5" type="primary" size="small" v-auth="'agent_getSelfVarietyPointDiffConfig'"
@click="handleMarginRatio(row)">
修改
</el-button>
</template>
<template #commissionRatio="{ row }">
<el-button v-if="row.role_id === 5" type="primary" size="small" @click="handleCommissionRatio(row)"
v-auth="'agent_editAgent'">
修改
</el-button>
</template>
<template #action="{ row }">
<!-- <el-button link type="primary" size="small" @click="handleDetail(row)" v-if="row.userId">
查看详情
</el-button> -->
<!-- <el-divider direction="vertical" /> -->
<el-button link type="primary" size="small" @click="handleEditCustomer(row)">
编辑
</el-button>
<el-divider direction="vertical" />
<el-button link type="warning" size="small" @click="handleAdjustAmount(row)">
调整金额
</el-button>
</template>
</CustomerListTable>
<!-- 分页 -->
<CustomerListPagination v-model="currentPage" v-model:pageSizeValue="pageSize" :total="total"
@pagination-change="handlePaginationChange" />
<!-- dialog -->
<CustomerListDialog :visible="dialogVisible" :title="dialogTitle" :type="dialogType" :fullscreen="dialogFullscreen"
:show-footer="dialogType !== 'view'" :button-loading="submitLoading" @confirm="handleSubmit" @cancel="handleCancel" @close="handleClose">
<CustomerListTable :table-data="marginRatioTree" :columns="marginRatioTableColumnsOptions" row-key="id"
v-if="dialogType === 'editMarginRatio'" style="height: 500px">
<template #assignedPointDiff="{ row }">
<el-form :model="row" :rules="marginRatioRules(row)" :ref="(el) => setFormRef(el, row.id)">
<el-form-item prop="assignedPointDifference">
<el-input v-model="row.assignedPointDifference" size="small" placeholder="请输入点差" />
</el-form-item>
</el-form>
</template>
</CustomerListTable>
<CustomerListForm :form-data="commissionRatioForm" :form-rules="commissionRatioFormRules"
:form-items="commissionRatioFormItemOptions" ref="commissionRatioFormRef"
v-if="dialogType === 'editCommissionRatio'"></CustomerListForm>
</CustomerListDialog>
<!-- 调整金额弹窗 -->
<CustomerListDialog :visible="adjustAmountVisible" title="调整金额" type="adjust" :button-loading="adjustAmountLoading" @confirm="handleAdjustAmountSubmit"
@cancel="handleAdjustAmountCancel" @close="handleAdjustAmountClose">
<el-form :model="adjustAmountForm" :rules="adjustAmountRules" ref="adjustAmountFormRef" label-width="120px">
<el-form-item label="账号名" prop="username">
<el-input v-model="adjustAmountForm.username" disabled />
</el-form-item>
<el-form-item label="币种" prop="currency">
<el-input v-model="adjustAmountForm.currency" disabled />
</el-form-item>
<el-form-item label="当前余额" prop="currentBalance">
<el-input v-model="adjustAmountForm.currentBalance" disabled />
</el-form-item>
<el-form-item label="调整金额" prop="adjustAmount">
<el-input v-model="adjustAmountForm.adjustAmount" placeholder="请输入调整金额(可为负数)"
@input="handleAdjustAmountInput" />
</el-form-item>
<el-form-item label="调整后余额" prop="afterBalance">
<el-input v-model="adjustAmountForm.afterBalance" disabled />
</el-form-item>
</el-form>
</CustomerListDialog>
<!-- 修改客户弹窗 -->
<CustomerListDialog :visible="editCustomerVisible" title="修改客户" type="editCustomer"
:button-loading="editCustomerLoading" @confirm="handleEditCustomerSubmit" @cancel="handleEditCustomerCancel" @close="handleEditCustomerClose">
<el-form :model="editCustomerForm" :rules="editCustomerRules" ref="editCustomerFormRef" label-width="140px">
<el-form-item label="手续费模板" prop="feeSettingId">
<el-select v-model="editCustomerForm.feeSettingId" placeholder="请选择手续费模板" style="width: 100%">
<el-option v-for="item in feeTemplateOptions" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</el-form-item>
<el-form-item label="风控模板" prop="riskControlId">
<el-select v-model="editCustomerForm.riskControlId" placeholder="请选择风控模板" style="width: 100%">
<el-option v-for="item in riskTemplateOptions" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</el-form-item>
<el-form-item label="客户名称" prop="username">
<el-input v-model="editCustomerForm.username" placeholder="请输入客户名称" />
</el-form-item>
<el-form-item label="选择状态" prop="status">
<el-radio-group v-model="editCustomerForm.status">
<el-radio :label="1">正常</el-radio>
<el-radio :label="2">封禁</el-radio>
</el-radio-group>
</el-form-item>
</el-form>
</CustomerListDialog>
</div>
</template>
<script setup lang="ts">
defineOptions({
name: 'Agent'
})
// 组件
import CustomerListSearch from '@/components/common/Search.vue'
import CustomerListTable from '@/components/common/Table.vue'
import { usePageLoading, useButtonLoading } from '@/composables/useLoading'
import CustomerListPagination from '@/components/common/Pagination.vue'
import CustomerListDialog from '@/components/common/Dialog.vue'
import CustomerListForm from '@/components/common/Form.vue'
// 配置以及表单验证
import { search, tableColumns, marginRatioTableColumns, commissionRatioFormItem } from './options'
// 接口
import { getSelfVarietyPointDiffConfigApi, editCustomerApi } from '@/api/modules/agent/customerList'
import { updateCapitalApi, editUserApi } from '@/api/modules/user'
import { getFeeTemplateOptionsApi, getRiskTemplateOptionsApi } from '@/api/modules/account/client'
import { getAgentListApi } from '@/api/modules/profile/agent.ts'
// 公用方法
import { getStorage } from '@/utils/storage'
const router = useRouter()
/**
* @description: 获取用户id
*/
const userInfo: any = getStorage('userInfo')
const userId = ref(userInfo?.id || '')
/**
* @description: 定义搜索数据
*/
const searchForm = ref({
accountName: '',
startTime: '',
endTime: '',
status: '',
})
const searchOptions = ref(search)
const tableColumnsOptions = ref(tableColumns)
const { loading, startLoading, stopLoading } = usePageLoading()
const { buttonLoading: submitLoading, startButtonLoading: startSubmitLoading, stopButtonLoading: stopSubmitLoading } = useButtonLoading()
const { buttonLoading: adjustAmountLoading, startButtonLoading: startAdjustAmountLoading, stopButtonLoading: stopAdjustAmountLoading } = useButtonLoading()
const { buttonLoading: editCustomerLoading, startButtonLoading: startEditCustomerLoading, stopButtonLoading: stopEditCustomerLoading } = useButtonLoading()
/**
* @description: 定义表格数据
*/
const tableTree = ref([])
const treeProps = { children: 'children', hasChildren: 'hasChildren' }
/**
* @description: 定义分页数据
*/
const total = ref(0)
const currentPage = ref(1)
const pageSize = ref(10)
/**
* @description: 定义弹窗数据
*/
const dialogVisible = ref<boolean>(false)
const dialogTitle = ref<string>('')
const dialogType = ref<string>('')
const dialogFullscreen = ref(false)
/**
* @description: 定义点差表格数据
*/
const marginRatioTree = ref([])
const marginRatioTableColumnsOptions = ref(marginRatioTableColumns)
// 存储所有行的表单
const formRefs: any = ref({})
// 动态存储每行表单
const setFormRef = (el: any, id: any) => {
if (el) formRefs.value[id] = el
}
// 点差验证规则
const marginRatioRules = (row: any) => {
return {
assignedPointDifference: [
{ required: true, message: '请输入数字', trigger: ['blur', 'change'] },
{
pattern: /^\d+(\.\d+)?$/,
message: '只能输入数字(可带小数)',
trigger: ['blur', 'change'],
},
{
validator: (rule: any, value: any, callback: any) => {
const inputVal = Number(value || 0)
const maxVal = Number(row.pointDifference || 0)
if (inputVal > maxVal) {
callback(new Error('不能大于可分配点数'))
} else {
callback()
}
},
trigger: ['blur', 'change'],
},
],
}
}
/**
* @description: 定义手续费form数据
*/
const commissionRatioForm = ref({
commissionRatio: '',
})
const commissionRatioFormRef = ref()
const commissionRatioFormRules = {
commissionRatio: [
{ required: true, message: '请输入手续费分成比例', trigger: ['blur', 'change'] },
{ pattern: /^\d+(\.\d+)?$/, message: '只能输入数字(可带小数)', trigger: ['blur', 'change'] },
],
}
const commissionRatioFormItemOptions = ref(commissionRatioFormItem)
const selectId = ref('')
/**
* @description 定义修改客户弹窗数据
*/
const editCustomerVisible = ref(false)
const editCustomerFormRef = ref()
const editCustomerUserId = ref<number>(0)
const editCustomerForm = ref({
feeSettingId: '',
riskControlId: '',
username: '',
status: 1,
roleId: 0,
})
const editCustomerRules = {
feeSettingId: [{ required: true, message: '请选择手续费模板', trigger: 'change' }],
riskControlId: [{ required: true, message: '请选择风控模板', trigger: 'change' }],
status: [{ required: true, message: '请选择状态', trigger: 'change' }],
}
const feeTemplateOptions = ref<any[]>([])
const riskTemplateOptions = ref<any[]>([])
const templateOptionsFetched = ref(false)
/**
* @description 定义调整金额弹窗数据
*/
const adjustAmountVisible = ref(false)
const adjustAmountFormRef = ref()
const adjustUserId = ref<number>(0)
const adjustAmountForm = ref({
username: '',
currency: '',
currentBalance: '',
adjustAmount: '',
afterBalance: '',
})
const adjustAmountRules = {
adjustAmount: [
{ required: true, message: '请输入调整金额', trigger: 'blur' },
{
validator: (rule: any, value: any, callback: any) => {
if (value === '' || value === null || value === undefined) {
callback(new Error('请输入调整金额'))
} else if (!/^-?\d+(\.\d{1,5})?$/.test(value)) {
callback(new Error('请输入有效的金额格式,最多五位小数'))
} else {
callback()
}
},
trigger: 'blur',
},
],
}
/**
* @description: 角色映射方法
*/
const roleMap: any = {
1: '平台',
2: '承包商',
3: '特殊做市商',
4: '普通做市商',
5: '代理',
6: '用户',
}
/**
* @description: 定义公共请求数据方法
*/
// 获取客户列表
const getCustomerList = async () => {
startLoading()
const params = {
page: currentPage.value,
page_size: pageSize.value,
user_name: searchForm.value.accountName,
reg_start_time: searchForm.value.startTime,
reg_end_time: searchForm.value.endTime,
status: searchForm.value.status,
}
const data: any = await getAgentListApi(params)
tableTree.value = data.data.map((item: any) => ({
...item,
accountName: item.username,
amount: item.wallet_capital.amount,
userId: item.id,
status: item.status === 1 ? '正常' : '禁用',
role: item.role.title || '未知',
accountQty: item.son_user[0]?.son_user_count,
commissionRatio: item?.wallet_capital?.fee_handling_percent,
createTime: item.created_at,
role_id: item.role_id,
}))
//分页数据
total.value = data.total
stopLoading()
currentPage.value = data.current_page
pageSize.value = Number(data.per_page)
}
//获取代理点差数据
const getSelfVarietyPointDiffConfig = async (id: string) => {
const params = {
user_id: id,
}
const data: any = await getSelfVarietyPointDiffConfigApi(params)
marginRatioTree.value = data.map((item: any) => ({
id: item.id,
varietyName: item.name,
varietyCode: item.code,
pointDifference: item.point_diff,
assignedPointDifference: item.target_point_diff,
}))
}
/**
* @description: 页面加载完成需要请求的数据
*/
onMounted(() => {
getCustomerList()
})
/**
* @description: 定义搜索方法
*/
const handleSearch = async () => {
getCustomerList()
}
const handleReset = () => {
searchForm.value = {
accountName: '',
startTime: '',
endTime: '',
status: '',
}
getCustomerList()
}
/**
* @description: 定义表格方法
*/
const handleDetail = (row: any) => {
console.log('查看详情', row)
router.push(`/agent/customerDetail/${row.userId}`)
}
// 修改点差
const handleMarginRatio = (row: any) => {
getSelfVarietyPointDiffConfig(row.userId)
console.log('修改点差', row)
dialogVisible.value = true
dialogTitle.value = '修改点差'
dialogType.value = 'editMarginRatio'
selectId.value = row.userId
}
// 修改手续费比例
const handleCommissionRatio = (row: any) => {
console.log('修改手续费比例', row)
dialogVisible.value = true
dialogTitle.value = '修改手续费'
dialogType.value = 'editCommissionRatio'
selectId.value = row.userId
commissionRatioForm.value.commissionRatio = row.commissionRatio
}
// 获取子列表
const handleGetSubList = async (row: any) => {
const params = {
user_name: '',
user_id: row.userId,
page: currentPage.value,
page_size: pageSize.value,
reg_start_time: '',
reg_end_time: '',
status: '',
}
const data: any = await getAgentListApi(params)
if (data.data.length === 0) {
ElMessage({
message: '暂无数据',
type: 'error',
})
row.children = []
return
}
row.children = data.data.map((item: any) => ({
accountName: item.username,
userId: item.id,
status: item.status === 1 ? '正常' : '禁用',
role: roleMap[item.role_id] || '未知',
accountQty: item.account[0].account_count,
commissionRatio: item.wallet_capital.fee_handling_percent,
createTime: item.created_at,
role_id: item.role_id,
children:
item.role_id === 5
? [
{
hasChildren: true,
},
]
: undefined,
}))
}
/**
* @description: 定义分页方法
*/
const handlePaginationChange = (page: { currentPage: number; pageSize: number }) => {
currentPage.value = page.currentPage
pageSize.value = page.pageSize
getCustomerList()
}
/**
* @description: 定义弹窗方法
*/
const handleSubmit = async () => {
startSubmitLoading()
try {
const params = {
user_id: selectId.value,
toucun_percent: '',
point_diffs_json: '',
fee_handling_percent: '',
fee_setting_id: '',
risk_control_id: '',
}
if (dialogType.value === 'editMarginRatio') {
// 逐行验证
for (const row of marginRatioTree.value) {
const form = formRefs.value[(row as any).id]
if (!form) continue
try {
await form.validate()
} catch (err) {
console.error(`${(row as any).id} 行验证不通过,请检查`)
return
}
}
//转换为接口需要的格式 { id: assignedPointDifference }
const marginRatioJSON = marginRatioTree.value.reduce((acc: any, cur: any) => {
acc[cur.id] = cur.assignedPointDifference * 1
return acc
}, {})
// 调用接口
try {
await editCustomerApi({ ...params, point_diffs_json: JSON.stringify(marginRatioJSON) })
dialogVisible.value = false
} catch (err) {
console.log('提交失败:', err)
}
}
if (dialogType.value === 'editCommissionRatio') {
await commissionRatioFormRef.value.validate()
try {
await editCustomerApi({
...params,
fee_handling_percent: commissionRatioForm.value.commissionRatio,
})
dialogVisible.value = false
await getCustomerList()
} catch (err) {
console.log('提交失败:', err)
}
}
} finally {
stopSubmitLoading()
}
}
// 取消
const handleCancel = () => {
dialogVisible.value = false
}
// 关闭
const handleClose = () => {
dialogVisible.value = false
}
/**
* @description: 定义弹窗表格方法
*/
/**
* @description 调整金额相关方法
*/
// 打开调整金额弹窗
const handleAdjustAmount = (row: any) => {
adjustAmountVisible.value = true
adjustUserId.value = row.userId
const balance = row.balance || row.wallet_capital?.amount || '0'
adjustAmountForm.value = {
username: row.accountName,
currency: 'USDT',
currentBalance: balance,
adjustAmount: '',
afterBalance: balance,
}
}
// 调整金额输入变化时计算调整后余额
const handleAdjustAmountInput = () => {
const currentBalance = parseFloat(adjustAmountForm.value.currentBalance) || 0
const adjustAmount = parseFloat(adjustAmountForm.value.adjustAmount) || 0
const afterBalance = currentBalance + adjustAmount
adjustAmountForm.value.afterBalance = afterBalance.toFixed(5)
}
// 提交调整金额
const handleAdjustAmountSubmit = async () => {
startAdjustAmountLoading()
try {
await adjustAmountFormRef.value?.validate()
await updateCapitalApi({
target_user_id: adjustUserId.value,
amount: adjustAmountForm.value.adjustAmount,
})
await getCustomerList()
adjustAmountVisible.value = false
} catch (err) {
console.error('调整金额表单验证失败', err)
} finally {
stopAdjustAmountLoading()
}
}
// 取消调整金额
const handleAdjustAmountCancel = () => {
adjustAmountVisible.value = false
}
// 关闭调整金额弹窗
const handleAdjustAmountClose = () => {
adjustAmountVisible.value = false
}
/**
* @description 修改客户相关方法
*/
// 获取模板选项
const getTemplateOptions = async () => {
if (templateOptionsFetched.value) return
try {
const [feeTemplateRes, riskTemplateRes] = await Promise.all([
getFeeTemplateOptionsApi(),
getRiskTemplateOptionsApi(),
])
feeTemplateOptions.value = Object.entries(feeTemplateRes as Record<string, string>).map(
([label, value]) => ({
label,
value,
}),
)
riskTemplateOptions.value = Object.entries(riskTemplateRes as Record<string, string>).map(
([label, value]) => ({
label,
value,
}),
)
templateOptionsFetched.value = true
} catch (error) {
console.error('获取模板选项失败:', error)
}
}
// 打开修改客户弹窗
const handleEditCustomer = async (row: any) => {
await getTemplateOptions()
editCustomerVisible.value = true
editCustomerUserId.value = row.userId
editCustomerForm.value = {
feeSettingId: row.wallet_capital?.fee_setting_id || '',
riskControlId: row.wallet_capital?.risk_control_id || '',
username: row.username || row.accountName || '',
status: row.status === '正常' ? 1 : row.status === '封禁' ? 2 : row.status,
roleId: row.role_id,
}
}
// 提交修改客户
const handleEditCustomerSubmit = async () => {
startEditCustomerLoading()
try {
await editCustomerFormRef.value?.validate()
await editUserApi({
user_id: editCustomerUserId.value,
fee_setting_id: editCustomerForm.value.feeSettingId,
risk_control_id: editCustomerForm.value.riskControlId,
username: editCustomerForm.value.username,
is_levelup: null,
status: editCustomerForm.value.status,
})
await getCustomerList()
editCustomerVisible.value = false
} catch (err) {
console.error('修改客户表单验证失败', err)
} finally {
stopEditCustomerLoading()
}
}
// 取消修改客户
const handleEditCustomerCancel = () => {
editCustomerVisible.value = false
}
// 关闭修改客户弹窗
const handleEditCustomerClose = () => {
editCustomerVisible.value = false
}
</script>
<style scoped lang="scss">
:deep(.placeholder-row) {
text-align: center;
color: #909399;
/* 灰色和Element空状态颜色一致 */
}
</style>