363 lines
12 KiB
Vue
363 lines
12 KiB
Vue
<template>
|
|
<div class="risk">
|
|
<div class="bar">
|
|
<span>风控管理</span>
|
|
<el-button type="primary" @click="handleAddRisk">添加</el-button>
|
|
<el-button type="primary" @click="handleModifyRisk">修改</el-button>
|
|
<el-button type="danger" @click="handleRiskStatus">停用</el-button>
|
|
</div>
|
|
<!-- 表格 -->
|
|
<div class="risk-table-content">
|
|
<RiskTableSwitch :columns="tableColumnsSwitch" :table-data="tableTreeSwitch" class="table-switch"
|
|
@row-click="handleRowClick" row-key="id" highlight-current-row :current-row-key="selectedRowId">
|
|
<template #status="{ row }">
|
|
<span>{{ row.status === 1 ? '启用' : '停用' }}</span>
|
|
</template>
|
|
</RiskTableSwitch>
|
|
<RiskTableContent :columns="tableColumnsContent" :table-data="[currentContent]" class="table-content"
|
|
row-key="id">
|
|
<template #contentName="{ row }">
|
|
<div class="risk-content-group">
|
|
<span>单笔开仓最大数量:{{ row.maxOpenPosition }}</span>
|
|
<span>单品种最大持仓数量:{{ row.maxPositionPerSymbol }}</span>
|
|
<span>总品种最大持仓数量:{{ row.maxTotalPosition }}</span>
|
|
<span>强平比例:{{ row.strongCloseRatio }}</span>
|
|
<span>每次出金最大金额:{{ row.maxWithdrawalAmount }}</span>
|
|
<span>是否允许出金:{{ row.isWithdrawalAllowed }}</span>
|
|
<span>出金时间设置:{{ row.withdrawalTimeSetting }}</span>
|
|
<span>是否需要出金审核:{{ row.isWithdrawalAuditRequired }}</span>
|
|
<span>建仓多少秒不能平仓:{{ row.buildCloseTime }}</span>
|
|
<span>每次出金最小金额:{{ row.minWithdrawalAmount }}</span>
|
|
<span>滑点:{{ row.slippage }}</span>
|
|
<span>每次入金最小金额:{{ row.minDepositAmount }}</span>
|
|
</div>
|
|
</template>
|
|
</RiskTableContent>
|
|
</div>
|
|
<!-- dialog -->
|
|
<RiskDialog :visible="dialogVisible" :title="dialogTitle" :type="dialogType" @confirm="handleSubmit"
|
|
@cancel="handleCancel" @close="handleClose">
|
|
<RiskForm :form-data="dialogForm" :form-rules="riskRules" :form-items="RiskFormItems"
|
|
:options-map="riskFormOptionsMap" :row-gutter="rowGutter" :col-span="colSpan" ref="riskFormRef" />
|
|
</RiskDialog>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
// 组件
|
|
import RiskTableSwitch from '@/components/common/Table.vue'
|
|
import RiskTableContent from '@/components/common/Table.vue'
|
|
import RiskDialog from '@/components/common/Dialog.vue'
|
|
import RiskForm from '@/components/common/Form.vue'
|
|
// 配置以及表单验证
|
|
import { tableColumnsSwitch, tableColumnsContent, formItem } from './options'
|
|
import { rules } from './rules'
|
|
|
|
// 接口
|
|
import { getRiskListApi, addRiskApi, editRiskApi } from '@/api/modules/risk'
|
|
|
|
// 公用方法
|
|
|
|
/**
|
|
* @description: 定义表格数据
|
|
*/
|
|
const tableTreeSwitch = ref([])
|
|
const tableTreeContent = ref([])
|
|
// 当前选中的行ID
|
|
const selectedRowId = ref<number | null>(null)
|
|
// 新增:存储接口返回的原始完整数据
|
|
const riskOriginData = ref<any[]>([])
|
|
// 当前选中的行数据
|
|
const selectedRow = ref<any>({})
|
|
// 右侧要展示的内容数据
|
|
const currentContent = ref<any>({})
|
|
|
|
/**
|
|
* @description: 定义弹窗数据
|
|
*/
|
|
const dialogVisible = ref(false)
|
|
const dialogTitle = ref('')
|
|
const dialogType = ref('')
|
|
/**
|
|
* @description: 定义弹窗表单数据
|
|
*/
|
|
const dialogForm = ref({
|
|
id: null,
|
|
name: '',
|
|
status: 1,
|
|
// 是否默认
|
|
isDefault: 1,
|
|
maxOpenPosition: null,
|
|
maxPositionPerSymbol: null,
|
|
maxTotalPosition: null,
|
|
strongCloseRatio: null,
|
|
maxWithdrawalAmount: null,
|
|
isWithdrawalAllowed: 1,
|
|
withdrawalTimeSetting: '',
|
|
isWithdrawalAuditRequired: 1,
|
|
buildCloseTime: null,
|
|
minWithdrawalAmount: null,
|
|
slippage: null,
|
|
minDepositAmount: null,
|
|
})
|
|
const riskRules = ref(rules())
|
|
const riskFormRef = ref()
|
|
|
|
const RiskFormItems = ref(formItem)
|
|
const riskFormOptionsMap = ref({
|
|
// 状态
|
|
status: [
|
|
{ label: '启用', value: 1 },
|
|
{ label: '停用', value: 2 },
|
|
],
|
|
// 是否默认
|
|
isDefault: [
|
|
{ label: '是', value: 1 },
|
|
{ label: '否', value: 2 },
|
|
],
|
|
// 是否允许出金
|
|
isWithdrawalAllowed: [
|
|
{ label: '是', value: 1 },
|
|
{ label: '否', value: 2 },
|
|
],
|
|
// 是否需要出金审核
|
|
isWithdrawalAuditRequired: [
|
|
{ label: '是', value: 1 },
|
|
{ label: '否', value: 2 },
|
|
],
|
|
})
|
|
const rowGutter = ref(20)
|
|
const colSpan = ref(12)
|
|
/**
|
|
* @description: 定义公共数据处理方法
|
|
*/
|
|
/**
|
|
* @description: 定义请求数据方法
|
|
*/
|
|
const getRiskList = async () => {
|
|
const data: any = await getRiskListApi()
|
|
// 保存原始数据
|
|
riskOriginData.value = data
|
|
// 处理数据
|
|
tableTreeSwitch.value = data.map((item: any) => ({
|
|
id: item.id,
|
|
name: item.name,
|
|
status: item.status,
|
|
}))
|
|
tableTreeContent.value = data.map((item: any) => ({
|
|
id: item.id,
|
|
isDefault: item.is_default,
|
|
// 单笔开仓最大数量
|
|
maxOpenPosition: item.max_opening_quantity_per_transaction,
|
|
// 单品种最大持仓数量
|
|
maxPositionPerSymbol: item.max_holding_quantity_per_variety,
|
|
// 总品种最大持仓数量
|
|
maxTotalPosition: item.max_holding_quantity_per_transaction,
|
|
// 强平比例
|
|
strongCloseRatio: item.strong_to_average_ratio,
|
|
// 每次出金最大金额
|
|
maxWithdrawalAmount: item.max_withdrawal_amount_per_transaction,
|
|
// 是否允许出金
|
|
isWithdrawalAllowed: item.withdraw_status === 1 ? '是' : '否',
|
|
// 出金时间设置
|
|
withdrawalTimeSetting: item.withdraw_time,
|
|
// 是否需要出金审核
|
|
isWithdrawalAuditRequired: item.withdraw_is_check === 1 ? '是' : '否',
|
|
// 建仓多少秒不能平仓
|
|
buildCloseTime: item.open_close_time,
|
|
// 每次出金最小金额
|
|
minWithdrawalAmount: item.min_withdrawal_amount_per_transaction,
|
|
// 滑点
|
|
slippage: item.slippage,
|
|
// 每次入金最小金额
|
|
minDepositAmount: item.min_recharge_amount_per_transaction,
|
|
}))
|
|
// 初始化默认选中第一条数据
|
|
if (tableTreeSwitch.value.length > 0) {
|
|
handleRowClick(tableTreeSwitch.value[0])
|
|
}
|
|
}
|
|
/**
|
|
* @description: 页面加载完成需要请求的数据
|
|
*/
|
|
onMounted(() => {
|
|
getRiskList()
|
|
})
|
|
|
|
/**
|
|
* @description: 定义bar方法
|
|
*/
|
|
const handleAddRisk = () => {
|
|
dialogVisible.value = true
|
|
dialogTitle.value = '添加'
|
|
dialogType.value = 'add'
|
|
dialogForm.value = {
|
|
id: null,
|
|
name: '',
|
|
status: 1,
|
|
// 是否默认
|
|
isDefault: 1,
|
|
maxOpenPosition: null,
|
|
maxPositionPerSymbol: null,
|
|
maxTotalPosition: null,
|
|
strongCloseRatio: null,
|
|
maxWithdrawalAmount: null,
|
|
isWithdrawalAllowed: 1,
|
|
withdrawalTimeSetting: '',
|
|
isWithdrawalAuditRequired: 1,
|
|
buildCloseTime: null,
|
|
minWithdrawalAmount: null,
|
|
slippage: null,
|
|
minDepositAmount: null,
|
|
}
|
|
}
|
|
const handleModifyRisk = () => {
|
|
dialogVisible.value = true
|
|
dialogTitle.value = '修改'
|
|
dialogType.value = 'edit'
|
|
dialogForm.value = {
|
|
name: selectedRow.value.name,
|
|
status: selectedRow.value.status,
|
|
// 是否默认
|
|
isDefault: selectedRow.value.is_default,
|
|
maxOpenPosition: selectedRow.value.max_opening_quantity_per_transaction,
|
|
maxPositionPerSymbol: selectedRow.value.max_holding_quantity_per_variety,
|
|
maxTotalPosition: selectedRow.value.max_holding_quantity_per_transaction,
|
|
strongCloseRatio: selectedRow.value.strong_to_average_ratio,
|
|
maxWithdrawalAmount: selectedRow.value.max_withdrawal_amount_per_transaction,
|
|
isWithdrawalAllowed: selectedRow.value.withdraw_status,
|
|
withdrawalTimeSetting: selectedRow.value.withdraw_time.split('-'),
|
|
isWithdrawalAuditRequired: selectedRow.value.withdraw_is_check,
|
|
buildCloseTime: selectedRow.value.open_close_time,
|
|
minWithdrawalAmount: selectedRow.value.min_withdrawal_amount_per_transaction,
|
|
slippage: selectedRow.value.slippage,
|
|
minDepositAmount: selectedRow.value.min_recharge_amount_per_transaction,
|
|
} as any
|
|
}
|
|
|
|
const handleRiskStatus = async () => {
|
|
dialogTitle.value = '停用'
|
|
dialogType.value = 'status'
|
|
await editRiskApi({ ...selectedRow.value, status: 2 })
|
|
getRiskList()
|
|
}
|
|
|
|
/**
|
|
* @description: 定义表格方法
|
|
*/
|
|
const handleRowClick = (row: any) => {
|
|
// 从原始数据中匹配完整的行信息
|
|
const originRow = riskOriginData.value.find(item => item.id === row.id)
|
|
if (originRow) {
|
|
selectedRow.value = originRow // 保存完整原始数据
|
|
} else {
|
|
selectedRow.value = row
|
|
}
|
|
selectedRowId.value = row.id
|
|
// 找到对应的数据并更新右侧内容
|
|
const targetItem = tableTreeContent.value.find((item: any) => item.id === row.id)
|
|
if (targetItem) {
|
|
currentContent.value = targetItem
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @description: 定义弹窗方法
|
|
*/
|
|
const handleSubmit = async () => {
|
|
await riskFormRef.value?.validate()
|
|
const params = {
|
|
name: dialogForm.value.name,
|
|
status: dialogForm.value.status,
|
|
// 是否默认
|
|
is_default: dialogForm.value.isDefault,
|
|
// 单笔开仓最大数量
|
|
max_opening_quantity_per_transaction: dialogForm.value.maxOpenPosition,
|
|
// 单品种最大持仓数量
|
|
max_holding_quantity_per_variety: dialogForm.value.maxPositionPerSymbol,
|
|
// 总品种最大持仓数量
|
|
max_holding_quantity_per_transaction: dialogForm.value.maxTotalPosition,
|
|
// 强平比例
|
|
strong_to_average_ratio: dialogForm.value.strongCloseRatio,
|
|
// 每次出金最大金额
|
|
max_withdrawal_amount_per_transaction: dialogForm.value.maxWithdrawalAmount,
|
|
// 是否允许出金
|
|
withdraw_status: dialogForm.value.isWithdrawalAllowed,
|
|
// 出金时间设置
|
|
withdraw_time: Array.from(dialogForm.value.withdrawalTimeSetting || []).join('-'),
|
|
// 是否需要出金审核
|
|
withdraw_is_check: dialogForm.value.isWithdrawalAuditRequired,
|
|
// 建仓多少秒不能平仓
|
|
open_close_time: dialogForm.value.buildCloseTime,
|
|
// 每次出金最小金额
|
|
min_withdrawal_amount_per_transaction: dialogForm.value.minWithdrawalAmount,
|
|
// 滑点
|
|
slippage: dialogForm.value.slippage,
|
|
// 每次入金最小金额
|
|
min_recharge_amount_per_transaction: dialogForm.value.minDepositAmount,
|
|
}
|
|
// 添加风险控制
|
|
if (dialogType.value === 'add') {
|
|
// 添加风险控制
|
|
await addRiskApi(params)
|
|
getRiskList()
|
|
dialogVisible.value = false
|
|
dialogTitle.value = '添加'
|
|
dialogType.value = 'add'
|
|
}
|
|
else {
|
|
// 编辑风险控制
|
|
await editRiskApi({ ...params, id: selectedRow.value.id })
|
|
getRiskList()
|
|
dialogVisible.value = false
|
|
dialogTitle.value = '编辑'
|
|
dialogType.value = 'edit'
|
|
}
|
|
}
|
|
const handleCancel = () => {
|
|
dialogVisible.value = false
|
|
}
|
|
const handleClose = () => {
|
|
dialogVisible.value = false
|
|
}
|
|
</script>
|
|
|
|
|
|
<style scoped>
|
|
.risk {
|
|
.bar {
|
|
margin-bottom: 10px;
|
|
display: flex;
|
|
align-items: center;
|
|
|
|
span {
|
|
margin-right: 10px;
|
|
}
|
|
}
|
|
|
|
.risk-table-content {
|
|
display: flex;
|
|
gap: 10px;
|
|
|
|
.table-switch {
|
|
flex-basis: 20%;
|
|
min-width: 200px;
|
|
|
|
:deep(.el-table__row.current-row) {
|
|
background-color: #ecf5ff !important;
|
|
}
|
|
}
|
|
}
|
|
|
|
.table-content {
|
|
flex: 1;
|
|
|
|
.risk-content-group {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 5px;
|
|
}
|
|
}
|
|
}
|
|
</style>
|