This commit is contained in:
parent
5e940ceade
commit
4b712be3be
|
|
@ -18,6 +18,6 @@ export async function getFeeTemplateOptionsApi(): Promise<any> {
|
||||||
return request.get<any>('user/getFeeSettingOptions')
|
return request.get<any>('user/getFeeSettingOptions')
|
||||||
}
|
}
|
||||||
//编辑代理点差
|
//编辑代理点差
|
||||||
export async function editPointDiffConfigApi(params: pointDiffConfigParams): Promise<any> {
|
export async function editPointDiffApi(params: pointDiffConfigParams): Promise<any> {
|
||||||
return request.post<any>('/agent/editAgent',{...params})
|
return request.post<any>('/agent/editAgent',{...params})
|
||||||
}
|
}
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import { request } from '@/api';
|
import { request } from '@/api';
|
||||||
import type{ searchParams,pointDiffConfigParams } from '@/api/types/account/market'
|
import type{ searchParams,pointDiffConfigParams } from '@/api/types/account/market'
|
||||||
|
|
||||||
// 查询做市商列表
|
// 查询和获取做市商列表
|
||||||
export async function getMarketListApi(params: searchParams): Promise<any> {
|
export async function getMarketListApi(params: searchParams): Promise<any> {
|
||||||
return request.get<any>('agent/getAgentList', { ...params })
|
return request.get<any>('agent/getAgentList', { ...params })
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,7 @@
|
||||||
<!-- 操作按钮 -->
|
<!-- 操作按钮 -->
|
||||||
<el-form-item>
|
<el-form-item>
|
||||||
<el-button type="primary" @click="$emit('search')">
|
<el-button type="primary" @click="$emit('search')">
|
||||||
{{ buttonConfig.searchText || '查询' }}
|
{{ buttonConfig.searchText || '搜索' }}
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button @click="$emit('reset')">
|
<el-button @click="$emit('reset')">
|
||||||
{{ buttonConfig.resetText || '重置' }}
|
{{ buttonConfig.resetText || '重置' }}
|
||||||
|
|
|
||||||
|
|
@ -1,27 +1,67 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="agent">
|
<div class="agent">
|
||||||
<!-- 搜索 -->
|
<!-- 搜索 -->
|
||||||
<MarketSearch :search-form="searchForm" :search-options="searchOptions" @search="handleSearch" />
|
<AgentSearch :search-form="searchForm" :search-options="searchOptions" @search="handleSearch"
|
||||||
|
@reset="handleReset" />
|
||||||
<!-- 表格 -->
|
<!-- 表格 -->
|
||||||
<!-- <MarketTable :table-data="tableData" :table-columns="tableColumns" @change="handleChange" /> -->
|
<AgentTable :table-data="agentTree" :columns="agentTableColumnsOptions" row-key="id">
|
||||||
|
<template #status="{ row }">
|
||||||
|
<el-switch :model-value="row.status === 1" :active-value="true" :inactive-value="false" />
|
||||||
|
</template>
|
||||||
|
<template #pointDifference="{ row }">
|
||||||
|
<el-button type="primary" size="small" @click="handleViewPointDiff(row)">
|
||||||
|
查看
|
||||||
|
</el-button>
|
||||||
|
</template>
|
||||||
|
<template #edit="{ row }">
|
||||||
|
<el-button type="primary" size="small" @click="handleEdit(row)">
|
||||||
|
编辑
|
||||||
|
</el-button>
|
||||||
|
</template>
|
||||||
|
</AgentTable>
|
||||||
<!-- 分页 -->
|
<!-- 分页 -->
|
||||||
<!-- <MarketPagination :pagination="pagination" @change="handlePaginationChange" /> -->
|
<AgentPagination v-model="currentPage" v-model:pageSizeValue="pageSize" :total="total"
|
||||||
|
@pagination-change="handlePaginationChange" />
|
||||||
</div>
|
</div>
|
||||||
<!-- 弹窗 -->
|
<!-- 弹窗 -->
|
||||||
|
<AgentDialog :visible="dialogVisible" :title="dialogTitle" :type="dialogType" :fullscreen="dialogFullscreen"
|
||||||
|
:show-footer="dialogType !== 'view'" @confirm="handleSubmit" @cancel="handleCancel" @close="handleClose">
|
||||||
|
<!-- 编辑表单 -->
|
||||||
|
<AgentForm :form-data="agentForm" :form-rules="agentFormRules" :form-items="agentFormItemOptions"
|
||||||
|
:options-map="agentFormOptionsMap" ref="agentFormRef" v-if="dialogType !== 'view'"></AgentForm>
|
||||||
|
<!-- 点差表格 -->
|
||||||
|
<AgentTable :table-data="agentPointTree" :columns="agentPointTableColumnsOptions" row-key="id">
|
||||||
|
<template #assignedPointDiff="{ row }">
|
||||||
|
<el-form :model="row" :rules="rules()">
|
||||||
|
<el-form-item prop="assignedPointDifference">
|
||||||
|
<el-input v-model="row.assignedPointDifference" size="small" placeholder="请输入点差" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</template>
|
||||||
|
</AgentTable>
|
||||||
|
</AgentDialog>
|
||||||
<!-- 编辑/查看表单 -->
|
<!-- 编辑/查看表单 -->
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
//组件
|
//组件
|
||||||
import MarketSearch from '@/components/common/Search.vue'
|
import AgentSearch from '@/components/common/Search.vue'
|
||||||
import MarketTable from '@/components/common/Table.vue'
|
import AgentTable from '@/components/common/Table.vue'
|
||||||
import MarketPagination from '@/components/common/Pagination.vue'
|
import AgentPagination from '@/components/common/Pagination.vue'
|
||||||
import MarketDialog from '@/components/common/Dialog.vue'
|
import AgentDialog from '@/components/common/Dialog.vue'
|
||||||
import MarketForm from '@/components/common/Form.vue'
|
import AgentForm from '@/components/common/Form.vue'
|
||||||
|
|
||||||
//配置
|
//配置
|
||||||
|
import { agentSearch, agentTableColumns, viewAgentPointTableColumns, agentPointTableColumns, PointDiffFormItem } from './options'
|
||||||
|
import { rules } from './rules'
|
||||||
|
|
||||||
//接口
|
//接口
|
||||||
|
import { getAgentListApi, getPointDiffConfigApi, getRiskTemplateOptionsApi, getFeeTemplateOptionsApi, editPointDiffApi } from '@/api/modules/account/agent'
|
||||||
|
|
||||||
|
//引入公用方法
|
||||||
|
import { getStorage } from '@/utils/storage';
|
||||||
|
|
||||||
|
//获取当前登录用户的id
|
||||||
|
const useInfo = ref<any>(getStorage('userInfo'))
|
||||||
/**
|
/**
|
||||||
* @description 定义搜索数据
|
* @description 定义搜索数据
|
||||||
*/
|
*/
|
||||||
|
|
@ -31,18 +71,21 @@ const searchForm = ref({
|
||||||
startDateTime: '',
|
startDateTime: '',
|
||||||
endDateTime: '',
|
endDateTime: '',
|
||||||
})
|
})
|
||||||
const searchOptions = ref()
|
const searchOptions = ref(agentSearch)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description 定义表格数据
|
* @description 定义表格数据
|
||||||
*/
|
*/
|
||||||
const AgentTree = ref([])
|
const agentTree = ref([])
|
||||||
const agentTableColumnsOptions = ref()
|
const agentTableColumnsOptions = ref(agentTableColumns)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description 定义分页数据
|
* @description 定义分页数据
|
||||||
*/
|
*/
|
||||||
const total = ref(0)
|
const total = ref(0)
|
||||||
const pageSize = ref(10)
|
const pageSize = ref(10)
|
||||||
const currentPage = ref(1)
|
const currentPage = ref(1)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description 定义弹窗数据
|
* @description 定义弹窗数据
|
||||||
*/
|
*/
|
||||||
|
|
@ -50,44 +93,276 @@ const dialogVisible = ref<boolean>(false)
|
||||||
const dialogTitle = ref<string>('')
|
const dialogTitle = ref<string>('')
|
||||||
const dialogType = ref<string>('edit')
|
const dialogType = ref<string>('edit')
|
||||||
const dialogFullscreen = ref(false)
|
const dialogFullscreen = ref(false)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description 定义弹窗form数据
|
* @description 定义弹窗form数据
|
||||||
*/
|
*/
|
||||||
const agentForm = ref({})
|
const agentForm = ref({
|
||||||
const agentFormRules = ref()
|
username: '',
|
||||||
|
parentUsername: '',
|
||||||
|
riskTemplate: '',
|
||||||
|
feeTemplate: '',
|
||||||
|
positionRatio: '',
|
||||||
|
feeRate: '',
|
||||||
|
//存用户id
|
||||||
|
id: '',
|
||||||
|
})
|
||||||
|
const agentFormRules = rules()
|
||||||
const agentFormRef = ref()
|
const agentFormRef = ref()
|
||||||
const agentFormItemOptions = ref()
|
const agentFormItemOptions = ref(PointDiffFormItem)
|
||||||
const agentFormOptionsMap = ref()
|
//使用这个判断请求是否完成,去缓存请求
|
||||||
|
const optionsFetched = ref(false)
|
||||||
|
interface SelectOption {
|
||||||
|
label: string
|
||||||
|
value: string | number
|
||||||
|
}
|
||||||
|
const agentFormOptionsMap = ref({
|
||||||
|
riskTemplate: [] as SelectOption[],
|
||||||
|
feeTemplate: [] as SelectOption[],
|
||||||
|
})
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description 定义弹窗表格数据
|
* @description 定义弹窗表格数据
|
||||||
*/
|
*/
|
||||||
|
const agentPointTree = ref([])
|
||||||
|
const agentPointTableColumnsOptions = computed(() => {
|
||||||
|
return dialogType.value !== 'view' ? agentPointTableColumns : viewAgentPointTableColumns;
|
||||||
|
});
|
||||||
/**
|
/**
|
||||||
* @description 定义通用数据处理方法
|
* @description 定义通用数据处理方法
|
||||||
*/
|
*/
|
||||||
|
//处理字符串数值:转数字 + 相加 + 保留五位小数
|
||||||
|
function sumStrNumsWith5Decimals(strNums: string[]) {
|
||||||
|
// 1. 初始化总和
|
||||||
|
let total = 0;
|
||||||
|
|
||||||
|
// 2. 遍历数组,逐个转换并累加
|
||||||
|
strNums.forEach(strNum => {
|
||||||
|
// 转数字(处理空值/非数字,兜底为0)
|
||||||
|
const num = parseFloat(strNum) || 0;
|
||||||
|
total += num;
|
||||||
|
});
|
||||||
|
|
||||||
|
// 3. 保留五位小数(四舍五入),转回数字类型
|
||||||
|
const result = parseFloat(total.toFixed(5));
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 映射对象为数组通用方法
|
||||||
|
const mapObjectToOptions = (obj: Record<string, string>) => {
|
||||||
|
return Object.entries(obj).map(([label, value]) => ({
|
||||||
|
label, // 模板/代理名称
|
||||||
|
value // 模板/代理ID
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description 定义通用数据获取方法
|
* @description 定义通用数据获取方法
|
||||||
*/
|
*/
|
||||||
|
//获取代理列表
|
||||||
|
const getAgentList = async () => {
|
||||||
|
const params = {
|
||||||
|
user_id: useInfo.value.id,
|
||||||
|
page: currentPage.value,
|
||||||
|
page_size: pageSize.value,
|
||||||
|
user_name: searchForm.value.username,
|
||||||
|
status: searchForm.value.status,
|
||||||
|
reg_start_time: searchForm.value.startDateTime,
|
||||||
|
reg_end_time: searchForm.value.endDateTime,
|
||||||
|
}
|
||||||
|
const data = await getAgentListApi(params)
|
||||||
|
// 表格数据
|
||||||
|
agentTree.value = data.data.map((item: any) => {
|
||||||
|
//针对当前item提取需要相加的字段(每次循环都重新取当前行数据)
|
||||||
|
const walletNums = [
|
||||||
|
// 兜底空值,避免undefined导致计算错误
|
||||||
|
item.wallet_capital?.commission_fee_handling || '0.00000',
|
||||||
|
item.wallet_capital?.commission_point_diff || '0.00000'
|
||||||
|
];
|
||||||
|
// 计算返佣总金额的值
|
||||||
|
const rebateTotalAmount = sumStrNumsWith5Decimals(walletNums);
|
||||||
|
return {
|
||||||
|
...item,
|
||||||
|
createTime: item.created_at || '',
|
||||||
|
feeRate: item.wallet_capital.fee_handling_percent,
|
||||||
|
rebateRate: item.wallet_capital.commission_fee_handling,
|
||||||
|
pointDifference: item.wallet_capital.commission_point_diff,
|
||||||
|
rebateTotalAmount: rebateTotalAmount,
|
||||||
|
clientCount: item.son_user.length,
|
||||||
|
level: item.role.title,
|
||||||
|
parentUsername: item.par_uid === item.parent.id ? item.parent.username : '',
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
//分页数据
|
||||||
|
total.value = data.total
|
||||||
|
currentPage.value = data.current_page
|
||||||
|
pageSize.value = Number(data.per_page)
|
||||||
|
}
|
||||||
|
|
||||||
|
//获取点差配置
|
||||||
|
const getPointDiffConfig = async (row: any) => {
|
||||||
|
const params = {
|
||||||
|
user_id: row.par_uid,
|
||||||
|
}
|
||||||
|
const data = await getPointDiffConfigApi(params)
|
||||||
|
// 表格数据
|
||||||
|
agentPointTree.value = data.map((item: any) => ({
|
||||||
|
...item,
|
||||||
|
varietyName: item.name,
|
||||||
|
varietyCode: item.code,
|
||||||
|
pointDifference: item.target_point_diff,
|
||||||
|
assignedPointDifference: ''
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 合并获取表单下拉数据
|
||||||
|
const getOptions = async () => {
|
||||||
|
// 已获取过选项则直接返回,避免重复请求
|
||||||
|
if (optionsFetched.value) return
|
||||||
|
|
||||||
|
try {
|
||||||
|
const [riskTemplateRes, feeTemplateRes] = await Promise.all([
|
||||||
|
// 风控模板
|
||||||
|
getRiskTemplateOptionsApi(),
|
||||||
|
// 手续费模板
|
||||||
|
getFeeTemplateOptionsApi()
|
||||||
|
])
|
||||||
|
// label=名称,value=ID
|
||||||
|
agentFormOptionsMap.value.riskTemplate = riskTemplateRes.map((item: any) => ({
|
||||||
|
label: item.name,
|
||||||
|
value: item.id
|
||||||
|
}))
|
||||||
|
// label=名称,value=ID
|
||||||
|
agentFormOptionsMap.value.feeTemplate = mapObjectToOptions(feeTemplateRes as Record<string, string>)
|
||||||
|
optionsFetched.value = true // 标记已获取
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取表单选项失败:', error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description 页面加载完成需要调用的方法
|
* @description 页面加载完成需要调用的方法
|
||||||
*/
|
*/
|
||||||
|
onMounted(() => {
|
||||||
|
getAgentList()
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description 定义搜索方法
|
* @description 定义搜索组件的全部方法
|
||||||
*/
|
*/
|
||||||
|
const handleSearch = () => {
|
||||||
|
getAgentList()
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleReset = () => {
|
||||||
|
searchForm.value = {
|
||||||
|
username: '',
|
||||||
|
status: '正常',
|
||||||
|
startDateTime: '',
|
||||||
|
endDateTime: '',
|
||||||
|
}
|
||||||
|
getAgentList()
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description 定义表格方法
|
* @description 定义表格方法
|
||||||
*/
|
*/
|
||||||
|
// 查看点差
|
||||||
|
const handleViewPointDiff = (row: any) => {
|
||||||
|
getPointDiffConfig(row)
|
||||||
|
dialogVisible.value = true
|
||||||
|
dialogTitle.value = '查看点差'
|
||||||
|
dialogType.value = 'view'
|
||||||
|
dialogFullscreen.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// 编辑
|
||||||
|
const handleEdit = async (row: any) => {
|
||||||
|
console.log('编辑', row);
|
||||||
|
// 并行请求点差配置和下拉选项
|
||||||
|
await Promise.all([
|
||||||
|
getPointDiffConfig(row),
|
||||||
|
getOptions()
|
||||||
|
])
|
||||||
|
agentForm.value = {
|
||||||
|
username: row.username || '',
|
||||||
|
parentUsername: row.parentUsername || '',
|
||||||
|
riskTemplate: row.wallet_capital.risk_control_id || '',
|
||||||
|
feeTemplate: row.wallet_capital.fee_setting_id || '',
|
||||||
|
positionRatio: row.wallet_capital.toucun_percent || '',
|
||||||
|
feeRate: row.feeRate || '',
|
||||||
|
id: row.id || '',
|
||||||
|
}
|
||||||
|
console.log('agentForm.value', agentForm.value)
|
||||||
|
dialogVisible.value = true
|
||||||
|
dialogTitle.value = '编辑'
|
||||||
|
dialogType.value = 'edit'
|
||||||
|
dialogFullscreen.value = false
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description 定义分页方法
|
* @description 定义分页方法
|
||||||
*/
|
*/
|
||||||
|
// 分页变更
|
||||||
|
const handlePaginationChange = async (page: { currentPage: number, pageSize: number }) => {
|
||||||
|
currentPage.value = page.currentPage
|
||||||
|
pageSize.value = page.pageSize
|
||||||
|
await getAgentList()
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* @description 定义dialog方法
|
* @description 定义dialog方法
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 提交之前构造数据
|
||||||
|
|
||||||
|
*/
|
||||||
|
// 格式化点差为 { "1":"42", "2":"38" } 格式的对象
|
||||||
|
const formatPointDiffToObject = () => {
|
||||||
|
if (!agentPointTree.value || !agentPointTree.value.length) return {};
|
||||||
|
|
||||||
|
// 初始化空对象
|
||||||
|
const pointDiffObj: Record<string, string> = {};
|
||||||
|
|
||||||
|
// 遍历表格数据,构造 { 编号: 点差值 } 的对象
|
||||||
|
agentPointTree.value.forEach((item: { id: string | number; assignedPointDifference: string }) => {
|
||||||
|
// 类型安全的赋值
|
||||||
|
pointDiffObj[String(item.id)] = item.assignedPointDifference || '0';
|
||||||
|
});
|
||||||
|
|
||||||
|
return pointDiffObj; // 返回纯对象,而非数组
|
||||||
|
};
|
||||||
|
|
||||||
|
//提交
|
||||||
|
const handleSubmit = async () => {
|
||||||
|
await agentFormRef.value.validate()
|
||||||
|
const pointDiffObj = formatPointDiffToObject()
|
||||||
|
console.log('agentForm.value', agentForm.value)
|
||||||
|
const params = {
|
||||||
|
user_id: agentForm.value.id || '',
|
||||||
|
toucun_percent: agentForm.value.positionRatio || '',
|
||||||
|
point_diffs_json: JSON.stringify(pointDiffObj),
|
||||||
|
fee_handling_percent: agentForm.value.feeRate || '',
|
||||||
|
fee_setting_id: agentForm.value.feeTemplate || '',
|
||||||
|
risk_control_id: agentForm.value.riskTemplate || '',
|
||||||
|
}
|
||||||
|
await editPointDiffApi(params)
|
||||||
|
// 刷新表格数据
|
||||||
|
await getAgentList()
|
||||||
|
dialogVisible.value = false
|
||||||
|
}
|
||||||
|
// 取消
|
||||||
|
const handleCancel = () => {
|
||||||
|
dialogVisible.value = false
|
||||||
|
}
|
||||||
|
// 关闭
|
||||||
|
const handleClose = () => {
|
||||||
|
dialogVisible.value = false
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss"></style>
|
<style scoped lang="scss"></style>
|
||||||
|
|
|
||||||
|
|
@ -41,24 +41,36 @@ export const agentTableColumns = [
|
||||||
|
|
||||||
]
|
]
|
||||||
|
|
||||||
// 定义点差表格列配置
|
// 查看点差表格列配置
|
||||||
export const agentPointTableColumns = [
|
export const viewAgentPointTableColumns = [
|
||||||
{ prop: 'varietyName', label: '品种名称', align: 'center' as const },
|
{ prop: 'varietyName', label: '品种名称', align: 'center' as const },
|
||||||
{ prop: 'varietyCode', label: '品种编号', align: 'center' as const },
|
{ prop: 'varietyCode', label: '品种编号', align: 'center' as const },
|
||||||
{ prop: 'pointDifference', label: '可用点差', align: 'center' as const },
|
{ prop: 'pointDifference', label: '可用点差', align: 'center' as const },
|
||||||
{ prop: 'assignedPointDifference', label: '已分配点差', align: 'center' as const },
|
{ prop: 'assignedPointDifference', label: '已分配点差', align: 'center' as const },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
//编辑点差表格列配置
|
||||||
|
export const agentPointTableColumns = ([
|
||||||
|
{ prop: 'varietyName', label: '名称', align: 'center' as const },
|
||||||
|
{ prop: 'varietyCode', label: '编号', align: 'center' as const },
|
||||||
|
{ prop: 'pointDifference', label: '可分配点差', align: 'center' as const },
|
||||||
|
{ prop: 'assignedPointDifference', label: '已分配点差', align: 'center' as const, slotName: 'assignedPointDiff' },
|
||||||
|
])
|
||||||
|
|
||||||
|
|
||||||
//编辑点差form配置
|
//编辑点差form配置
|
||||||
export const PointDiffFormItem = [
|
export const PointDiffFormItem = [
|
||||||
//代理名称
|
//代理名称
|
||||||
{ prop: 'username', label: '代理名称', type: 'input' as const, placeholder: '代理名称', width: '120px' },
|
{ prop: 'username', label: '代理名称', type: 'input' as const, placeholder: '代理名称', width: '120px' },
|
||||||
//所属上级
|
//所属上级
|
||||||
{ prop: 'parentUsername', label: '所属上级', type: 'input' as const, placeholder: '所属上级', width: '120px' },
|
{ prop: 'parentUsername', label: '所属上级', type: 'input' as const, placeholder: '所属上级', width: '120px' },
|
||||||
//手续费
|
|
||||||
{ prop: 'feeRate', label: '手续费', type: 'input' as const, placeholder: '手续费', width: '120px' },
|
|
||||||
//风控模板
|
//风控模板
|
||||||
{ prop: 'riskTemplate', label: '风控模板', type: 'select' as const, placeholder: '风控模板', width: '120px' },
|
{ prop: 'riskTemplate', label: '风控模板', type: 'select' as const, placeholder: '风控模板', width: '120px' },
|
||||||
//手续费模板
|
//手续费模板
|
||||||
{ prop: 'feeTemplate', label: '手续费模板', type: 'select' as const, placeholder: '手续费模板', width: '120px' },
|
{ prop: 'feeTemplate', label: '手续费模板', type: 'select' as const, placeholder: '手续费模板', width: '120px' },
|
||||||
|
//头寸
|
||||||
|
{ prop: 'positionRatio', label: '头寸', type: 'input' as const, placeholder: '请输入头寸', width: '120px' },
|
||||||
|
//手续费
|
||||||
|
{ prop: 'feeRate', label: '手续费', type: 'input' as const, placeholder: '手续费', width: '120px' },
|
||||||
|
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
import type{ FormRules } from 'element-plus'
|
||||||
|
|
||||||
|
export const rules = (): FormRules => {
|
||||||
|
return {
|
||||||
|
name: [
|
||||||
|
{ required: true, message: '请输入名称', trigger: ['blur'] }
|
||||||
|
],
|
||||||
|
pointDiff: [
|
||||||
|
{ required: true, message: '请输入点差', trigger: ['blur'] }
|
||||||
|
],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,341 +0,0 @@
|
||||||
<template>
|
|
||||||
<div class="agent">
|
|
||||||
<AgentSearch :search-form="agentSearchForm" :search-options="agentSearchOptions" @search="handleSearch"
|
|
||||||
@reset="handleReset">
|
|
||||||
</AgentSearch>
|
|
||||||
|
|
||||||
<AgentTable :table-data="agentTree" :columns="agentTableColumnsOptions" row-key="id">
|
|
||||||
<template #status="{ row }">
|
|
||||||
<el-switch :model-value="row.status === 1" :active-value="true" :inactive-value="false" active-text="启用"
|
|
||||||
inactive-text="禁用" />
|
|
||||||
</template>
|
|
||||||
<template #pointDifference="{ row }">
|
|
||||||
<el-button type="primary" size="small" @click="handlePointDifference(row)">
|
|
||||||
查看
|
|
||||||
</el-button>
|
|
||||||
</template>
|
|
||||||
<template #edit="{ row }">
|
|
||||||
<el-button type="primary" size="small" @click="handleEdit(row)">
|
|
||||||
编辑
|
|
||||||
</el-button>
|
|
||||||
</template>
|
|
||||||
</AgentTable>
|
|
||||||
|
|
||||||
<AgentPagination v-model="agentSearchForm.page" v-model:page-size-value="agentSearchForm.pageSize"
|
|
||||||
:total="agentSearchForm.total" @pagination-change="handlePaginationChange" />
|
|
||||||
<AgentDialog :visible="dialogVisible" :title="dialogTitle" :type="dialogType" :fullscreen="dialogFullscreen" @submit="handleSubmit"
|
|
||||||
@cancel="handleCancel" @close="handleClose" :class="{ 'edit-dialog': isEdit }">
|
|
||||||
<AgentForm :form-data="agentForm" :form-rules="agentFormRules" :form-items="agentFormItems"
|
|
||||||
:options-map="agentFormOptionsMap" v-if="isEdit" />
|
|
||||||
<AgentTable :table-data="agentPointTree" :columns="agentPointTableColumnsOptions" row-key="id" />
|
|
||||||
</AgentDialog>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<script lang="ts" setup>
|
|
||||||
// 组件
|
|
||||||
import AgentSearch from '@/components/common/Search.vue'
|
|
||||||
import AgentTable from '@/components/common/Table.vue'
|
|
||||||
import AgentPagination from '@/components/common/Pagination.vue'
|
|
||||||
import AgentDialog from '@/components/common/Dialog.vue'
|
|
||||||
import AgentForm from '@/components/common/Form.vue'
|
|
||||||
|
|
||||||
//接口
|
|
||||||
import { getAgentListApi, getPointDiffConfigApi, getRiskTemplateOptionsApi, getFeeTemplateOptionsApi,editPointDiffConfigApi } from '@/api/modules/account/agent'
|
|
||||||
|
|
||||||
// 引入配置
|
|
||||||
import { agentSearch, agentTableColumns, agentPointTableColumns, PointDiffFormItem } from './options'
|
|
||||||
|
|
||||||
//定义客户搜索表单配置
|
|
||||||
const agentSearchOptions = ref(agentSearch)
|
|
||||||
const agentSearchForm = ref({
|
|
||||||
username: '',
|
|
||||||
status: '正常',
|
|
||||||
startDateTime: '',
|
|
||||||
endDateTime: '',
|
|
||||||
page: 1,
|
|
||||||
pageSize: 100,
|
|
||||||
total: 100,
|
|
||||||
})
|
|
||||||
|
|
||||||
// 定义表格配置
|
|
||||||
const agentTree = ref<any[]>([])
|
|
||||||
const agentTableColumnsOptions = ref(agentTableColumns)
|
|
||||||
|
|
||||||
// 定义弹窗配置
|
|
||||||
const dialogVisible = ref(false)
|
|
||||||
const dialogTitle = ref('查看点差')
|
|
||||||
const dialogFullscreen = ref(false)
|
|
||||||
const dialogType = ref('add')
|
|
||||||
const agentPointTree = ref<any[]>([])
|
|
||||||
const agentPointTableColumnsOptions = ref(agentPointTableColumns)
|
|
||||||
|
|
||||||
// 定义弹窗表单配置
|
|
||||||
const isEdit = ref(false)
|
|
||||||
const agentFormItems = ref(PointDiffFormItem)
|
|
||||||
const agentFormRules = ref({
|
|
||||||
username: [{ required: true, message: '请输入代理名称', trigger: ['blur'] }],
|
|
||||||
parentUsername: [{ required: true, message: '请输入所属上级', trigger: ['blur'] }],
|
|
||||||
feeRate: [{ required: true, message: '请输入手续费', trigger: ['blur'] }],
|
|
||||||
riskTemplate: [{ required: true, message: '请选择风控模板', trigger: ['change'] }],
|
|
||||||
feeTemplate: [{ required: true, message: '请选择手续费模板', trigger: ['change'] }],
|
|
||||||
})
|
|
||||||
const agentForm = ref({
|
|
||||||
username: '',
|
|
||||||
parentUsername: '',
|
|
||||||
feeRate: '',
|
|
||||||
riskTemplate: '',
|
|
||||||
feeTemplate: '',
|
|
||||||
})
|
|
||||||
const agentFormOptionsMap = ref<any>({
|
|
||||||
riskTemplate: [],
|
|
||||||
feeTemplate: [],
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @description 统一获取数据
|
|
||||||
*/
|
|
||||||
/**
|
|
||||||
* 处理字符串数值:转数字 + 相加 + 保留五位小数
|
|
||||||
* @param {Array<string>} strNums - 待处理的字符串数值数组(如 ["0.00000", "0.00000"])
|
|
||||||
* @returns {number} 相加后保留五位小数的数字(最终结果)
|
|
||||||
*/
|
|
||||||
function sumStrNumsWith5Decimals(strNums: string[]) {
|
|
||||||
// 1. 初始化总和
|
|
||||||
let total = 0;
|
|
||||||
|
|
||||||
// 2. 遍历数组,逐个转换并累加
|
|
||||||
strNums.forEach(strNum => {
|
|
||||||
// 转数字(处理空值/非数字,兜底为0)
|
|
||||||
const num = parseFloat(strNum) || 0;
|
|
||||||
total += num;
|
|
||||||
});
|
|
||||||
|
|
||||||
// 3. 保留五位小数(四舍五入),转回数字类型
|
|
||||||
const result = parseFloat(total.toFixed(5));
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 映射对象为数组通用方法
|
|
||||||
const mapObjectToOptions = (obj: Record<string, string>) => {
|
|
||||||
console.log('obj', obj)
|
|
||||||
return Object.entries(obj).map(([label, value]) => ({
|
|
||||||
label, // 模板/代理名称
|
|
||||||
value // 模板/代理ID
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
|
|
||||||
//获取代理列表
|
|
||||||
const fetchAgentList = async () => {
|
|
||||||
const params = {
|
|
||||||
page: agentSearchForm.value.page,
|
|
||||||
page_size: agentSearchForm.value.pageSize,
|
|
||||||
user_name: agentSearchForm.value.username,
|
|
||||||
reg_start_time: agentSearchForm.value.startDateTime.length > 0 ? `${agentSearchForm.value.startDateTime} 0:00:00` : '',
|
|
||||||
reg_end_time: agentSearchForm.value.endDateTime.length > 0 ? `${agentSearchForm.value.endDateTime} 23:59:59` : '',
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
const data = await getAgentListApi(params)
|
|
||||||
//分页数据
|
|
||||||
agentSearchForm.value.total = data.total || 0
|
|
||||||
agentSearchForm.value.pageSize = Number(data.per_page) || 0
|
|
||||||
|
|
||||||
// 表格数据
|
|
||||||
agentTree.value = data.data.map((item: any) => {
|
|
||||||
|
|
||||||
//针对当前item提取需要相加的字段(每次循环都重新取当前行数据)
|
|
||||||
const walletNums = [
|
|
||||||
// 兜底空值,避免undefined导致计算错误
|
|
||||||
item.wallet_capital?.commission_fee_handling || '0.00000',
|
|
||||||
item.wallet_capital?.commission_point_diff || '0.00000'
|
|
||||||
];
|
|
||||||
// 计算当前行的累加值
|
|
||||||
const rebateTotalAmount = sumStrNumsWith5Decimals(walletNums);
|
|
||||||
|
|
||||||
return {
|
|
||||||
...item,
|
|
||||||
createTime: item.created_at || '',
|
|
||||||
feeRate: item.wallet_capital.fee_handling_percent,
|
|
||||||
rebateRate: item.wallet_capital.commission_fee_handling,
|
|
||||||
pointDifference: item.wallet_capital.commission_point_diff,
|
|
||||||
rebateTotalAmount: rebateTotalAmount,
|
|
||||||
clientCount: item.son_user.length,
|
|
||||||
level: item.role.title,
|
|
||||||
parentUsername: item.par_uid === item.parent.id ? item.parent.username : '',
|
|
||||||
}
|
|
||||||
})
|
|
||||||
} catch (err) {
|
|
||||||
console.error('获取代理列表失败', err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//获取代理点差配置
|
|
||||||
const fetchAgentPointDiffConfig = async (id: number | string) => {
|
|
||||||
console.log(id)
|
|
||||||
const params = {
|
|
||||||
user_id: id
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
const data = await getPointDiffConfigApi(params)
|
|
||||||
// 表格数据
|
|
||||||
agentPointTree.value = data.map((item: any) => ({
|
|
||||||
...item,
|
|
||||||
varietyName: item.name,
|
|
||||||
varietyCode: item.code,
|
|
||||||
pointDifference: item.point_diff,
|
|
||||||
assignedPointDifference: item.target_point_diff
|
|
||||||
}))
|
|
||||||
} catch (err) {
|
|
||||||
console.error('获取代理点差配置失败', err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//统一获取表单选项
|
|
||||||
const optionsFetched = ref(false)
|
|
||||||
const getOptions = async () => {
|
|
||||||
// 已获取过选项则直接返回,避免重复请求
|
|
||||||
if (optionsFetched.value) return
|
|
||||||
|
|
||||||
try {
|
|
||||||
const [riskTemplateRes, feeTemplateRes] = await Promise.all([
|
|
||||||
getRiskTemplateOptionsApi(), // 风控模板请求 → 对应 riskTemplateRes
|
|
||||||
getFeeTemplateOptionsApi(), // 手续费模板请求 → 对应 feeTemplateRes
|
|
||||||
])
|
|
||||||
console.log('获取表单选项:', riskTemplateRes, feeTemplateRes)
|
|
||||||
// 修正映射:label=名称,value=ID
|
|
||||||
|
|
||||||
agentFormOptionsMap.value.riskTemplate = mapObjectToOptions(feeTemplateRes as Record<string, string>)
|
|
||||||
agentFormOptionsMap.value.feeTemplate = riskTemplateRes.map((item: any) => ({
|
|
||||||
label: item.name,
|
|
||||||
value: item.id
|
|
||||||
}))
|
|
||||||
|
|
||||||
optionsFetched.value = true // 标记已获取
|
|
||||||
} catch (error) {
|
|
||||||
console.error('获取表单选项失败:', error)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @description 页面加载完成后获取数据
|
|
||||||
*/
|
|
||||||
onMounted(() => {
|
|
||||||
fetchAgentList()
|
|
||||||
})
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @description 搜索方法
|
|
||||||
*/
|
|
||||||
const handleSearch = () => {
|
|
||||||
fetchAgentList()
|
|
||||||
}
|
|
||||||
const handleReset = () => {
|
|
||||||
// 处理重置逻辑
|
|
||||||
agentSearchForm.value = {
|
|
||||||
username: '',
|
|
||||||
status: '正常',
|
|
||||||
startDateTime: '',
|
|
||||||
endDateTime: '',
|
|
||||||
page: 1,
|
|
||||||
pageSize: 10,
|
|
||||||
total: 100,
|
|
||||||
}
|
|
||||||
fetchAgentList()
|
|
||||||
}
|
|
||||||
const handleDialogType = (type: string) => {
|
|
||||||
console.log('handleDialogType', type)
|
|
||||||
if (type === 'edit') {
|
|
||||||
isEdit.value = true
|
|
||||||
dialogFullscreen.value = false
|
|
||||||
} else {
|
|
||||||
isEdit.value = false
|
|
||||||
dialogFullscreen.value = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @description 查看点差方法
|
|
||||||
*/
|
|
||||||
const handlePointDifference = (row: any) => {
|
|
||||||
dialogVisible.value = true
|
|
||||||
dialogTitle.value = '查看点差'
|
|
||||||
dialogType.value = 'view'
|
|
||||||
handleDialogType(dialogType.value)
|
|
||||||
console.log(dialogType.value)
|
|
||||||
fetchAgentPointDiffConfig(row.id)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @description 编辑方法
|
|
||||||
*/
|
|
||||||
const handleEdit = (row: any) => {
|
|
||||||
dialogVisible.value = true
|
|
||||||
dialogTitle.value = '编辑点差'
|
|
||||||
dialogType.value = 'edit'
|
|
||||||
dialogFullscreen.value = false
|
|
||||||
handleDialogType(dialogType.value)
|
|
||||||
console.log(dialogType.value)
|
|
||||||
getOptions()
|
|
||||||
// fetchAgentPointDiffConfig(row.id)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @description 分页方法
|
|
||||||
*/
|
|
||||||
const handlePaginationChange = (page: { currentPage: number, pageSize: number }) => {
|
|
||||||
agentSearchForm.value.page = page.currentPage
|
|
||||||
agentSearchForm.value.pageSize = page.pageSize
|
|
||||||
handleSearch()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @description dialog方法
|
|
||||||
*/
|
|
||||||
|
|
||||||
const handleSubmit = async () => {
|
|
||||||
if (dialogType.value === 'edit') {
|
|
||||||
const params = {
|
|
||||||
user_id: "",
|
|
||||||
toucun_percent: "",
|
|
||||||
point_diffs_json: "",
|
|
||||||
fee_handling_percent: "",
|
|
||||||
}
|
|
||||||
await editPointDiffConfigApi(params)
|
|
||||||
await fetchAgentList()
|
|
||||||
dialogVisible.value = false
|
|
||||||
} else {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 弹窗取消
|
|
||||||
const handleCancel = () => {
|
|
||||||
dialogVisible.value = false
|
|
||||||
dialogType.value = 'view'
|
|
||||||
}
|
|
||||||
|
|
||||||
// 弹窗关闭
|
|
||||||
const handleClose = () => {
|
|
||||||
dialogVisible.value = false
|
|
||||||
dialogType.value = 'view'
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped lang="scss">
|
|
||||||
.agent {
|
|
||||||
:deep(.el-dialog) {
|
|
||||||
.el-dialog__footer {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
:deep(.edit-dialog) {
|
|
||||||
.el-dialog__footer {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
@ -512,6 +512,7 @@ const handleSubmit = async () => {
|
||||||
fee_handling_percent: marketForm.value.commissionRatio,
|
fee_handling_percent: marketForm.value.commissionRatio,
|
||||||
point_diffs_json: JSON.stringify(pointDiffObj),
|
point_diffs_json: JSON.stringify(pointDiffObj),
|
||||||
risk_control_id: marketForm.value.riskControlTemplate,
|
risk_control_id: marketForm.value.riskControlTemplate,
|
||||||
|
fee_setting_id: '',
|
||||||
}
|
}
|
||||||
await addMarketApi(params)
|
await addMarketApi(params)
|
||||||
// 5. 刷新表格数据
|
// 5. 刷新表格数据
|
||||||
|
|
@ -525,6 +526,7 @@ const handleSubmit = async () => {
|
||||||
point_diffs_json: JSON.stringify(pointDiffObj),
|
point_diffs_json: JSON.stringify(pointDiffObj),
|
||||||
risk_control_id: marketForm.value.riskControlTemplate,
|
risk_control_id: marketForm.value.riskControlTemplate,
|
||||||
fee_handling_percent: marketForm.value.commissionRatio,
|
fee_handling_percent: marketForm.value.commissionRatio,
|
||||||
|
fee_setting_id: '',
|
||||||
}
|
}
|
||||||
// 4. 调用编辑接口
|
// 4. 调用编辑接口
|
||||||
await editMarketApi(params)
|
await editMarketApi(params)
|
||||||
|
|
|
||||||
|
|
@ -48,11 +48,11 @@ export const marketFormItem = [
|
||||||
//账户名称
|
//账户名称
|
||||||
{ label: '账户名称', prop: 'accountName', type: 'input' as const, placeholder: '请输入账户名称', },
|
{ label: '账户名称', prop: 'accountName', type: 'input' as const, placeholder: '请输入账户名称', },
|
||||||
//级别
|
//级别
|
||||||
{ label: '级别', prop: 'level', type: 'select' as const, placeholder: '请选择级别'},
|
{ label: '级别', prop: 'level', type: 'select' as const, placeholder: '请选择级别' },
|
||||||
//所属上级
|
//所属上级
|
||||||
{ label: '所属上级', prop: 'parentAccountName', type: 'select' as const, placeholder: '请选择所属上级账户名称', },
|
{ label: '所属上级', prop: 'parentAccountName', type: 'select' as const, placeholder: '请选择所属上级账户名称', },
|
||||||
// 风控模板
|
// 风控模板
|
||||||
{ label: '风控模板', prop: 'riskControlTemplate', type: 'select' as const, placeholder: '请选择风控模板'},
|
{ label: '风控模板', prop: 'riskControlTemplate', type: 'select' as const, placeholder: '请选择风控模板' },
|
||||||
//头寸
|
//头寸
|
||||||
{ label: '头寸', prop: 'positionRatio', type: 'input' as const, placeholder: '请输入头寸', },
|
{ label: '头寸', prop: 'positionRatio', type: 'input' as const, placeholder: '请输入头寸', },
|
||||||
//手续费
|
//手续费
|
||||||
|
|
@ -79,7 +79,7 @@ export const marketPointTableColumns = ([
|
||||||
{ prop: 'varietyName', label: '名称', align: 'center' as const },
|
{ prop: 'varietyName', label: '名称', align: 'center' as const },
|
||||||
{ prop: 'varietyCode', label: '编号', align: 'center' as const },
|
{ prop: 'varietyCode', label: '编号', align: 'center' as const },
|
||||||
{ prop: 'pointDifference', label: '可分配点差', align: 'center' as const },
|
{ prop: 'pointDifference', label: '可分配点差', align: 'center' as const },
|
||||||
{ prop: 'assignedPointDifference', label: '已分配点差', align: 'center' as const, slotName:'assignedPointDiff'},
|
{ prop: 'assignedPointDifference', label: '已分配点差', align: 'center' as const, slotName: 'assignedPointDiff' },
|
||||||
])
|
])
|
||||||
|
|
||||||
// 查看点差表格列配置
|
// 查看点差表格列配置
|
||||||
|
|
@ -87,5 +87,5 @@ export const viewMarketPointTableColumns = ([
|
||||||
{ prop: 'varietyName', label: '名称', align: 'center' as const },
|
{ prop: 'varietyName', label: '名称', align: 'center' as const },
|
||||||
{ prop: 'varietyCode', label: '编号', align: 'center' as const },
|
{ prop: 'varietyCode', label: '编号', align: 'center' as const },
|
||||||
{ prop: 'pointDifference', label: '可分配点差', align: 'center' as const },
|
{ prop: 'pointDifference', label: '可分配点差', align: 'center' as const },
|
||||||
{ prop: 'assignedPointDifference', label: '已分配点差', align: 'center' as const},
|
{ prop: 'assignedPointDifference', label: '已分配点差', align: 'center' as const },
|
||||||
])
|
])
|
||||||
|
|
@ -135,7 +135,7 @@ export const rules = (marketForm: any, row?: any): FormRules => {
|
||||||
if (row && row.pointDifference !== undefined) {
|
if (row && row.pointDifference !== undefined) {
|
||||||
const maxPointDiff = Number(row.pointDifference)
|
const maxPointDiff = Number(row.pointDifference)
|
||||||
if (numValue > maxPointDiff) {
|
if (numValue > maxPointDiff) {
|
||||||
return callback(new Error(`不能超过可分配点差(${maxPointDiff})`))
|
return callback(new Error(`可分配点差为(${maxPointDiff})`))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue