代理列表

This commit is contained in:
2026-05-11 16:26:27 +08:00
parent d1a1cd1976
commit db0bfc7fd4
6 changed files with 308 additions and 128 deletions

View File

@ -81,7 +81,7 @@ export async function editUserApi(params: {
risk_control_id?: string | number; risk_control_id?: string | number;
fee_setting_id?: string | number; fee_setting_id?: string | number;
username?: string; username?: string;
is_levelup?: number; is_levelup?: number | null;
status?: number; status?: number;
}) { }) {
return request.post<boolean>('/user/editUser', params); return request.post<boolean>('/user/editUser', params);

View File

@ -3,60 +3,38 @@
<el-form :model="searchForm" inline @submit.prevent> <el-form :model="searchForm" inline @submit.prevent>
<!-- 动态生成的表单项 --> <!-- 动态生成的表单项 -->
<template v-for="item in searchOptions" :key="item.prop"> <template v-for="item in searchOptions" :key="item.prop">
<el-form-item <el-form-item v-auth="item.auth || ''" :label="item.label" :prop="item.prop" v-if="!item.slot" :style="{
v-auth="item.auth || ''" minWidth: item.minWidth,
:label="item.label" width: item.width,
:prop="item.prop" flex: item.width ? '0 0 auto' : '',
v-if="!item.slot" }">
:style="{
minWidth: item.minWidth,
width: item.width,
flex: item.width ? '0 0 auto' : '',
}"
>
<!-- 输入框 --> <!-- 输入框 -->
<el-input <el-input v-if="item.type === 'input'" v-model="searchForm[item.prop]"
v-if="item.type === 'input'" :placeholder="item.placeholder || `请输入${item.label}`" :clearable="item.clearable ?? true"
v-model="searchForm[item.prop]" :disabled="item.disabled" @blur="handleBlur" />
:placeholder="item.placeholder || `请输入${item.label}`"
:clearable="item.clearable ?? true"
:disabled="item.disabled"
@blur="handleBlur"
/>
<!-- 选择器 --> <!-- 选择器 -->
<el-select <el-select v-else-if="item.type === 'select'" v-model="searchForm[item.prop]"
v-else-if="item.type === 'select'" :placeholder="item.placeholder || `请选择${item.label}`" :clearable="item.clearable ?? true"
v-model="searchForm[item.prop]" :disabled="item.disabled">
:placeholder="item.placeholder || `请选择${item.label}`" <el-option v-for="option in item.options" :key="option.value" :label="option.label" :value="option.value" />
:clearable="item.clearable ?? true"
:disabled="item.disabled"
>
<el-option
v-for="option in item.options"
:key="option.value"
:label="option.label"
:value="option.value"
/>
</el-select> </el-select>
<!-- 日期选择器单个/范围 --> <!-- 日期选择器单个/范围 -->
<el-date-picker <el-date-picker v-else-if="item.type === 'date'" v-model="searchForm[item.prop]"
v-else-if="item.type === 'date'" :type="item.dateType || 'date'" :range-separator="item.rangeSeparator || '至'"
v-model="searchForm[item.prop]" :placeholder="item.placeholder"
:type="item.dateType || 'date'" :start-placeholder="item.startPlaceholder || '开始日期'" :end-placeholder="item.endPlaceholder || '结束日期'"
:range-separator="item.rangeSeparator || '至'" :value-format="item.valueFormat || 'YYYY-MM-DD'" :clearable="item.clearable ?? true"
:start-placeholder="item.startPlaceholder || '开始日期'" :disabled-date="item.disabledDate" :locale="'zhCn'" />
:end-placeholder="item.endPlaceholder || '结束日期'"
:value-format="item.valueFormat || 'YYYY-MM-DD'"
:clearable="item.clearable ?? true"
:disabled-date="item.disabledDate"
:locale="'zhCn'"
/>
</el-form-item> </el-form-item>
<!-- 自定义插槽项 --> <!-- 自定义插槽项 -->
<el-form-item :label="item.label" :prop="item.prop" v-else> <el-form-item v-else :label="item.label" :prop="item.prop" :style="{
minWidth: item.minWidth,
width: item.width,
flex: item.width ? '0 0 auto' : '',
}">
<slot :name="item.prop" :form="searchForm" /> <slot :name="item.prop" :form="searchForm" />
</el-form-item> </el-form-item>
</template> </template>
@ -137,20 +115,34 @@ const handleBlur = () => {
.el-form { .el-form {
display: flex; display: flex;
flex-wrap: wrap;
width: 100%; width: 100%;
row-gap: 8px;
.el-form-item {
flex: 1 1 auto;
}
} }
:deep(.el-form-item) { :deep(.el-form-item) {
margin-bottom: 0; margin-bottom: 0;
margin-right: 16px; margin-right: 16px;
flex: 1 1 auto;
min-width: 200px;
} }
:deep(.el-button) { :deep(.el-button) {
margin-left: 8px; margin-left: 8px;
white-space: nowrap;
}
:deep(.el-form-item:last-child) {
display: flex;
width: fit-content;
flex: 0 0 auto;
flex-wrap: wrap;
gap: 8px;
.el-form-item__content {
justify-content: flex-start;
row-gap: 4px;
}
} }
} }
</style> </style>

View File

@ -3,12 +3,12 @@ export const search = [
{ prop: 'accountName', label: '账号名称', type: 'input' as const, placeholder: '请输入账号名称', width: '150px' }, { prop: 'accountName', label: '账号名称', type: 'input' as const, placeholder: '请输入账号名称', width: '150px' },
// 开始时间 // 开始时间
{ {
prop: "startTime", label: '注册开始时间', type: 'date' as const, dateType: 'date' as const, // 时间范围选择器 prop: "startTime", label: '注册开始时间', type: 'date' as const, dateType: 'date' as const,placeholder: '请选择注册开始时间', width: '270px', // 时间范围选择器
valueFormat: 'YYYY-MM-DD', valueFormat: 'YYYY-MM-DD',
}, },
// 结束时间 // 结束时间
{ {
prop: "endTime", label: '注册结束时间', type: 'date' as const, dateType: 'date' as const, // 时间范围选择器 prop: "endTime", label: '注册结束时间', type: 'date' as const, dateType: 'date' as const,placeholder: '请选择注册结束时间', width: '270px', // 时间范围选择器
valueFormat: 'YYYY-MM-DD', valueFormat: 'YYYY-MM-DD',
}, },
// 状态 // 状态

View File

@ -323,8 +323,8 @@ onMounted(() => {
<style scoped lang="scss"> <style scoped lang="scss">
.rechange-page { .rechange-page {
height: 100%; max-height: 100%;
height: 100%;
.page-title { .page-title {
margin-bottom: 16px; margin-bottom: 16px;
font-size: 28px; font-size: 28px;

View File

@ -1,99 +1,107 @@
<template> <template>
<div> <div>
<!-- 搜索 --> <!-- 搜索 -->
<CustomerListSearch <CustomerListSearch :search-form="searchForm" :search-options="searchOptions" @search="handleSearch"
:search-form="searchForm" @reset="handleReset"></CustomerListSearch>
:search-options="searchOptions"
@search="handleSearch"
@reset="handleReset"
></CustomerListSearch>
<!-- 表格 --> <!-- 表格 -->
<CustomerListTable <CustomerListTable :table-data="tableTree" :columns="tableColumnsOptions" row-key="userId"
:table-data="tableTree" :default-sort="{ prop: 'createTime', order: 'descending' }" @expand-change="handleGetSubList">
:columns="tableColumnsOptions"
row-key="userId"
:default-sort="{ prop: 'createTime', order: 'descending' }"
@expand-change="handleGetSubList"
>
<template #marginRatio="{ row }"> <template #marginRatio="{ row }">
<el-button <el-button v-if="row.role_id === 5" type="primary" size="small" v-auth="'agent_getSelfVarietyPointDiffConfig'"
v-if="row.role_id === 5" @click="handleMarginRatio(row)">
type="primary"
size="small"
v-auth="'agent_getSelfVarietyPointDiffConfig'"
@click="handleMarginRatio(row)"
>
修改 修改
</el-button> </el-button>
</template> </template>
<template #commissionRatio="{ row }"> <template #commissionRatio="{ row }">
{{ row.commissionRatio }} {{ row.commissionRatio }}
<el-button <el-button v-if="row.role_id === 5" type="primary" size="small" @click="handleCommissionRatio(row)"
v-if="row.role_id === 5" v-auth="'agent_editAgent'">
type="primary"
size="small"
@click="handleCommissionRatio(row)"
v-auth="'agent_editAgent'"
>
修改 修改
</el-button> </el-button>
</template> </template>
<template #action="{ row }"> <template #action="{ row }">
<el-button link type="primary" size="small" @click="handleDetail(row)" v-if="row.userId"> <!-- <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> </el-button>
</template> </template>
</CustomerListTable> </CustomerListTable>
<!-- 分页 --> <!-- 分页 -->
<CustomerListPagination <CustomerListPagination v-model="currentPage" v-model:pageSizeValue="pageSize" :total="total"
v-model="currentPage" @pagination-change="handlePaginationChange" />
v-model:pageSizeValue="pageSize"
:total="total"
@pagination-change="handlePaginationChange"
/>
<!-- dialog --> <!-- dialog -->
<CustomerListDialog <CustomerListDialog :visible="dialogVisible" :title="dialogTitle" :type="dialogType" :fullscreen="dialogFullscreen"
:visible="dialogVisible" :show-footer="dialogType !== 'view'" @confirm="handleSubmit" @cancel="handleCancel" @close="handleClose">
:title="dialogTitle" <CustomerListTable :table-data="marginRatioTree" :columns="marginRatioTableColumnsOptions" row-key="id"
:type="dialogType" v-if="dialogType === 'editMarginRatio'" style="height: 500px">
:fullscreen="dialogFullscreen"
:show-footer="dialogType !== 'view'"
@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 }"> <template #assignedPointDiff="{ row }">
<el-form <el-form :model="row" :rules="marginRatioRules(row)" :ref="(el) => setFormRef(el, row.id)">
:model="row"
:rules="marginRatioRules(row)"
:ref="(el) => setFormRef(el, row.id)"
>
<el-form-item prop="assignedPointDifference"> <el-form-item prop="assignedPointDifference">
<el-input <el-input v-model="row.assignedPointDifference" size="small" placeholder="请输入点差" />
v-model="row.assignedPointDifference"
size="small"
placeholder="请输入点差"
/>
</el-form-item> </el-form-item>
</el-form> </el-form>
</template> </template>
</CustomerListTable> </CustomerListTable>
<CustomerListForm <CustomerListForm :form-data="commissionRatioForm" :form-rules="commissionRatioFormRules"
:form-data="commissionRatioForm" :form-items="commissionRatioFormItemOptions" ref="commissionRatioFormRef"
:form-rules="commissionRatioFormRules" v-if="dialogType === 'editCommissionRatio'"></CustomerListForm>
:form-items="commissionRatioFormItemOptions" </CustomerListDialog>
ref="commissionRatioFormRef"
v-if="dialogType === 'editCommissionRatio'" <!-- 调整金额弹窗 -->
></CustomerListForm> <CustomerListDialog :visible="adjustAmountVisible" title="调整金额" type="adjust" @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"
@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> </CustomerListDialog>
<!-- dialog表格 -->
</div> </div>
</template> </template>
@ -113,6 +121,8 @@ import { search, tableColumns, marginRatioTableColumns, commissionRatioFormItem
// //
import { getSelfVarietyPointDiffConfigApi, editCustomerApi } from '@/api/modules/agent/customerList' 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 { getAgentListApi } from '@/api/modules/profile/agent.ts'
// //
@ -212,6 +222,59 @@ const commissionRatioFormRules = {
const commissionRatioFormItemOptions = ref(commissionRatioFormItem) const commissionRatioFormItemOptions = ref(commissionRatioFormItem)
const selectId = ref('') 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: 角色映射方法 * @description: 角色映射方法
*/ */
@ -355,10 +418,10 @@ const handleGetSubList = async (row: any) => {
children: children:
item.role_id === 5 item.role_id === 5
? [ ? [
{ {
hasChildren: true, hasChildren: true,
}, },
] ]
: undefined, : undefined,
})) }))
} }
@ -435,6 +498,131 @@ const handleClose = () => {
/** /**
* @description: 定义弹窗表格方法 * @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 () => {
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)
}
}
//
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.feeSettingId || '',
riskControlId: row.riskControlId || '',
username: row.accountName || '',
status: row.status === '正常' ? 1 : 2,
roleId: row.role_id,
}
}
//
const handleEditCustomerSubmit = async () => {
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)
}
}
//
const handleEditCustomerCancel = () => {
editCustomerVisible.value = false
}
//
const handleEditCustomerClose = () => {
editCustomerVisible.value = false
}
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">

View File

@ -46,7 +46,7 @@ export const tableColumns = [
// 注册时间 // 注册时间
{ prop: 'createTime', label: '注册时间', sortable: true }, { prop: 'createTime', label: '注册时间', sortable: true },
// 操作 // 操作
// { label: '操作', slotName: 'action' } { label: '操作', slotName: 'action', width: '150px'}
] ]
// 点差表格配置 // 点差表格配置