This commit is contained in:
parent
c8e9b79bce
commit
6d180b94a8
|
|
@ -6,12 +6,26 @@ export async function getMarketListApi(params: searchParams): Promise<any> {
|
|||
return request.get<any>('agent/getAgentList', { ...params })
|
||||
}
|
||||
|
||||
//获取代理点差配置
|
||||
export async function getPointDiffConfigApi(params: pointDiffConfigParams): Promise<any> {
|
||||
return request.get<any>('/agent/getSelfVarietyPointDiffConfig',{...params})
|
||||
}
|
||||
|
||||
//获取所属上级列表
|
||||
export async function getParAgentListApi(params: pointDiffConfigParams): Promise<any> {
|
||||
return request.get<any>('/agent/getParAgentListByRoleId',{...params})
|
||||
}
|
||||
|
||||
//获取代理点差列表
|
||||
export async function getPointDiffConfigListApi(params: pointDiffConfigParams): Promise<any> {
|
||||
return request.get<any>('/agent/getSelfVarietyPointDiffConfig',{...params})
|
||||
}
|
||||
|
||||
//获取风控模板选列表
|
||||
export async function getRiskTemplateListApi(): Promise<any> {
|
||||
return request.get<any>('/agent/getRiskControlOptions')
|
||||
}
|
||||
|
||||
//添加做市商
|
||||
export async function addMarketApi(params:any): Promise<any> {
|
||||
return request.post<any>('/agent/createAgent',{...params})
|
||||
}
|
||||
//编辑做市商
|
||||
export async function editMarketApi(params:any): Promise<any> {
|
||||
return request.post<any>('/agent/editAgent',{...params})
|
||||
}
|
||||
|
|
@ -4,6 +4,6 @@ export interface searchParams {
|
|||
}
|
||||
//获取代理点差配置
|
||||
export interface pointDiffConfigParams {
|
||||
user_id?: number | null
|
||||
user_id?: number | string
|
||||
role_id?: number | string
|
||||
}
|
||||
|
|
@ -5,7 +5,7 @@
|
|||
<slot />
|
||||
|
||||
<!-- 底部按钮插槽 -->
|
||||
<template #footer>
|
||||
<template #footer v-if="showFooter">
|
||||
<slot name="footer">
|
||||
<el-button @click="handleCancel">取消</el-button>
|
||||
<el-button type="primary" @click="handleConfirm">确定</el-button>
|
||||
|
|
@ -21,6 +21,7 @@ interface Props {
|
|||
width?: string | number
|
||||
destroyOnClose?: boolean
|
||||
type?: string
|
||||
showFooter?: boolean
|
||||
}
|
||||
|
||||
interface Emits {
|
||||
|
|
@ -33,6 +34,7 @@ interface Emits {
|
|||
const props = withDefaults(defineProps<Props>(), {
|
||||
width: '600px',
|
||||
destroyOnClose: true,
|
||||
showFooter: true,
|
||||
})
|
||||
|
||||
const emit = defineEmits<Emits>()
|
||||
|
|
@ -51,5 +53,4 @@ const handleClose = () => {
|
|||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
</style>
|
||||
<style scoped lang="scss"></style>
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ const props = defineProps({
|
|||
},
|
||||
// 可选的每页条数
|
||||
pageSizes: {
|
||||
type: Array,
|
||||
type: Array as PropType<number[]>,
|
||||
default: () => [1, 10, 20, 50, 100] as unknown[]
|
||||
},
|
||||
// 是否禁用分页
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
<template>
|
||||
<div class="table-container">
|
||||
<el-table :data="tableData" :row-key="rowKey" :tree-props="treeProps" :border="border" :highlight-current-row="highlightCurrentRow"
|
||||
v-bind="$attrs">
|
||||
<el-table :data="tableData" :row-key="rowKey" :tree-props="treeProps" :border="border"
|
||||
:highlight-current-row="highlightCurrentRow" v-bind="$attrs" @row-click="handleRowClick">
|
||||
<!-- 动态表头列 -->
|
||||
<template v-for="(column, index) in columns" :key="index">
|
||||
<el-table-column v-if="!column.slotName" :prop="column.prop" :label="column.label" :width="column.width"
|
||||
|
|
@ -44,6 +44,20 @@ const props = withDefaults(defineProps<Props>(), {
|
|||
border: true,
|
||||
highlightCurrentRow: true,
|
||||
})
|
||||
|
||||
// 定义组件抛出的事件
|
||||
const emit = defineEmits<{
|
||||
(e: 'row-click', row: any): void // 保留原有行点击事件
|
||||
}>()
|
||||
|
||||
/**
|
||||
* 处理行点击事件(兼容原有逻辑)
|
||||
*/
|
||||
const handleRowClick = (row: any) => {
|
||||
// 增加空值保护,避免传递 null 给父组件
|
||||
if (!row) return
|
||||
emit('row-click', row)
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
|
|
|||
|
|
@ -7,21 +7,77 @@
|
|||
<el-button type="primary" @click="handleAddMarket()">
|
||||
添加
|
||||
</el-button>
|
||||
<el-button type="primary" @click="handleEditMarket()">
|
||||
<el-button type="primary" :disabled="!selectedRow" @click="handleEditMarket()">
|
||||
编辑
|
||||
</el-button>
|
||||
</template>
|
||||
</MarketSearch>
|
||||
|
||||
<!-- 表格 -->
|
||||
<MarketTable :table-data="marketTree" :columns="marketTableColumnsOptions" row-key="id">
|
||||
<MarketTable :table-data="marketTree" :columns="marketTableColumnsOptions" row-key="id"
|
||||
@row-click="handleRowClick">
|
||||
<template #pointSpread="{ row }">
|
||||
<el-button type="primary" size="small" @click="handleViewPointDiff(row)">
|
||||
查看
|
||||
</el-button>
|
||||
</template>
|
||||
</MarketTable>
|
||||
|
||||
<!-- 分页 -->
|
||||
<MarketPagination v-model="currentPage" v-model:pageSizeValue="pageSize" :total="total"
|
||||
@pagination-change="handlePaginationChange" />
|
||||
</div>
|
||||
|
||||
<!-- dialog -->
|
||||
<MarketDialog :visible="dialogVisible" :title="dialogTitle" :type="dialogType" :fullscreen="dialogFullscreen"
|
||||
:show-footer="dialogType !== 'view'" @confirm="handleSubmit" @cancel="handleCancel" @close="handleClose">
|
||||
<!-- 表单 -->
|
||||
<MarketForm :form-data="marketForm" :form-rules="marketFormRules" :form-items="marketFormItemOptions"
|
||||
:options-map="marketFormOptionsMap" ref="marketFormRef" v-if="dialogType !== 'view'">
|
||||
<template #phoneOrEmail="{ formData }" v-if="dialogType === 'add'">
|
||||
<div class="phone-email">
|
||||
<div class="tab-btn">
|
||||
<el-button :type="activeTab === 'email' ? 'primary' : 'default'" size="small"
|
||||
@click="activeTab = 'email'">
|
||||
邮箱
|
||||
</el-button>
|
||||
<el-button :type="activeTab === 'phone' ? 'primary' : 'default'" size="small"
|
||||
@click="activeTab = 'phone'">
|
||||
手机号
|
||||
</el-button>
|
||||
</div>
|
||||
<div class="group">
|
||||
<el-form-item prop="email" v-if="activeTab === 'email'">
|
||||
<el-input v-model="marketForm.email" placeholder="请输入邮箱" />
|
||||
</el-form-item>
|
||||
<el-form-item prop="phone" class="phone-item" v-if="activeTab === 'phone'">
|
||||
<el-select v-model="marketForm.countryCode" placeholder="请选择国家区号">
|
||||
<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="marketForm.phone" placeholder="请输入手机号" />
|
||||
</el-form-item>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</MarketForm>
|
||||
|
||||
<!-- 点差表格 -->
|
||||
<MarketTable :table-data="marketPointTree" :columns="marketPointTableColumnsOptions" row-key="id">
|
||||
<template #assignedPointDiff="{ row }">
|
||||
<el-form :model="row" :rules="rules(marketForm, row)">
|
||||
<el-form-item prop="assignedPointDifference">
|
||||
<el-input v-model="row.assignedPointDifference" size="small" placeholder="请输入点差" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</template>
|
||||
</MarketTable>
|
||||
</MarketDialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
|
|
@ -33,10 +89,12 @@ import MarketDialog from '@/components/common/Dialog.vue'
|
|||
import MarketForm from '@/components/common/Form.vue'
|
||||
|
||||
//配置选项和表单验证
|
||||
import { marketSearch, marketTableColumns } from './options'
|
||||
import { marketSearch, marketTableColumns, marketFormItem, marketPointTableColumns, countryOptions, viewMarketPointTableColumns } from './options'
|
||||
import { rules } from './rules'
|
||||
|
||||
//接口
|
||||
import { getMarketListApi } from '@/api/modules/account/market'
|
||||
import { getMarketListApi, getPointDiffConfigListApi, getParAgentListApi, getRiskTemplateListApi, addMarketApi, editMarketApi } from '@/api/modules/account/market'
|
||||
|
||||
|
||||
/**
|
||||
* @description 定义搜索数据
|
||||
|
|
@ -57,13 +115,68 @@ const marketTableColumnsOptions = ref(marketTableColumns)
|
|||
* @description 定义分页数据
|
||||
*/
|
||||
const total = ref(0)
|
||||
const page = ref(1)
|
||||
const pageSize = ref(10)
|
||||
const currentPage = ref(1)
|
||||
|
||||
/**
|
||||
* @description 定义dialog数据
|
||||
*/
|
||||
const dialogVisible = ref<boolean>(false)
|
||||
const dialogTitle = ref<string>('')
|
||||
const dialogType = ref<string>('add')
|
||||
const dialogFullscreen = ref(false)
|
||||
|
||||
/**
|
||||
* @description 定义dialog表单数据
|
||||
*/
|
||||
const marketForm = ref({
|
||||
//邮箱或手机号
|
||||
email: '',
|
||||
phone: '',
|
||||
countryCode: '+86',
|
||||
accountName: '',
|
||||
level: '',
|
||||
parentAccountName: '',
|
||||
riskControlTemplate: '',
|
||||
positionRatio: '',
|
||||
commissionRatio: '',
|
||||
//拿最大去比较值
|
||||
maxPositionRatio: '',
|
||||
maxCommissionRatio: '',
|
||||
})
|
||||
const marketFormRules = rules(marketForm.value)
|
||||
const marketFormRef = ref()
|
||||
const marketFormItemOptions = ref(marketFormItem)
|
||||
interface SelectOption {
|
||||
label: string
|
||||
value: string | number
|
||||
row?: any // 存储完整对象
|
||||
}
|
||||
const marketFormOptionsMap = ref<{
|
||||
level: SelectOption[]
|
||||
parentAccountName: SelectOption[]
|
||||
riskControlTemplate: SelectOption[]
|
||||
}>({
|
||||
level: [
|
||||
{ label: '平台', value: '1' },
|
||||
{ label: '承包商', value: '2' },
|
||||
{ label: '特殊做市', value: '3' },
|
||||
{ label: '普通做市', value: '4' },
|
||||
{ label: '一级代理', value: '5' },
|
||||
],
|
||||
parentAccountName: [],
|
||||
riskControlTemplate: [],
|
||||
})
|
||||
const activeTab = ref('email')
|
||||
/**
|
||||
* @description 定义点差表格数据
|
||||
*/
|
||||
|
||||
const marketPointTree = ref<any>([])
|
||||
const marketPointTableColumnsOptions = computed(() => {
|
||||
return dialogType.value !== 'view' ? marketPointTableColumns : viewMarketPointTableColumns;
|
||||
});//保存当前选中的表格行
|
||||
const selectedRow = ref<any>(null)
|
||||
/**
|
||||
* @description 数据处理方法
|
||||
*/
|
||||
|
|
@ -71,8 +184,8 @@ const pageSize = ref(10)
|
|||
const mapMarketTree = (data: any) => {
|
||||
return data.map((item: any) => ({
|
||||
...item,
|
||||
id:item.id, //id
|
||||
agentRelation:item.path_name,//代理关系
|
||||
id: item.id, //id
|
||||
agentRelation: item.path_name,//代理关系
|
||||
accountName: item.username,//账户名
|
||||
level: item.role_id,//级别
|
||||
basicAccount: item.wallet_capital.amount,//基本账户
|
||||
|
|
@ -83,13 +196,72 @@ const mapMarketTree = (data: any) => {
|
|||
pointSpreadCommission: item.wallet_capital.commission_point_diff,//点差返佣
|
||||
commissionRatio: item.wallet_capital.fee_handling_percent,//手续费比例
|
||||
commissionReturn: item.wallet_capital.commission_fee_handling,//手续费返佣
|
||||
floatProfitLoss:"后续添加",//浮动盈亏
|
||||
floatProfitLoss: "后续添加",//浮动盈亏
|
||||
closeProfitLoss: item.wallet_capital.closing_profit,//平仓盈亏
|
||||
riskMargin: item.wallet_capital.risk,//风险保证金
|
||||
serviceFee: item.wallet_capital.service//服务费
|
||||
}))
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 统一处理做市商表单联动逻辑
|
||||
* @param type 联动类型:level(级别变更) / parentAccountName(上级账户变更)
|
||||
* @param value 选中的值(级别值/上级账户名)
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
const handleMarketFormLinkage = async (type: 'level' | 'parentAccountName', value: string) => {
|
||||
try {
|
||||
// 1. 级别变更:获取所属上级账户列表
|
||||
if (type === 'level') {
|
||||
// 清空关联数据,避免脏数据
|
||||
marketForm.value.parentAccountName = ''
|
||||
marketFormOptionsMap.value.parentAccountName = []
|
||||
marketPointTree.value = []
|
||||
|
||||
if (!value) return // 未选择级别,直接返回
|
||||
|
||||
// 调用获取上级账户列表接口
|
||||
const data = await getParAgentListApi({ role_id: value })
|
||||
console.log('datasssssssssssss', data);
|
||||
// 格式化下拉选项
|
||||
marketFormOptionsMap.value.parentAccountName = data.map((item: any) => ({
|
||||
label: item.username,
|
||||
value: String(item.id), // 按实际接口返回字段调整
|
||||
row: item
|
||||
}))
|
||||
}
|
||||
|
||||
// 2. 上级账户变更:获取点差列表
|
||||
if (type === 'parentAccountName') {
|
||||
// 清空点差数据
|
||||
marketPointTree.value = []
|
||||
|
||||
if (!value) return // 未选择上级账户,直接返回
|
||||
|
||||
// 新增:根据选中的value匹配完整的上级账户对象
|
||||
const rulesData = marketFormOptionsMap.value.parentAccountName.find((item) => item.value === value)
|
||||
if (!rulesData) return // 未找到匹配项,直接返回
|
||||
|
||||
// 赋值最大头寸和手续费比例
|
||||
marketForm.value.maxPositionRatio = rulesData.row.wallet_capital.toucun_percent
|
||||
marketForm.value.maxCommissionRatio = rulesData.row.wallet_capital.fee_handling_percent
|
||||
|
||||
// 调用获取点差列表接口
|
||||
const data = await getPointDiffConfigListApi({ user_id: value })
|
||||
// 格式化点差表格数据(按实际需求调整)
|
||||
marketPointTree.value = data.map((item: any) => ({
|
||||
...item,
|
||||
varietyName: item.name,
|
||||
varietyCode: item.code,
|
||||
pointDifference: item.target_point_diff,
|
||||
assignedPointDifference: '',
|
||||
}))
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`[${type}] 联动数据获取失败:`, error)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @description 统一数据获取
|
||||
|
|
@ -97,18 +269,27 @@ const mapMarketTree = (data: any) => {
|
|||
//获取做市商列表
|
||||
const getMarketList = async () => {
|
||||
const params = {
|
||||
page: page.value,
|
||||
page: currentPage.value,
|
||||
page_size: pageSize.value,
|
||||
user_name: marketSearchForm.value.accountName
|
||||
}
|
||||
const data = await getMarketListApi(params)
|
||||
console.log('data', data);
|
||||
// 表格数据
|
||||
marketTree.value = mapMarketTree(data.data)
|
||||
//分页数据
|
||||
total.value = data.total
|
||||
page.value = data.current_page
|
||||
pageSize.value = data.per_page
|
||||
currentPage.value = data.current_page
|
||||
pageSize.value = Number(data.per_page)
|
||||
}
|
||||
|
||||
//获取风控模板选列表
|
||||
const getRiskTemplateList = async () => {
|
||||
const data = await getRiskTemplateListApi()
|
||||
// 格式化下拉选项
|
||||
marketFormOptionsMap.value.riskControlTemplate = data.map((item: any) => ({
|
||||
label: item.name,
|
||||
value: item.id // 按实际接口返回字段调整
|
||||
}))
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -116,8 +297,48 @@ const getMarketList = async () => {
|
|||
*/
|
||||
onMounted(() => {
|
||||
getMarketList()
|
||||
getRiskTemplateList()
|
||||
})
|
||||
|
||||
/**
|
||||
* @description 监听数据变化
|
||||
*/
|
||||
|
||||
// 监听级别变化
|
||||
watch(
|
||||
() => marketForm.value.level,
|
||||
(newLevel) => {
|
||||
handleMarketFormLinkage('level', newLevel)
|
||||
},
|
||||
{ immediate: false } // 初始不触发,选择后触发
|
||||
)
|
||||
|
||||
// 监听上级账户变化
|
||||
watch(
|
||||
() => marketForm.value.parentAccountName,
|
||||
(newParentAccountName) => {
|
||||
handleMarketFormLinkage('parentAccountName', newParentAccountName)
|
||||
},
|
||||
{ immediate: false }
|
||||
)
|
||||
|
||||
/**
|
||||
* @description 定义表单初始值方法
|
||||
*/
|
||||
// 1. 定义表单初始值常量(方便复用)
|
||||
const initMarketForm = {
|
||||
email: '',
|
||||
phone: '',
|
||||
countryCode: '+86',
|
||||
accountName: '',
|
||||
level: '',
|
||||
parentAccountName: '',
|
||||
riskControlTemplate: '',
|
||||
positionRatio: '',
|
||||
commissionRatio: '',
|
||||
maxPositionRatio: '',
|
||||
maxCommissionRatio: '',
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
|
|
@ -133,22 +354,81 @@ const handleReset = async () => {
|
|||
marketSearchForm.value = {
|
||||
accountName: ''
|
||||
}
|
||||
page.value = 1
|
||||
currentPage.value = 1
|
||||
pageSize.value = 10
|
||||
await getMarketList()
|
||||
}
|
||||
|
||||
// 添加做市商
|
||||
const handleAddMarket = async () => {
|
||||
console.log('添加做市商');
|
||||
|
||||
dialogVisible.value = true
|
||||
dialogTitle.value = '添加'
|
||||
dialogType.value = 'add'
|
||||
// 2. 重置表单数据
|
||||
marketForm.value = { ...initMarketForm }
|
||||
dialogFullscreen.value = false;
|
||||
}
|
||||
|
||||
// 编辑做市商
|
||||
const handleEditMarket = async () => {
|
||||
console.log('编辑做市商');
|
||||
if (!selectedRow.value) {
|
||||
ElMessage.warning('请先选择要编辑的做市商!');
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
const row = selectedRow.value;
|
||||
console.log('row', row);
|
||||
|
||||
// 解析上级ID
|
||||
const getParentIdFromPath = (path: string, level: number) => {
|
||||
const segments = path.split('/').filter(Boolean);
|
||||
const levelNum = Number(level);
|
||||
const parentIndex = levelNum - 2;
|
||||
if (levelNum <= 1 || segments.length <= parentIndex) return '';
|
||||
return segments[parentIndex];
|
||||
};
|
||||
const parentId = getParentIdFromPath(row.path, row.level);
|
||||
console.log('解析后的上级ID:', parentId);
|
||||
|
||||
// 先初始化表单数据
|
||||
marketForm.value = {
|
||||
...initMarketForm,
|
||||
accountName: row.accountName || '',
|
||||
level: String(row.level) || '',
|
||||
parentAccountName: '',
|
||||
riskControlTemplate: row.wallet_capital.risk_control_id || '',
|
||||
positionRatio: row.positionRatio || '',
|
||||
commissionRatio: row.commissionRatio || '',
|
||||
};
|
||||
|
||||
try {
|
||||
// 先加载上级选项
|
||||
await handleMarketFormLinkage('level', marketForm.value.level);
|
||||
if (parentId) {
|
||||
marketForm.value.parentAccountName = parentId;
|
||||
}
|
||||
|
||||
// 再加载点差数据
|
||||
if (row.id) {
|
||||
const data = await getPointDiffConfigListApi({ user_id: row.id });
|
||||
marketPointTree.value = data.map((item: any) => ({
|
||||
...item,
|
||||
varietyName: item.name,
|
||||
varietyCode: item.code,
|
||||
pointDifference: item.point_diff,
|
||||
assignedPointDifference: item.target_point_diff || '', // 确保赋值正确
|
||||
}));
|
||||
}
|
||||
|
||||
// 所有数据加载完成后,再打开弹窗
|
||||
dialogVisible.value = true;
|
||||
dialogTitle.value = '编辑';
|
||||
dialogType.value = 'edit';
|
||||
dialogFullscreen.value = false;
|
||||
} catch (error) {
|
||||
console.error('编辑数据加载失败:', error);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
|
@ -157,14 +437,118 @@ const handleEditMarket = async () => {
|
|||
*/
|
||||
// 查看点差
|
||||
const handleViewPointDiff = async (row: any) => {
|
||||
console.log('查看点差', row);
|
||||
try {
|
||||
const data = await getPointDiffConfigListApi({ user_id: row.id });
|
||||
marketPointTree.value = data.map((item: any) => ({
|
||||
...item,
|
||||
varietyName: item.name,
|
||||
varietyCode: item.code,
|
||||
pointDifference: item.point_diff,
|
||||
assignedPointDifference: item.target_point_diff || ''
|
||||
}));
|
||||
|
||||
// 数据加载完成后再打开弹窗
|
||||
dialogVisible.value = true;
|
||||
dialogTitle.value = '查看点差';
|
||||
dialogType.value = 'view';
|
||||
dialogFullscreen.value = true;
|
||||
} catch (error) {
|
||||
console.error('加载点差数据失败:', error);
|
||||
}
|
||||
}
|
||||
|
||||
// 点击行事件
|
||||
const handleRowClick = (row: any) => {
|
||||
if (!row) {
|
||||
selectedRow.value = null
|
||||
return
|
||||
}
|
||||
selectedRow.value = row
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 分页方法
|
||||
*/
|
||||
// 分页变更
|
||||
const handlePaginationChange = async (page: { currentPage: number, pageSize: number }) => {
|
||||
currentPage.value = page.currentPage
|
||||
await getMarketList()
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @description dialog方法
|
||||
*/
|
||||
|
||||
//提交
|
||||
|
||||
/**
|
||||
* @description 提交之前构造数据
|
||||
|
||||
*/
|
||||
// 格式化点差为 { "1":"42", "2":"38" } 格式的对象
|
||||
const formatPointDiffToObject = () => {
|
||||
if (!marketPointTree.value || !marketPointTree.value.length) return {};
|
||||
|
||||
// 初始化空对象
|
||||
const pointDiffObj: Record<string, string> = {};
|
||||
|
||||
// 遍历表格数据,构造 { 编号: 点差值 } 的对象
|
||||
marketPointTree.value.forEach((item: { id: string | number; assignedPointDifference: string }) => {
|
||||
// 类型安全的赋值
|
||||
pointDiffObj[String(item.id)] = item.assignedPointDifference || '0';
|
||||
});
|
||||
|
||||
return pointDiffObj; // 返回纯对象,而非数组
|
||||
};
|
||||
|
||||
const handleSubmit = async () => {
|
||||
// console.log('提交', marketPointTree.value);
|
||||
await marketFormRef.value?.validate()
|
||||
const pointDiffObj = formatPointDiffToObject()
|
||||
if (dialogType.value === 'add') {
|
||||
const params = {
|
||||
role_id: marketForm.value.level,
|
||||
reg_type: activeTab.value === 'email' ? '1' : '2',
|
||||
username: marketForm.value.accountName,
|
||||
par_user_id: marketForm.value.parentAccountName,
|
||||
mobile: activeTab.value === 'phone' ? marketForm.value.phone : '',
|
||||
email: activeTab.value === 'email' ? marketForm.value.email : '',
|
||||
password: '888888',
|
||||
toucun_percent: marketForm.value.positionRatio,
|
||||
fee_handling_percent: marketForm.value.commissionRatio,
|
||||
point_diffs_json: JSON.stringify(pointDiffObj),
|
||||
risk_control_id: marketForm.value.riskControlTemplate,
|
||||
}
|
||||
await addMarketApi(params)
|
||||
// 5. 刷新表格数据
|
||||
await getMarketList()
|
||||
dialogVisible.value = false
|
||||
marketForm.value = { ...initMarketForm }
|
||||
} else if (dialogType.value === 'edit') {
|
||||
const params = {
|
||||
user_id: selectedRow.value.id,
|
||||
toucun_percent: marketForm.value.positionRatio,
|
||||
point_diffs_json: JSON.stringify(pointDiffObj),
|
||||
risk_control_id: marketForm.value.riskControlTemplate,
|
||||
fee_handling_percent: marketForm.value.commissionRatio,
|
||||
}
|
||||
// 4. 调用编辑接口
|
||||
await editMarketApi(params)
|
||||
}
|
||||
}
|
||||
|
||||
// 取消
|
||||
const handleCancel = async () => {
|
||||
dialogVisible.value = false
|
||||
// 重置点差数据和dialog类型
|
||||
}
|
||||
|
||||
// 关闭
|
||||
const handleClose = async () => {
|
||||
dialogVisible.value = false
|
||||
// 重置点差数据和dialog类型
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
|
@ -177,4 +561,38 @@ const handleViewPointDiff = async (row: any) => {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
.phone-email {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
|
||||
.tab-btn {
|
||||
display: flex;
|
||||
margin-right: 10px;
|
||||
|
||||
.el-button {
|
||||
height: 32px;
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.group {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
|
||||
.el-form-item {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.phone-item {
|
||||
:deep(.el-form-item__content) {
|
||||
flex-wrap: nowrap;
|
||||
}
|
||||
|
||||
.el-select {
|
||||
width: 110px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -43,27 +43,21 @@ export const marketTableColumns = [
|
|||
|
||||
//做市商添加配置
|
||||
export const marketFormItem = [
|
||||
//注册方式
|
||||
//邮箱或手机号
|
||||
{ prop: 'phoneOrEmail', label: '', type: 'slot' as const, slotName: 'phoneOrEmail' },
|
||||
//账户名称
|
||||
{ label: '账户名称', prop: 'accountName', type: 'input', placeholder: '请输入账户名称', },
|
||||
{ label: '账户名称', prop: 'accountName', type: 'input' as const, placeholder: '请输入账户名称', },
|
||||
//级别
|
||||
{ label: '级别', prop: 'level', type: 'select', placeholder: '请选择级别'},
|
||||
{ label: '级别', prop: 'level', type: 'select' as const, placeholder: '请选择级别'},
|
||||
//所属上级
|
||||
{ label: '所属上级', prop: 'parentAccountName', type: 'select', placeholder: '请输入所属上级账户名称', },
|
||||
{ label: '所属上级', prop: 'parentAccountName', type: 'select' as const, placeholder: '请选择所属上级账户名称', },
|
||||
// 风控模板
|
||||
{ label: '风控模板', prop: 'riskControlTemplate', type: 'select', placeholder: '请选择风控模板'},
|
||||
{ label: '风控模板', prop: 'riskControlTemplate', type: 'select' as const, placeholder: '请选择风控模板'},
|
||||
//头寸
|
||||
{ label: '头寸', prop: 'position', type: 'input', placeholder: '请输入头寸', },
|
||||
{ label: '头寸', prop: 'positionRatio', type: 'input' as const, placeholder: '请输入头寸', },
|
||||
//手续费
|
||||
{ label: '手续费', prop: 'commissionRatio', type: 'input', placeholder: '请输入手续费', },
|
||||
{ label: '手续费', prop: 'commissionRatio', type: 'input' as const, placeholder: '请输入手续费', },
|
||||
]
|
||||
export const marketPointTableColumns = ([
|
||||
{ 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' ,width:'160px',height:'600px'},
|
||||
])
|
||||
|
||||
// 国家码选项
|
||||
interface CountryItem {
|
||||
|
|
@ -78,4 +72,19 @@ export const countryOptions = ref<CountryItem[]>([
|
|||
{ name: '韩国', code: '+82' },
|
||||
{ name: '美国', code: '+1' },
|
||||
{ name: '新加坡', code: '+65' }
|
||||
])
|
||||
|
||||
export const marketPointTableColumns = ([
|
||||
{ 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'},
|
||||
])
|
||||
|
||||
// 查看点差表格列配置
|
||||
export const viewMarketPointTableColumns = ([
|
||||
{ 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},
|
||||
])
|
||||
|
|
@ -1,95 +1,148 @@
|
|||
// rules.ts
|
||||
import type { FormRules } from 'element-plus'
|
||||
|
||||
// 接收上级上限参数
|
||||
export const rules = (parentLimit: any = { position: 0, commissionRatio: 0 }): FormRules => {
|
||||
|
||||
export const rules = (marketForm: any, row?: any): FormRules => {
|
||||
return {
|
||||
//手机号
|
||||
phone: [
|
||||
{ required: true, message: '请输入手机号', trigger: ['blur'] },
|
||||
{ pattern: /^1[3-9]\d{9}$/, message: '请输入正确的手机号格式', trigger: ['blur'] },
|
||||
],
|
||||
//邮箱
|
||||
email: [
|
||||
{ required: true, message: '请输入邮箱地址', trigger: ['blur'] },
|
||||
{ type: 'email', message: '请输入正确的邮箱格式', trigger: ['blur'] }
|
||||
{ required: true, message: '请输入邮箱地址', trigger: ['blur', 'change'] },
|
||||
{ type: 'email', message: '请输入正确的邮箱格式', trigger: ['blur', 'change'] }
|
||||
],
|
||||
phone: [
|
||||
{
|
||||
validator: (rule, value, callback) => {
|
||||
// 验证国家码必填
|
||||
if (!marketForm.countryCode) {
|
||||
return callback(new Error('请选择国家/地区码'));
|
||||
}
|
||||
// 验证手机号必填
|
||||
if (!value) {
|
||||
return callback(new Error('请输入手机号码'));
|
||||
}
|
||||
// 中国大陆手机号格式验证(仅+86时生效)
|
||||
if (marketForm.countryCode === '+86' && !/^1[3-9]\d{9}$/.test(value)) {
|
||||
return callback(new Error('请输入正确的中国大陆手机号'));
|
||||
}
|
||||
callback();
|
||||
},
|
||||
trigger: ['blur', 'change']
|
||||
}
|
||||
],
|
||||
accountName: [
|
||||
{ required: true, message: '请输入账户名称', trigger: 'blur' },
|
||||
{ min: 2, max: 50, message: '账户名称长度需在2-50个字符之间', trigger: 'blur' }
|
||||
{ required: true, message: '请输入账号名称', trigger: 'blur' }
|
||||
],
|
||||
level: [
|
||||
{ required: true, message: '请选择级别', trigger: 'change' }
|
||||
{ required: true, message: '请选择等级', trigger: 'change' }
|
||||
],
|
||||
parentAccountName: [
|
||||
{ required: true, message: '请选择所属上级', trigger: 'change' }
|
||||
{ required: true, message: '请选择上级账号', trigger: 'change' }
|
||||
],
|
||||
riskControlTemplate: [
|
||||
{ required: true, message: '请选择风控模板', trigger: 'change' }
|
||||
],
|
||||
// 头寸:新增「不超过上级」校验
|
||||
position: [
|
||||
{ required: true, message: '请输入头寸', trigger: 'blur' },
|
||||
{ pattern: /^-?\d+(\.\d+)?$/, message: '头寸需为数字(支持整数/小数/负数)', trigger: 'blur' },
|
||||
{
|
||||
validator: (rule, value, callback) => {
|
||||
if (!value) return callback()
|
||||
const inputVal = Number(value)
|
||||
const maxVal = parentLimit.position
|
||||
if (inputVal > maxVal) {
|
||||
callback(new Error(`头寸不能大于上级的 ${maxVal}`))
|
||||
} else {
|
||||
callback()
|
||||
}
|
||||
},
|
||||
trigger: 'blur'
|
||||
}
|
||||
],
|
||||
// 手续费:新增「不超过上级」校验
|
||||
commissionRatio: [
|
||||
{ required: true, message: '请输入手续费', trigger: 'blur' },
|
||||
{ pattern: /^\d+(\.\d+)?$/, message: '手续费需为非负数字(支持整数/小数)', trigger: 'blur' },
|
||||
{ min: 0, max: 100, message: '手续费范围需在0-100之间', trigger: 'blur' },
|
||||
{
|
||||
validator: (rule, value, callback) => {
|
||||
if (!value) return callback()
|
||||
const inputVal = Number(value)
|
||||
const maxVal = parentLimit.commissionRatio
|
||||
if (inputVal > maxVal) {
|
||||
callback(new Error(`手续费不能大于上级的 ${maxVal}`))
|
||||
} else {
|
||||
callback()
|
||||
}
|
||||
},
|
||||
trigger: 'blur'
|
||||
}
|
||||
],
|
||||
// 新增:批量校验已分配点差
|
||||
pointDiffList: [
|
||||
{
|
||||
validator: (rule, value, callback) => {
|
||||
// value 是 marketPointTree 数组
|
||||
if (!value || value.length === 0) {
|
||||
return callback() // 没有点差数据时不校验
|
||||
// 空值已经由 required 校验处理
|
||||
if (value === '' || value === undefined || value === null) {
|
||||
return callback();
|
||||
}
|
||||
|
||||
// 遍历所有点差行,校验必填和数值合法性
|
||||
for (const row of value) {
|
||||
// 校验必填
|
||||
if (row.assignedPointDifference === '' || row.assignedPointDifference === undefined) {
|
||||
return callback(new Error(`品种【${row.varietyName || row.name}】的已分配点差不能为空`))
|
||||
}
|
||||
// 校验数值格式(非负数字)
|
||||
const numVal = Number(row.assignedPointDifference)
|
||||
if (isNaN(numVal) || numVal < 0) {
|
||||
return callback(new Error(`品种【${row.varietyName || row.name}】的已分配点差需为非负数字`))
|
||||
}
|
||||
// 可选:校验不超过上级点差
|
||||
if (row.pointDifference && numVal > Number(row.pointDifference)) {
|
||||
return callback(new Error(`品种【${row.varietyName || row.name}】的已分配点差不能超过可分配点差 ${row.pointDifference}`))
|
||||
// 尝试转换为数字
|
||||
const numValue = Number(value);
|
||||
|
||||
// 转换失败 → 不是有效数字
|
||||
if (isNaN(numValue)) {
|
||||
return callback(new Error('头寸必须为数字'));
|
||||
}
|
||||
|
||||
// 非负数校验
|
||||
if (numValue < 0) {
|
||||
return callback(new Error('头寸不能为负数'));
|
||||
}
|
||||
|
||||
// 精度校验(最多2位小数)
|
||||
if (!/^\d+(\.\d{1,2})?$/.test(value.toString())) {
|
||||
return callback(new Error('头寸最多保留2位小数'));
|
||||
}
|
||||
|
||||
// 不超过上级最大头寸校验
|
||||
if (marketForm.maxPositionRatio && numValue > Number(marketForm.maxPositionRatio)) {
|
||||
return callback(new Error(`头寸不能超过上级账户的最大头寸(${marketForm.maxPositionRatio})`));
|
||||
}
|
||||
|
||||
callback();
|
||||
},
|
||||
trigger: ['blur', 'change']
|
||||
}
|
||||
],
|
||||
commissionRatio: [
|
||||
{ required: true, message: '请输入手续费比例', trigger: 'blur' },
|
||||
{
|
||||
validator: (rule, value, callback) => {
|
||||
if (value === '' || value === undefined || value === null) {
|
||||
return callback();
|
||||
}
|
||||
|
||||
const numValue = Number(value);
|
||||
|
||||
if (isNaN(numValue)) {
|
||||
return callback(new Error('手续费比例必须为数字'));
|
||||
}
|
||||
|
||||
// // 范围校验(0-100)
|
||||
// if (numValue < 0 || numValue > 100) {
|
||||
// return callback(new Error('手续费比例需在0-100之间'));
|
||||
// }
|
||||
|
||||
// 精度校验(最多2位小数)
|
||||
if (!/^\d+(\.\d{1,2})?$/.test(value.toString())) {
|
||||
return callback(new Error('手续费比例最多保留2位小数'));
|
||||
}
|
||||
|
||||
// 不超过上级最大手续费比例校验
|
||||
if (marketForm.maxCommissionRatio && numValue > Number(marketForm.maxCommissionRatio)) {
|
||||
return callback(new Error(`手续费比例不能超过上级账户的最大比例(${marketForm.maxCommissionRatio})`));
|
||||
}
|
||||
|
||||
callback();
|
||||
},
|
||||
trigger: ['blur', 'change']
|
||||
}
|
||||
],
|
||||
assignedPointDifference: [
|
||||
{ required: true, message: '请输入点差', trigger: 'blur' },
|
||||
{
|
||||
validator: (rule, value, callback) => {
|
||||
if (value === '' || value === undefined || value === null) {
|
||||
return callback()
|
||||
}
|
||||
|
||||
const numValue = Number(value)
|
||||
|
||||
// 1. 基础数字校验
|
||||
if (isNaN(numValue)) {
|
||||
return callback(new Error('点差必须为数字'))
|
||||
}
|
||||
if (numValue < 0) {
|
||||
return callback(new Error('点差不能为负数'))
|
||||
}
|
||||
if (!/^\d+(\.\d{1,2})?$/.test(value.toString())) {
|
||||
return callback(new Error('点差最多保留2位小数'))
|
||||
}
|
||||
|
||||
// 2. 核心校验:已分配点差 ≤ 可分配点差
|
||||
if (row && row.pointDifference !== undefined) {
|
||||
const maxPointDiff = Number(row.pointDifference)
|
||||
if (numValue > maxPointDiff) {
|
||||
return callback(new Error(`不能超过可分配点差(${maxPointDiff})`))
|
||||
}
|
||||
}
|
||||
|
||||
callback()
|
||||
},
|
||||
trigger: 'change' // 数据变化时触发
|
||||
trigger: ['blur', 'change']
|
||||
}
|
||||
]
|
||||
],
|
||||
}
|
||||
}
|
||||
|
|
@ -1,523 +0,0 @@
|
|||
<template>
|
||||
<div class="market">
|
||||
<MarketSearch :search-form="marketSearchForm" :search-options="marketSearchOptions" @search="handleSearch"
|
||||
@reset="handleReset">
|
||||
<template #button="{ form }">
|
||||
<el-button type="primary" @click="handleAddAgent()">
|
||||
添加代理
|
||||
</el-button>
|
||||
<el-button type="primary" @click="handleEditAgent(tableRow)" :disabled="!tableRow">
|
||||
编辑
|
||||
</el-button>
|
||||
</template>
|
||||
</MarketSearch>
|
||||
|
||||
<MarketTable :table-data="marketTree" :columns="marketTableColumnsOptions" row-key="id"
|
||||
@row-click="handleRowClick">
|
||||
<template #pointSpread="{ row }">
|
||||
<el-button type="primary" size="small" @click="handleViewPointDiff(row)">
|
||||
查看
|
||||
</el-button>
|
||||
</template>
|
||||
</MarketTable>
|
||||
<MarketPagination v-model="marketSearchForm.page" v-model:page-size-value="marketSearchForm.pageSize"
|
||||
:total="total" @pagination-change="handlePaginationChange" />
|
||||
|
||||
<MarketDialog :visible="dialogVisible" :title="dialogTitle" :type="dialogType"
|
||||
:class="{ 'showForm-dialog': dialogType !== 'view' }" @confirm="handleSubmit" @cancel="handleCancel"
|
||||
@close="handleClose" :fullscreen="dialogFullscreen">
|
||||
<MarketForm :form-data="marketForm" :form-rules="marketFormRules" :form-items="marketFormItemOptions"
|
||||
:options-map="marketFormOptionsMap" ref="marketFormRef" @form-item-change="handleFormItemChange"
|
||||
v-if="dialogType !== 'view'">
|
||||
</MarketForm>
|
||||
<MarketTable :table-data="marketPointTree" :columns="marketPointTableColumnsOptions" row-key="id">
|
||||
<template #assignedPointDiff="{ row }">
|
||||
<el-form-item prop="assignedPointDifference">
|
||||
<el-input v-if="dialogType !== 'view'" v-model.number="row.assignedPointDifference" size="small"
|
||||
placeholder="请输入点差" />
|
||||
</el-form-item>
|
||||
</template>
|
||||
</MarketTable>
|
||||
</MarketDialog>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
// 组件
|
||||
import MarketSearch from '@/components/common/Search.vue'
|
||||
import MarketTable from '@/components/common/Table.vue'
|
||||
import MarketPagination from '@/components/common/Pagination.vue'
|
||||
import MarketDialog from '@/components/common/Dialog.vue'
|
||||
import MarketForm from '@/components/common/Form.vue'
|
||||
|
||||
// 接口
|
||||
import { getMarketListApi, getPointDiffConfigApi, getParAgentListApi } from '@/api/modules/account/market'
|
||||
|
||||
// 配置
|
||||
import { marketSearch, marketTableColumns, marketFormItem, marketPointTableColumns, countryOptions } from './options'
|
||||
import { rules } from './rules'
|
||||
|
||||
/**
|
||||
* @description 搜索配置
|
||||
*/
|
||||
const marketSearchForm = ref<any>({
|
||||
accountName: '',
|
||||
page: 1,
|
||||
pageSize: 10,
|
||||
})
|
||||
const marketSearchOptions = ref<any>(marketSearch)
|
||||
|
||||
/**
|
||||
* @description 表格配置
|
||||
*/
|
||||
const marketTableColumnsOptions = ref<any>(marketTableColumns)
|
||||
// 可选:存储完整的选中行数据
|
||||
const tableRow = ref<any>(null)
|
||||
const tableRowId = ref<number | null>(null)
|
||||
const tableRowRoleId = ref<number | null>(null)
|
||||
const marketTree = ref<any>([])
|
||||
/**
|
||||
* @description 分页配置
|
||||
*/
|
||||
const total = ref<number>(0)
|
||||
|
||||
/**
|
||||
* @description dialog配置
|
||||
*/
|
||||
|
||||
const dialogVisible = ref<boolean>(false)
|
||||
const dialogTitle = ref<string>('')
|
||||
const dialogType = ref<string>('add')
|
||||
const dialogFullscreen = ref(false)
|
||||
const activeTab = ref('email')
|
||||
/**
|
||||
* @description 点差表格配置
|
||||
*/
|
||||
const marketPointTree = ref<any>([])
|
||||
const marketPointTableColumnsOptions = ref<any>(marketPointTableColumns)
|
||||
|
||||
/**
|
||||
* @description 表单数据
|
||||
*/
|
||||
const marketForm = ref<any>({
|
||||
accountName: '',
|
||||
level: '',
|
||||
parentAccountName: '',
|
||||
position: '',
|
||||
commissionRatio: '',
|
||||
assignedPointDifference: '',
|
||||
pointDiffList: [] // 新增:存储点差表格数据,关联到表单规则
|
||||
})
|
||||
// 新增:存储上级做市商的钱包数据(用于手续费校验)
|
||||
const walletCapital = ref<any>({
|
||||
position: 0,
|
||||
commissionRatio: 0,
|
||||
})
|
||||
const marketFormOptionsMap = ref<any>({
|
||||
level: [
|
||||
{ label: '平台', value: '1' },
|
||||
{ label: '承包商', value: '2' },
|
||||
{ label: '特殊做市', value: '3' },
|
||||
{ label: '普通做市', value: '4' },
|
||||
{ label: '一级代理', value: '5' },
|
||||
],
|
||||
parentAccountName: [] // 新增:存储动态加载的上级代理列表
|
||||
})
|
||||
const showForm = ref<boolean>(true)
|
||||
const marketFormRef = ref<any>()
|
||||
const marketFormItemOptions = ref<any>(marketFormItem)
|
||||
const marketFormRules = ref<any>(rules(walletCapital.value))
|
||||
const pointDiffData = ref<any>({})
|
||||
/**
|
||||
* 级别映射工具函数(全局复用)
|
||||
* @param roleId 级别数字(1/2/3/4/5)
|
||||
* @returns 对应的文字标签
|
||||
*/
|
||||
const getLevelLabel = (roleId: number | string): string => {
|
||||
const levelMap: Record<string | number, string> = {
|
||||
'1': '平台',
|
||||
'2': '承包商',
|
||||
'3': '特殊做市',
|
||||
'4': '普通做市',
|
||||
'5': '一级代理'
|
||||
}
|
||||
return levelMap[roleId] || '未知级别'
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 点击表格行时,存储选中行的ID和数据
|
||||
*/
|
||||
const handleRowClick = (row: any) => {
|
||||
tableRow.value = row
|
||||
tableRowId.value = row.id
|
||||
tableRowRoleId.value = row.role_id
|
||||
console.log('点击行数据', row)
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 监听表单字段变化,获取所属上级列表 / 点差数据
|
||||
*/
|
||||
const handleFormItemChange = (field: string, value: any) => {
|
||||
// 监听 level 字段变化 → 加载所属上级列表
|
||||
if (field === 'level') {
|
||||
const levelRoleMap: Record<string, number> = {
|
||||
'1': 1, // 平台
|
||||
'2': 2, // 承包商
|
||||
'3': 3, // 特殊做市
|
||||
'4': 4, // 普通做市
|
||||
'5': 5 // 一级代理
|
||||
}
|
||||
const roleId = levelRoleMap[value]
|
||||
if (roleId) {
|
||||
fetchParAgentList(roleId)
|
||||
} else {
|
||||
marketFormOptionsMap.value.parentAccountName = []
|
||||
// 清空已选上级和表格数据
|
||||
marketForm.value.parentAccountName = ''
|
||||
marketPointTree.value = []
|
||||
}
|
||||
}
|
||||
|
||||
// 监听 parentAccountName 字段变化 → 用上级ID请求点差表格数据
|
||||
if (field === 'parentAccountName' && value) {
|
||||
// value 就是上级的 id(你在 fetchParAgentList 里配置的 value: item.id)
|
||||
fetchPointDiffConfigByParentId(value)
|
||||
|
||||
// 核心:获取选中上级的上限值
|
||||
const parentAgent = marketFormOptionsMap.value.parentAccountName.find(
|
||||
(item: any) => item.value === value
|
||||
)
|
||||
walletCapital.value.position = parentAgent.position
|
||||
walletCapital.value.commissionRatio = parentAgent.commissionRatio
|
||||
} else if (field === 'parentAccountName' && !value) {
|
||||
// 清空上级时,清空表格数据
|
||||
marketPointTree.value = []
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 统一获取数据
|
||||
*/
|
||||
|
||||
//获取做市商列表
|
||||
const fetchMarketList = async () => {
|
||||
const params = {
|
||||
page: marketSearchForm.value.page,
|
||||
page_size: marketSearchForm.value.pageSize,
|
||||
user_name: marketSearchForm.value.accountName
|
||||
}
|
||||
const data = await getMarketListApi(params)
|
||||
|
||||
// 处理表格数据
|
||||
marketTree.value = data.data.map((item: any) => ({
|
||||
...item,
|
||||
agentRelation: item.path_name || '--', // 代理关系
|
||||
accountName: item.username || '', // 账号名称
|
||||
level: getLevelLabel(item.role_id), // 等级(可根据role_id做枚举映射,比如 1->管理员 2->代理)
|
||||
basicAccount: item.wallet_capital?.amount || '0.00000', // 基本账户
|
||||
margin: item.wallet_capital?.bail || '0.00000', // 保证金
|
||||
stopOrderMargin: item.wallet_capital?.bail_stop_order || '0.00000', // 止单保证金
|
||||
positionTransferMargin: item.wallet_capital?.bail_change_order || '0.00000', // 转仓保证金
|
||||
pointSpreadCommission: item.wallet_capital?.commission_point_diff || '0.00000', // 点差佣金
|
||||
commissionRatio: item.wallet_capital?.toucun_percent || '0.00000', // 佣金比例
|
||||
commissionReturn: item.wallet_capital?.commission_fee_handling || '0.00000', // 佣金返还
|
||||
closeProfitLoss: item.wallet_capital?.closing_profit || '0.00000', // 平仓盈亏
|
||||
riskMargin: item.wallet_capital?.risk || '0.00000', // 风险保证金
|
||||
serviceFee: item.wallet_capital?.service || '0.00000' // 服务费
|
||||
}))
|
||||
|
||||
//分页数据
|
||||
total.value = Number(data.total)
|
||||
marketSearchForm.value.page = Number(data.current_page)
|
||||
marketSearchForm.value.pageSize = Number(data.per_page)
|
||||
|
||||
}
|
||||
|
||||
//获取代理点差配置
|
||||
const fetchPointDiffConfig = async () => {
|
||||
const params = {
|
||||
user_id: tableRowId.value
|
||||
}
|
||||
try {
|
||||
const data = await getPointDiffConfigApi(params)
|
||||
// 表格数据
|
||||
marketPointTree.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 fetchParAgentList = async (roleId?: number) => {
|
||||
const params = { role_id: roleId }
|
||||
try {
|
||||
const data = await getParAgentListApi(params)
|
||||
marketFormOptionsMap.value.parentAccountName = data.map((item: any) => ({
|
||||
label: item.accountName || item.username, // 显示的文字
|
||||
value: item.id, // 绑定的ID(必须和row.parent_id一致)
|
||||
position: item.wallet_capital.toucun_percent,
|
||||
commissionRatio: item.wallet_capital.toucun_percent
|
||||
}))
|
||||
} catch (err) {
|
||||
console.error('获取所属上级列表失败', err)
|
||||
marketFormOptionsMap.value.parentAccountName = []
|
||||
}
|
||||
}
|
||||
|
||||
// 根据上级代理ID获取点差配置表格数据
|
||||
const fetchPointDiffConfigByParentId = async (parentId: number) => {
|
||||
if (!parentId) {
|
||||
marketPointTree.value = []
|
||||
return
|
||||
}
|
||||
const params = { user_id: parentId }
|
||||
try {
|
||||
const data = await getPointDiffConfigApi(params)
|
||||
marketPointTree.value = data.map((item: any) => ({
|
||||
...item,
|
||||
varietyName: item.name,
|
||||
varietyCode: item.code,
|
||||
pointDifference: item.target_point_diff, // 可分配点差
|
||||
assignedPointDifference: '' // 已分配点差
|
||||
}))
|
||||
} catch (err) {
|
||||
console.error('获取上级点差配置失败', err)
|
||||
marketPointTree.value = []
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 组件挂载时获取数据
|
||||
*/
|
||||
onMounted(() => {
|
||||
fetchMarketList()
|
||||
})
|
||||
|
||||
/**
|
||||
* @description 搜索
|
||||
*/
|
||||
const handleSearch = async () => {
|
||||
await fetchMarketList()
|
||||
}
|
||||
const handleReset = () => {
|
||||
marketSearchForm.value.accountName = ''
|
||||
handleSearch()
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 处理弹窗类型
|
||||
*/
|
||||
const handleDialogType = (type: string) => {
|
||||
if (type === "view") {
|
||||
dialogFullscreen.value = true
|
||||
showForm.value = false
|
||||
} else {
|
||||
dialogFullscreen.value = false
|
||||
showForm.value = true
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 新增做市商
|
||||
*/
|
||||
const handleAddAgent = () => {
|
||||
dialogVisible.value = true
|
||||
dialogTitle.value = '新增做市商'
|
||||
dialogType.value = 'add'
|
||||
handleDialogType(dialogType.value)
|
||||
|
||||
// 重置表单
|
||||
marketForm.value = {
|
||||
accountName: '',
|
||||
level: '',
|
||||
parentAccountName: '',
|
||||
position: '',
|
||||
commissionRatio: '',
|
||||
}
|
||||
// 清空上级列表和点差表格
|
||||
marketFormOptionsMap.value.parentAccountName = []
|
||||
marketPointTree.value = []
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 编辑做市商
|
||||
*/
|
||||
const handleEditAgent = (row: any) => {
|
||||
if (!row) return
|
||||
dialogVisible.value = true
|
||||
dialogTitle.value = '编辑做市商'
|
||||
dialogType.value = 'edit'
|
||||
handleDialogType(dialogType.value)
|
||||
|
||||
// 1. 级别映射:数字 → 字符串value
|
||||
const levelValueMap: Record<string | number, string> = {
|
||||
'1': '1', '2': '2', '3': '3', '4': '4', '5': '5'
|
||||
}
|
||||
const levelValue = levelValueMap[row.role_id] || ''
|
||||
|
||||
// 2. 从 path 中提取上级 ID(path 格式: "/1/30/33" → 倒数第二段是上级ID)
|
||||
const pathSegments = row.path.split('/').filter(Boolean) // 分割后得到 ['1', '30', '33']
|
||||
const parentId = pathSegments.length >= 2 ? Number(pathSegments[pathSegments.length - 2]) : null
|
||||
|
||||
// 3. 回填表单
|
||||
marketForm.value = {
|
||||
...row,
|
||||
level: levelValue,
|
||||
parentAccountName: parentId // 用解析出的上级ID回填
|
||||
}
|
||||
|
||||
// 4. 加载上级列表
|
||||
const levelRoleMap: Record<string, number> = {
|
||||
'1': 1, '2': 2, '3': 3, '4': 4, '5': 5
|
||||
}
|
||||
const roleId = levelRoleMap[levelValue]
|
||||
if (roleId) {
|
||||
fetchParAgentList(roleId)
|
||||
}
|
||||
|
||||
// 5. 加载点差数据
|
||||
if (parentId) {
|
||||
fetchPointDiffConfigByParentId(parentId)
|
||||
} else {
|
||||
marketPointTree.value = []
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 查看点差
|
||||
*/
|
||||
const handleViewPointDiff = (row: any) => {
|
||||
tableRowId.value = row.id
|
||||
dialogVisible.value = true
|
||||
dialogTitle.value = '查看点差'
|
||||
dialogType.value = 'view'
|
||||
handleDialogType(dialogType.value)
|
||||
fetchPointDiffConfig()
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 分页变更
|
||||
*/
|
||||
const handlePaginationChange = (params: any) => {
|
||||
marketSearchForm.value.page = params.currentPage
|
||||
marketSearchForm.value.pageSize = params.pageSize
|
||||
handleSearch()
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 提交表单(新增/编辑做市商)
|
||||
*/
|
||||
const handleSubmit = async () => {
|
||||
// 组装成对象(按id为key),也可以组装成数组:const pointDiffList = []
|
||||
marketPointTree.value.forEach((row: any) => {
|
||||
if (row.assignedPointDifference || row.assignedPointDifference === 0) {
|
||||
pointDiffData.value[row.id] = row.assignedPointDifference
|
||||
}
|
||||
console.log('pointDiffData', pointDiffData.value)
|
||||
})
|
||||
await marketFormRef.value?.validate()
|
||||
if (dialogType.value === 'add') {
|
||||
// 新增做市商
|
||||
const params = {
|
||||
username: '',
|
||||
}
|
||||
} else if (dialogType.value === 'edit') {
|
||||
// 编辑做市商
|
||||
} else {
|
||||
// 查看点差
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 取消操作
|
||||
*/
|
||||
const handleCancel = () => {
|
||||
dialogVisible.value = false
|
||||
dialogType.value = 'add'
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 关闭弹窗
|
||||
*/
|
||||
const handleClose = () => {
|
||||
dialogVisible.value = false
|
||||
dialogType.value = 'add'
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.el-form {
|
||||
.el-form-item {
|
||||
flex: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
.market {
|
||||
.search-container {
|
||||
:deep(.el-form) {
|
||||
.el-form-item {
|
||||
flex: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.el-dialog) {
|
||||
.el-dialog__footer {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.showForm-dialog) {
|
||||
.el-dialog__footer {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
.phone-email {
|
||||
display: flex;
|
||||
|
||||
:deep(.el-form-item__content) {
|
||||
flex-wrap: nowrap;
|
||||
}
|
||||
|
||||
.tab-btn {
|
||||
display: flex;
|
||||
margin-right: 10px;
|
||||
|
||||
.el-button {
|
||||
margin-left: 0;
|
||||
background-color: transparent;
|
||||
border: 1px solid #DCDFE6;
|
||||
color: #303133;
|
||||
height: 32px;
|
||||
|
||||
}
|
||||
|
||||
.active {
|
||||
background-color: #409EFF;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
.email-item {
|
||||
.el-input {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.phone-item {
|
||||
.el-select {
|
||||
width: 120px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -41,7 +41,7 @@
|
|||
</el-checkbox>
|
||||
<!-- 添加子权限 change 事件监听 -->
|
||||
<el-checkbox-group v-model="formData.permissions" @change="handlePermissionChange">
|
||||
<el-checkbox v-for="perm in group" :key="perm.id" :label="perm.id">
|
||||
<el-checkbox v-for="perm in group" :key="perm.id" :value="perm.id">
|
||||
{{ perm.title }} ({{ perm.name }})
|
||||
</el-checkbox>
|
||||
</el-checkbox-group>
|
||||
|
|
|
|||
Loading…
Reference in New Issue