Merge branch 'yueyixin'
This commit is contained in:
commit
609764b39c
13
src/App.vue
13
src/App.vue
|
|
@ -1,8 +1,21 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="app-container">
|
<div class="app-container">
|
||||||
|
<TopLoading ref="topLoadingRef" />
|
||||||
<KeepAlive>
|
<KeepAlive>
|
||||||
<router-view></router-view>
|
<router-view></router-view>
|
||||||
</KeepAlive>
|
</KeepAlive>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, onMounted } from 'vue'
|
||||||
|
import TopLoading from '@/components/common/TopLoading.vue'
|
||||||
|
|
||||||
|
const topLoadingRef = ref<InstanceType<typeof TopLoading>>()
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
// 将 TopLoading 实例挂载到 window 上,供 api 模块调用
|
||||||
|
// @ts-ignore
|
||||||
|
window.__topLoading__ = topLoadingRef.value
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -1,35 +1,33 @@
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
import type { AxiosResponse, AxiosError, InternalAxiosRequestConfig } from 'axios'
|
import type { AxiosResponse, AxiosError, InternalAxiosRequestConfig } from 'axios'
|
||||||
import type { ApiResponse } from '@/api/types'
|
import type { ApiResponse } from '@/api/types'
|
||||||
import { ElLoading, ElNotification } from 'element-plus'
|
import { ElNotification } from 'element-plus'
|
||||||
import { getStorage, setStorage, removeStorage } from '@/utils/storage'
|
import { getStorage, setStorage, removeStorage } from '@/utils/storage'
|
||||||
import router from '../router'
|
import router from '../router'
|
||||||
|
|
||||||
// 定义loading实例类型,用于控制loading的显示和关闭
|
// 记录当前请求数量,用于控制顶部进度条
|
||||||
let loadingInstance: ReturnType<typeof ElLoading.service> | null = null
|
|
||||||
// 记录当前请求数量,防止多个请求重复显示/关闭loading
|
|
||||||
let requestCount = 0
|
let requestCount = 0
|
||||||
|
|
||||||
// 显示loading的方法
|
// 获取 TopLoading 实例
|
||||||
|
const getTopLoading = () => {
|
||||||
|
// @ts-ignore
|
||||||
|
return window.__topLoading__
|
||||||
|
}
|
||||||
|
|
||||||
|
// 显示顶部进度条
|
||||||
const showLoading = () => {
|
const showLoading = () => {
|
||||||
if (requestCount === 0 && !loadingInstance) {
|
if (requestCount === 0) {
|
||||||
loadingInstance = ElLoading.service({
|
getTopLoading()?.start()
|
||||||
lock: true, // 锁定屏幕滚动
|
|
||||||
fullscreen: true, // 全屏显示
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
requestCount++
|
requestCount++
|
||||||
}
|
}
|
||||||
|
|
||||||
// 关闭loading的方法
|
// 关闭顶部进度条
|
||||||
const hideLoading = () => {
|
const hideLoading = () => {
|
||||||
requestCount--
|
requestCount--
|
||||||
if (requestCount <= 0) {
|
if (requestCount <= 0) {
|
||||||
if (loadingInstance) {
|
getTopLoading()?.complete()
|
||||||
loadingInstance.close()
|
requestCount = 0
|
||||||
loadingInstance = null
|
|
||||||
}
|
|
||||||
requestCount = 0 // 重置计数,防止负数
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -49,10 +47,8 @@ const service = axios.create({
|
||||||
const requestInterceptor = (config: InternalAxiosRequestConfig) => {
|
const requestInterceptor = (config: InternalAxiosRequestConfig) => {
|
||||||
console.log('请求配置', config)
|
console.log('请求配置', config)
|
||||||
|
|
||||||
// 显示loading(可通过config配置项控制是否显示,比如某些请求不需要loading)
|
// 显示顶部进度条
|
||||||
if (config.headers?.showLoading !== false) {
|
showLoading()
|
||||||
showLoading()
|
|
||||||
}
|
|
||||||
// 添加token到请求头
|
// 添加token到请求头
|
||||||
const token = getStorage('token')
|
const token = getStorage('token')
|
||||||
if (token) {
|
if (token) {
|
||||||
|
|
|
||||||
|
|
@ -14,3 +14,8 @@ export const getSelfVarietyPointDiffConfigApi = (params: any) => {
|
||||||
export const editCustomerApi = (params: any) => {
|
export const editCustomerApi = (params: any) => {
|
||||||
return request.post('/agent/editAgent', {...params})
|
return request.post('/agent/editAgent', {...params})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//编辑代理客户接口
|
||||||
|
export const updateToAgent = (params: any) => {
|
||||||
|
return request.post('/agent/updateToAgent', {...params})
|
||||||
|
}
|
||||||
|
|
@ -16,7 +16,7 @@
|
||||||
<template #footer v-if="showFooter">
|
<template #footer v-if="showFooter">
|
||||||
<slot name="footer">
|
<slot name="footer">
|
||||||
<el-button @click="handleCancel">取消</el-button>
|
<el-button @click="handleCancel">取消</el-button>
|
||||||
<el-button type="primary" @click="handleConfirm">确定</el-button>
|
<el-button type="primary" :loading="buttonLoading" @click="handleConfirm">确定</el-button>
|
||||||
</slot>
|
</slot>
|
||||||
</template>
|
</template>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
|
@ -31,6 +31,7 @@ interface Props {
|
||||||
type?: string
|
type?: string
|
||||||
showFooter?: boolean
|
showFooter?: boolean
|
||||||
fullscreen?: boolean
|
fullscreen?: boolean
|
||||||
|
buttonLoading?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Emits {
|
interface Emits {
|
||||||
|
|
@ -45,6 +46,7 @@ const props = withDefaults(defineProps<Props>(), {
|
||||||
destroyOnClose: true,
|
destroyOnClose: true,
|
||||||
showFooter: true,
|
showFooter: true,
|
||||||
fullscreen: false,
|
fullscreen: false,
|
||||||
|
buttonLoading: false,
|
||||||
})
|
})
|
||||||
|
|
||||||
const emit = defineEmits<Emits>()
|
const emit = defineEmits<Emits>()
|
||||||
|
|
|
||||||
|
|
@ -44,10 +44,10 @@
|
||||||
|
|
||||||
<!-- 操作按钮 -->
|
<!-- 操作按钮 -->
|
||||||
<el-form-item>
|
<el-form-item>
|
||||||
<el-button type="primary" @click="$emit('search')">
|
<el-button type="primary" :loading="buttonLoading" @click="$emit('search')">
|
||||||
{{ buttonConfig.searchText || '搜索' }}
|
{{ buttonConfig.searchText || '搜索' }}
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button @click="$emit('reset')">
|
<el-button :loading="buttonLoading" @click="$emit('reset')">
|
||||||
{{ buttonConfig.resetText || '重置' }}
|
{{ buttonConfig.resetText || '重置' }}
|
||||||
</el-button>
|
</el-button>
|
||||||
<!-- 按钮区插槽 -->
|
<!-- 按钮区插槽 -->
|
||||||
|
|
@ -99,6 +99,10 @@ const props = defineProps({
|
||||||
type: Object as () => ButtonConfig,
|
type: Object as () => ButtonConfig,
|
||||||
default: () => ({}),
|
default: () => ({}),
|
||||||
},
|
},
|
||||||
|
buttonLoading: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
// 暴露事件
|
// 暴露事件
|
||||||
|
|
|
||||||
|
|
@ -8,10 +8,16 @@
|
||||||
:tree-props="treeProps"
|
:tree-props="treeProps"
|
||||||
:border="border"
|
:border="border"
|
||||||
:highlight-current-row="highlightCurrentRow"
|
:highlight-current-row="highlightCurrentRow"
|
||||||
|
v-loading="loading"
|
||||||
v-bind="$attrs"
|
v-bind="$attrs"
|
||||||
@row-click="handleRowClick"
|
@row-click="handleRowClick"
|
||||||
@row-contextmenu="handleRowContextmenu"
|
@row-contextmenu="handleRowContextmenu"
|
||||||
|
@selection-change="handleSelectionChange"
|
||||||
|
@current-change="handleCurrentChange"
|
||||||
>
|
>
|
||||||
|
<!-- 勾选列 -->
|
||||||
|
<el-table-column v-if="showSelection" type="selection" width="55" align="center" />
|
||||||
|
|
||||||
<!-- 动态表头列 -->
|
<!-- 动态表头列 -->
|
||||||
<template v-for="(column, index) in columns" :key="index">
|
<template v-for="(column, index) in columns" :key="index">
|
||||||
<el-table-column
|
<el-table-column
|
||||||
|
|
@ -28,7 +34,11 @@
|
||||||
:width="column.width"
|
:width="column.width"
|
||||||
:align="column.align || 'left'"
|
:align="column.align || 'left'"
|
||||||
:sortable="column.sortable"
|
:sortable="column.sortable"
|
||||||
/>
|
>
|
||||||
|
<template v-if="column.isNumber" #default="{ row }">
|
||||||
|
<span>{{ formatDecimalTruncate(row[column.prop]) }}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
|
||||||
<!-- 具名插槽列 -->
|
<!-- 具名插槽列 -->
|
||||||
<el-table-column
|
<el-table-column
|
||||||
|
|
@ -49,6 +59,7 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, watch } from 'vue'
|
import { ref, watch } from 'vue'
|
||||||
import type { TableInstance } from 'element-plus'
|
import type { TableInstance } from 'element-plus'
|
||||||
|
import { formatDecimalTruncate } from '@/utils/formatDecimal'
|
||||||
|
|
||||||
// 定义表格列配置接口
|
// 定义表格列配置接口
|
||||||
interface TableColumn {
|
interface TableColumn {
|
||||||
|
|
@ -59,6 +70,7 @@ interface TableColumn {
|
||||||
align?: 'left' | 'center' | 'right'
|
align?: 'left' | 'center' | 'right'
|
||||||
slotName?: string // 具名插槽名称
|
slotName?: string // 具名插槽名称
|
||||||
sortable?: boolean // 是否可排序
|
sortable?: boolean // 是否可排序
|
||||||
|
isNumber?: boolean // 是否为数字类型(自动截取小数位)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 定义表格组件属性接口
|
// 定义表格组件属性接口
|
||||||
|
|
@ -71,19 +83,39 @@ interface Props {
|
||||||
columns?: TableColumn[]
|
columns?: TableColumn[]
|
||||||
border?: boolean // 是否显示边框
|
border?: boolean // 是否显示边框
|
||||||
highlightCurrentRow?: boolean // 是否高亮当前行
|
highlightCurrentRow?: boolean // 是否高亮当前行
|
||||||
|
loading?: boolean // 是否显示加载状态
|
||||||
|
showSelection?: boolean // 是否显示勾选列
|
||||||
}
|
}
|
||||||
|
|
||||||
const props = withDefaults(defineProps<Props>(), {
|
const props = withDefaults(defineProps<Props>(), {
|
||||||
border: true,
|
border: true,
|
||||||
highlightCurrentRow: true,
|
highlightCurrentRow: true,
|
||||||
|
loading: false,
|
||||||
|
showSelection: false,
|
||||||
})
|
})
|
||||||
|
|
||||||
// 定义组件抛出的事件
|
// 定义组件抛出的事件
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
(e: 'row-click', row: any): void // 保留原有行点击事件
|
(e: 'row-click', row: any): void // 保留原有行点击事件
|
||||||
(e: 'row-contextmenu', row: any, column: any, event: MouseEvent): void
|
(e: 'row-contextmenu', row: any, column: any, event: MouseEvent): void
|
||||||
|
(e: 'selection-change', rows: any[]): void // 勾选变化事件
|
||||||
|
(e: 'current-change', row: any): void // 当前行变化事件
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
|
// 处理勾选变化
|
||||||
|
const handleSelectionChange = (rows: any[]) => {
|
||||||
|
emit('selection-change', rows)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理当前行变化
|
||||||
|
const handleCurrentChange = (row: any) => {
|
||||||
|
// 添加空值保护,避免传递 null 导致 Vue 响应式系统报错
|
||||||
|
if (row === null || row === undefined) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
emit('current-change', row)
|
||||||
|
}
|
||||||
|
|
||||||
const tableRef = ref<TableInstance>()
|
const tableRef = ref<TableInstance>()
|
||||||
|
|
||||||
// 维护当前选中行状态,用于二次点击取消选中
|
// 维护当前选中行状态,用于二次点击取消选中
|
||||||
|
|
@ -100,7 +132,7 @@ const handleRowClick = (row: any) => {
|
||||||
if (selectedRow.value && selectedRow.value === row) {
|
if (selectedRow.value && selectedRow.value === row) {
|
||||||
// 二次点击:取消选中
|
// 二次点击:取消选中
|
||||||
selectedRow.value = null
|
selectedRow.value = null
|
||||||
tableRef.value?.setCurrentRow() // 不传参即清除选中 [^14^]
|
tableRef.value?.setCurrentRow(null) // 传 null 清除选中
|
||||||
} else {
|
} else {
|
||||||
// 首次点击或点击不同行:选中该行
|
// 首次点击或点击不同行:选中该行
|
||||||
selectedRow.value = row
|
selectedRow.value = row
|
||||||
|
|
@ -124,16 +156,29 @@ watch(
|
||||||
() => {
|
() => {
|
||||||
// 数据更新时,清除选中状态
|
// 数据更新时,清除选中状态
|
||||||
selectedRow.value = null
|
selectedRow.value = null
|
||||||
tableRef.value?.setCurrentRow() // 不传参即清除选中 [^14^]
|
tableRef.value?.setCurrentRow(null)
|
||||||
},
|
},
|
||||||
{ deep: true }, // 深度监听,防止数组元素变化未触发
|
{ deep: true }, // 深度监听,防止数组元素变化未触发
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// 监听 loading 属性变化,确保状态同步
|
||||||
|
watch(
|
||||||
|
() => props.loading,
|
||||||
|
(newVal) => {
|
||||||
|
// loading 状态变化时可以执行额外的处理
|
||||||
|
console.log('Table loading status changed:', newVal)
|
||||||
|
},
|
||||||
|
{ flush: 'sync' }, // 使用 sync 模式确保即时响应
|
||||||
|
)
|
||||||
|
|
||||||
// 暴露清除当前选中行的方法
|
// 暴露清除当前选中行的方法
|
||||||
defineExpose({
|
defineExpose({
|
||||||
clearCurrentRow: () => {
|
clearCurrentRow: () => {
|
||||||
selectedRow.value = null
|
selectedRow.value = null
|
||||||
tableRef.value?.setCurrentRow()
|
tableRef.value?.setCurrentRow(null)
|
||||||
|
},
|
||||||
|
setCurrentRow: (row: any) => {
|
||||||
|
tableRef.value?.setCurrentRow(row)
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,62 @@
|
||||||
|
<template>
|
||||||
|
<Teleport to="body">
|
||||||
|
<div v-if="visible" class="top-loading-bar">
|
||||||
|
<div class="loading-progress" :style="{ width: progress + '%' }"></div>
|
||||||
|
</div>
|
||||||
|
</Teleport>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref } from 'vue'
|
||||||
|
|
||||||
|
const visible = ref(false)
|
||||||
|
const progress = ref(0)
|
||||||
|
let timer: ReturnType<typeof setInterval> | null = null
|
||||||
|
|
||||||
|
const start = () => {
|
||||||
|
visible.value = true
|
||||||
|
progress.value = 0
|
||||||
|
// 模拟进度条动画,最多到 90%
|
||||||
|
timer = setInterval(() => {
|
||||||
|
if (progress.value < 90) {
|
||||||
|
progress.value += Math.random() * 15 + 5
|
||||||
|
}
|
||||||
|
}, 150)
|
||||||
|
}
|
||||||
|
|
||||||
|
const complete = () => {
|
||||||
|
if (timer) {
|
||||||
|
clearInterval(timer)
|
||||||
|
timer = null
|
||||||
|
}
|
||||||
|
progress.value = 100
|
||||||
|
setTimeout(() => {
|
||||||
|
visible.value = false
|
||||||
|
progress.value = 0
|
||||||
|
}, 200)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 暴露方法给外部调用
|
||||||
|
defineExpose({
|
||||||
|
start,
|
||||||
|
complete,
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.top-loading-bar {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 3px;
|
||||||
|
z-index: 9999;
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading-progress {
|
||||||
|
height: 100%;
|
||||||
|
background: #409eff; // Element Plus 主色调
|
||||||
|
transition: width 0.15s linear;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -11,7 +11,7 @@
|
||||||
<!-- 右侧内容区:页签 + 主体内容 -->
|
<!-- 右侧内容区:页签 + 主体内容 -->
|
||||||
<section class="content-container">
|
<section class="content-container">
|
||||||
<!-- 页签标签栏 -->
|
<!-- 页签标签栏 -->
|
||||||
<!-- <Tabs /> -->
|
<Tabs />
|
||||||
|
|
||||||
<!-- 主体内容区 -->
|
<!-- 主体内容区 -->
|
||||||
<main class="main-content">
|
<main class="main-content">
|
||||||
|
|
@ -22,9 +22,9 @@
|
||||||
>
|
>
|
||||||
<router-view v-slot="{ Component }">
|
<router-view v-slot="{ Component }">
|
||||||
<KeepAlive v-if="route.meta.keepAlive">
|
<KeepAlive v-if="route.meta.keepAlive">
|
||||||
<component :is="Component" :key="route.path" />
|
<component :is="Component" :key="refreshKey" />
|
||||||
</KeepAlive>
|
</KeepAlive>
|
||||||
<component v-else :is="Component" :key="route.path" />
|
<component v-else :is="Component" :key="refreshKey" />
|
||||||
</router-view>
|
</router-view>
|
||||||
</transition>
|
</transition>
|
||||||
</main>
|
</main>
|
||||||
|
|
@ -40,8 +40,19 @@ defineOptions({
|
||||||
import Header from './Header.vue'
|
import Header from './Header.vue'
|
||||||
import Sidebar from './Sidebar.vue'
|
import Sidebar from './Sidebar.vue'
|
||||||
import Tabs from './Tabs.vue'
|
import Tabs from './Tabs.vue'
|
||||||
|
import { useTabsStore } from '@/stores/modules/tabs'
|
||||||
|
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
|
const tabsStore = useTabsStore()
|
||||||
|
|
||||||
|
// 用于组件重新渲染的 key
|
||||||
|
const refreshKey = computed(() => {
|
||||||
|
// 当 refreshKey 包含当前路由时,重新渲染组件
|
||||||
|
if (tabsStore.refreshKey.startsWith(route.path)) {
|
||||||
|
return tabsStore.refreshKey
|
||||||
|
}
|
||||||
|
return route.path
|
||||||
|
})
|
||||||
|
|
||||||
// 侧边栏收缩状态
|
// 侧边栏收缩状态
|
||||||
const sidebarCollapsed = ref(false)
|
const sidebarCollapsed = ref(false)
|
||||||
|
|
|
||||||
|
|
@ -82,7 +82,11 @@
|
||||||
:style="contextMenuStyle"
|
:style="contextMenuStyle"
|
||||||
@click.stop
|
@click.stop
|
||||||
>
|
>
|
||||||
<div class="context-menu-item" @click="handleContextMenuCommand('refresh')">
|
<div
|
||||||
|
class="context-menu-item"
|
||||||
|
:class="{ 'is-disabled': !canRefresh }"
|
||||||
|
@click="canRefresh && handleContextMenuCommand('refresh')"
|
||||||
|
>
|
||||||
<el-icon><Refresh /></el-icon>
|
<el-icon><Refresh /></el-icon>
|
||||||
<span>刷新当前页</span>
|
<span>刷新当前页</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -140,6 +144,12 @@ const canCloseCurrent = computed(() => {
|
||||||
return !isFixedTab(path)
|
return !isFixedTab(path)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// 能否刷新(右键点击的 tab 是当前打开的页面)
|
||||||
|
const canRefresh = computed(() => {
|
||||||
|
const path = contextMenuPath.value || ''
|
||||||
|
return path === route.path
|
||||||
|
})
|
||||||
|
|
||||||
// 能否关闭其他(除了固定标签和右键点击的标签外还有其他标签)
|
// 能否关闭其他(除了固定标签和右键点击的标签外还有其他标签)
|
||||||
const canCloseOther = computed(() => {
|
const canCloseOther = computed(() => {
|
||||||
const path = contextMenuPath.value || tabsStore.activeTab || ''
|
const path = contextMenuPath.value || tabsStore.activeTab || ''
|
||||||
|
|
@ -393,11 +403,32 @@ const handleDragEnd = () => {
|
||||||
const handleContextMenuCommand = (command: string) => {
|
const handleContextMenuCommand = (command: string) => {
|
||||||
// 使用右键选中的路径,如果没有则用当前激活的标签
|
// 使用右键选中的路径,如果没有则用当前激活的标签
|
||||||
const currentPath = contextMenuPath.value || tabsStore.activeTab
|
const currentPath = contextMenuPath.value || tabsStore.activeTab
|
||||||
|
|
||||||
|
// 保存右键点击的路径(在关闭菜单前保存)
|
||||||
|
const rightClickedPath = contextMenuPath.value
|
||||||
|
|
||||||
closeContextMenu()
|
closeContextMenu()
|
||||||
|
|
||||||
switch (command) {
|
switch (command) {
|
||||||
case 'refresh':
|
case 'refresh':
|
||||||
router.go(0)
|
// 获取当前右键点击的 tab 或当前激活的 tab
|
||||||
|
const refreshPath = rightClickedPath || tabsStore.activeTab
|
||||||
|
if (refreshPath) {
|
||||||
|
const targetTab = tabsStore.tabs.find(item => item.path === refreshPath)
|
||||||
|
// 如果不是当前页面,先跳转过去并更新 activeTab
|
||||||
|
if (refreshPath !== route.path) {
|
||||||
|
tabsStore.setActiveTab(refreshPath)
|
||||||
|
router.push({ path: refreshPath, query: targetTab?.query }).then(() => {
|
||||||
|
// 等待路由切换完成后再刷新
|
||||||
|
nextTick(() => {
|
||||||
|
tabsStore.refreshTab(refreshPath)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
// 当前页面直接刷新
|
||||||
|
tabsStore.refreshTab(refreshPath)
|
||||||
|
}
|
||||||
|
}
|
||||||
break
|
break
|
||||||
case 'close':
|
case 'close':
|
||||||
if (currentPath) {
|
if (currentPath) {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,44 @@
|
||||||
|
import { ref } from 'vue'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 页面级加载状态管理
|
||||||
|
* @param initialLoading 初始 loading 状态,默认 false
|
||||||
|
*/
|
||||||
|
export function usePageLoading(initialLoading = false) {
|
||||||
|
const loading = ref(initialLoading)
|
||||||
|
|
||||||
|
const startLoading = () => {
|
||||||
|
loading.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
const stopLoading = () => {
|
||||||
|
loading.value = false
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
loading,
|
||||||
|
startLoading,
|
||||||
|
stopLoading,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按钮级别加载状态管理
|
||||||
|
*/
|
||||||
|
export function useButtonLoading() {
|
||||||
|
const buttonLoading = ref(false)
|
||||||
|
|
||||||
|
const startButtonLoading = () => {
|
||||||
|
buttonLoading.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
const stopButtonLoading = () => {
|
||||||
|
buttonLoading.value = false
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
buttonLoading,
|
||||||
|
startButtonLoading,
|
||||||
|
stopButtonLoading,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -241,6 +241,14 @@ export const useTabsStore = defineStore('tabs', () => {
|
||||||
saveTabs()
|
saveTabs()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 刷新指定 tab 的 key(用于触发组件刷新)
|
||||||
|
const refreshKey = ref<string>('')
|
||||||
|
|
||||||
|
// 刷新指定路径的 tab
|
||||||
|
const refreshTab = (path: string) => {
|
||||||
|
refreshKey.value = path + '-' + Date.now()
|
||||||
|
}
|
||||||
|
|
||||||
// 保存到本地存储
|
// 保存到本地存储
|
||||||
const saveTabs = () => {
|
const saveTabs = () => {
|
||||||
setStorage('tabs', tabs.value)
|
setStorage('tabs', tabs.value)
|
||||||
|
|
@ -283,6 +291,8 @@ export const useTabsStore = defineStore('tabs', () => {
|
||||||
closeRightTabs,
|
closeRightTabs,
|
||||||
setActiveTab,
|
setActiveTab,
|
||||||
clearTabs,
|
clearTabs,
|
||||||
setTabs
|
setTabs,
|
||||||
|
refreshKey,
|
||||||
|
refreshTab
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,46 @@
|
||||||
|
/**
|
||||||
|
* @description: 金额格式化工具函数
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description: 截取数字到小数点后指定位数(不四舍五入)
|
||||||
|
* @param value 需要格式化的值
|
||||||
|
* @param decimals 保留的小数位数,默认2位
|
||||||
|
* @returns 格式化后的字符串或数字
|
||||||
|
*/
|
||||||
|
export function formatDecimalTruncate(value: string | number | null | undefined, decimals: number = 2): string | number {
|
||||||
|
// 处理空值
|
||||||
|
if (value === null || value === undefined || value === '') {
|
||||||
|
return value ?? ''
|
||||||
|
}
|
||||||
|
|
||||||
|
// 转换为字符串检查原始格式
|
||||||
|
const originalStr = String(value)
|
||||||
|
|
||||||
|
// 转换为数字检查是否有效
|
||||||
|
const num = Number(value)
|
||||||
|
|
||||||
|
// 如果不是有效数字,返回原值
|
||||||
|
if (isNaN(num)) {
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
|
// 分割整数和小数部分
|
||||||
|
const dotIndex = originalStr.indexOf('.')
|
||||||
|
|
||||||
|
// 如果没有小数点,添加小数位后返回
|
||||||
|
if (dotIndex === -1) {
|
||||||
|
return `${originalStr}.${'0'.repeat(decimals)}`
|
||||||
|
}
|
||||||
|
|
||||||
|
const integerPart = originalStr.substring(0, dotIndex)
|
||||||
|
const decimalPart = originalStr.substring(dotIndex + 1)
|
||||||
|
|
||||||
|
// 截取到指定小数位(不四舍五入)
|
||||||
|
const truncatedDecimal = decimalPart.substring(0, decimals)
|
||||||
|
|
||||||
|
// 补齐小数位到指定位数
|
||||||
|
const paddedDecimal = truncatedDecimal.padEnd(decimals, '0')
|
||||||
|
|
||||||
|
return `${integerPart}.${paddedDecimal}`
|
||||||
|
}
|
||||||
|
|
@ -1,3 +1,6 @@
|
||||||
|
|
||||||
|
import dayjs from 'dayjs'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取近七天的开始和结束时间
|
* 获取近七天的开始和结束时间
|
||||||
* @param format 日期格式,默认 'YYYY-MM-DD HH:mm:ss'
|
* @param format 日期格式,默认 'YYYY-MM-DD HH:mm:ss'
|
||||||
|
|
@ -37,22 +40,22 @@ export const getRecentSevenDays = (format = 'YYYY-MM-DD HH:mm:ss'):{ start: stri
|
||||||
* @returns {string} UTC+8 时间字符串,格式:YYYY-MM-DD HH:mm:ss
|
* @returns {string} UTC+8 时间字符串,格式:YYYY-MM-DD HH:mm:ss
|
||||||
*/
|
*/
|
||||||
export function utcToUtc8(utcStr: string): string {
|
export function utcToUtc8(utcStr: string): string {
|
||||||
// 将字符串解析为 UTC 时间
|
// // 将字符串解析为 UTC 时间
|
||||||
const utcDate = new Date(utcStr.replace(' ', 'T') + 'Z')
|
// const utcDate = new Date(utcStr.replace(' ', 'T') + 'Z')
|
||||||
|
|
||||||
// 转换为 UTC+8(东八区)
|
// // 转换为 UTC+8(东八区)
|
||||||
const utc8Date = new Date(utcDate.getTime() + 8 * 60 * 60 * 1000)
|
// const utc8Date = new Date(utcDate.getTime() + 8 * 60 * 60 * 1000)
|
||||||
|
|
||||||
// 格式化为 YYYY-MM-DD HH:mm:ss
|
// // 格式化为 YYYY-MM-DD HH:mm:ss
|
||||||
const pad = (n) => String(n).padStart(2, '0')
|
// const pad = (n) => String(n).padStart(2, '0')
|
||||||
|
|
||||||
const year = utc8Date.getUTCFullYear()
|
// const year = utc8Date.getUTCFullYear()
|
||||||
const month = pad(utc8Date.getUTCMonth() + 1)
|
// const month = pad(utc8Date.getUTCMonth() + 1)
|
||||||
const day = pad(utc8Date.getUTCDate())
|
// const day = pad(utc8Date.getUTCDate())
|
||||||
const hour = pad(utc8Date.getUTCHours())
|
// const hour = pad(utc8Date.getUTCHours())
|
||||||
const minute = pad(utc8Date.getUTCMinutes())
|
// const minute = pad(utc8Date.getUTCMinutes())
|
||||||
const second = pad(utc8Date.getUTCSeconds())
|
// const second = pad(utc8Date.getUTCSeconds())
|
||||||
|
|
||||||
return `${year}-${month}-${day} ${hour}:${minute}:${second}`
|
return dayjs(utcStr).format('YYYY-MM-DD HH:mm:ss')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,12 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="table_form-container">
|
<div class="table_form-container">
|
||||||
<!-- 搜索 -->
|
<!-- 搜索 -->
|
||||||
<CustomerListSearch :search-form="searchForm" :search-options="searchOptions" @search="handleSearch"
|
<CustomerListSearch :search-form="searchForm" :search-options="searchOptions" :button-loading="searchLoading" @search="handleSearch"
|
||||||
@reset="handleReset"></CustomerListSearch>
|
@reset="handleReset"></CustomerListSearch>
|
||||||
|
|
||||||
<!-- 表格 -->
|
<!-- 表格 -->
|
||||||
<CustomerListTable :table-data="tableTree" :columns="tableColumnsOptions" row-key="userId" :tree-props="treeProps"
|
<CustomerListTable :table-data="tableTree" :columns="tableColumnsOptions" row-key="userId" :tree-props="treeProps"
|
||||||
:default-sort="{ prop: 'createTime', order: 'descending' }" @expand-change="handleGetSubList">
|
:default-sort="{ prop: 'createTime', order: 'descending' }" :loading="loading" @expand-change="handleGetSubList">
|
||||||
<template #marginRatio="{ row }">
|
<template #marginRatio="{ row }">
|
||||||
<el-button v-if="row.role_id === 5" type="primary" size="small" @click="handleMarginRatio(row)">
|
<el-button v-if="row.role_id === 5" type="primary" size="small" @click="handleMarginRatio(row)">
|
||||||
修改
|
修改
|
||||||
|
|
@ -40,7 +40,7 @@
|
||||||
|
|
||||||
<!-- dialog -->
|
<!-- dialog -->
|
||||||
<CustomerListDialog :visible="dialogVisible" :title="dialogTitle" :type="dialogType" :fullscreen="dialogFullscreen"
|
<CustomerListDialog :visible="dialogVisible" :title="dialogTitle" :type="dialogType" :fullscreen="dialogFullscreen"
|
||||||
:show-footer="dialogType !== 'view'" @confirm="handleSubmit" @cancel="handleCancel" @close="handleClose">
|
:show-footer="dialogType !== 'view'" :button-loading="submitLoading" @confirm="handleSubmit" @cancel="handleCancel" @close="handleClose">
|
||||||
<CustomerListTable :table-data="marginRatioTree" :columns="marginRatioTableColumnsOptions" row-key="id"
|
<CustomerListTable :table-data="marginRatioTree" :columns="marginRatioTableColumnsOptions" row-key="id"
|
||||||
v-if="dialogType === 'editMarginRatio'" style="height: 600px">
|
v-if="dialogType === 'editMarginRatio'" style="height: 600px">
|
||||||
<template #assignedPointDiff="{ row }">
|
<template #assignedPointDiff="{ row }">
|
||||||
|
|
@ -57,7 +57,7 @@
|
||||||
</CustomerListDialog>
|
</CustomerListDialog>
|
||||||
|
|
||||||
<!-- 调整金额弹窗 -->
|
<!-- 调整金额弹窗 -->
|
||||||
<CustomerListDialog :visible="adjustAmountVisible" title="调整金额" type="adjust" @confirm="handleAdjustAmountSubmit"
|
<CustomerListDialog :visible="adjustAmountVisible" title="调整金额" type="adjust" :button-loading="adjustAmountLoading" @confirm="handleAdjustAmountSubmit"
|
||||||
@cancel="handleAdjustAmountCancel" @close="handleAdjustAmountClose">
|
@cancel="handleAdjustAmountCancel" @close="handleAdjustAmountClose">
|
||||||
<el-form :model="adjustAmountForm" :rules="adjustAmountRules" ref="adjustAmountFormRef" label-width="120px">
|
<el-form :model="adjustAmountForm" :rules="adjustAmountRules" ref="adjustAmountFormRef" label-width="120px">
|
||||||
<el-form-item label="账号名" prop="username">
|
<el-form-item label="账号名" prop="username">
|
||||||
|
|
@ -81,7 +81,7 @@
|
||||||
|
|
||||||
<!-- 修改客户弹窗 -->
|
<!-- 修改客户弹窗 -->
|
||||||
<CustomerListDialog :visible="editCustomerVisible" title="" type="editCustomer"
|
<CustomerListDialog :visible="editCustomerVisible" title="" type="editCustomer"
|
||||||
@confirm="handleEditCustomerSubmit" @cancel="handleEditCustomerCancel" @close="handleEditCustomerClose">
|
:button-loading="editCustomerLoading" @confirm="handleEditCustomerSubmit" @cancel="handleEditCustomerCancel" @close="handleEditCustomerClose">
|
||||||
<el-form :model="editCustomerForm" :rules="editCustomerRules" ref="editCustomerFormRef" label-width="140px">
|
<el-form :model="editCustomerForm" :rules="editCustomerRules" ref="editCustomerFormRef" label-width="140px">
|
||||||
<!-- <el-form-item label="手续费模板" prop="feeSettingId">
|
<!-- <el-form-item label="手续费模板" prop="feeSettingId">
|
||||||
<el-select v-model="editCustomerForm.feeSettingId" placeholder="请选择手续费模板" style="width: 100%">
|
<el-select v-model="editCustomerForm.feeSettingId" placeholder="请选择手续费模板" style="width: 100%">
|
||||||
|
|
@ -126,6 +126,7 @@ defineOptions({
|
||||||
// 组件
|
// 组件
|
||||||
import CustomerListSearch from '@/components/common/Search.vue'
|
import CustomerListSearch from '@/components/common/Search.vue'
|
||||||
import CustomerListTable from '@/components/common/Table.vue'
|
import CustomerListTable from '@/components/common/Table.vue'
|
||||||
|
import { usePageLoading, useButtonLoading } from '@/composables/useLoading'
|
||||||
import CustomerListPagination from '@/components/common/Pagination.vue'
|
import CustomerListPagination from '@/components/common/Pagination.vue'
|
||||||
import CustomerListDialog from '@/components/common/Dialog.vue'
|
import CustomerListDialog from '@/components/common/Dialog.vue'
|
||||||
import CustomerListForm from '@/components/common/Form.vue'
|
import CustomerListForm from '@/components/common/Form.vue'
|
||||||
|
|
@ -170,6 +171,11 @@ const searchForm = ref({
|
||||||
const searchOptions = ref(search)
|
const searchOptions = ref(search)
|
||||||
const tableColumnsOptions = ref(tableColumns)
|
const tableColumnsOptions = ref(tableColumns)
|
||||||
|
|
||||||
|
const { loading, startLoading, stopLoading } = usePageLoading()
|
||||||
|
const { buttonLoading: searchLoading, startButtonLoading: startSearchLoading, stopButtonLoading: stopSearchLoading } = useButtonLoading()
|
||||||
|
const { buttonLoading: submitLoading, startButtonLoading: startSubmitLoading, stopButtonLoading: stopSubmitLoading } = useButtonLoading()
|
||||||
|
const { buttonLoading: adjustAmountLoading, startButtonLoading: startAdjustAmountLoading, stopButtonLoading: stopAdjustAmountLoading } = useButtonLoading()
|
||||||
|
const { buttonLoading: editCustomerLoading, startButtonLoading: startEditCustomerLoading, stopButtonLoading: stopEditCustomerLoading } = useButtonLoading()
|
||||||
/**
|
/**
|
||||||
* @description: 定义表格数据
|
* @description: 定义表格数据
|
||||||
*/
|
*/
|
||||||
|
|
@ -323,64 +329,75 @@ const roleMap: any = {
|
||||||
*/
|
*/
|
||||||
// 获取客户列表
|
// 获取客户列表
|
||||||
const getCustomerList = async (id: string) => {
|
const getCustomerList = async (id: string) => {
|
||||||
const params = {
|
startLoading()
|
||||||
user_id: id,
|
try {
|
||||||
page: currentPage.value,
|
const params = {
|
||||||
page_size: pageSize.value,
|
user_id: id,
|
||||||
user_name: searchForm.value.accountName,
|
page: currentPage.value,
|
||||||
reg_start_time:
|
page_size: pageSize.value,
|
||||||
searchForm.value.startTime.length > 0
|
user_name: searchForm.value.accountName,
|
||||||
? `${searchForm.value.startTime} 0:00:00`
|
reg_start_time:
|
||||||
: '2026-01-01 0:00:00',
|
searchForm.value.startTime.length > 0
|
||||||
reg_end_time:
|
? `${searchForm.value.startTime} 0:00:00`
|
||||||
searchForm.value.endTime.length > 0
|
: '2026-01-01 0:00:00',
|
||||||
? `${searchForm.value.endTime} 23:59:59`
|
reg_end_time:
|
||||||
: '2026-03-01 23:59:59',
|
searchForm.value.endTime.length > 0
|
||||||
status: searchForm.value.status,
|
? `${searchForm.value.endTime} 23:59:59`
|
||||||
}
|
: '2026-03-01 23:59:59',
|
||||||
const data: any = await getCustomerListApi(params)
|
status: searchForm.value.status,
|
||||||
|
}
|
||||||
|
const data: any = await getCustomerListApi(params)
|
||||||
|
|
||||||
tableTree.value = data.data.map((item: any) => ({
|
tableTree.value = data.data.map((item: any) => ({
|
||||||
accountName: item.username,
|
accountName: item.username,
|
||||||
userId: item.id,
|
userId: item.id,
|
||||||
status: item.status === 1 ? '正常' : '禁用',
|
status: item.status === 1 ? '正常' : '禁用',
|
||||||
role: roleMap[item.role_id] || '未知',
|
role: roleMap[item.role_id] || '未知',
|
||||||
accountQty: item.account[0].account_count,
|
accountQty: item.account[0].account_count,
|
||||||
commissionRatio: item.wallet_capital.fee_handling_percent,
|
commissionRatio: item.wallet_capital.fee_handling_percent,
|
||||||
createTime: item.created_at,
|
createTime: item.created_at,
|
||||||
role_id: item.role_id,
|
role_id: item.role_id,
|
||||||
children:
|
children:
|
||||||
item.role_id === 5
|
item.role_id === 5
|
||||||
? [
|
? [
|
||||||
{
|
{
|
||||||
hasChildren: true,
|
hasChildren: true,
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
: undefined,
|
: undefined,
|
||||||
}))
|
}))
|
||||||
console.log('tableTree', tableTree.value)
|
console.log('tableTree', tableTree.value)
|
||||||
//分页数据
|
//分页数据
|
||||||
total.value = data.total
|
total.value = data.total
|
||||||
currentPage.value = data.current_page
|
currentPage.value = data.current_page
|
||||||
pageSize.value = Number(data.per_page)
|
pageSize.value = Number(data.per_page)
|
||||||
|
} catch (err) {
|
||||||
|
console.error('获取客户列表失败:', err)
|
||||||
|
} finally {
|
||||||
|
stopLoading()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//获取代理点差数据
|
//获取代理点差数据
|
||||||
const getSelfVarietyPointDiffConfig = async (id: string) => {
|
const getSelfVarietyPointDiffConfig = async (id: string) => {
|
||||||
const params = {
|
try {
|
||||||
user_id: id,
|
const params = {
|
||||||
}
|
user_id: id,
|
||||||
const data: any = await getSelfVarietyPointDiffConfigApi(params)
|
|
||||||
marginRatioTree.value = data.map((item: any) => {
|
|
||||||
return {
|
|
||||||
id: item.id,
|
|
||||||
varietyName: item.name,
|
|
||||||
varietyCode: item.code,
|
|
||||||
pointDifference: item.point_diff,
|
|
||||||
assignedPointDifference: item.target_point_diff,
|
|
||||||
}
|
}
|
||||||
})
|
const data: any = await getSelfVarietyPointDiffConfigApi(params)
|
||||||
console.log('marginRatioTree', marginRatioTree.value)
|
marginRatioTree.value = data.map((item: any) => {
|
||||||
|
return {
|
||||||
|
id: item.id,
|
||||||
|
varietyName: item.name,
|
||||||
|
varietyCode: item.code,
|
||||||
|
pointDifference: item.point_diff,
|
||||||
|
assignedPointDifference: item.target_point_diff,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
console.log('marginRatioTree', marginRatioTree.value)
|
||||||
|
} catch (err) {
|
||||||
|
console.error('获取代理点差数据失败:', err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -394,7 +411,15 @@ onMounted(() => {
|
||||||
* @description: 定义搜索方法
|
* @description: 定义搜索方法
|
||||||
*/
|
*/
|
||||||
const handleSearch = async () => {
|
const handleSearch = async () => {
|
||||||
getCustomerList(userId.value)
|
currentPage.value = 1
|
||||||
|
startSearchLoading()
|
||||||
|
try {
|
||||||
|
await getCustomerList(userId.value)
|
||||||
|
} catch (err) {
|
||||||
|
console.error('搜索失败:', err)
|
||||||
|
} finally {
|
||||||
|
stopSearchLoading()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
const handleReset = () => {
|
const handleReset = () => {
|
||||||
searchForm.value = {
|
searchForm.value = {
|
||||||
|
|
@ -403,7 +428,7 @@ const handleReset = () => {
|
||||||
endTime: '',
|
endTime: '',
|
||||||
status: '',
|
status: '',
|
||||||
}
|
}
|
||||||
getCustomerList(userId.value)
|
handleSearch()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -444,42 +469,46 @@ const handleCommissionRatio = (row: any) => {
|
||||||
|
|
||||||
// 获取子列表
|
// 获取子列表
|
||||||
const handleGetSubList = async (row: any) => {
|
const handleGetSubList = async (row: any) => {
|
||||||
const params = {
|
try {
|
||||||
user_name: '',
|
const params = {
|
||||||
user_id: row.userId,
|
user_name: '',
|
||||||
page: currentPage.value,
|
user_id: row.userId,
|
||||||
page_size: pageSize.value,
|
page: currentPage.value,
|
||||||
reg_start_time: '',
|
page_size: pageSize.value,
|
||||||
reg_end_time: '',
|
reg_start_time: '',
|
||||||
status: '',
|
reg_end_time: '',
|
||||||
|
status: '',
|
||||||
|
}
|
||||||
|
const data: any = await getCustomerListApi(params)
|
||||||
|
if (data.data.length === 0) {
|
||||||
|
ElMessage({
|
||||||
|
message: '暂无数据',
|
||||||
|
type: 'error',
|
||||||
|
})
|
||||||
|
row.children = []
|
||||||
|
return
|
||||||
|
}
|
||||||
|
row.children = data.data.map((item: any) => ({
|
||||||
|
accountName: item.username,
|
||||||
|
userId: item.id,
|
||||||
|
status: item.status === 1 ? '正常' : '禁用',
|
||||||
|
role: roleMap[item.role_id] || '未知',
|
||||||
|
accountQty: item.account[0].account_count,
|
||||||
|
commissionRatio: item.wallet_capital.fee_handling_percent,
|
||||||
|
createTime: item.created_at,
|
||||||
|
role_id: item.role_id,
|
||||||
|
children:
|
||||||
|
item.role_id === 5
|
||||||
|
? [
|
||||||
|
{
|
||||||
|
hasChildren: true,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
: undefined,
|
||||||
|
}))
|
||||||
|
} catch (err) {
|
||||||
|
console.error('获取子列表失败:', err)
|
||||||
}
|
}
|
||||||
const data: any = await getCustomerListApi(params)
|
|
||||||
if (data.data.length === 0) {
|
|
||||||
ElMessage({
|
|
||||||
message: '暂无数据',
|
|
||||||
type: 'error',
|
|
||||||
})
|
|
||||||
row.children = []
|
|
||||||
return
|
|
||||||
}
|
|
||||||
row.children = data.data.map((item: any) => ({
|
|
||||||
accountName: item.username,
|
|
||||||
userId: item.id,
|
|
||||||
status: item.status === 1 ? '正常' : '禁用',
|
|
||||||
role: roleMap[item.role_id] || '未知',
|
|
||||||
accountQty: item.account[0].account_count,
|
|
||||||
commissionRatio: item.wallet_capital.fee_handling_percent,
|
|
||||||
createTime: item.created_at,
|
|
||||||
role_id: item.role_id,
|
|
||||||
children:
|
|
||||||
item.role_id === 5
|
|
||||||
? [
|
|
||||||
{
|
|
||||||
hasChildren: true,
|
|
||||||
},
|
|
||||||
]
|
|
||||||
: undefined,
|
|
||||||
}))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -496,53 +525,58 @@ const handlePaginationChange = (page: { currentPage: number; pageSize: number })
|
||||||
*/
|
*/
|
||||||
//提交
|
//提交
|
||||||
const handleSubmit = async () => {
|
const handleSubmit = async () => {
|
||||||
const params = {
|
startSubmitLoading()
|
||||||
user_id: selectId.value,
|
try {
|
||||||
toucun_percent: '',
|
const params = {
|
||||||
point_diffs_json: '',
|
user_id: selectId.value,
|
||||||
fee_handling_percent: '',
|
toucun_percent: '',
|
||||||
fee_setting_id: '',
|
point_diffs_json: '',
|
||||||
risk_control_id: '',
|
fee_handling_percent: '',
|
||||||
}
|
fee_setting_id: '',
|
||||||
if (dialogType.value === 'editMarginRatio') {
|
risk_control_id: '',
|
||||||
// 逐行验证
|
}
|
||||||
for (const row of marginRatioTree.value) {
|
if (dialogType.value === 'editMarginRatio') {
|
||||||
const form = formRefs.value[(row as any).id]
|
// 逐行验证
|
||||||
if (!form) continue
|
for (const row of marginRatioTree.value) {
|
||||||
|
const form = formRefs.value[(row as any).id]
|
||||||
|
if (!form) continue
|
||||||
|
try {
|
||||||
|
await form.validate()
|
||||||
|
} catch (err) {
|
||||||
|
console.error(`第 ${(row as any).id} 行验证不通过,请检查`)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//转换为接口需要的格式 { id: assignedPointDifference }
|
||||||
|
const marginRatioJSON = marginRatioTree.value.reduce((acc: any, cur: any) => {
|
||||||
|
acc[cur.id] = cur.assignedPointDifference
|
||||||
|
return acc
|
||||||
|
}, {})
|
||||||
|
|
||||||
|
// 调用接口
|
||||||
try {
|
try {
|
||||||
await form.validate()
|
await editCustomerApi({ ...params, point_diffs_json: JSON.stringify(marginRatioJSON) })
|
||||||
|
dialogVisible.value = false
|
||||||
|
await getCustomerList(userId.value)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(`第 ${(row as any).id} 行验证不通过,请检查`)
|
console.error('提交失败:', err)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//转换为接口需要的格式 { id: assignedPointDifference }
|
if (dialogType.value === 'editCommissionRatio') {
|
||||||
const marginRatioJSON = marginRatioTree.value.reduce((acc: any, cur: any) => {
|
await commissionRatioFormRef.value.validate()
|
||||||
acc[cur.id] = cur.assignedPointDifference
|
try {
|
||||||
return acc
|
await editCustomerApi({
|
||||||
}, {})
|
...params,
|
||||||
|
fee_handling_percent: commissionRatioForm.value.commissionRatio,
|
||||||
// 调用接口
|
})
|
||||||
try {
|
dialogVisible.value = false
|
||||||
await editCustomerApi({ ...params, point_diffs_json: JSON.stringify(marginRatioJSON) })
|
await getCustomerList(userId.value)
|
||||||
dialogVisible.value = false
|
} catch (err) {
|
||||||
await getCustomerList(userId.value)
|
console.error('提交失败:', err)
|
||||||
} catch (err) {
|
}
|
||||||
console.log('提交失败:', err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (dialogType.value === 'editCommissionRatio') {
|
|
||||||
await commissionRatioFormRef.value.validate()
|
|
||||||
try {
|
|
||||||
await editCustomerApi({
|
|
||||||
...params,
|
|
||||||
fee_handling_percent: commissionRatioForm.value.commissionRatio,
|
|
||||||
})
|
|
||||||
dialogVisible.value = false
|
|
||||||
await getCustomerList(userId.value)
|
|
||||||
} catch (err) {
|
|
||||||
console.log('提交失败:', err)
|
|
||||||
}
|
}
|
||||||
|
} finally {
|
||||||
|
stopSubmitLoading()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 取消
|
// 取消
|
||||||
|
|
@ -583,6 +617,7 @@ const handleAdjustAmountInput = () => {
|
||||||
|
|
||||||
// 提交调整金额
|
// 提交调整金额
|
||||||
const handleAdjustAmountSubmit = async () => {
|
const handleAdjustAmountSubmit = async () => {
|
||||||
|
startAdjustAmountLoading()
|
||||||
try {
|
try {
|
||||||
await adjustAmountFormRef.value?.validate()
|
await adjustAmountFormRef.value?.validate()
|
||||||
await updateCapitalApi({
|
await updateCapitalApi({
|
||||||
|
|
@ -593,6 +628,8 @@ const handleAdjustAmountSubmit = async () => {
|
||||||
adjustAmountVisible.value = false
|
adjustAmountVisible.value = false
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('调整金额表单验证失败', err)
|
console.error('调整金额表单验证失败', err)
|
||||||
|
} finally {
|
||||||
|
stopAdjustAmountLoading()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -655,6 +692,7 @@ const handleEditCustomer = async (row: any) => {
|
||||||
|
|
||||||
// 提交修改客户
|
// 提交修改客户
|
||||||
const handleEditCustomerSubmit = async () => {
|
const handleEditCustomerSubmit = async () => {
|
||||||
|
startEditCustomerLoading()
|
||||||
try {
|
try {
|
||||||
await editCustomerFormRef.value?.validate()
|
await editCustomerFormRef.value?.validate()
|
||||||
await editUserApi({
|
await editUserApi({
|
||||||
|
|
@ -669,6 +707,8 @@ const handleEditCustomerSubmit = async () => {
|
||||||
editCustomerVisible.value = false
|
editCustomerVisible.value = false
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('修改客户表单验证失败', err)
|
console.error('修改客户表单验证失败', err)
|
||||||
|
} finally {
|
||||||
|
stopEditCustomerLoading()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,10 +4,12 @@
|
||||||
<FundDetailHeader title="入金货币" :buttons="buttonsOptions" @button-click="handleButtonClick">
|
<FundDetailHeader title="入金货币" :buttons="buttonsOptions" @button-click="handleButtonClick">
|
||||||
</FundDetailHeader>
|
</FundDetailHeader>
|
||||||
<!-- 表格 -->
|
<!-- 表格 -->
|
||||||
<FundDetailTable :table-data="tableData" :columns="tableColumnsOptions" @row-click="handleRowClick" row-key="id" />
|
<FundDetailTable :table-data="tableData" :columns="tableColumnsOptions" @row-click="handleRowClick" row-key="id"
|
||||||
<FundDetailDialog :visible="visible" :title="dialogTitle" @close="visible = false" @cancel="visible = false"
|
:loading="loading" />
|
||||||
@confirm="handleConfirm">
|
<FundDetailDialog :visible="visible" :title="dialogTitle" :button-loading="buttonLoading" @close="visible = false"
|
||||||
<FundDetailForm :formData="formData" :formItems="formItems" :formRules="formRules" :optionsMap="optionsMap">
|
@cancel="visible = false" @confirm="handleConfirm">
|
||||||
|
<FundDetailForm :formData="formData" ref="commissionRatioFormRef" :formItems="formItems" :formRules="formRules"
|
||||||
|
:optionsMap="optionsMap">
|
||||||
</FundDetailForm>
|
</FundDetailForm>
|
||||||
</FundDetailDialog>
|
</FundDetailDialog>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -20,6 +22,7 @@ defineOptions({
|
||||||
})
|
})
|
||||||
import FundDetailHeader from '@/components/common/header.vue'
|
import FundDetailHeader from '@/components/common/header.vue'
|
||||||
import FundDetailTable from '@/components/common/Table.vue'
|
import FundDetailTable from '@/components/common/Table.vue'
|
||||||
|
import { usePageLoading, useButtonLoading } from '@/composables/useLoading'
|
||||||
import FundDetailDialog from '@/components/common/Dialog.vue'
|
import FundDetailDialog from '@/components/common/Dialog.vue'
|
||||||
import FundDetailForm from '@/components/common/Form.vue'
|
import FundDetailForm from '@/components/common/Form.vue'
|
||||||
import type { ButtonProps } from 'element-plus'
|
import type { ButtonProps } from 'element-plus'
|
||||||
|
|
@ -41,11 +44,14 @@ interface HeaderButton {
|
||||||
key?: string | number // 可选的唯一标识
|
key?: string | number // 可选的唯一标识
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const { loading, startLoading, stopLoading } = usePageLoading()
|
||||||
|
const { buttonLoading, startButtonLoading, stopButtonLoading } = useButtonLoading()
|
||||||
const buttonsOptions = ref(buttons)
|
const buttonsOptions = ref(buttons)
|
||||||
const formItems = ref(form)
|
const formItems = ref(form)
|
||||||
const tableData = ref([])
|
const tableData = ref([])
|
||||||
const tableColumnsOptions = ref(tableColumns)
|
const tableColumnsOptions = ref(tableColumns)
|
||||||
const dialogTitle = ref('')
|
const dialogTitle = ref('')
|
||||||
|
const commissionRatioFormRef = ref()
|
||||||
const formRules = ref(rules)
|
const formRules = ref(rules)
|
||||||
const formData = ref({
|
const formData = ref({
|
||||||
name: '',
|
name: '',
|
||||||
|
|
@ -70,15 +76,22 @@ let rowData: any = {}
|
||||||
const visible = ref<boolean>(false)
|
const visible = ref<boolean>(false)
|
||||||
|
|
||||||
const getTableList = async () => {
|
const getTableList = async () => {
|
||||||
const data = await getCurrencyList()
|
try {
|
||||||
tableData.value = (data || []).map((item: any) => {
|
|
||||||
return {
|
startLoading()
|
||||||
...item,
|
const data = await getCurrencyList()
|
||||||
typeStr: ['', '法币', '数字货币'][item.type],
|
|
||||||
statusStr: ['', '正常', '禁用'][item.status],
|
tableData.value = (data || []).map((item: any) => {
|
||||||
}
|
return {
|
||||||
})
|
...item,
|
||||||
console.log('tableData.value', tableData.value)
|
typeStr: ['', '法币', '数字货币'][item.type],
|
||||||
|
statusStr: ['', '正常', '禁用'][item.status],
|
||||||
|
}
|
||||||
|
})
|
||||||
|
console.log('tableData.value', tableData.value)
|
||||||
|
} finally {
|
||||||
|
stopLoading()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleRowClick = (row: any) => {
|
const handleRowClick = (row: any) => {
|
||||||
|
|
@ -136,14 +149,20 @@ const handleEdit = () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleConfirm = async () => {
|
const handleConfirm = async () => {
|
||||||
if (dialogTitle.value === '添加') {
|
await commissionRatioFormRef.value.validate()
|
||||||
await createCurrency(formData.value)
|
startButtonLoading()
|
||||||
} else {
|
try {
|
||||||
await editCurrency({ ...formData.value, id: rowData.id })
|
if (dialogTitle.value === '添加') {
|
||||||
|
await createCurrency(formData.value)
|
||||||
|
} else {
|
||||||
|
await editCurrency({ ...formData.value, id: rowData.id })
|
||||||
|
}
|
||||||
|
visible.value = false
|
||||||
|
resetForm()
|
||||||
|
await getTableList()
|
||||||
|
} finally {
|
||||||
|
stopButtonLoading()
|
||||||
}
|
}
|
||||||
visible.value = false
|
|
||||||
resetForm()
|
|
||||||
await getTableList()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
|
|
|
||||||
|
|
@ -1,25 +1,17 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="table_form-container">
|
<div class="table_form-container">
|
||||||
<!-- 搜索 -->
|
<!-- 搜索 -->
|
||||||
<FundDetailSearch
|
<FundDetailSearch :search-form="searchForm" :search-options="searchOptions" @search="handleSearch"
|
||||||
:search-form="searchForm"
|
@reset="handleReset">
|
||||||
:search-options="searchOptions"
|
|
||||||
@search="handleSearch"
|
|
||||||
@reset="handleReset"
|
|
||||||
>
|
|
||||||
<template #button="{ form }">
|
<template #button="{ form }">
|
||||||
<el-button type="primary" @click="handleExport()"> 导出 </el-button>
|
<el-button type="primary" @click="handleExport()"> 导出 </el-button>
|
||||||
</template>
|
</template>
|
||||||
</FundDetailSearch>
|
</FundDetailSearch>
|
||||||
<!-- 表格 -->
|
<!-- 表格 -->
|
||||||
<FundDetailTable :table-data="tableTree" :columns="tableColumnsOptions" row-key="id" />
|
<FundDetailTable :table-data="tableTree" :columns="tableColumnsOptions" row-key="id" :loading="loading" />
|
||||||
<!-- 分页 -->
|
<!-- 分页 -->
|
||||||
<FundDetailPagination
|
<FundDetailPagination v-model="currentPage" v-model:pageSizeValue="pageSize" :total="total"
|
||||||
v-model="currentPage"
|
@pagination-change="handlePaginationChange" />
|
||||||
v-model:pageSizeValue="pageSize"
|
|
||||||
:total="total"
|
|
||||||
@pagination-change="handlePaginationChange"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
@ -32,6 +24,7 @@ defineOptions({
|
||||||
import FundDetailSearch from '@/components/common/Search.vue'
|
import FundDetailSearch from '@/components/common/Search.vue'
|
||||||
import FundDetailTable from '@/components/common/Table.vue'
|
import FundDetailTable from '@/components/common/Table.vue'
|
||||||
import FundDetailPagination from '@/components/common/Pagination.vue'
|
import FundDetailPagination from '@/components/common/Pagination.vue'
|
||||||
|
import { usePageLoading } from '@/composables/useLoading'
|
||||||
// 配置以及表单验证
|
// 配置以及表单验证
|
||||||
import { search, tableColumns } from './options'
|
import { search, tableColumns } from './options'
|
||||||
// 接口
|
// 接口
|
||||||
|
|
@ -51,6 +44,7 @@ const searchForm = ref({
|
||||||
startTime: initTime.start,
|
startTime: initTime.start,
|
||||||
endTime: initTime.end,
|
endTime: initTime.end,
|
||||||
})
|
})
|
||||||
|
const { loading, startLoading, stopLoading } = usePageLoading()
|
||||||
/**
|
/**
|
||||||
* @description: 定义表格数据
|
* @description: 定义表格数据
|
||||||
*/
|
*/
|
||||||
|
|
@ -68,40 +62,45 @@ const total = ref(0)
|
||||||
*/
|
*/
|
||||||
//获取资金明细列表
|
//获取资金明细列表
|
||||||
const getFundDetailList = async () => {
|
const getFundDetailList = async () => {
|
||||||
const params = {
|
startLoading()
|
||||||
page: currentPage.value,
|
try {
|
||||||
page_size: pageSize.value,
|
const params = {
|
||||||
start_time:
|
page: currentPage.value,
|
||||||
searchForm.value.startTime.length > 0
|
page_size: pageSize.value,
|
||||||
? `${searchForm.value.startTime} 0:00:00`
|
start_time:
|
||||||
: '2026-01-01 0:00:00',
|
searchForm.value.startTime.length > 0
|
||||||
end_time:
|
? `${searchForm.value.startTime} 0:00:00`
|
||||||
searchForm.value.endTime.length > 0
|
: '2026-01-01 0:00:00',
|
||||||
? `${searchForm.value.endTime} 23:59:59`
|
end_time:
|
||||||
: '2026-03-15 23:59:59',
|
searchForm.value.endTime.length > 0
|
||||||
user_name: searchForm.value.username,
|
? `${searchForm.value.endTime} 23:59:59`
|
||||||
account_id: searchForm.value.subAccountId,
|
: '2026-03-15 23:59:59',
|
||||||
}
|
user_name: searchForm.value.username,
|
||||||
// 调用接口获取数据
|
account_id: searchForm.value.subAccountId,
|
||||||
const data: any = await getFundDetailListApi(params)
|
}
|
||||||
console.log(data)
|
// 调用接口获取数据
|
||||||
tableTree.value = data.data.map((item: any) => ({
|
const data: any = await getFundDetailListApi(params)
|
||||||
|
console.log(data)
|
||||||
|
tableTree.value = data.data.map((item: any) => ({
|
||||||
...item,
|
...item,
|
||||||
// 用户名
|
// 用户名
|
||||||
username: item.user.username,
|
username: item.user.username,
|
||||||
//单号
|
//单号
|
||||||
orderNo: item.trade_id,
|
orderNo: item.trade_id,
|
||||||
//操作类型
|
//操作类型
|
||||||
type: item.enum_dic.value,
|
type: item.enum_dic.value,
|
||||||
//创建时间
|
//创建时间
|
||||||
createTime: utcToUtc8(item.created_at),
|
createTime: utcToUtc8(item.created_at),
|
||||||
//钱包类型
|
//钱包类型
|
||||||
walletType: item.wallet_type === '1' ? '主钱包' : '子钱包',
|
walletType: item.wallet_type === '1' ? '主钱包' : '子钱包',
|
||||||
}))
|
}))
|
||||||
//分页数据
|
//分页数据
|
||||||
total.value = data.total
|
total.value = data.total
|
||||||
currentPage.value = data.current_page
|
currentPage.value = data.current_page
|
||||||
pageSize.value = Number(data.per_page)
|
pageSize.value = Number(data.per_page)
|
||||||
|
} finally {
|
||||||
|
stopLoading()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -62,9 +62,9 @@ export const tableColumns = [
|
||||||
//资金流向
|
//资金流向
|
||||||
// { prop: 'fundDirection', label: '资金流向' },
|
// { prop: 'fundDirection', label: '资金流向' },
|
||||||
//原有金额
|
//原有金额
|
||||||
{ prop: 'amount', label: '变动金额' },
|
{ prop: 'amount', label: '变动金额', isNumber: true },
|
||||||
//余额变动
|
//余额变动
|
||||||
{ prop: 'balance', label: '变动后余额' },
|
{ prop: 'balance', label: '变动后余额' , isNumber: true},
|
||||||
//现有余额
|
//现有余额
|
||||||
// { prop: 'currentBalance', label: '现有余额' },
|
// { prop: 'currentBalance', label: '现有余额' },
|
||||||
//状态
|
//状态
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
<div class="page-title">存款</div>
|
<div class="page-title">存款</div>
|
||||||
|
|
||||||
<!-- 存款渠道列表:每行提供一个"存款"按钮 -->
|
<!-- 存款渠道列表:每行提供一个"存款"按钮 -->
|
||||||
<RechangeTable :table-data="channelList" :columns="tableColumns" :highlight-current-row="false">
|
<RechangeTable :table-data="channelList" :columns="tableColumns" :highlight-current-row="false" :loading="loading">
|
||||||
<template #action="{ row }">
|
<template #action="{ row }">
|
||||||
<el-button type="primary" size="small" @click="handleOpenDialog(row)">
|
<el-button type="primary" size="small" @click="handleOpenDialog(row)">
|
||||||
存款
|
存款
|
||||||
|
|
@ -113,6 +113,7 @@ import { ElMessage } from 'element-plus'
|
||||||
import { nextTick, onMounted, ref } from 'vue'
|
import { nextTick, onMounted, ref } from 'vue'
|
||||||
import RechangeTable from '@/components/common/Table.vue'
|
import RechangeTable from '@/components/common/Table.vue'
|
||||||
import RechangeDialog from '@/components/common/Dialog.vue'
|
import RechangeDialog from '@/components/common/Dialog.vue'
|
||||||
|
import { usePageLoading } from '@/composables/useLoading'
|
||||||
import { rechangeTableColumns } from './options'
|
import { rechangeTableColumns } from './options'
|
||||||
import { uploadImageApi } from '@/api/modules/upload'
|
import { uploadImageApi } from '@/api/modules/upload'
|
||||||
import { getRechargeChannelList, rechargeApi } from '@/api/modules/capital/rechangeChanl'
|
import { getRechargeChannelList, rechargeApi } from '@/api/modules/capital/rechangeChanl'
|
||||||
|
|
@ -151,6 +152,7 @@ const submitLoading = ref(false)
|
||||||
const voucherUrl = ref('')
|
const voucherUrl = ref('')
|
||||||
const uploadLoading = ref(false)
|
const uploadLoading = ref(false)
|
||||||
|
|
||||||
|
const { loading, startLoading, stopLoading } = usePageLoading()
|
||||||
// 渠道列表数据
|
// 渠道列表数据
|
||||||
const channelList = ref<ChannelRow[]>([])
|
const channelList = ref<ChannelRow[]>([])
|
||||||
|
|
||||||
|
|
@ -202,10 +204,13 @@ const rechangeFormRules = ref<FormRules<RechangeFormData>>({
|
||||||
|
|
||||||
// 获取渠道列表
|
// 获取渠道列表
|
||||||
const fetchChannelList = async () => {
|
const fetchChannelList = async () => {
|
||||||
|
startLoading()
|
||||||
try {
|
try {
|
||||||
const res = await getRechargeChannelList() as ChannelRow[]
|
const res = await getRechargeChannelList() as ChannelRow[]
|
||||||
|
stopLoading()
|
||||||
channelList.value = res || []
|
channelList.value = res || []
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
stopLoading()
|
||||||
console.error('获取充值渠道列表失败', error)
|
console.error('获取充值渠道列表失败', error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,6 @@ export const rechangeTableColumns = [
|
||||||
label: '支持货币',
|
label: '支持货币',
|
||||||
align: 'center' as const
|
align: 'center' as const
|
||||||
},
|
},
|
||||||
{ prop: 'channel_fee', label: '渠道费用', align: 'center' as const },
|
{ prop: 'channel_fee', label: '渠道费用', align: 'center' as const , isNumber: true },
|
||||||
{ label: '操作', slotName: 'action', align: 'center' as const, width: 120 },
|
{ label: '操作', slotName: 'action', align: 'center' as const, width: 120 },
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -5,28 +5,14 @@
|
||||||
<el-button type="primary" @click="handleEdit" v-auth="'channel_editChannel'">编辑</el-button>
|
<el-button type="primary" @click="handleEdit" v-auth="'channel_editChannel'">编辑</el-button>
|
||||||
<el-button type="danger" @click="handleDelete" v-auth="'channel_delChannel'">删除</el-button>
|
<el-button type="danger" @click="handleDelete" v-auth="'channel_delChannel'">删除</el-button>
|
||||||
</div>
|
</div>
|
||||||
<DepositChannelTable
|
<DepositChannelTable ref="tableRef" :table-data="tableData" :columns="tableColumnsOptions" row-key="id"
|
||||||
ref="tableRef"
|
:loading="loading" @rowClick="handleRowClick" />
|
||||||
:table-data="tableData"
|
<el-dialog v-model="dialogVisible" :title="dialogTitleType === 1 ? '添加充值渠道' : '编辑充值渠道'" width="700">
|
||||||
:columns="tableColumnsOptions"
|
<Form :formItems="formItems" ref="formRef" :formRules="formRules" :formData="formData" :optionsMap="optionsMap" />
|
||||||
row-key="id"
|
|
||||||
@rowClick="handleRowClick"
|
|
||||||
/>
|
|
||||||
<el-dialog
|
|
||||||
v-model="dialogVisible"
|
|
||||||
:title="dialogTitleType === 1 ? '添加充值渠道' : '编辑充值渠道'"
|
|
||||||
width="700"
|
|
||||||
>
|
|
||||||
<Form
|
|
||||||
:formItems="formItems"
|
|
||||||
:formRules="formRules"
|
|
||||||
:formData="formData"
|
|
||||||
:optionsMap="optionsMap"
|
|
||||||
/>
|
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<div class="dialog-footer">
|
<div class="dialog-footer">
|
||||||
<el-button @click="dialogVisible = false">取消</el-button>
|
<el-button @click="dialogVisible = false">取消</el-button>
|
||||||
<el-button type="primary" @click="submitDetail">确认</el-button>
|
<el-button type="primary" :loading="submitLoading" @click="submitDetail">确认</el-button>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
|
@ -40,6 +26,7 @@ defineOptions({
|
||||||
//组件
|
//组件
|
||||||
import DepositChannelTable from '@/components/common/Table.vue'
|
import DepositChannelTable from '@/components/common/Table.vue'
|
||||||
import Form from '@/components/common/Form.vue'
|
import Form from '@/components/common/Form.vue'
|
||||||
|
import { usePageLoading, useButtonLoading } from '@/composables/useLoading'
|
||||||
import { tableColumns, formItemsData, formRulesData, optionsMapData } from './options'
|
import { tableColumns, formItemsData, formRulesData, optionsMapData } from './options'
|
||||||
import {
|
import {
|
||||||
getChannelList,
|
getChannelList,
|
||||||
|
|
@ -65,14 +52,22 @@ const getStatusText = (status: number | string) => {
|
||||||
return ['', '正常', '禁用'][status]
|
return ['', '正常', '禁用'][status]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const formRef = ref()
|
||||||
|
const { loading, startLoading, stopLoading } = usePageLoading()
|
||||||
|
const { buttonLoading: submitLoading, startButtonLoading: startSubmitLoading, stopButtonLoading: stopSubmitLoading } = useButtonLoading()
|
||||||
const initData = async () => {
|
const initData = async () => {
|
||||||
const res = await getChannelList()
|
try {
|
||||||
console.log(res)
|
startLoading()
|
||||||
tableData.value = res.map((item: ChannelType) => ({
|
const res = await getChannelList()
|
||||||
...item,
|
console.log(res)
|
||||||
statusStr: getStatusText(item.status),
|
tableData.value = res.map((item: ChannelType) => ({
|
||||||
})) as ChannelType[]
|
...item,
|
||||||
clearSelection()
|
statusStr: getStatusText(item.status),
|
||||||
|
})) as ChannelType[]
|
||||||
|
clearSelection()
|
||||||
|
} finally {
|
||||||
|
stopLoading()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//表格数据
|
//表格数据
|
||||||
|
|
@ -102,11 +97,17 @@ const formItems = ref(formItemsData)
|
||||||
const formRules = ref(formRulesData)
|
const formRules = ref(formRulesData)
|
||||||
const optionsMap = ref(optionsMapData)
|
const optionsMap = ref(optionsMapData)
|
||||||
const submitDetail = async () => {
|
const submitDetail = async () => {
|
||||||
dialogVisible.value = false
|
await formRef.value.validate()
|
||||||
if (dialogTitleType.value === 1) {
|
startSubmitLoading();
|
||||||
await createChannel(formData.value)
|
try {
|
||||||
} else {
|
if (dialogTitleType.value === 1) {
|
||||||
await editChannel(formData.value)
|
await createChannel(formData.value)
|
||||||
|
} else {
|
||||||
|
await editChannel(formData.value)
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
dialogVisible.value = false
|
||||||
|
stopSubmitLoading();
|
||||||
}
|
}
|
||||||
await initData()
|
await initData()
|
||||||
}
|
}
|
||||||
|
|
@ -199,4 +200,3 @@ onMounted(() => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ export const tableColumns = [
|
||||||
//存款渠道名称
|
//存款渠道名称
|
||||||
{ label: '渠道名称', prop: 'name' },
|
{ label: '渠道名称', prop: 'name' },
|
||||||
//存款渠道费用
|
//存款渠道费用
|
||||||
{ label: '渠道费用', prop: 'channel_fee' },
|
{ label: '渠道费用', prop: 'channel_fee', isNumber: true },
|
||||||
//存款渠道类型
|
//存款渠道类型
|
||||||
{ label: '入金货币', prop: 'currency.symbol' },
|
{ label: '入金货币', prop: 'currency.symbol' },
|
||||||
// 接口地址
|
// 接口地址
|
||||||
|
|
|
||||||
|
|
@ -19,36 +19,16 @@
|
||||||
</template>
|
</template>
|
||||||
</RechangeSearch>
|
</RechangeSearch>
|
||||||
|
|
||||||
<!-- 列表区域:改为真实接口数据,仍保留勾选列供后续审核动作使用 -->
|
<!-- 列表区域:使用公共 Table 组件 -->
|
||||||
<div class="table-wrapper">
|
<Table
|
||||||
<el-table
|
ref="tableRef"
|
||||||
ref="tableRef"
|
:table-data="tableData"
|
||||||
v-loading="loading"
|
:columns="tableColumns"
|
||||||
:data="tableData"
|
row-key="id"
|
||||||
border
|
:loading="loading"
|
||||||
height="100%"
|
:show-selection="true"
|
||||||
row-key="id"
|
@selection-change="handleSelectionChange"
|
||||||
@selection-change="handleSelectionChange"
|
/>
|
||||||
>
|
|
||||||
<el-table-column type="selection" width="55" align="center" />
|
|
||||||
|
|
||||||
<el-table-column label="序号" width="70" align="center">
|
|
||||||
<template #default="scope">
|
|
||||||
{{ (currentPage - 1) * pageSize + scope.$index + 1 }}
|
|
||||||
</template>
|
|
||||||
</el-table-column>
|
|
||||||
|
|
||||||
<el-table-column
|
|
||||||
v-for="column in tableColumns"
|
|
||||||
:key="column.prop"
|
|
||||||
:prop="column.prop"
|
|
||||||
:label="column.label"
|
|
||||||
:min-width="column.width"
|
|
||||||
:align="column.align || 'center'"
|
|
||||||
show-overflow-tooltip
|
|
||||||
/>
|
|
||||||
</el-table>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 分页区域:使用接口返回的 total / current_page / per_page -->
|
<!-- 分页区域:使用接口返回的 total / current_page / per_page -->
|
||||||
<RechangePagination
|
<RechangePagination
|
||||||
|
|
@ -65,9 +45,11 @@ defineOptions({
|
||||||
name: 'RechangeCheck',
|
name: 'RechangeCheck',
|
||||||
})
|
})
|
||||||
|
|
||||||
import { ElMessage } from 'element-plus'
|
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||||
import { onMounted, ref } from 'vue'
|
import { onMounted, ref } from 'vue'
|
||||||
import RechangeSearch from '@/components/common/Search.vue'
|
import RechangeSearch from '@/components/common/Search.vue'
|
||||||
|
import Table from '@/components/common/Table.vue'
|
||||||
|
import { usePageLoading } from '@/composables/useLoading'
|
||||||
import RechangePagination from '@/components/common/Pagination.vue'
|
import RechangePagination from '@/components/common/Pagination.vue'
|
||||||
import { exportToExcel } from '@/utils/exportToExcel'
|
import { exportToExcel } from '@/utils/exportToExcel'
|
||||||
import { getRechargeCheckListApi, reviewRechargeOrder } from '@/api/modules/capital/rechargeCheck'
|
import { getRechargeCheckListApi, reviewRechargeOrder } from '@/api/modules/capital/rechargeCheck'
|
||||||
|
|
@ -101,10 +83,10 @@ interface SearchFormData {
|
||||||
const searchOptions = ref(rechangeCheckSearch)
|
const searchOptions = ref(rechangeCheckSearch)
|
||||||
const tableColumns = ref(rechangeCheckTableColumns)
|
const tableColumns = ref(rechangeCheckTableColumns)
|
||||||
|
|
||||||
|
const { loading, startLoading, stopLoading } = usePageLoading()
|
||||||
// 表格、勾选状态和 loading 状态。
|
// 表格、勾选状态和 loading 状态。
|
||||||
const tableData = ref<TableRow[]>([])
|
const tableData = ref<TableRow[]>([])
|
||||||
const selectedRows = ref<TableRow[]>([])
|
const selectedRows = ref<TableRow[]>([])
|
||||||
const loading = ref(false)
|
|
||||||
|
|
||||||
// 分页状态。
|
// 分页状态。
|
||||||
const total = ref(0)
|
const total = ref(0)
|
||||||
|
|
@ -137,7 +119,7 @@ const getRechargeStatusText = (status: string | number | null | undefined) => {
|
||||||
|
|
||||||
// 获取审核列表:page / page_size / start_time / end_time 必传,其余空值统一传 null。
|
// 获取审核列表:page / page_size / start_time / end_time 必传,其余空值统一传 null。
|
||||||
const getList = async () => {
|
const getList = async () => {
|
||||||
loading.value = true
|
startLoading()
|
||||||
selectedRows.value = []
|
selectedRows.value = []
|
||||||
|
|
||||||
const params = {
|
const params = {
|
||||||
|
|
@ -175,7 +157,7 @@ const getList = async () => {
|
||||||
total.value = 0
|
total.value = 0
|
||||||
console.error('获取充值审核列表失败', error)
|
console.error('获取充值审核列表失败', error)
|
||||||
} finally {
|
} finally {
|
||||||
loading.value = false
|
stopLoading()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -220,10 +202,23 @@ const handleApprove = async () => {
|
||||||
ElMessage.warning('请先选择要通过的记录')
|
ElMessage.warning('请先选择要通过的记录')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
console.log(selectedRows.value)
|
try {
|
||||||
await reviewRechargeOrder({ id: selectedRows.value[0].id, status: '3' })
|
await ElMessageBox.confirm(`是否确认通过该审核?订单号:${selectedRows.value[0].orderNo}`, '审核确认', {
|
||||||
ElMessage.success('审核通过')
|
confirmButtonText: '确认',
|
||||||
await getList()
|
cancelButtonText: '取消',
|
||||||
|
type: 'warning',
|
||||||
|
})
|
||||||
|
} catch {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
startLoading()
|
||||||
|
try {
|
||||||
|
await reviewRechargeOrder({ id: selectedRows.value[0].id, status: '3' })
|
||||||
|
await getList()
|
||||||
|
} finally {
|
||||||
|
stopLoading()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 审核驳回:当前保留前端提示,等待后续接接口。
|
// 审核驳回:当前保留前端提示,等待后续接接口。
|
||||||
|
|
@ -232,10 +227,24 @@ const handleReject = async () => {
|
||||||
ElMessage.warning('请先选择要驳回的记录')
|
ElMessage.warning('请先选择要驳回的记录')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
try {
|
||||||
|
await ElMessageBox.confirm(`是否确认驳回该审核?订单号:${selectedRows.value[0].orderNo}`, '审核确认', {
|
||||||
|
confirmButtonText: '确认',
|
||||||
|
cancelButtonText: '取消',
|
||||||
|
type: 'warning',
|
||||||
|
})
|
||||||
|
} catch {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
//充值状态:1未审核,2未付款,3已付款,4驳回
|
//充值状态:1未审核,2未付款,3已付款,4驳回
|
||||||
await reviewRechargeOrder({ id: selectedRows.value[0].id, status: '4' })
|
startLoading()
|
||||||
ElMessage.success('审核驳回')
|
try {
|
||||||
await getList()
|
await reviewRechargeOrder({ id: selectedRows.value[0].id, status: '4' })
|
||||||
|
await getList()
|
||||||
|
} finally {
|
||||||
|
stopLoading()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 导出:先导出当前页接口数据,后续如需全量导出可切成独立导出接口。
|
// 导出:先导出当前页接口数据,后续如需全量导出可切成独立导出接口。
|
||||||
|
|
|
||||||
|
|
@ -39,12 +39,12 @@ export const rechangeCheckSearch = [
|
||||||
// 表格列配置:返回数据与 `rechargeOrder` 一致,因此按同一份结构展示。
|
// 表格列配置:返回数据与 `rechargeOrder` 一致,因此按同一份结构展示。
|
||||||
export const rechangeCheckTableColumns = [
|
export const rechangeCheckTableColumns = [
|
||||||
{ prop: 'orderNo', label: '订单号', align: 'center' as const, width: 220 },
|
{ prop: 'orderNo', label: '订单号', align: 'center' as const, width: 220 },
|
||||||
{ prop: 'userName', label: '用户名', align: 'center' as const, width: 160 },
|
{ prop: 'userName', label: '用户名', align: 'center' as const },
|
||||||
{ prop: 'currency', label: '充值币种', align: 'center' as const, width: 120 },
|
{ prop: 'currency', label: '充值币种', align: 'center' as const, width: 120 },
|
||||||
{ prop: 'amount', label: '充值金额', align: 'center' as const, width: 120 },
|
{ prop: 'amount', label: '充值金额', align: 'center' as const, width: 120, isNumber: true },
|
||||||
{ prop: 'realCurrency', label: '实际币种', align: 'center' as const, width: 120 },
|
{ prop: 'realCurrency', label: '实际币种', align: 'center' as const, width: 120 },
|
||||||
{ prop: 'realAmount', label: '实际金额', align: 'center' as const, width: 120 },
|
{ prop: 'realAmount', label: '实际金额', align: 'center' as const, width: 120, isNumber: true },
|
||||||
{ prop: 'rate', label: '汇率', align: 'center' as const, width: 100 },
|
{ prop: 'rate', label: '汇率', align: 'center' as const, width: 100 },
|
||||||
{ prop: 'statusText', label: '状态', align: 'center' as const, width: 100 },
|
{ prop: 'statusText', label: '状态', align: 'center' as const, width: 100 },
|
||||||
{ prop: 'rechangeTime', label: '充值时间', align: 'center' as const, width: 180 },
|
{ prop: 'rechangeTime', label: '充值时间', align: 'center' as const },
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
:table-data="tableData"
|
:table-data="tableData"
|
||||||
:columns="tableColumnsOptions"
|
:columns="tableColumnsOptions"
|
||||||
row-key="id"
|
row-key="id"
|
||||||
v-loading="tableLoading"
|
:loading="loading"
|
||||||
@rowClick="handleRowClick"
|
@rowClick="handleRowClick"
|
||||||
>
|
>
|
||||||
<template #action="{ row }">
|
<template #action="{ row }">
|
||||||
|
|
@ -33,6 +33,7 @@ import { ref, reactive, onMounted } from 'vue'
|
||||||
import { ElMessage } from 'element-plus'
|
import { ElMessage } from 'element-plus'
|
||||||
import Table from '@/components/common/Table.vue'
|
import Table from '@/components/common/Table.vue'
|
||||||
import Pagination from '@/components/common/Pagination.vue'
|
import Pagination from '@/components/common/Pagination.vue'
|
||||||
|
import { usePageLoading } from '@/composables/useLoading'
|
||||||
import WithdrawDialog from './components/WithdrawDialog.vue'
|
import WithdrawDialog from './components/WithdrawDialog.vue'
|
||||||
import { tableColumns } from './options'
|
import { tableColumns } from './options'
|
||||||
import { getWithdrawChannel } from '@/api/modules/capital/withdraw'
|
import { getWithdrawChannel } from '@/api/modules/capital/withdraw'
|
||||||
|
|
@ -54,7 +55,7 @@ interface TableRow {
|
||||||
|
|
||||||
const tableRef = ref()
|
const tableRef = ref()
|
||||||
const tableData = ref<TableRow[]>([])
|
const tableData = ref<TableRow[]>([])
|
||||||
const tableLoading = ref(false)
|
const { loading, startLoading, stopLoading } = usePageLoading()
|
||||||
const total = ref(0)
|
const total = ref(0)
|
||||||
const withdrawDialogVisible = ref(false)
|
const withdrawDialogVisible = ref(false)
|
||||||
const currentChannelId = ref<number>()
|
const currentChannelId = ref<number>()
|
||||||
|
|
@ -70,7 +71,7 @@ const tableColumnsOptions = tableColumns
|
||||||
|
|
||||||
// 获取列表数据
|
// 获取列表数据
|
||||||
const getList = async () => {
|
const getList = async () => {
|
||||||
tableLoading.value = true
|
startLoading()
|
||||||
try {
|
try {
|
||||||
const res: any = await getWithdrawChannel()
|
const res: any = await getWithdrawChannel()
|
||||||
if (res) {
|
if (res) {
|
||||||
|
|
@ -83,7 +84,7 @@ const getList = async () => {
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('获取列表失败', error)
|
console.error('获取列表失败', error)
|
||||||
} finally {
|
} finally {
|
||||||
tableLoading.value = false
|
stopLoading()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ export const tableColumns = [
|
||||||
// 渠道名称
|
// 渠道名称
|
||||||
{ label: '渠道名称', prop: 'name' },
|
{ label: '渠道名称', prop: 'name' },
|
||||||
// 渠道费用
|
// 渠道费用
|
||||||
{ label: '渠道费用', prop: 'channel_fee' },
|
{ label: '渠道费用', prop: 'channel_fee', isNumber: true },
|
||||||
{
|
{
|
||||||
label: '出金货币',
|
label: '出金货币',
|
||||||
prop: 'currency.symbol',
|
prop: 'currency.symbol',
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@
|
||||||
:table-data="tableData"
|
:table-data="tableData"
|
||||||
:columns="tableColumnsOptions"
|
:columns="tableColumnsOptions"
|
||||||
row-key="id"
|
row-key="id"
|
||||||
|
:loading="loading"
|
||||||
@rowClick="handleRowClick"
|
@rowClick="handleRowClick"
|
||||||
/>
|
/>
|
||||||
<el-dialog
|
<el-dialog
|
||||||
|
|
@ -18,6 +19,7 @@
|
||||||
width="700"
|
width="700"
|
||||||
>
|
>
|
||||||
<Form
|
<Form
|
||||||
|
ref="formRef"
|
||||||
:formItems="formItems"
|
:formItems="formItems"
|
||||||
:formRules="formRules"
|
:formRules="formRules"
|
||||||
:formData="formData"
|
:formData="formData"
|
||||||
|
|
@ -26,7 +28,7 @@
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<div class="dialog-footer">
|
<div class="dialog-footer">
|
||||||
<el-button @click="dialogVisible = false">取消</el-button>
|
<el-button @click="dialogVisible = false">取消</el-button>
|
||||||
<el-button type="primary" @click="submitDetail">确认</el-button>
|
<el-button type="primary" :loading="submitLoading" @click="submitDetail">确认</el-button>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
|
@ -39,6 +41,7 @@ defineOptions({
|
||||||
//组件
|
//组件
|
||||||
import Table from '@/components/common/Table.vue'
|
import Table from '@/components/common/Table.vue'
|
||||||
import Form from '@/components/common/Form.vue'
|
import Form from '@/components/common/Form.vue'
|
||||||
|
import { usePageLoading, useButtonLoading } from '@/composables/useLoading'
|
||||||
import { tableColumns, formItemsData, formRulesData, optionsMapData } from './options'
|
import { tableColumns, formItemsData, formRulesData, optionsMapData } from './options'
|
||||||
import {
|
import {
|
||||||
getChannelWithdrawList,
|
getChannelWithdrawList,
|
||||||
|
|
@ -65,8 +68,13 @@ const getStatusText = (status: number | string) => {
|
||||||
return ['', '正常', '禁用'][status]
|
return ['', '正常', '禁用'][status]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const formRef = ref()
|
||||||
|
const { loading, startLoading, stopLoading } = usePageLoading()
|
||||||
|
const { buttonLoading: submitLoading, startButtonLoading: startSubmitLoading, stopButtonLoading: stopSubmitLoading } = useButtonLoading()
|
||||||
const initData = async () => {
|
const initData = async () => {
|
||||||
|
startLoading()
|
||||||
const res = await getChannelWithdrawList()
|
const res = await getChannelWithdrawList()
|
||||||
|
stopLoading()
|
||||||
console.log(res)
|
console.log(res)
|
||||||
tableData.value = res.map((item: ChannelType) => ({
|
tableData.value = res.map((item: ChannelType) => ({
|
||||||
...item,
|
...item,
|
||||||
|
|
@ -96,13 +104,19 @@ const formItems = ref(formItemsData)
|
||||||
const formRules = ref(formRulesData)
|
const formRules = ref(formRulesData)
|
||||||
const optionsMap = ref(optionsMapData)
|
const optionsMap = ref(optionsMapData)
|
||||||
const submitDetail = async () => {
|
const submitDetail = async () => {
|
||||||
dialogVisible.value = false
|
await formRef.value.validate()
|
||||||
if (dialogTitleType.value === 1) {
|
startSubmitLoading();
|
||||||
await createChannelWithdraw(formData.value)
|
try {
|
||||||
} else {
|
dialogVisible.value = false
|
||||||
await editChannelWithdraw(formData.value)
|
if (dialogTitleType.value === 1) {
|
||||||
|
await createChannelWithdraw(formData.value)
|
||||||
|
} else {
|
||||||
|
await editChannelWithdraw(formData.value)
|
||||||
|
}
|
||||||
|
await initData()
|
||||||
|
} finally {
|
||||||
|
stopSubmitLoading();
|
||||||
}
|
}
|
||||||
await initData()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let currentRow: any = {}
|
let currentRow: any = {}
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ export const tableColumns = [
|
||||||
//渠道名称
|
//渠道名称
|
||||||
{ label: '渠道名称', prop: 'name' },
|
{ label: '渠道名称', prop: 'name' },
|
||||||
//渠道费用
|
//渠道费用
|
||||||
{ label: '渠道费用', prop: 'channel_fee' },
|
{ label: '渠道费用', prop: 'channel_fee', isNumber: true },
|
||||||
//货币类型
|
//货币类型
|
||||||
// { label: '入金货币', prop: 'currency.name' },
|
// { label: '入金货币', prop: 'currency.name' },
|
||||||
// 接口地址
|
// 接口地址
|
||||||
|
|
|
||||||
|
|
@ -8,25 +8,16 @@
|
||||||
</template>
|
</template>
|
||||||
</WithdrawSearch>
|
</WithdrawSearch>
|
||||||
|
|
||||||
<!-- 列表区域:当前使用页面内表格,避免改动公共 Table 组件 -->
|
<!-- 列表区域:使用公共 Table 组件 -->
|
||||||
<div class="table-wrapper">
|
<Table
|
||||||
<el-table v-loading="loading" :data="tableData" border height="100%" row-key="id"
|
ref="tableRef"
|
||||||
@selection-change="handleSelectionChange">
|
:table-data="tableData"
|
||||||
<!-- 勾选列:用于后续审核通过/驳回 -->
|
:columns="tableColumns"
|
||||||
<el-table-column type="selection" width="55" align="center" />
|
row-key="id"
|
||||||
|
:loading="loading"
|
||||||
<!-- 序号列:根据当前分页动态计算 -->
|
:show-selection="true"
|
||||||
<el-table-column label="序号" width="70" align="center">
|
@selection-change="handleSelectionChange"
|
||||||
<template #default="scope">
|
/>
|
||||||
{{ (currentPage - 1) * pageSize + scope.$index + 1 }}
|
|
||||||
</template>
|
|
||||||
</el-table-column>
|
|
||||||
|
|
||||||
<!-- 业务字段列:通过配置项统一渲染 -->
|
|
||||||
<el-table-column v-for="column in tableColumns" :key="column.prop" :prop="column.prop" :label="column.label"
|
|
||||||
:width="column.width" :align="column.align || 'center'" show-overflow-tooltip />
|
|
||||||
</el-table>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 分页区域:复用项目内分页组件 -->
|
<!-- 分页区域:复用项目内分页组件 -->
|
||||||
<WithdrawPagination v-model="currentPage" v-model:pageSizeValue="pageSize" :total="total"
|
<WithdrawPagination v-model="currentPage" v-model:pageSizeValue="pageSize" :total="total"
|
||||||
|
|
@ -43,6 +34,8 @@ import { ElMessage, ElMessageBox } from 'element-plus'
|
||||||
import { computed, onMounted, ref } from 'vue'
|
import { computed, onMounted, ref } from 'vue'
|
||||||
import dayjs from 'dayjs'
|
import dayjs from 'dayjs'
|
||||||
import WithdrawSearch from '@/components/common/Search.vue'
|
import WithdrawSearch from '@/components/common/Search.vue'
|
||||||
|
import Table from '@/components/common/Table.vue'
|
||||||
|
import { usePageLoading } from '@/composables/useLoading'
|
||||||
import WithdrawPagination from '@/components/common/Pagination.vue'
|
import WithdrawPagination from '@/components/common/Pagination.vue'
|
||||||
import { withdrawCheckSearch, withdrawCheckTableColumns } from './options'
|
import { withdrawCheckSearch, withdrawCheckTableColumns } from './options'
|
||||||
import { getWithdrawReviewList, withdrawReviewOrder } from '@/api/modules/capital/withdraw'
|
import { getWithdrawReviewList, withdrawReviewOrder } from '@/api/modules/capital/withdraw'
|
||||||
|
|
@ -117,11 +110,11 @@ const searchForm = ref({
|
||||||
timeRange: [] as string[]
|
timeRange: [] as string[]
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const { loading, startLoading, stopLoading } = usePageLoading()
|
||||||
// 表格、勾选状态和 loading 状态
|
// 表格、勾选状态和 loading 状态
|
||||||
const tableColumns = computed(() => withdrawCheckTableColumns)
|
const tableColumns = computed(() => withdrawCheckTableColumns)
|
||||||
const tableData = ref<TransformedTableRow[]>([])
|
const tableData = ref<TransformedTableRow[]>([])
|
||||||
const selectedRows = ref<TableRow[]>([])
|
const selectedRows = ref<TableRow[]>([])
|
||||||
const loading = ref(false)
|
|
||||||
|
|
||||||
// 审核操作 loading 状态
|
// 审核操作 loading 状态
|
||||||
const approveLoading = ref(false)
|
const approveLoading = ref(false)
|
||||||
|
|
@ -172,7 +165,7 @@ interface ListResponse {
|
||||||
|
|
||||||
// 获取列表数据
|
// 获取列表数据
|
||||||
const getList = async () => {
|
const getList = async () => {
|
||||||
loading.value = true
|
startLoading()
|
||||||
selectedRows.value = []
|
selectedRows.value = []
|
||||||
|
|
||||||
const [start_time, end_time] = searchForm.value.timeRange || []
|
const [start_time, end_time] = searchForm.value.timeRange || []
|
||||||
|
|
@ -192,7 +185,7 @@ const getList = async () => {
|
||||||
console.error('获取提现审核列表失败:', error)
|
console.error('获取提现审核列表失败:', error)
|
||||||
ElMessage.error('获取列表失败')
|
ElMessage.error('获取列表失败')
|
||||||
} finally {
|
} finally {
|
||||||
loading.value = false
|
stopLoading()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -25,18 +25,18 @@ export const withdrawCheckSearch = [
|
||||||
// 表格列配置
|
// 表格列配置
|
||||||
export const withdrawCheckTableColumns = [
|
export const withdrawCheckTableColumns = [
|
||||||
{ prop: 'trade_id', label: '订单号', align: 'center' as const, width: 200 },
|
{ prop: 'trade_id', label: '订单号', align: 'center' as const, width: 200 },
|
||||||
{ prop: 'user_name', label: '账户持有人', align: 'center' as const, width: 120 },
|
{ prop: 'user_name', label: '账户持有人', align: 'center' as const},
|
||||||
{ prop: 'withdraw_currency_symbol', label: '取款币种', align: 'center' as const, width: 100 },
|
{ prop: 'withdraw_currency_symbol', label: '取款币种', align: 'center' as const, width: 100 },
|
||||||
{ prop: 'withdraw_amount', label: '取款金额', align: 'center' as const, width: 120 },
|
{ prop: 'withdraw_amount', label: '取款金额', align: 'center' as const, width: 120, isNumber: true },
|
||||||
{ prop: 'real_currency_symbol', label: '到账币种', align: 'center' as const, width: 100 },
|
{ prop: 'real_currency_symbol', label: '到账币种', align: 'center' as const, width: 100 },
|
||||||
{ prop: 'real_amount', label: '到账金额', align: 'center' as const, width: 120 },
|
{ prop: 'real_amount', label: '到账金额', align: 'center' as const, width: 120, isNumber: true },
|
||||||
{ prop: 'rate', label: '汇率', align: 'center' as const, width: 100 },
|
{ prop: 'rate', label: '汇率', align: 'center' as const, width: 100 },
|
||||||
{ prop: 'channel_name', label: '渠道', align: 'center' as const, width: 140 },
|
{ prop: 'channel_name', label: '渠道', align: 'center' as const, width: 140 },
|
||||||
{ prop: 'withdraw_service_fee', label: '服务费', align: 'center' as const, width: 100 },
|
{ prop: 'withdraw_service_fee', label: '服务费', align: 'center' as const, width: 100, isNumber: true },
|
||||||
{ prop: 'withdraw_head_fee', label: '总部手续费', align: 'center' as const, width: 120 },
|
{ prop: 'withdraw_head_fee', label: '总部手续费', align: 'center' as const, width: 120, isNumber: true },
|
||||||
{ prop: 'withdraw_fee_handle', label: '代理手续费', align: 'center' as const, width: 120 },
|
{ prop: 'withdraw_fee_handle', label: '代理手续费', align: 'center' as const, width: 120, isNumber: true },
|
||||||
{ prop: 'withdraw_point_diff', label: '点差', align: 'center' as const, width: 100 },
|
{ prop: 'withdraw_point_diff', label: '点差', align: 'center' as const, width: 100, isNumber: true },
|
||||||
{ prop: 'withdraw_risk_fee', label: '风控费', align: 'center' as const, width: 100 },
|
{ prop: 'withdraw_risk_fee', label: '风控费', align: 'center' as const, isNumber: true },
|
||||||
{ prop: 'withdraw_address', label: '提现地址', align: 'center' as const, width: 180 },
|
{ prop: 'withdraw_address', label: '提现地址', align: 'center' as const},
|
||||||
{ prop: 'created_at', label: '申请时间', align: 'center' as const, width: 180 }
|
{ prop: 'created_at', label: '申请时间', align: 'center' as const}
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -2,63 +2,28 @@
|
||||||
<div class="mould-fee table_form-container">
|
<div class="mould-fee table_form-container">
|
||||||
<header>
|
<header>
|
||||||
<div class="header-actions">
|
<div class="header-actions">
|
||||||
<el-button type="primary" @click="addFee" v-auth="'feeHandl_createFeeSetting'"
|
<el-button type="primary" @click="addFee" v-auth="'feeHandl_createFeeSetting'">添加模板</el-button>
|
||||||
>添加模板</el-button
|
<el-button type="primary" @click="editFee" v-auth="'feeHandl_editFeeSetting'">编辑模板</el-button>
|
||||||
>
|
<el-button type="primary" @click="changeStatus(1)" v-auth="'feeHandl_editFeeSetting'">启用模板</el-button>
|
||||||
<el-button type="primary" @click="editFee" v-auth="'feeHandl_editFeeSetting'"
|
<el-button type="danger" @click="changeStatus(2)" v-auth="'feeHandl_editFeeSetting'">禁用模板</el-button>
|
||||||
>编辑模板</el-button
|
<el-button type="primary" @click="editFeeDetail" v-auth="'feeHandl_setFeeSettingDetail'">编辑模板详情</el-button>
|
||||||
>
|
|
||||||
<el-button type="primary" @click="changeStatus(1)" v-auth="'feeHandl_editFeeSetting'"
|
|
||||||
>启用模板</el-button
|
|
||||||
>
|
|
||||||
<el-button type="danger" @click="changeStatus(2)" v-auth="'feeHandl_editFeeSetting'"
|
|
||||||
>禁用模板</el-button
|
|
||||||
>
|
|
||||||
<el-button type="primary" @click="editFeeDetail" v-auth="'feeHandl_setFeeSettingDetail'"
|
|
||||||
>编辑模板详情</el-button
|
|
||||||
>
|
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
<div class="table-container">
|
<div class="table-container">
|
||||||
<div class="table-container-left">
|
<div class="table-container-left">
|
||||||
<el-table
|
<Table ref="singleTableRef" :table-data="tableData" :columns="tableColumns" row-key="id" :loading="loading"
|
||||||
ref="singleTableRef"
|
:highlight-current-row="true" @current-change="handleCurrentChange" />
|
||||||
height="100%"
|
|
||||||
:data="tableData"
|
|
||||||
highlight-current-row
|
|
||||||
border
|
|
||||||
@current-change="handleCurrentChange"
|
|
||||||
>
|
|
||||||
<el-table-column type="index" width="55" />
|
|
||||||
<el-table-column
|
|
||||||
v-for="column in tableColumns"
|
|
||||||
:key="column.prop"
|
|
||||||
:prop="column.prop"
|
|
||||||
:label="column.label"
|
|
||||||
/>
|
|
||||||
</el-table>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="table-container-right">
|
<div class="table-container-right">
|
||||||
<el-table height="100%" :data="tableDataDetail">
|
<Table row-key="id" :table-data="tableDataDetail" :columns="tableColumnsDetail" :loading="detailLoading" />
|
||||||
<el-table-column
|
|
||||||
v-for="column in tableColumnsDetail"
|
|
||||||
:key="column.prop"
|
|
||||||
:prop="column.prop"
|
|
||||||
:label="column.label"
|
|
||||||
/>
|
|
||||||
</el-table>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<el-dialog
|
<el-dialog v-model="dialogVisible" :title="dialogTitleType === 1 ? '添加手续费模板' : '编辑手续费模板'" width="500">
|
||||||
v-model="dialogVisible"
|
|
||||||
:title="dialogTitleType === 1 ? '添加手续费模板' : '编辑手续费模板'"
|
|
||||||
width="500"
|
|
||||||
>
|
|
||||||
<Form :formItems="formItems" :formRules="formRules" :formData="formData" />
|
<Form :formItems="formItems" :formRules="formRules" :formData="formData" />
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<div class="dialog-footer">
|
<div class="dialog-footer">
|
||||||
<el-button @click="dialogVisible = false">取消</el-button>
|
<el-button @click="dialogVisible = false">取消</el-button>
|
||||||
<el-button type="primary" @click="submit">确认</el-button>
|
<el-button type="primary" :loading="submitLoading" @click="submit">确认</el-button>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
|
@ -67,12 +32,7 @@
|
||||||
<template v-for="column in tableColumnsDetail" :key="column.prop">
|
<template v-for="column in tableColumnsDetail" :key="column.prop">
|
||||||
<el-table-column v-if="column.prop === 'fee'" :prop="column.prop" :label="column.label">
|
<el-table-column v-if="column.prop === 'fee'" :prop="column.prop" :label="column.label">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-input-number
|
<el-input-number :min="0" :max="999999999" :controls="false" v-model="scope.row.fee" />
|
||||||
:min="0"
|
|
||||||
:max="999999999"
|
|
||||||
:controls="false"
|
|
||||||
v-model="scope.row.fee"
|
|
||||||
/>
|
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column v-else :prop="column.prop" :label="column.label" />
|
<el-table-column v-else :prop="column.prop" :label="column.label" />
|
||||||
|
|
@ -81,7 +41,7 @@
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<div class="dialog-footer">
|
<div class="dialog-footer">
|
||||||
<el-button @click="detaildialogVisible = false">取消</el-button>
|
<el-button @click="detaildialogVisible = false">取消</el-button>
|
||||||
<el-button type="primary" @click="submitDetail">确认</el-button>
|
<el-button type="primary" :loading="submitDetailLoading" @click="submitDetail">确认</el-button>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
|
@ -93,7 +53,9 @@
|
||||||
defineOptions({
|
defineOptions({
|
||||||
name: 'HandleFee'
|
name: 'HandleFee'
|
||||||
})
|
})
|
||||||
|
|
||||||
import { ref, onMounted } from 'vue'
|
import { ref, onMounted } from 'vue'
|
||||||
|
import { usePageLoading, useButtonLoading } from '@/composables/useLoading'
|
||||||
import {
|
import {
|
||||||
getFeeSettingList,
|
getFeeSettingList,
|
||||||
getFeeSettingDetail,
|
getFeeSettingDetail,
|
||||||
|
|
@ -102,18 +64,42 @@ import {
|
||||||
setFeeSettingDetail,
|
setFeeSettingDetail,
|
||||||
} from '@/api/modules/mould/handleFee.ts'
|
} from '@/api/modules/mould/handleFee.ts'
|
||||||
import Form from '@/components/common/Form.vue'
|
import Form from '@/components/common/Form.vue'
|
||||||
|
import Table from '@/components/common/Table.vue'
|
||||||
import { formDataList, formRulesList } from './option.ts'
|
import { formDataList, formRulesList } from './option.ts'
|
||||||
|
|
||||||
|
// 弹窗相关
|
||||||
const dialogVisible = ref(false)
|
const dialogVisible = ref(false)
|
||||||
const dialogTitleType = ref(1)
|
const dialogTitleType = ref(1)
|
||||||
|
|
||||||
|
// 表单相关
|
||||||
const formData = ref({
|
const formData = ref({
|
||||||
name: '',
|
name: '',
|
||||||
status: 1,
|
status: 1,
|
||||||
type: 2,
|
type: 2,
|
||||||
description: '',
|
description: '',
|
||||||
})
|
})
|
||||||
const formItems = ref(formDataList)
|
const formItems = formDataList
|
||||||
const formRules = ref(formRulesList)
|
const formRules = formRulesList
|
||||||
|
|
||||||
|
// 详情弹窗相关
|
||||||
|
const detaildialogVisible = ref(false)
|
||||||
|
|
||||||
|
// 加载状态
|
||||||
|
const { loading, startLoading, stopLoading } = usePageLoading()
|
||||||
|
const { buttonLoading: detailLoading, startButtonLoading: startDetailLoading, stopButtonLoading: stopDetailLoading } = useButtonLoading()
|
||||||
|
const { buttonLoading: submitLoading, startButtonLoading: startSubmitLoading, stopButtonLoading: stopSubmitLoading } = useButtonLoading()
|
||||||
|
const { buttonLoading: submitDetailLoading, startButtonLoading: startSubmitDetailLoading, stopButtonLoading: stopSubmitDetailLoading } = useButtonLoading()
|
||||||
|
|
||||||
|
// 主表格相关
|
||||||
|
const tableData = ref<any[]>([])
|
||||||
|
const tableColumns = [
|
||||||
|
{ prop: 'name', label: '名称' },
|
||||||
|
{ prop: 'type', label: '状态' },
|
||||||
|
]
|
||||||
|
const currentRow = ref<Record<string, any>>({})
|
||||||
|
const singleTableRef = ref()
|
||||||
|
|
||||||
|
// 重置表单数据
|
||||||
const resetFormData = () => {
|
const resetFormData = () => {
|
||||||
formData.value = {
|
formData.value = {
|
||||||
name: '',
|
name: '',
|
||||||
|
|
@ -123,56 +109,72 @@ const resetFormData = () => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const tableData = ref([])
|
// 设置当前选中行
|
||||||
const tableColumns = ref([
|
const setCurrent = (row: any) => {
|
||||||
{ prop: 'name', label: '名称' },
|
singleTableRef.value?.setCurrentRow(row)
|
||||||
{ prop: 'type', label: '状态' },
|
|
||||||
])
|
|
||||||
const currentRow = ref({})
|
|
||||||
const singleTableRef = ref()
|
|
||||||
const setCurrent = (row) => {
|
|
||||||
singleTableRef.value.setCurrentRow(row)
|
|
||||||
}
|
|
||||||
const handleCurrentChange = (row: any) => {
|
|
||||||
currentRow.value = row
|
|
||||||
getItemDetail(row.id)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const tableDataDetail = ref([])
|
// 主表格行选中变化
|
||||||
const tableColumnsDetail = ref([
|
const handleCurrentChange = (row: any) => {
|
||||||
|
currentRow.value = row
|
||||||
|
fetchItemDetail(row.id)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 详情表格相关
|
||||||
|
const tableDataDetail = ref<any[]>([])
|
||||||
|
const tableColumnsDetail = [
|
||||||
{ prop: 'name', label: '品种' },
|
{ prop: 'name', label: '品种' },
|
||||||
{ prop: 'code', label: '编号' },
|
{ prop: 'code', label: '编号' },
|
||||||
{ prop: 'fee', label: '开仓手续费' },
|
{ prop: 'fee', label: '开仓手续费' },
|
||||||
])
|
]
|
||||||
|
|
||||||
|
// 获取主表格数据
|
||||||
const getTableData = async () => {
|
const getTableData = async () => {
|
||||||
const res = await getFeeSettingList()
|
startLoading()
|
||||||
const savedId = currentRow.value?.id
|
try {
|
||||||
tableData.value = res
|
const res = await getFeeSettingList()
|
||||||
console.log(res)
|
tableData.value = Array.isArray(res) ? res : []
|
||||||
if (res && res.length > 0) {
|
handleTableDataAfterLoad()
|
||||||
const targetRow = savedId ? res.find((item: any) => item.id === savedId) : null
|
} finally {
|
||||||
if (targetRow) {
|
stopLoading()
|
||||||
setCurrent(targetRow)
|
|
||||||
handleCurrentChange(targetRow)
|
|
||||||
} else {
|
|
||||||
setCurrent(res[0])
|
|
||||||
handleCurrentChange(res[0])
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const getItemDetail = async (id: number) => {
|
// 处理表格数据加载后的逻辑
|
||||||
const res = await getFeeSettingDetail({ id })
|
const handleTableDataAfterLoad = () => {
|
||||||
tableDataDetail.value = res
|
const savedId = currentRow.value?.id
|
||||||
|
|
||||||
|
if (tableData.value.length === 0) {
|
||||||
|
tableDataDetail.value = []
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const targetRow = savedId ? tableData.value.find((item) => item.id === savedId) : null
|
||||||
|
const rowToSelect = targetRow || tableData.value[0]
|
||||||
|
|
||||||
|
setCurrent(rowToSelect)
|
||||||
|
handleCurrentChange(rowToSelect)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 获取详情数据
|
||||||
|
const fetchItemDetail = async (id: number) => {
|
||||||
|
startDetailLoading();
|
||||||
|
try {
|
||||||
|
const res = await getFeeSettingDetail({ id })
|
||||||
|
tableDataDetail.value = res || []
|
||||||
|
} finally {
|
||||||
|
stopDetailLoading();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 打开添加弹窗
|
||||||
const addFee = () => {
|
const addFee = () => {
|
||||||
dialogVisible.value = true
|
dialogVisible.value = true
|
||||||
dialogTitleType.value = 1
|
dialogTitleType.value = 1
|
||||||
resetFormData()
|
resetFormData()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 打开编辑弹窗
|
||||||
const editFee = () => {
|
const editFee = () => {
|
||||||
dialogVisible.value = true
|
dialogVisible.value = true
|
||||||
dialogTitleType.value = 2
|
dialogTitleType.value = 2
|
||||||
|
|
@ -184,6 +186,7 @@ const editFee = () => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 切换模板状态
|
||||||
const changeStatus = (status: number) => {
|
const changeStatus = (status: number) => {
|
||||||
dialogTitleType.value = 2
|
dialogTitleType.value = 2
|
||||||
formData.value = {
|
formData.value = {
|
||||||
|
|
@ -196,35 +199,48 @@ const changeStatus = (status: number) => {
|
||||||
submit()
|
submit()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 提交主表单
|
||||||
const submit = async () => {
|
const submit = async () => {
|
||||||
console.log(formData.value)
|
startSubmitLoading();
|
||||||
if (dialogTitleType.value === 1) {
|
try {
|
||||||
await createFeeSetting(formData.value)
|
if (dialogTitleType.value === 1) {
|
||||||
} else {
|
await createFeeSetting(formData.value)
|
||||||
await editFeeSetting(formData.value)
|
} else {
|
||||||
|
await editFeeSetting(formData.value)
|
||||||
|
}
|
||||||
|
resetFormData()
|
||||||
|
dialogVisible.value = false
|
||||||
|
getTableData()
|
||||||
|
} finally {
|
||||||
|
stopSubmitLoading();
|
||||||
}
|
}
|
||||||
resetFormData()
|
|
||||||
dialogVisible.value = false
|
|
||||||
getTableData()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const detaildialogVisible = ref(false)
|
// 打开编辑详情弹窗
|
||||||
const editFeeDetail = () => {
|
const editFeeDetail = () => {
|
||||||
detaildialogVisible.value = true
|
detaildialogVisible.value = true
|
||||||
console.log(tableDataDetail.value)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 提交详情表单
|
||||||
const submitDetail = async () => {
|
const submitDetail = async () => {
|
||||||
let contents_json = {}
|
startSubmitDetailLoading();
|
||||||
tableDataDetail.value.forEach((item) => {
|
try {
|
||||||
contents_json[item.variety_id] = item.fee
|
const contentsJson: Record<string, any> = {}
|
||||||
})
|
|
||||||
await setFeeSettingDetail({
|
tableDataDetail.value.forEach((item) => {
|
||||||
id: currentRow.value.id,
|
contentsJson[item.variety_id] = item.fee
|
||||||
contents_json: JSON.stringify(contents_json),
|
})
|
||||||
})
|
|
||||||
detaildialogVisible.value = false
|
await setFeeSettingDetail({
|
||||||
getTableData()
|
id: currentRow.value.id,
|
||||||
|
contents_json: JSON.stringify(contentsJson),
|
||||||
|
})
|
||||||
|
|
||||||
|
detaildialogVisible.value = false
|
||||||
|
getTableData()
|
||||||
|
} finally {
|
||||||
|
stopSubmitDetailLoading();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
|
|
@ -237,19 +253,23 @@ onMounted(() => {
|
||||||
// height: 100%;
|
// height: 100%;
|
||||||
// overflow: hidden;
|
// overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
header {
|
header {
|
||||||
margin-bottom: 8px;
|
margin-bottom: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.table-container {
|
.table-container {
|
||||||
display: flex;
|
display: flex;
|
||||||
column-gap: 20px;
|
column-gap: 20px;
|
||||||
height: calc(100% - 40px);
|
height: calc(100% - 40px);
|
||||||
|
|
||||||
.table-container-left {
|
.table-container-left {
|
||||||
width: 300px;
|
width: 300px;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
flex: 0 0 auto;
|
flex: 0 0 auto;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.table-container-right {
|
.table-container-right {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
|
@ -257,3 +277,4 @@ header {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,69 +2,31 @@
|
||||||
<div class="risk table_form-container">
|
<div class="risk table_form-container">
|
||||||
<div class="bar">
|
<div class="bar">
|
||||||
<span>风控管理</span>
|
<span>风控管理</span>
|
||||||
<el-button type="primary" @click="handleAddRisk" v-auth="'riskControl_createRiskControl'"
|
<el-button type="primary" @click="handleAddRisk" v-auth="'riskControl_createRiskControl'">添加</el-button>
|
||||||
>添加</el-button
|
<el-button type="primary" @click="handleModifyRisk" v-auth="'riskControl_editRiskControlSetting'">修改</el-button>
|
||||||
>
|
<el-button type="danger" @click="handleChangeStatus(2)"
|
||||||
<el-button
|
v-auth="'riskControl_editRiskControlSetting'">停用</el-button>
|
||||||
type="primary"
|
<el-button type="primary" @click="handleChangeStatus(1)"
|
||||||
@click="handleModifyRisk"
|
v-auth="'riskControl_editRiskControlSetting'">启用</el-button>
|
||||||
v-auth="'riskControl_editRiskControlSetting'"
|
|
||||||
>修改</el-button
|
|
||||||
>
|
|
||||||
<el-button
|
|
||||||
type="danger"
|
|
||||||
@click="handleChangeStatus(2)"
|
|
||||||
v-auth="'riskControl_editRiskControlSetting'"
|
|
||||||
>停用</el-button
|
|
||||||
>
|
|
||||||
<el-button
|
|
||||||
type="primary"
|
|
||||||
@click="handleChangeStatus(1)"
|
|
||||||
v-auth="'riskControl_editRiskControlSetting'"
|
|
||||||
>启用</el-button
|
|
||||||
>
|
|
||||||
</div>
|
</div>
|
||||||
<!-- 表格 -->
|
<!-- 表格 -->
|
||||||
<div class="risk-table-content">
|
<div class="risk-table-content">
|
||||||
<RiskTableSwitch
|
<RiskTableSwitch :columns="tableColumnsSwitch" :table-data="tableTreeSwitch" class="table-switch"
|
||||||
:columns="tableColumnsSwitch"
|
@row-click="handleRowClick" row-key="id" highlight-current-row :current-row-key="selectedRowId"
|
||||||
:table-data="tableTreeSwitch"
|
:loading="loading">
|
||||||
class="table-switch"
|
|
||||||
@row-click="handleRowClick"
|
|
||||||
row-key="id"
|
|
||||||
highlight-current-row
|
|
||||||
:current-row-key="selectedRowId"
|
|
||||||
>
|
|
||||||
<template #status="{ row }">
|
<template #status="{ row }">
|
||||||
<span>{{ row.status === 1 ? '启用' : '停用' }}</span>
|
<span>{{ row.status === 1 ? '启用' : '停用' }}</span>
|
||||||
</template>
|
</template>
|
||||||
</RiskTableSwitch>
|
</RiskTableSwitch>
|
||||||
<RiskTableContent
|
<RiskTableContent :columns="tableColumnsContent" :table-data="currentContent" class="table-content" row-key="id"
|
||||||
:columns="tableColumnsContent"
|
:loading="detailLoading">
|
||||||
:table-data="currentContent"
|
|
||||||
class="table-content"
|
|
||||||
row-key="id"
|
|
||||||
>
|
|
||||||
</RiskTableContent>
|
</RiskTableContent>
|
||||||
</div>
|
</div>
|
||||||
<!-- dialog -->
|
<!-- dialog -->
|
||||||
<RiskDialog
|
<RiskDialog :visible="dialogVisible" :title="dialogTitle" :type="dialogType" :button-loading="submitLoading" @confirm="handleSubmit"
|
||||||
:visible="dialogVisible"
|
@cancel="handleCancel" @close="handleClose">
|
||||||
:title="dialogTitle"
|
<RiskForm :form-data="dialogForm" :form-rules="riskRules" :form-items="RiskFormItems"
|
||||||
:type="dialogType"
|
:options-map="riskFormOptionsMap" :row-gutter="rowGutter" :col-span="colSpan" ref="riskFormRef" />
|
||||||
@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>
|
</RiskDialog>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
@ -75,6 +37,10 @@ defineOptions({
|
||||||
name: 'Risk'
|
name: 'Risk'
|
||||||
})
|
})
|
||||||
// 组件
|
// 组件
|
||||||
|
import { usePageLoading, useButtonLoading } from '@/composables/useLoading'
|
||||||
|
const { loading, startLoading, stopLoading } = usePageLoading()
|
||||||
|
const { buttonLoading: submitLoading, startButtonLoading: startSubmitLoading, stopButtonLoading: stopSubmitLoading } = useButtonLoading()
|
||||||
|
|
||||||
import RiskTableSwitch from '@/components/common/Table.vue'
|
import RiskTableSwitch from '@/components/common/Table.vue'
|
||||||
import RiskTableContent from '@/components/common/Table.vue'
|
import RiskTableContent from '@/components/common/Table.vue'
|
||||||
import RiskDialog from '@/components/common/Dialog.vue'
|
import RiskDialog from '@/components/common/Dialog.vue'
|
||||||
|
|
@ -132,6 +98,8 @@ const dialogForm = ref({
|
||||||
})
|
})
|
||||||
const riskRules = ref(rules())
|
const riskRules = ref(rules())
|
||||||
const riskFormRef = ref()
|
const riskFormRef = ref()
|
||||||
|
const detailLoading = ref(false)
|
||||||
|
|
||||||
|
|
||||||
const RiskFormItems = ref(formItem)
|
const RiskFormItems = ref(formItem)
|
||||||
const riskFormOptionsMap = ref({
|
const riskFormOptionsMap = ref({
|
||||||
|
|
@ -165,7 +133,9 @@ const colSpan = ref(12)
|
||||||
* @description: 定义请求数据方法
|
* @description: 定义请求数据方法
|
||||||
*/
|
*/
|
||||||
const getRiskList = async () => {
|
const getRiskList = async () => {
|
||||||
|
startLoading()
|
||||||
const data: any = await getRiskListApi()
|
const data: any = await getRiskListApi()
|
||||||
|
stopLoading()
|
||||||
// 保存原始数据
|
// 保存原始数据
|
||||||
riskOriginData.value = data
|
riskOriginData.value = data
|
||||||
// 处理数据
|
// 处理数据
|
||||||
|
|
@ -265,7 +235,7 @@ const handleModifyRisk = () => {
|
||||||
} as any
|
} as any
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleChangeStatus = async (status) => {
|
const handleChangeStatus = async (status:any) => {
|
||||||
dialogTitle.value = '停用'
|
dialogTitle.value = '停用'
|
||||||
dialogType.value = 'status'
|
dialogType.value = 'status'
|
||||||
await editRiskApi({ ...selectedRow.value, status: status })
|
await editRiskApi({ ...selectedRow.value, status: status })
|
||||||
|
|
@ -276,6 +246,7 @@ const handleChangeStatus = async (status) => {
|
||||||
* @description: 定义表格方法
|
* @description: 定义表格方法
|
||||||
*/
|
*/
|
||||||
const handleRowClick = (row: any) => {
|
const handleRowClick = (row: any) => {
|
||||||
|
detailLoading.value = true
|
||||||
// 从原始数据中匹配完整的行信息
|
// 从原始数据中匹配完整的行信息
|
||||||
const originRow = riskOriginData.value.find((item) => item.id === row.id)
|
const originRow = riskOriginData.value.find((item) => item.id === row.id)
|
||||||
if (originRow) {
|
if (originRow) {
|
||||||
|
|
@ -285,7 +256,7 @@ const handleRowClick = (row: any) => {
|
||||||
}
|
}
|
||||||
selectedRowId.value = row.id
|
selectedRowId.value = row.id
|
||||||
// 找到对应的数据并更新右侧内容
|
// 找到对应的数据并更新右侧内容
|
||||||
const targetItem = tableTreeContent.value.find((item: any) => item.id === row.id)
|
const targetItem:any = tableTreeContent.value.find((item: any) => item.id === row.id)
|
||||||
|
|
||||||
const fields = [
|
const fields = [
|
||||||
{ text: '单笔开仓最大数量' + targetItem.maxOpenPosition },
|
{ text: '单笔开仓最大数量' + targetItem.maxOpenPosition },
|
||||||
|
|
@ -305,58 +276,65 @@ const handleRowClick = (row: any) => {
|
||||||
if (targetItem) {
|
if (targetItem) {
|
||||||
currentContent.value = fields
|
currentContent.value = fields
|
||||||
}
|
}
|
||||||
|
|
||||||
|
detailLoading.value = false
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description: 定义弹窗方法
|
* @description: 定义弹窗方法
|
||||||
*/
|
*/
|
||||||
const handleSubmit = async () => {
|
const handleSubmit = async () => {
|
||||||
await riskFormRef.value?.validate()
|
startSubmitLoading()
|
||||||
const params = {
|
try {
|
||||||
name: dialogForm.value.name,
|
await riskFormRef.value?.validate()
|
||||||
status: dialogForm.value.status,
|
const params = {
|
||||||
// 是否默认
|
name: dialogForm.value.name,
|
||||||
is_default: dialogForm.value.isDefault,
|
status: dialogForm.value.status,
|
||||||
// 单笔开仓最大数量
|
// 是否默认
|
||||||
max_opening_quantity_per_transaction: dialogForm.value.maxOpenPosition,
|
is_default: dialogForm.value.isDefault,
|
||||||
// 单品种最大持仓数量
|
// 单笔开仓最大数量
|
||||||
max_holding_quantity_per_variety: dialogForm.value.maxPositionPerSymbol,
|
max_opening_quantity_per_transaction: dialogForm.value.maxOpenPosition,
|
||||||
// 总品种最大持仓数量
|
// 单品种最大持仓数量
|
||||||
max_holding_quantity_per_transaction: dialogForm.value.maxTotalPosition,
|
max_holding_quantity_per_variety: dialogForm.value.maxPositionPerSymbol,
|
||||||
// 强平比例
|
// 总品种最大持仓数量
|
||||||
strong_to_average_ratio: dialogForm.value.strongCloseRatio,
|
max_holding_quantity_per_transaction: dialogForm.value.maxTotalPosition,
|
||||||
// 每次出金最大金额
|
// 强平比例
|
||||||
max_withdrawal_amount_per_transaction: dialogForm.value.maxWithdrawalAmount,
|
strong_to_average_ratio: dialogForm.value.strongCloseRatio,
|
||||||
// 是否允许出金
|
// 每次出金最大金额
|
||||||
withdraw_status: dialogForm.value.isWithdrawalAllowed,
|
max_withdrawal_amount_per_transaction: dialogForm.value.maxWithdrawalAmount,
|
||||||
// 出金时间设置
|
// 是否允许出金
|
||||||
withdraw_time: Array.from(dialogForm.value.withdrawalTimeSetting || []).join('-'),
|
withdraw_status: dialogForm.value.isWithdrawalAllowed,
|
||||||
// 是否需要出金审核
|
// 出金时间设置
|
||||||
withdraw_is_check: dialogForm.value.isWithdrawalAuditRequired,
|
withdraw_time: Array.from(dialogForm.value.withdrawalTimeSetting || []).join('-'),
|
||||||
// 建仓多少秒不能平仓
|
// 是否需要出金审核
|
||||||
open_close_time: dialogForm.value.buildCloseTime,
|
withdraw_is_check: dialogForm.value.isWithdrawalAuditRequired,
|
||||||
// 每次出金最小金额
|
// 建仓多少秒不能平仓
|
||||||
min_withdrawal_amount_per_transaction: dialogForm.value.minWithdrawalAmount,
|
open_close_time: dialogForm.value.buildCloseTime,
|
||||||
// 滑点
|
// 每次出金最小金额
|
||||||
slippage: dialogForm.value.slippage,
|
min_withdrawal_amount_per_transaction: dialogForm.value.minWithdrawalAmount,
|
||||||
// 每次入金最小金额
|
// 滑点
|
||||||
min_recharge_amount_per_transaction: dialogForm.value.minDepositAmount,
|
slippage: dialogForm.value.slippage,
|
||||||
}
|
// 每次入金最小金额
|
||||||
// 添加风险控制
|
min_recharge_amount_per_transaction: dialogForm.value.minDepositAmount,
|
||||||
if (dialogType.value === 'add') {
|
}
|
||||||
// 添加风险控制
|
// 添加风险控制
|
||||||
await addRiskApi(params)
|
if (dialogType.value === 'add') {
|
||||||
getRiskList()
|
// 添加风险控制
|
||||||
dialogVisible.value = false
|
await addRiskApi(params)
|
||||||
dialogTitle.value = '添加'
|
getRiskList()
|
||||||
dialogType.value = 'add'
|
dialogVisible.value = false
|
||||||
} else {
|
dialogTitle.value = '添加'
|
||||||
// 编辑风险控制
|
dialogType.value = 'add'
|
||||||
await editRiskApi({ ...params, id: selectedRow.value.id })
|
} else {
|
||||||
getRiskList()
|
// 编辑风险控制
|
||||||
dialogVisible.value = false
|
await editRiskApi({ ...params, id: selectedRow.value.id })
|
||||||
dialogTitle.value = '编辑'
|
getRiskList()
|
||||||
dialogType.value = 'edit'
|
dialogVisible.value = false
|
||||||
|
dialogTitle.value = '编辑'
|
||||||
|
dialogType.value = 'edit'
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
stopSubmitLoading()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const handleCancel = () => {
|
const handleCancel = () => {
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="table_form-container">
|
<div class="table_form-container">
|
||||||
<!-- 搜索 -->
|
<!-- 搜索 -->
|
||||||
<CustomerTradeOrderSearch :search-form="searchForm" :search-options="searchOptions" @search="handleSearch"
|
<CustomerTradeOrderSearch :buttonLoading="loading" :search-form="searchForm" :search-options="searchOptions"
|
||||||
@reset="handleReset" @blur-input="getSubAccountList">
|
@search="handleSearch" @reset="handleReset" @blur-input="getSubAccountList">
|
||||||
</CustomerTradeOrderSearch>
|
</CustomerTradeOrderSearch>
|
||||||
<div class="bar" v-if="searchForm.orderId === '1'">
|
<div class="bar" v-if="searchForm.orderId === '1'">
|
||||||
<div>持仓量:0</div>
|
<div>持仓量:0</div>
|
||||||
|
|
@ -10,7 +10,8 @@
|
||||||
<div>交易盈亏:0.00 USD</div>
|
<div>交易盈亏:0.00 USD</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- 表格 -->
|
<!-- 表格 -->
|
||||||
<CustomerTradeOrderTable :table-data="tableTree" :columns="tableColumnsOptions" row-key="id" />
|
<CustomerTradeOrderTable :table-data="tableTree" :columns="tableColumnsOptions" row-key="id"
|
||||||
|
:loading="loading" />
|
||||||
|
|
||||||
<!-- 分页 -->
|
<!-- 分页 -->
|
||||||
<CustomerTradeOrderPagination v-model="currentPage" v-model:pageSizeValue="pageSize" :total="total"
|
<CustomerTradeOrderPagination v-model="currentPage" v-model:pageSizeValue="pageSize" :total="total"
|
||||||
|
|
@ -22,11 +23,12 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
|
||||||
defineOptions({
|
defineOptions({
|
||||||
name: 'History'
|
name: 'History'
|
||||||
})
|
})
|
||||||
// 组件
|
// 组件
|
||||||
import CustomerTradeOrderSearch from '@/components/common/Search.vue'
|
import CustomerTradeOrderSearch from '@/components/common/Search.vue'
|
||||||
import CustomerTradeOrderTable from '@/components/common/Table.vue'
|
import CustomerTradeOrderTable from '@/components/common/Table.vue'
|
||||||
|
import { usePageLoading } from '@/composables/useLoading'
|
||||||
import CustomerTradeOrderPagination from '@/components/common/Pagination.vue'
|
import CustomerTradeOrderPagination from '@/components/common/Pagination.vue'
|
||||||
// 配置以及表单验证
|
// 配置以及表单验证
|
||||||
import { search, tradeOrderTableColumns, positionOrderTableColumns } from './options'
|
import { search, tradeOrderTableColumns, positionOrderTableColumns } from './options'
|
||||||
|
|
@ -63,6 +65,7 @@ const subAccountOptions = ref([])
|
||||||
//获取用户数据,用来判断当前查询的是不是自己的账号
|
//获取用户数据,用来判断当前查询的是不是自己的账号
|
||||||
const userInfo: any = getStorage('userInfo')
|
const userInfo: any = getStorage('userInfo')
|
||||||
|
|
||||||
|
const { loading, startLoading, stopLoading } = usePageLoading()
|
||||||
/**
|
/**
|
||||||
* @description: 定义表格数据
|
* @description: 定义表格数据
|
||||||
*/
|
*/
|
||||||
|
|
@ -80,38 +83,43 @@ const total = ref(0)
|
||||||
* @description: 定义公共请求数据方法
|
* @description: 定义公共请求数据方法
|
||||||
*/
|
*/
|
||||||
const getCustomerTradeOrderList = async () => {
|
const getCustomerTradeOrderList = async () => {
|
||||||
const params = {
|
try {
|
||||||
page: currentPage.value,
|
startLoading()
|
||||||
page_size: pageSize.value,
|
const params = {
|
||||||
user_name: searchForm.value.accountName,
|
page: currentPage.value,
|
||||||
account_id: searchForm.value.subAccountName,
|
page_size: pageSize.value,
|
||||||
order_no: '',
|
user_name: searchForm.value.accountName,
|
||||||
type: searchForm.value.tradeType,
|
account_id: searchForm.value.subAccountName,
|
||||||
start_time: dateRange.start,
|
order_no: '',
|
||||||
end_time: dateRange.end,
|
type: searchForm.value.tradeType,
|
||||||
|
start_time: dateRange.start,
|
||||||
|
end_time: dateRange.end,
|
||||||
|
}
|
||||||
|
console.log(params)
|
||||||
|
const data: any = await getCustomTradeOrderListApi(params)
|
||||||
|
//表格数据
|
||||||
|
// table数据映射
|
||||||
|
tableTree.value = data.data.map((item: any) => ({
|
||||||
|
accountName: item.user.username,
|
||||||
|
orderId: item.order_id,
|
||||||
|
variety: item.variety.name,
|
||||||
|
type: item.type === 1 ? '买入' : '卖出',
|
||||||
|
quantity: item.num,
|
||||||
|
openPrice: item.build_price,
|
||||||
|
closePrice: item.close_price,
|
||||||
|
closeProfitLoss: item.profit_loss,
|
||||||
|
amount: item.amount,
|
||||||
|
createdTime: item.created_at,
|
||||||
|
}))
|
||||||
|
|
||||||
|
//分页数据
|
||||||
|
total.value = data.total
|
||||||
|
currentPage.value = data.current_page
|
||||||
|
pageSize.value = Number(data.per_page)
|
||||||
|
} finally {
|
||||||
|
|
||||||
|
stopLoading()
|
||||||
}
|
}
|
||||||
console.log(params)
|
|
||||||
const data: any = await getCustomTradeOrderListApi(params)
|
|
||||||
|
|
||||||
//表格数据
|
|
||||||
// table数据映射
|
|
||||||
tableTree.value = data.data.map((item: any) => ({
|
|
||||||
accountName: item.user.username,
|
|
||||||
orderId: item.order_id,
|
|
||||||
variety: item.variety.name,
|
|
||||||
type: item.type === 1 ? '买入' : '卖出',
|
|
||||||
quantity: item.num,
|
|
||||||
openPrice: item.build_price,
|
|
||||||
closePrice: item.close_price,
|
|
||||||
closeProfitLoss: item.profit_loss,
|
|
||||||
amount: item.amount,
|
|
||||||
createdTime: item.created_at,
|
|
||||||
}))
|
|
||||||
|
|
||||||
//分页数据
|
|
||||||
total.value = data.total
|
|
||||||
currentPage.value = data.current_page
|
|
||||||
pageSize.value = Number(data.per_page)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const getSubAccountList = async () => {
|
const getSubAccountList = async () => {
|
||||||
|
|
|
||||||
|
|
@ -2,11 +2,8 @@
|
||||||
<div class="position-stat table_form-container">
|
<div class="position-stat table_form-container">
|
||||||
<!-- 搜索 -->
|
<!-- 搜索 -->
|
||||||
<PositionStatSearch
|
<PositionStatSearch
|
||||||
:search-form="searchForm"
|
:buttonLoading="loading" :search-form="searchForm" :search-options="searchOptions" @search="handleSearch"
|
||||||
:search-options="searchOptions"
|
@reset="handleReset">
|
||||||
@search="handleSearch"
|
|
||||||
@reset="handleReset"
|
|
||||||
>
|
|
||||||
<!-- <template #button="{ form }">-->
|
<!-- <template #button="{ form }">-->
|
||||||
<!-- <el-button type="primary" @click="handleExport()">-->
|
<!-- <el-button type="primary" @click="handleExport()">-->
|
||||||
<!-- 导出-->
|
<!-- 导出-->
|
||||||
|
|
@ -14,11 +11,8 @@
|
||||||
<!-- </template>-->
|
<!-- </template>-->
|
||||||
</PositionStatSearch>
|
</PositionStatSearch>
|
||||||
<!-- 表格 -->
|
<!-- 表格 -->
|
||||||
<PositionStatTable
|
<PositionStatTable :table-data="orderPositionStore.positionOrderList" :columns="tableColumnsOptions"
|
||||||
:table-data="orderPositionStore.positionOrderList"
|
:loading="loading" row-key="id" />
|
||||||
:columns="tableColumnsOptions"
|
|
||||||
row-key="id"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
@ -35,6 +29,10 @@ import { search, tableColumns } from './options'
|
||||||
|
|
||||||
import { useTransactionStore } from '@/stores/modules/transaction.ts'
|
import { useTransactionStore } from '@/stores/modules/transaction.ts'
|
||||||
import { useOrderPositionStore } from '@/stores/modules/orderPosition.ts'
|
import { useOrderPositionStore } from '@/stores/modules/orderPosition.ts'
|
||||||
|
import { usePageLoading } from '@/composables/useLoading'
|
||||||
|
|
||||||
|
// 按钮 loading
|
||||||
|
const { loading, startLoading, stopLoading } = usePageLoading()
|
||||||
|
|
||||||
// 导出表格
|
// 导出表格
|
||||||
import { exportToExcel } from '@/utils/exportToExcel'
|
import { exportToExcel } from '@/utils/exportToExcel'
|
||||||
|
|
@ -57,11 +55,15 @@ const tableColumnsOptions = ref(tableColumns)
|
||||||
* @description: 定义搜索方法
|
* @description: 定义搜索方法
|
||||||
*/
|
*/
|
||||||
const handleSearch = async () => {
|
const handleSearch = async () => {
|
||||||
const data = await checkAccountIdIsSonForUser({ account_id: searchForm.value.account_id })
|
try {
|
||||||
if (!data.flag) {
|
startLoading()
|
||||||
|
const data = await checkAccountIdIsSonForUser({ account_id: searchForm.value.account_id })
|
||||||
|
|
||||||
|
if (!data.flag) {
|
||||||
return ElMessage.warning('请输入下级ID')
|
return ElMessage.warning('请输入下级ID')
|
||||||
}
|
}
|
||||||
transactionStore.getPositionList(searchForm.value.account_id)
|
transactionStore.getPositionList(searchForm.value.account_id)
|
||||||
|
} finally { stopLoading() }
|
||||||
}
|
}
|
||||||
const handleReset = () => {
|
const handleReset = () => {
|
||||||
console.log('重置搜索')
|
console.log('重置搜索')
|
||||||
|
|
|
||||||
|
|
@ -14,9 +14,9 @@ export const tableColumns = [
|
||||||
// 操作类型
|
// 操作类型
|
||||||
{ prop: 'tradeType', label: '操作类型' },
|
{ prop: 'tradeType', label: '操作类型' },
|
||||||
// 金额
|
// 金额
|
||||||
{ prop: 'amount', label: '金额' },
|
{ prop: 'amount', label: '金额', isNumber: true },
|
||||||
// 交易数量
|
// 交易数量
|
||||||
{ prop: 'tradeQty', label: '交易数量' },
|
{ prop: 'tradeQty', label: '交易数量'},
|
||||||
// 交易时间
|
// 交易时间
|
||||||
{ prop: 'tradeTime', label: '交易时间' },
|
{ prop: 'tradeTime', label: '交易时间' },
|
||||||
// 浮动盈亏
|
// 浮动盈亏
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
<div class="order-rechange-page table_form-container">
|
<div class="order-rechange-page table_form-container">
|
||||||
<!-- 搜索区域:按接口参数保留订单号、用户名称、状态、开始/结束时间 -->
|
<!-- 搜索区域:按接口参数保留订单号、用户名称、状态、开始/结束时间 -->
|
||||||
<OrderRechangeSearch
|
<OrderRechangeSearch
|
||||||
|
:buttonLoading="loading"
|
||||||
:search-form="searchForm"
|
:search-form="searchForm"
|
||||||
:search-options="searchOptions"
|
:search-options="searchOptions"
|
||||||
@search="handleSearch"
|
@search="handleSearch"
|
||||||
|
|
@ -13,6 +14,7 @@
|
||||||
:table-data="tableTree"
|
:table-data="tableTree"
|
||||||
:columns="tableColumnsOptions"
|
:columns="tableColumnsOptions"
|
||||||
:highlight-current-row="false"
|
:highlight-current-row="false"
|
||||||
|
:loading="loading"
|
||||||
>
|
>
|
||||||
<!-- 操作列插槽 -->
|
<!-- 操作列插槽 -->
|
||||||
<!-- <template #operation="{ row }">-->
|
<!-- <template #operation="{ row }">-->
|
||||||
|
|
@ -43,6 +45,7 @@ defineOptions({
|
||||||
import { onMounted, ref } from 'vue'
|
import { onMounted, ref } from 'vue'
|
||||||
import OrderRechangeSearch from '@/components/common/Search.vue'
|
import OrderRechangeSearch from '@/components/common/Search.vue'
|
||||||
import OrderRechangeTable from '@/components/common/Table.vue'
|
import OrderRechangeTable from '@/components/common/Table.vue'
|
||||||
|
import { usePageLoading } from '@/composables/useLoading'
|
||||||
import OrderRechangePagination from '@/components/common/Pagination.vue'
|
import OrderRechangePagination from '@/components/common/Pagination.vue'
|
||||||
import { getRechargeOrderListApi, reviewRechargeOrder } from '@/api/modules/order/rechange.ts'
|
import { getRechargeOrderListApi, reviewRechargeOrder } from '@/api/modules/order/rechange.ts'
|
||||||
import { search, tableColumns } from './options'
|
import { search, tableColumns } from './options'
|
||||||
|
|
@ -86,6 +89,7 @@ const createDefaultSearchForm = (): SearchFormData => ({
|
||||||
|
|
||||||
const searchForm = ref<SearchFormData>(createDefaultSearchForm())
|
const searchForm = ref<SearchFormData>(createDefaultSearchForm())
|
||||||
|
|
||||||
|
const { loading, startLoading, stopLoading } = usePageLoading()
|
||||||
// 表格数据与列配置。
|
// 表格数据与列配置。
|
||||||
const tableTree = ref<RechangeOrderItem[]>([])
|
const tableTree = ref<RechangeOrderItem[]>([])
|
||||||
const tableColumnsOptions = ref(tableColumns)
|
const tableColumnsOptions = ref(tableColumns)
|
||||||
|
|
@ -109,6 +113,7 @@ const getRechargeStatusText = (status: string | number | null | undefined) => {
|
||||||
|
|
||||||
// 获取充值订单列表:把接口返回字段统一映射成页面表格结构。
|
// 获取充值订单列表:把接口返回字段统一映射成页面表格结构。
|
||||||
const getRechargeOrderList = async () => {
|
const getRechargeOrderList = async () => {
|
||||||
|
startLoading()
|
||||||
const params = {
|
const params = {
|
||||||
page: currentPage.value,
|
page: currentPage.value,
|
||||||
page_size: pageSize.value,
|
page_size: pageSize.value,
|
||||||
|
|
@ -150,6 +155,8 @@ const getRechargeOrderList = async () => {
|
||||||
tableTree.value = []
|
tableTree.value = []
|
||||||
total.value = 0
|
total.value = 0
|
||||||
console.error('获取充值订单列表失败', error)
|
console.error('获取充值订单列表失败', error)
|
||||||
|
} finally {
|
||||||
|
stopLoading()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -51,7 +51,7 @@ export const search = [
|
||||||
export const tableColumns = [
|
export const tableColumns = [
|
||||||
{ prop: 'orderNo', label: '订单号', align: 'center' as const },
|
{ prop: 'orderNo', label: '订单号', align: 'center' as const },
|
||||||
{ prop: 'currency', label: '充值币种', align: 'center' as const },
|
{ prop: 'currency', label: '充值币种', align: 'center' as const },
|
||||||
{ prop: 'amount', label: '金额', align: 'center' as const },
|
{ prop: 'amount', label: '金额', align: 'center' as const, isNumber: true },
|
||||||
{ prop: 'statusText', label: '状态', align: 'center' as const },
|
{ prop: 'statusText', label: '状态', align: 'center' as const },
|
||||||
{ prop: 'rechangeTime', label: '充值时间', align: 'center' as const },
|
{ prop: 'rechangeTime', label: '充值时间', align: 'center' as const },
|
||||||
{ prop: 'rechangeAccount', label: '充值账号', align: 'center' as const },
|
{ prop: 'rechangeAccount', label: '充值账号', align: 'center' as const },
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
<div class="table_form-container">
|
<div class="table_form-container">
|
||||||
<!-- 搜索 -->
|
<!-- 搜索 -->
|
||||||
<TransferSearch
|
<TransferSearch
|
||||||
|
:buttonLoading="loading"
|
||||||
:search-form="searchForm"
|
:search-form="searchForm"
|
||||||
:search-options="searchOptions"
|
:search-options="searchOptions"
|
||||||
@search="handleSearch"
|
@search="handleSearch"
|
||||||
|
|
@ -16,6 +17,7 @@
|
||||||
:table-data="tableTree"
|
:table-data="tableTree"
|
||||||
:columns="tableColumnsOptions"
|
:columns="tableColumnsOptions"
|
||||||
row-key="id"
|
row-key="id"
|
||||||
|
:loading="loading"
|
||||||
ref="tableRef"
|
ref="tableRef"
|
||||||
>
|
>
|
||||||
</TransferTable>
|
</TransferTable>
|
||||||
|
|
@ -37,6 +39,7 @@ defineOptions({
|
||||||
// 组件
|
// 组件
|
||||||
import TransferSearch from '@/components/common/Search.vue'
|
import TransferSearch from '@/components/common/Search.vue'
|
||||||
import TransferTable from '@/components/common/Table.vue'
|
import TransferTable from '@/components/common/Table.vue'
|
||||||
|
import { usePageLoading } from '@/composables/useLoading'
|
||||||
import TransferPagination from '@/components/common/Pagination.vue'
|
import TransferPagination from '@/components/common/Pagination.vue'
|
||||||
// 配置以及表单验证
|
// 配置以及表单验证
|
||||||
import { search, tableColumns } from './options'
|
import { search, tableColumns } from './options'
|
||||||
|
|
@ -54,12 +57,13 @@ const initTime = getRecentSevenDays()
|
||||||
/**
|
/**
|
||||||
* @description: 定义搜索数据
|
* @description: 定义搜索数据
|
||||||
*/
|
*/
|
||||||
const searchForm = ref({
|
const searchForm = ref<any>({
|
||||||
transferAccount: '',
|
transferAccount: '',
|
||||||
type: '',
|
type: '',
|
||||||
transferTime: [initTime.start, initTime.end],
|
transferTime: [initTime.start, initTime.end],
|
||||||
})
|
})
|
||||||
const searchOptions = ref(search)
|
const searchOptions = ref(search)
|
||||||
|
const { loading, startLoading, stopLoading } = usePageLoading()
|
||||||
/**
|
/**
|
||||||
* @description: 定义表格数据
|
* @description: 定义表格数据
|
||||||
*/
|
*/
|
||||||
|
|
@ -77,6 +81,7 @@ const total = ref(0)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const getTransferDetailList = async () => {
|
const getTransferDetailList = async () => {
|
||||||
|
startLoading()
|
||||||
const params = {
|
const params = {
|
||||||
page: currentPage.value,
|
page: currentPage.value,
|
||||||
page_size: pageSize.value,
|
page_size: pageSize.value,
|
||||||
|
|
@ -108,6 +113,8 @@ const getTransferDetailList = async () => {
|
||||||
}))
|
}))
|
||||||
// 分页数据
|
// 分页数据
|
||||||
total.value = data.total
|
total.value = data.total
|
||||||
|
|
||||||
|
stopLoading()
|
||||||
currentPage.value = data.current_page
|
currentPage.value = data.current_page
|
||||||
pageSize.value = Number(data.per_page)
|
pageSize.value = Number(data.per_page)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ export const search = [
|
||||||
export const tableColumns = [
|
export const tableColumns = [
|
||||||
{ prop: 'orderNo', label: '订单号', align: 'center' as const },
|
{ prop: 'orderNo', label: '订单号', align: 'center' as const },
|
||||||
{ prop: 'currency', label: '提现币种', align: 'center' as const },
|
{ prop: 'currency', label: '提现币种', align: 'center' as const },
|
||||||
{ prop: 'amount', label: '金额', align: 'center' as const },
|
{ prop: 'amount', label: '金额', align: 'center' as const, isNumber: true },
|
||||||
{ prop: 'statusText', label: '状态', align: 'center' as const },
|
{ prop: 'statusText', label: '状态', align: 'center' as const },
|
||||||
{ prop: 'withdrawTime', label: '提现时间', align: 'center' as const },
|
{ prop: 'withdrawTime', label: '提现时间', align: 'center' as const },
|
||||||
{ prop: 'withdrawAccount', label: '提现账号', align: 'center' as const },
|
{ prop: 'withdrawAccount', label: '提现账号', align: 'center' as const },
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="table_form-container">
|
<div class="table_form-container">
|
||||||
<!-- 搜索 -->
|
<!-- 搜索 -->
|
||||||
<CustomerListSearch :search-form="searchForm" :search-options="searchOptions" @search="handleSearch"
|
<CustomerListSearch :buttonLoading="loading" :search-form="searchForm" :search-options="searchOptions" @search="handleSearch"
|
||||||
@reset="handleReset"></CustomerListSearch>
|
@reset="handleReset"></CustomerListSearch>
|
||||||
<!-- 表格 -->
|
<!-- 表格 -->
|
||||||
<CustomerListTable :table-data="tableTree" :columns="tableColumnsOptions" row-key="userId"
|
<CustomerListTable :table-data="tableTree" :columns="tableColumnsOptions" row-key="userId"
|
||||||
:default-sort="{ prop: 'createTime', order: 'descending' }" @expand-change="handleGetSubList">
|
:default-sort="{ prop: 'createTime', order: 'descending' }" :loading="loading" @expand-change="handleGetSubList">
|
||||||
<template #marginRatio="{ row }">
|
<template #marginRatio="{ row }">
|
||||||
<el-button v-if="row.role_id === 5" type="primary" size="small" v-auth="'agent_getSelfVarietyPointDiffConfig'"
|
<el-button v-if="row.role_id === 5" type="primary" size="small" v-auth="'agent_getSelfVarietyPointDiffConfig'"
|
||||||
@click="handleMarginRatio(row)">
|
@click="handleMarginRatio(row)">
|
||||||
|
|
@ -37,7 +37,7 @@
|
||||||
@pagination-change="handlePaginationChange" />
|
@pagination-change="handlePaginationChange" />
|
||||||
<!-- dialog -->
|
<!-- dialog -->
|
||||||
<CustomerListDialog :visible="dialogVisible" :title="dialogTitle" :type="dialogType" :fullscreen="dialogFullscreen"
|
<CustomerListDialog :visible="dialogVisible" :title="dialogTitle" :type="dialogType" :fullscreen="dialogFullscreen"
|
||||||
:show-footer="dialogType !== 'view'" @confirm="handleSubmit" @cancel="handleCancel" @close="handleClose">
|
:show-footer="dialogType !== 'view'" :button-loading="submitLoading" @confirm="handleSubmit" @cancel="handleCancel" @close="handleClose">
|
||||||
<CustomerListTable :table-data="marginRatioTree" :columns="marginRatioTableColumnsOptions" row-key="id"
|
<CustomerListTable :table-data="marginRatioTree" :columns="marginRatioTableColumnsOptions" row-key="id"
|
||||||
v-if="dialogType === 'editMarginRatio'" style="height: 500px">
|
v-if="dialogType === 'editMarginRatio'" style="height: 500px">
|
||||||
<template #assignedPointDiff="{ row }">
|
<template #assignedPointDiff="{ row }">
|
||||||
|
|
@ -54,7 +54,7 @@
|
||||||
</CustomerListDialog>
|
</CustomerListDialog>
|
||||||
|
|
||||||
<!-- 调整金额弹窗 -->
|
<!-- 调整金额弹窗 -->
|
||||||
<CustomerListDialog :visible="adjustAmountVisible" title="调整金额" type="adjust" @confirm="handleAdjustAmountSubmit"
|
<CustomerListDialog :visible="adjustAmountVisible" title="调整金额" type="adjust" :button-loading="adjustAmountLoading" @confirm="handleAdjustAmountSubmit"
|
||||||
@cancel="handleAdjustAmountCancel" @close="handleAdjustAmountClose">
|
@cancel="handleAdjustAmountCancel" @close="handleAdjustAmountClose">
|
||||||
<el-form :model="adjustAmountForm" :rules="adjustAmountRules" ref="adjustAmountFormRef" label-width="120px">
|
<el-form :model="adjustAmountForm" :rules="adjustAmountRules" ref="adjustAmountFormRef" label-width="120px">
|
||||||
<el-form-item label="账号名" prop="username">
|
<el-form-item label="账号名" prop="username">
|
||||||
|
|
@ -78,7 +78,7 @@
|
||||||
|
|
||||||
<!-- 修改客户弹窗 -->
|
<!-- 修改客户弹窗 -->
|
||||||
<CustomerListDialog :visible="editCustomerVisible" title="修改客户" type="editCustomer"
|
<CustomerListDialog :visible="editCustomerVisible" title="修改客户" type="editCustomer"
|
||||||
@confirm="handleEditCustomerSubmit" @cancel="handleEditCustomerCancel" @close="handleEditCustomerClose">
|
:button-loading="editCustomerLoading" @confirm="handleEditCustomerSubmit" @cancel="handleEditCustomerCancel" @close="handleEditCustomerClose">
|
||||||
<el-form :model="editCustomerForm" :rules="editCustomerRules" ref="editCustomerFormRef" label-width="140px">
|
<el-form :model="editCustomerForm" :rules="editCustomerRules" ref="editCustomerFormRef" label-width="140px">
|
||||||
<el-form-item label="手续费模板" prop="feeSettingId">
|
<el-form-item label="手续费模板" prop="feeSettingId">
|
||||||
<el-select v-model="editCustomerForm.feeSettingId" placeholder="请选择手续费模板" style="width: 100%">
|
<el-select v-model="editCustomerForm.feeSettingId" placeholder="请选择手续费模板" style="width: 100%">
|
||||||
|
|
@ -112,6 +112,7 @@ defineOptions({
|
||||||
// 组件
|
// 组件
|
||||||
import CustomerListSearch from '@/components/common/Search.vue'
|
import CustomerListSearch from '@/components/common/Search.vue'
|
||||||
import CustomerListTable from '@/components/common/Table.vue'
|
import CustomerListTable from '@/components/common/Table.vue'
|
||||||
|
import { usePageLoading, useButtonLoading } from '@/composables/useLoading'
|
||||||
import CustomerListPagination from '@/components/common/Pagination.vue'
|
import CustomerListPagination from '@/components/common/Pagination.vue'
|
||||||
import CustomerListDialog from '@/components/common/Dialog.vue'
|
import CustomerListDialog from '@/components/common/Dialog.vue'
|
||||||
import CustomerListForm from '@/components/common/Form.vue'
|
import CustomerListForm from '@/components/common/Form.vue'
|
||||||
|
|
@ -145,6 +146,10 @@ const searchForm = ref({
|
||||||
const searchOptions = ref(search)
|
const searchOptions = ref(search)
|
||||||
const tableColumnsOptions = ref(tableColumns)
|
const tableColumnsOptions = ref(tableColumns)
|
||||||
|
|
||||||
|
const { loading, startLoading, stopLoading } = usePageLoading()
|
||||||
|
const { buttonLoading: submitLoading, startButtonLoading: startSubmitLoading, stopButtonLoading: stopSubmitLoading } = useButtonLoading()
|
||||||
|
const { buttonLoading: adjustAmountLoading, startButtonLoading: startAdjustAmountLoading, stopButtonLoading: stopAdjustAmountLoading } = useButtonLoading()
|
||||||
|
const { buttonLoading: editCustomerLoading, startButtonLoading: startEditCustomerLoading, stopButtonLoading: stopEditCustomerLoading } = useButtonLoading()
|
||||||
/**
|
/**
|
||||||
* @description: 定义表格数据
|
* @description: 定义表格数据
|
||||||
*/
|
*/
|
||||||
|
|
@ -291,6 +296,7 @@ const roleMap: any = {
|
||||||
*/
|
*/
|
||||||
// 获取客户列表
|
// 获取客户列表
|
||||||
const getCustomerList = async () => {
|
const getCustomerList = async () => {
|
||||||
|
startLoading()
|
||||||
const params = {
|
const params = {
|
||||||
page: currentPage.value,
|
page: currentPage.value,
|
||||||
page_size: pageSize.value,
|
page_size: pageSize.value,
|
||||||
|
|
@ -315,6 +321,8 @@ const getCustomerList = async () => {
|
||||||
|
|
||||||
//分页数据
|
//分页数据
|
||||||
total.value = data.total
|
total.value = data.total
|
||||||
|
|
||||||
|
stopLoading()
|
||||||
currentPage.value = data.current_page
|
currentPage.value = data.current_page
|
||||||
pageSize.value = Number(data.per_page)
|
pageSize.value = Number(data.per_page)
|
||||||
}
|
}
|
||||||
|
|
@ -437,54 +445,58 @@ const handlePaginationChange = (page: { currentPage: number; pageSize: number })
|
||||||
/**
|
/**
|
||||||
* @description: 定义弹窗方法
|
* @description: 定义弹窗方法
|
||||||
*/
|
*/
|
||||||
//提交
|
|
||||||
const handleSubmit = async () => {
|
const handleSubmit = async () => {
|
||||||
const params = {
|
startSubmitLoading()
|
||||||
user_id: selectId.value,
|
try {
|
||||||
toucun_percent: '',
|
const params = {
|
||||||
point_diffs_json: '',
|
user_id: selectId.value,
|
||||||
fee_handling_percent: '',
|
toucun_percent: '',
|
||||||
fee_setting_id: '',
|
point_diffs_json: '',
|
||||||
risk_control_id: '',
|
fee_handling_percent: '',
|
||||||
}
|
fee_setting_id: '',
|
||||||
if (dialogType.value === 'editMarginRatio') {
|
risk_control_id: '',
|
||||||
// 逐行验证
|
}
|
||||||
for (const row of marginRatioTree.value) {
|
if (dialogType.value === 'editMarginRatio') {
|
||||||
const form = formRefs.value[(row as any).id]
|
// 逐行验证
|
||||||
if (!form) continue
|
for (const row of marginRatioTree.value) {
|
||||||
|
const form = formRefs.value[(row as any).id]
|
||||||
|
if (!form) continue
|
||||||
|
try {
|
||||||
|
await form.validate()
|
||||||
|
} catch (err) {
|
||||||
|
console.error(`第 ${(row as any).id} 行验证不通过,请检查`)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//转换为接口需要的格式 { id: assignedPointDifference }
|
||||||
|
const marginRatioJSON = marginRatioTree.value.reduce((acc: any, cur: any) => {
|
||||||
|
acc[cur.id] = cur.assignedPointDifference * 1
|
||||||
|
return acc
|
||||||
|
}, {})
|
||||||
|
|
||||||
|
// 调用接口
|
||||||
try {
|
try {
|
||||||
await form.validate()
|
await editCustomerApi({ ...params, point_diffs_json: JSON.stringify(marginRatioJSON) })
|
||||||
|
dialogVisible.value = false
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(`第 ${(row as any).id} 行验证不通过,请检查`)
|
console.log('提交失败:', err)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//转换为接口需要的格式 { id: assignedPointDifference }
|
if (dialogType.value === 'editCommissionRatio') {
|
||||||
const marginRatioJSON = marginRatioTree.value.reduce((acc: any, cur: any) => {
|
await commissionRatioFormRef.value.validate()
|
||||||
acc[cur.id] = cur.assignedPointDifference * 1
|
try {
|
||||||
return acc
|
await editCustomerApi({
|
||||||
}, {})
|
...params,
|
||||||
|
fee_handling_percent: commissionRatioForm.value.commissionRatio,
|
||||||
// 调用接口
|
})
|
||||||
try {
|
dialogVisible.value = false
|
||||||
await editCustomerApi({ ...params, point_diffs_json: JSON.stringify(marginRatioJSON) })
|
await getCustomerList()
|
||||||
dialogVisible.value = false
|
} catch (err) {
|
||||||
} catch (err) {
|
console.log('提交失败:', err)
|
||||||
console.log('提交失败:', err)
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
if (dialogType.value === 'editCommissionRatio') {
|
|
||||||
await commissionRatioFormRef.value.validate()
|
|
||||||
try {
|
|
||||||
await editCustomerApi({
|
|
||||||
...params,
|
|
||||||
fee_handling_percent: commissionRatioForm.value.commissionRatio,
|
|
||||||
})
|
|
||||||
dialogVisible.value = false
|
|
||||||
await getCustomerList()
|
|
||||||
} catch (err) {
|
|
||||||
console.log('提交失败:', err)
|
|
||||||
}
|
}
|
||||||
|
} finally {
|
||||||
|
stopSubmitLoading()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 取消
|
// 取消
|
||||||
|
|
@ -526,6 +538,7 @@ const handleAdjustAmountInput = () => {
|
||||||
|
|
||||||
// 提交调整金额
|
// 提交调整金额
|
||||||
const handleAdjustAmountSubmit = async () => {
|
const handleAdjustAmountSubmit = async () => {
|
||||||
|
startAdjustAmountLoading()
|
||||||
try {
|
try {
|
||||||
await adjustAmountFormRef.value?.validate()
|
await adjustAmountFormRef.value?.validate()
|
||||||
await updateCapitalApi({
|
await updateCapitalApi({
|
||||||
|
|
@ -536,6 +549,8 @@ const handleAdjustAmountSubmit = async () => {
|
||||||
adjustAmountVisible.value = false
|
adjustAmountVisible.value = false
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('调整金额表单验证失败', err)
|
console.error('调整金额表单验证失败', err)
|
||||||
|
} finally {
|
||||||
|
stopAdjustAmountLoading()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -597,6 +612,7 @@ const handleEditCustomer = async (row: any) => {
|
||||||
|
|
||||||
// 提交修改客户
|
// 提交修改客户
|
||||||
const handleEditCustomerSubmit = async () => {
|
const handleEditCustomerSubmit = async () => {
|
||||||
|
startEditCustomerLoading()
|
||||||
try {
|
try {
|
||||||
await editCustomerFormRef.value?.validate()
|
await editCustomerFormRef.value?.validate()
|
||||||
await editUserApi({
|
await editUserApi({
|
||||||
|
|
@ -611,6 +627,8 @@ const handleEditCustomerSubmit = async () => {
|
||||||
editCustomerVisible.value = false
|
editCustomerVisible.value = false
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('修改客户表单验证失败', err)
|
console.error('修改客户表单验证失败', err)
|
||||||
|
} finally {
|
||||||
|
stopEditCustomerLoading()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@ export const tableColumns = [
|
||||||
{ prop: 'role', label: '账号角色' },
|
{ prop: 'role', label: '账号角色' },
|
||||||
// 账号数量
|
// 账号数量
|
||||||
{ prop: 'accountQty', label: '账号数量' },
|
{ prop: 'accountQty', label: '账号数量' },
|
||||||
{ prop: 'wallet_capital.amount', label: '资金', align: 'center' as const },
|
{ prop: 'wallet_capital.amount', label: '资金', align: 'center' as const, isNumber: true },
|
||||||
// 点差分配比例
|
// 点差分配比例
|
||||||
{ prop: 'marginRatio', label: '点差分配比例', slotName: 'marginRatio' },
|
{ prop: 'marginRatio', label: '点差分配比例', slotName: 'marginRatio' },
|
||||||
// 手续费分成比例
|
// 手续费分成比例
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
<!-- 搜索 -->
|
<!-- 搜索 -->
|
||||||
<MarketSearch
|
<MarketSearch
|
||||||
:search-form="marketSearchForm"
|
:search-form="marketSearchForm"
|
||||||
|
:buttonLoading="loading"
|
||||||
:search-options="marketSearchOptions"
|
:search-options="marketSearchOptions"
|
||||||
@search="handleSearch"
|
@search="handleSearch"
|
||||||
@reset="handleReset"
|
@reset="handleReset"
|
||||||
|
|
@ -27,6 +28,7 @@
|
||||||
:table-data="marketTree"
|
:table-data="marketTree"
|
||||||
:columns="marketTableColumnsOptions"
|
:columns="marketTableColumnsOptions"
|
||||||
row-key="id"
|
row-key="id"
|
||||||
|
:loading="loading"
|
||||||
@row-click="handleRowClick"
|
@row-click="handleRowClick"
|
||||||
@row-contextmenu="handleRowContextMenu"
|
@row-contextmenu="handleRowContextMenu"
|
||||||
>
|
>
|
||||||
|
|
@ -167,7 +169,7 @@
|
||||||
<template #footer v-if="dialogType !== 'view'">
|
<template #footer v-if="dialogType !== 'view'">
|
||||||
<div class="drawer-footer">
|
<div class="drawer-footer">
|
||||||
<el-button @click="handleCancel">取消</el-button>
|
<el-button @click="handleCancel">取消</el-button>
|
||||||
<el-button type="primary" @click="handleSubmit">确定</el-button>
|
<el-button type="primary" :loading="submitLoading" @click="handleSubmit">确定</el-button>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</el-drawer>
|
</el-drawer>
|
||||||
|
|
@ -195,6 +197,7 @@ defineOptions({
|
||||||
// 组件
|
// 组件
|
||||||
import MarketSearch from '@/components/common/Search.vue'
|
import MarketSearch from '@/components/common/Search.vue'
|
||||||
import MarketTable from '@/components/common/Table.vue'
|
import MarketTable from '@/components/common/Table.vue'
|
||||||
|
import { usePageLoading, useButtonLoading } from '@/composables/useLoading'
|
||||||
import MarketPagination from '@/components/common/Pagination.vue'
|
import MarketPagination from '@/components/common/Pagination.vue'
|
||||||
import MarketDialog from '@/components/common/Dialog.vue'
|
import MarketDialog from '@/components/common/Dialog.vue'
|
||||||
import MarketForm from '@/components/common/Form.vue'
|
import MarketForm from '@/components/common/Form.vue'
|
||||||
|
|
@ -239,6 +242,8 @@ const marketSearchForm = ref({
|
||||||
})
|
})
|
||||||
const marketSearchOptions = ref(marketSearch)
|
const marketSearchOptions = ref(marketSearch)
|
||||||
|
|
||||||
|
const { loading, startLoading, stopLoading } = usePageLoading()
|
||||||
|
const { buttonLoading: submitLoading, startButtonLoading: startSubmitLoading, stopButtonLoading: stopSubmitLoading } = useButtonLoading()
|
||||||
/**
|
/**
|
||||||
* @description 定义表格数据
|
* @description 定义表格数据
|
||||||
*/
|
*/
|
||||||
|
|
@ -565,6 +570,7 @@ const handleMarketFormLinkage = async (type: 'level' | 'parentAccountName', valu
|
||||||
*/
|
*/
|
||||||
//获取做市商列表
|
//获取做市商列表
|
||||||
const getMarketList = async () => {
|
const getMarketList = async () => {
|
||||||
|
startLoading()
|
||||||
const params = {
|
const params = {
|
||||||
page: currentPage.value,
|
page: currentPage.value,
|
||||||
page_size: pageSize.value,
|
page_size: pageSize.value,
|
||||||
|
|
@ -573,8 +579,10 @@ const getMarketList = async () => {
|
||||||
const data = await getMarketListApi(params)
|
const data = await getMarketListApi(params)
|
||||||
// 表格数据
|
// 表格数据
|
||||||
marketTree.value = mapMarketTree(data.data)
|
marketTree.value = mapMarketTree(data.data)
|
||||||
|
total.value = data.total
|
||||||
|
|
||||||
//分页数据
|
//分页数据
|
||||||
total.value = data.total
|
stopLoading()
|
||||||
currentPage.value = data.current_page
|
currentPage.value = data.current_page
|
||||||
pageSize.value = Number(data.per_page)
|
pageSize.value = Number(data.per_page)
|
||||||
}
|
}
|
||||||
|
|
@ -795,55 +803,60 @@ const formatPointDiffToObject = () => {
|
||||||
|
|
||||||
//提交
|
//提交
|
||||||
const handleSubmit = async () => {
|
const handleSubmit = async () => {
|
||||||
// console.log('提交', marketPointTree.value);
|
startSubmitLoading()
|
||||||
await marketFormRef.value?.validate()
|
try {
|
||||||
const pointDiffObj = formatPointDiffToObject()
|
// console.log('提交', marketPointTree.value);
|
||||||
console.log('pointDiffObj', pointDiffObj)
|
await marketFormRef.value?.validate()
|
||||||
if (!pointDiffObj) return
|
const pointDiffObj = formatPointDiffToObject()
|
||||||
if (dialogType.value === 'add') {
|
console.log('pointDiffObj', pointDiffObj)
|
||||||
const params: Record<string, any> = {
|
if (!pointDiffObj) return
|
||||||
role_id: marketForm.value.level,
|
if (dialogType.value === 'add') {
|
||||||
reg_type: activeTab.value === 'email' ? '1' : '2',
|
const params: Record<string, any> = {
|
||||||
username: marketForm.value.accountName,
|
role_id: marketForm.value.level,
|
||||||
par_user_id: marketForm.value.parentAccountName,
|
reg_type: activeTab.value === 'email' ? '1' : '2',
|
||||||
mobile: activeTab.value === 'phone' ? marketForm.value.phone : '',
|
username: marketForm.value.accountName,
|
||||||
email: activeTab.value === 'email' ? marketForm.value.email : '',
|
par_user_id: marketForm.value.parentAccountName,
|
||||||
password: '888888',
|
mobile: activeTab.value === 'phone' ? marketForm.value.phone : '',
|
||||||
toucun_percent: marketForm.value.positionRatio,
|
email: activeTab.value === 'email' ? marketForm.value.email : '',
|
||||||
fee_handling_percent: marketForm.value.commissionRatio,
|
password: '888888',
|
||||||
point_diffs_json: JSON.stringify(pointDiffObj),
|
toucun_percent: marketForm.value.positionRatio,
|
||||||
risk_control_id: marketForm.value.riskControlTemplate,
|
fee_handling_percent: marketForm.value.commissionRatio,
|
||||||
fee_setting_id: '',
|
point_diffs_json: JSON.stringify(pointDiffObj),
|
||||||
|
risk_control_id: marketForm.value.riskControlTemplate,
|
||||||
|
fee_setting_id: '',
|
||||||
|
}
|
||||||
|
if (marketForm.value.level === '5') params.flag = 1
|
||||||
|
if (marketForm.value.level === '6') {
|
||||||
|
params.flag = 2
|
||||||
|
params.role_id = '5'
|
||||||
|
}
|
||||||
|
await addMarketApi(params)
|
||||||
|
// 5. 刷新表格数据
|
||||||
|
await getMarketList()
|
||||||
|
dialogVisible.value = false
|
||||||
|
marketForm.value = { ...initMarketForm }
|
||||||
|
} else if (dialogType.value === 'edit') {
|
||||||
|
let flag = null
|
||||||
|
if (selectedRow.value.role_id * 1 === 5 && selectedRow.value.type * 1 === 1) flag = 1
|
||||||
|
if (selectedRow.value.role_id * 1 === 6 && selectedRow.value.type * 1 === 2) flag = 2
|
||||||
|
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,
|
||||||
|
flag: flag,
|
||||||
|
fee_setting_id: '',
|
||||||
|
}
|
||||||
|
// 4. 调用编辑接口
|
||||||
|
await editMarketApi(params)
|
||||||
|
// 5. 刷新表格数据
|
||||||
|
await getMarketList()
|
||||||
|
dialogVisible.value = false
|
||||||
|
marketForm.value = { ...initMarketForm }
|
||||||
}
|
}
|
||||||
if (marketForm.value.level === '5') params.flag = 1
|
} finally {
|
||||||
if (marketForm.value.level === '6') {
|
stopSubmitLoading()
|
||||||
params.flag = 2
|
|
||||||
params.role_id = '5'
|
|
||||||
}
|
|
||||||
await addMarketApi(params)
|
|
||||||
// 5. 刷新表格数据
|
|
||||||
await getMarketList()
|
|
||||||
dialogVisible.value = false
|
|
||||||
marketForm.value = { ...initMarketForm }
|
|
||||||
} else if (dialogType.value === 'edit') {
|
|
||||||
let flag = null
|
|
||||||
if (selectedRow.value.role_id * 1 === 5 && selectedRow.value.type * 1 === 1) flag = 1
|
|
||||||
if (selectedRow.value.role_id * 1 === 6 && selectedRow.value.type * 1 === 2) flag = 2
|
|
||||||
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,
|
|
||||||
flag: flag,
|
|
||||||
fee_setting_id: '',
|
|
||||||
}
|
|
||||||
// 4. 调用编辑接口
|
|
||||||
await editMarketApi(params)
|
|
||||||
// 5. 刷新表格数据
|
|
||||||
await getMarketList()
|
|
||||||
dialogVisible.value = false
|
|
||||||
marketForm.value = { ...initMarketForm }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -25,34 +25,35 @@ export const marketTableColumns = [
|
||||||
//基本账户
|
//基本账户
|
||||||
{ label: '基本账户', prop: 'basicAccount', align: 'center' as const, width: '200px' },
|
{ label: '基本账户', prop: 'basicAccount', align: 'center' as const, width: '200px' },
|
||||||
//保证金
|
//保证金
|
||||||
{ label: '保证金', prop: 'margin', align: 'center' as const, width: '200px' },
|
{ label: '保证金', prop: 'margin', align: 'center' as const, width: '200px', isNumber: true },
|
||||||
//停止接单保证金
|
//停止接单保证金
|
||||||
{ label: '停止接单保证金', prop: 'stopOrderMargin', align: 'center' as const, width: '200px' },
|
{ label: '停止接单保证金', prop: 'stopOrderMargin', align: 'center' as const, width: '200px', isNumber: true },
|
||||||
//持仓转移保证金
|
//持仓转移保证金
|
||||||
{
|
{
|
||||||
label: '持仓转移保证金',
|
label: '持仓转移保证金',
|
||||||
prop: 'positionTransferMargin',
|
prop: 'positionTransferMargin',
|
||||||
align: 'center' as const,
|
align: 'center' as const,
|
||||||
width: '200px',
|
width: '200px',
|
||||||
|
isNumber: true,
|
||||||
},
|
},
|
||||||
//头寸比率
|
//头寸比率
|
||||||
{ label: '头寸比率', prop: 'positionRatio', align: 'center' as const, width: '150px' },
|
{ label: '头寸比率', prop: 'positionRatio', align: 'center' as const, width: '150px', isNumber: true },
|
||||||
//点差返佣
|
//点差返佣
|
||||||
{ label: '点差返佣', prop: 'pointSpreadCommission', align: 'center' as const, width: '200px' },
|
{ label: '点差返佣', prop: 'pointSpreadCommission', align: 'center' as const, width: '200px', isNumber: true },
|
||||||
//点差
|
//点差
|
||||||
{ label: '点差', slotName: 'pointSpread', align: 'center' as const, width: '150px' },
|
{ label: '点差', slotName: 'pointSpread', align: 'center' as const, width: '150px' },
|
||||||
//手续费比例
|
//手续费比例
|
||||||
{ label: '手续费比例', prop: 'commissionRatio', align: 'center' as const, width: '150px' },
|
{ label: '手续费比例', prop: 'commissionRatio', align: 'center' as const, width: '150px', isNumber: true },
|
||||||
//手续费返佣
|
//手续费返佣
|
||||||
{ label: '手续费返佣', prop: 'commissionReturn', align: 'center' as const, width: '150px' },
|
{ label: '手续费返佣', prop: 'commissionReturn', align: 'center' as const, width: '150px', isNumber: true },
|
||||||
//浮动盈亏
|
//浮动盈亏
|
||||||
{ label: '浮动盈亏', prop: 'floatProfitLoss', align: 'center' as const, width: '100px' },
|
{ label: '浮动盈亏', prop: 'floatProfitLoss', align: 'center' as const, width: '100px', isNumber: true },
|
||||||
//平仓盈亏
|
//平仓盈亏
|
||||||
{ label: '平仓盈亏', prop: 'closeProfitLoss', align: 'center' as const, width: '150px' },
|
{ label: '平仓盈亏', prop: 'closeProfitLoss', align: 'center' as const, width: '150px', isNumber: true },
|
||||||
//风险金
|
//风险金
|
||||||
{ label: '风险金', prop: 'riskMargin', align: 'center' as const, width: '150px' },
|
{ label: '风险金', prop: 'riskMargin', align: 'center' as const, width: '150px', isNumber: true },
|
||||||
//服务费
|
//服务费
|
||||||
{ label: '服务费', prop: 'serviceFee', align: 'center' as const, width: '150px' },
|
{ label: '服务费', prop: 'serviceFee', align: 'center' as const, width: '150px', isNumber: true },
|
||||||
]
|
]
|
||||||
|
|
||||||
//做市商添加配置
|
//做市商添加配置
|
||||||
|
|
|
||||||
|
|
@ -69,7 +69,7 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 编辑弹窗 -->
|
<!-- 编辑弹窗 -->
|
||||||
<Dialog :visible="dialogVisible" :title="dialogTitle" width="500px" @confirm="handleEditConfirm"
|
<Dialog :visible="dialogVisible" :title="dialogTitle" width="500px" :button-loading="editLoading" @confirm="handleEditConfirm"
|
||||||
@cancel="handleEditDialogReset" @close="handleEditDialogReset">
|
@cancel="handleEditDialogReset" @close="handleEditDialogReset">
|
||||||
<el-form ref="editFormRef" :model="editForm" :rules="getEditRules()" label-width="80px" label-position="top">
|
<el-form ref="editFormRef" :model="editForm" :rules="getEditRules()" label-width="80px" label-position="top">
|
||||||
<el-form-item v-if="editField === 'mobile'" :label="editForm.label" prop="value" class="phone-item">
|
<el-form-item v-if="editField === 'mobile'" :label="editForm.label" prop="value" class="phone-item">
|
||||||
|
|
@ -96,7 +96,7 @@
|
||||||
|
|
||||||
<!-- 密码修改弹窗 → 验证码模式 -->
|
<!-- 密码修改弹窗 → 验证码模式 -->
|
||||||
<Dialog :visible="passwordDialogVisible" :title="t('personalCenter.modifyPassword')" width="500px"
|
<Dialog :visible="passwordDialogVisible" :title="t('personalCenter.modifyPassword')" width="500px"
|
||||||
@confirm="handlePasswordConfirm" @cancel="handlePasswordDialogReset" @close="handlePasswordDialogReset">
|
:button-loading="passwordLoading" @confirm="handlePasswordConfirm" @cancel="handlePasswordDialogReset" @close="handlePasswordDialogReset">
|
||||||
<el-form ref="passwordFormRef" :model="passwordForm" :rules="passwordFormRules" label-width="100px"
|
<el-form ref="passwordFormRef" :model="passwordForm" :rules="passwordFormRules" label-width="100px"
|
||||||
label-position="top">
|
label-position="top">
|
||||||
<!-- 选择验证方式 -->
|
<!-- 选择验证方式 -->
|
||||||
|
|
@ -174,6 +174,8 @@ import {
|
||||||
updatePwdByCaptchaApi
|
updatePwdByCaptchaApi
|
||||||
} from '@/api/modules/profile/personalCenter';
|
} from '@/api/modules/profile/personalCenter';
|
||||||
|
|
||||||
|
import { useButtonLoading } from '@/composables/useLoading';
|
||||||
|
|
||||||
const userInfo = reactive<UserInfo>({
|
const userInfo = reactive<UserInfo>({
|
||||||
id: 0,
|
id: 0,
|
||||||
username: '',
|
username: '',
|
||||||
|
|
@ -186,6 +188,8 @@ const userInfo = reactive<UserInfo>({
|
||||||
|
|
||||||
const dialogVisible = ref(false);
|
const dialogVisible = ref(false);
|
||||||
const passwordDialogVisible = ref(false);
|
const passwordDialogVisible = ref(false);
|
||||||
|
const { buttonLoading: editLoading, startButtonLoading: startEditLoading, stopButtonLoading: stopEditLoading } = useButtonLoading();
|
||||||
|
const { buttonLoading: passwordLoading, startButtonLoading: startPasswordLoading, stopButtonLoading: stopPasswordLoading } = useButtonLoading();
|
||||||
const editFormRef = ref<FormInstance>();
|
const editFormRef = ref<FormInstance>();
|
||||||
const passwordFormRef = ref<FormInstance>();
|
const passwordFormRef = ref<FormInstance>();
|
||||||
const editField = ref<string>('');
|
const editField = ref<string>('');
|
||||||
|
|
@ -399,6 +403,7 @@ const handleLanguageChange = async (val: number) => {
|
||||||
// 提交修改
|
// 提交修改
|
||||||
const handleEditConfirm = async () => {
|
const handleEditConfirm = async () => {
|
||||||
if (!editFormRef.value) return;
|
if (!editFormRef.value) return;
|
||||||
|
startEditLoading();
|
||||||
try {
|
try {
|
||||||
await editFormRef.value.validate();
|
await editFormRef.value.validate();
|
||||||
|
|
||||||
|
|
@ -425,6 +430,8 @@ const handleEditConfirm = async () => {
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
// 表单验证失败或API调用失败时,不显示错误消息,因为ElMessage已经在其他地方处理
|
// 表单验证失败或API调用失败时,不显示错误消息,因为ElMessage已经在其他地方处理
|
||||||
console.error('操作失败:', err);
|
console.error('操作失败:', err);
|
||||||
|
} finally {
|
||||||
|
stopEditLoading();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -512,6 +519,7 @@ watch(
|
||||||
// 提交修改密码
|
// 提交修改密码
|
||||||
const handlePasswordConfirm = async () => {
|
const handlePasswordConfirm = async () => {
|
||||||
if (!passwordFormRef.value) return;
|
if (!passwordFormRef.value) return;
|
||||||
|
startPasswordLoading();
|
||||||
try {
|
try {
|
||||||
await passwordFormRef.value.validate();
|
await passwordFormRef.value.validate();
|
||||||
|
|
||||||
|
|
@ -536,6 +544,8 @@ const handlePasswordConfirm = async () => {
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
// 表单验证失败或API调用失败时,不显示错误消息,因为ElMessage已经在其他地方处理
|
// 表单验证失败或API调用失败时,不显示错误消息,因为ElMessage已经在其他地方处理
|
||||||
console.error('密码修改失败:', err);
|
console.error('密码修改失败:', err);
|
||||||
|
} finally {
|
||||||
|
stopPasswordLoading();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,8 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="client table_form-container">
|
<div class="client table_form-container">
|
||||||
<!-- 搜索组件 -->
|
<!-- 搜索组件 -->
|
||||||
<ClientSearch
|
<ClientSearch :search-form="clientSearchForm" :search-options="clientSearchOptions" :buttonLoading="loading"
|
||||||
:search-form="clientSearchForm"
|
@search="handleSearch" @reset="handleReset">
|
||||||
:search-options="clientSearchOptions"
|
|
||||||
@search="handleSearch"
|
|
||||||
@reset="handleReset"
|
|
||||||
>
|
|
||||||
<template #button="{ form }">
|
<template #button="{ form }">
|
||||||
<el-button type="primary" @click="handleAdd()" v-auth="'user_createUser'">
|
<el-button type="primary" @click="handleAdd()" v-auth="'user_createUser'">
|
||||||
添加客户
|
添加客户
|
||||||
|
|
@ -15,7 +11,7 @@
|
||||||
</ClientSearch>
|
</ClientSearch>
|
||||||
|
|
||||||
<!-- 表格组件 -->
|
<!-- 表格组件 -->
|
||||||
<ClientTable :table-data="clientTree" :columns="clientTableColumns">
|
<ClientTable :table-data="clientTree" :columns="clientTableColumns" :loading="loading">
|
||||||
<template #status="{ row }">
|
<template #status="{ row }">
|
||||||
{{ row.status === 1 ? '正常' : '禁用' }}
|
{{ row.status === 1 ? '正常' : '禁用' }}
|
||||||
</template>
|
</template>
|
||||||
|
|
@ -29,44 +25,21 @@
|
||||||
</template>
|
</template>
|
||||||
</ClientTable>
|
</ClientTable>
|
||||||
<!-- 分页组件 -->
|
<!-- 分页组件 -->
|
||||||
<ClientPagination
|
<ClientPagination v-model="currentPage" v-model:pageSizeValue="pageSize" :total="total"
|
||||||
v-model="currentPage"
|
@pagination-change="handlePaginationChange" />
|
||||||
v-model:pageSizeValue="pageSize"
|
|
||||||
:total="total"
|
|
||||||
@pagination-change="handlePaginationChange"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
<!-- 客户弹窗 -->
|
<!-- 客户弹窗 -->
|
||||||
<ClientDialog
|
<ClientDialog :visible="dialogVisible" :title="dialogTitle" :type="dialogType" :button-loading="submitLoading"
|
||||||
:visible="dialogVisible"
|
@confirm="handleSubmit" @cancel="handleCancel" @close="handleClose">
|
||||||
:title="dialogTitle"
|
<ClientForm :form-data="clientForm" :form-rules="clientFormRules" :form-items="clientFormOptions"
|
||||||
:type="dialogType"
|
:options-map="clientFormOptionsMap" ref="clientFormRef">
|
||||||
@confirm="handleSubmit"
|
|
||||||
@cancel="handleCancel"
|
|
||||||
@close="handleClose"
|
|
||||||
>
|
|
||||||
<ClientForm
|
|
||||||
:form-data="clientForm"
|
|
||||||
:form-rules="clientFormRules"
|
|
||||||
:form-items="clientFormOptions"
|
|
||||||
:options-map="clientFormOptionsMap"
|
|
||||||
ref="clientFormRef"
|
|
||||||
>
|
|
||||||
<template #phoneOrEmail="{ formData }" style="margin-left: 0">
|
<template #phoneOrEmail="{ formData }" style="margin-left: 0">
|
||||||
<div class="phone-email">
|
<div class="phone-email">
|
||||||
<div class="tab-btn">
|
<div class="tab-btn">
|
||||||
<el-button
|
<el-button :type="activeTab === 'email' ? 'primary' : 'default'" size="small" @click="activeTab = 'email'">
|
||||||
:type="activeTab === 'email' ? 'primary' : 'default'"
|
|
||||||
size="small"
|
|
||||||
@click="activeTab = 'email'"
|
|
||||||
>
|
|
||||||
邮箱
|
邮箱
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button
|
<el-button :type="activeTab === 'phone' ? 'primary' : 'default'" size="small" @click="activeTab = 'phone'">
|
||||||
:type="activeTab === 'phone' ? 'primary' : 'default'"
|
|
||||||
size="small"
|
|
||||||
@click="activeTab = 'phone'"
|
|
||||||
>
|
|
||||||
手机号
|
手机号
|
||||||
</el-button>
|
</el-button>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -76,12 +49,7 @@
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item prop="phone" class="phone-item" v-if="activeTab === 'phone'">
|
<el-form-item prop="phone" class="phone-item" v-if="activeTab === 'phone'">
|
||||||
<el-select v-model="clientForm.countryCode" placeholder="请选择国家区号">
|
<el-select v-model="clientForm.countryCode" placeholder="请选择国家区号">
|
||||||
<el-option
|
<el-option v-for="item in countryOptions" :key="item.code" :label="item.code" :value="item.code">
|
||||||
v-for="item in countryOptions"
|
|
||||||
:key="item.code"
|
|
||||||
:label="item.code"
|
|
||||||
:value="item.code"
|
|
||||||
>
|
|
||||||
<div class="country-option">
|
<div class="country-option">
|
||||||
<span class="country-name">{{ item.name }}</span>
|
<span class="country-name">{{ item.name }}</span>
|
||||||
<span class="country-code">{{ item.code }}</span>
|
<span class="country-code">{{ item.code }}</span>
|
||||||
|
|
@ -97,14 +65,8 @@
|
||||||
</ClientDialog>
|
</ClientDialog>
|
||||||
|
|
||||||
<!-- 调整金额弹窗 -->
|
<!-- 调整金额弹窗 -->
|
||||||
<ClientDialog
|
<ClientDialog :visible="adjustAmountVisible" title="调整金额" type="adjust" :button-loading="adjustAmountLoading"
|
||||||
:visible="adjustAmountVisible"
|
@confirm="handleAdjustAmountSubmit" @cancel="handleAdjustAmountCancel" @close="handleAdjustAmountClose">
|
||||||
title="调整金额"
|
|
||||||
type="adjust"
|
|
||||||
@confirm="handleAdjustAmountSubmit"
|
|
||||||
@cancel="handleAdjustAmountCancel"
|
|
||||||
@close="handleAdjustAmountClose"
|
|
||||||
>
|
|
||||||
<el-form :model="adjustAmountForm" :rules="adjustAmountRules" ref="adjustAmountFormRef" label-width="120px">
|
<el-form :model="adjustAmountForm" :rules="adjustAmountRules" ref="adjustAmountFormRef" label-width="120px">
|
||||||
<el-form-item label="账号名" prop="username">
|
<el-form-item label="账号名" prop="username">
|
||||||
<el-input v-model="adjustAmountForm.username" disabled />
|
<el-input v-model="adjustAmountForm.username" disabled />
|
||||||
|
|
@ -116,11 +78,8 @@
|
||||||
<el-input v-model="adjustAmountForm.currentBalance" disabled />
|
<el-input v-model="adjustAmountForm.currentBalance" disabled />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="调整金额" prop="adjustAmount">
|
<el-form-item label="调整金额" prop="adjustAmount">
|
||||||
<el-input
|
<el-input v-model="adjustAmountForm.adjustAmount" placeholder="请输入调整金额(可为负数)"
|
||||||
v-model="adjustAmountForm.adjustAmount"
|
@input="handleAdjustAmountInput" />
|
||||||
placeholder="请输入调整金额(可为负数)"
|
|
||||||
@input="handleAdjustAmountInput"
|
|
||||||
/>
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="调整后余额" prop="afterBalance">
|
<el-form-item label="调整后余额" prop="afterBalance">
|
||||||
<el-input v-model="adjustAmountForm.afterBalance" disabled />
|
<el-input v-model="adjustAmountForm.afterBalance" disabled />
|
||||||
|
|
@ -137,6 +96,7 @@ defineOptions({
|
||||||
// 组件
|
// 组件
|
||||||
import ClientSearch from '@/components/common/Search.vue'
|
import ClientSearch from '@/components/common/Search.vue'
|
||||||
import ClientTable from '@/components/common/Table.vue'
|
import ClientTable from '@/components/common/Table.vue'
|
||||||
|
import { usePageLoading, useButtonLoading } from '@/composables/useLoading'
|
||||||
import ClientPagination from '@/components/common/Pagination.vue'
|
import ClientPagination from '@/components/common/Pagination.vue'
|
||||||
import ClientDialog from '@/components/common/Dialog.vue'
|
import ClientDialog from '@/components/common/Dialog.vue'
|
||||||
import ClientForm from '@/components/common/Form.vue'
|
import ClientForm from '@/components/common/Form.vue'
|
||||||
|
|
@ -172,6 +132,9 @@ const clientSearchForm = ref({
|
||||||
endDateTime: '',
|
endDateTime: '',
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const { loading, startLoading, stopLoading } = usePageLoading()
|
||||||
|
const { buttonLoading: submitLoading, startButtonLoading: startSubmitLoading, stopButtonLoading: stopSubmitLoading } = useButtonLoading()
|
||||||
|
const { buttonLoading: adjustAmountLoading, startButtonLoading: startAdjustAmountLoading, stopButtonLoading: stopAdjustAmountLoading } = useButtonLoading()
|
||||||
/**
|
/**
|
||||||
* @description 定义表格数据
|
* @description 定义表格数据
|
||||||
*/
|
*/
|
||||||
|
|
@ -281,33 +244,38 @@ const mapObjectToOptions = (obj: Record<string, string>) => {
|
||||||
* @description 统一获取数据方法
|
* @description 统一获取数据方法
|
||||||
*/
|
*/
|
||||||
const getClientList = async () => {
|
const getClientList = async () => {
|
||||||
const params = {
|
try {
|
||||||
page: currentPage.value,
|
startLoading()
|
||||||
page_size: pageSize.value,
|
const params = {
|
||||||
username: clientSearchForm.value.username,
|
page: currentPage.value,
|
||||||
status: clientSearchForm.value.status || '',
|
page_size: pageSize.value,
|
||||||
reg_start_time:
|
username: clientSearchForm.value.username,
|
||||||
clientSearchForm.value.startDateTime.length > 0
|
status: clientSearchForm.value.status || '',
|
||||||
? `${clientSearchForm.value.startDateTime} 0:00:00`
|
reg_start_time:
|
||||||
: '',
|
clientSearchForm.value.startDateTime.length > 0
|
||||||
reg_end_time:
|
? `${clientSearchForm.value.startDateTime} 0:00:00`
|
||||||
clientSearchForm.value.endDateTime.length > 0
|
: '',
|
||||||
? `${clientSearchForm.value.endDateTime} 23:59:59`
|
reg_end_time:
|
||||||
: '',
|
clientSearchForm.value.endDateTime.length > 0
|
||||||
|
? `${clientSearchForm.value.endDateTime} 23:59:59`
|
||||||
|
: '',
|
||||||
|
}
|
||||||
|
const data = await getClientListApi(params)
|
||||||
|
// 处理表格数据
|
||||||
|
clientTree.value = data.data.map((item) => ({
|
||||||
|
...item,
|
||||||
|
//注册时间
|
||||||
|
createdTime: item.created_at,
|
||||||
|
// 映射所属代理用户名
|
||||||
|
agentUsername: item.par_uid === item.parent?.id ? item.parent?.username : '',
|
||||||
|
}))
|
||||||
|
total.value = Number(data.total)
|
||||||
|
//分页数据
|
||||||
|
currentPage.value = Number(data.current_page)
|
||||||
|
pageSize.value = Number(data.per_page)
|
||||||
|
} finally {
|
||||||
|
stopLoading()
|
||||||
}
|
}
|
||||||
const data = await getClientListApi(params)
|
|
||||||
// 处理表格数据
|
|
||||||
clientTree.value = data.data.map((item) => ({
|
|
||||||
...item,
|
|
||||||
//注册时间
|
|
||||||
createdTime: item.created_at,
|
|
||||||
// 映射所属代理用户名
|
|
||||||
agentUsername: item.par_uid === item.parent?.id ? item.parent?.username : '',
|
|
||||||
}))
|
|
||||||
//分页数据
|
|
||||||
total.value = Number(data.total)
|
|
||||||
currentPage.value = Number(data.current_page)
|
|
||||||
pageSize.value = Number(data.per_page)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取客户表单选项
|
// 获取客户表单选项
|
||||||
|
|
@ -352,11 +320,8 @@ onMounted(async () => {
|
||||||
* @description 搜索方法
|
* @description 搜索方法
|
||||||
*/
|
*/
|
||||||
const handleSearch = async () => {
|
const handleSearch = async () => {
|
||||||
try {
|
|
||||||
await getClientList()
|
await getClientList()
|
||||||
} catch (err) {
|
|
||||||
console.error('获取客户列表失败', err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
const handleReset = async () => {
|
const handleReset = async () => {
|
||||||
// 重置搜索表单
|
// 重置搜索表单
|
||||||
|
|
@ -366,11 +331,7 @@ const handleReset = async () => {
|
||||||
startDateTime: '',
|
startDateTime: '',
|
||||||
endDateTime: '',
|
endDateTime: '',
|
||||||
}
|
}
|
||||||
try {
|
await getClientList()
|
||||||
await getClientList()
|
|
||||||
} catch (err) {
|
|
||||||
console.error('获取客户列表失败', err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// 添加客户
|
// 添加客户
|
||||||
const handleAdd = () => {
|
const handleAdd = () => {
|
||||||
|
|
@ -431,8 +392,9 @@ const handlePaginationChange = (page: { currentPage: number; pageSize: number })
|
||||||
* @description 客户弹窗方法
|
* @description 客户弹窗方法
|
||||||
*/
|
*/
|
||||||
const handleSubmit = async () => {
|
const handleSubmit = async () => {
|
||||||
|
await clientFormRef.value?.validate()
|
||||||
|
startSubmitLoading()
|
||||||
try {
|
try {
|
||||||
await clientFormRef.value?.validate()
|
|
||||||
if (dialogType.value === 'add') {
|
if (dialogType.value === 'add') {
|
||||||
const params = {
|
const params = {
|
||||||
reg_type: activeTab.value === 'email' ? 1 : 2,
|
reg_type: activeTab.value === 'email' ? 1 : 2,
|
||||||
|
|
@ -460,6 +422,8 @@ const handleSubmit = async () => {
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('客户表单验证失败', err)
|
console.error('客户表单验证失败', err)
|
||||||
|
} finally {
|
||||||
|
stopSubmitLoading()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const handleCancel = () => {
|
const handleCancel = () => {
|
||||||
|
|
@ -497,16 +461,19 @@ const handleAdjustAmountInput = () => {
|
||||||
|
|
||||||
// 提交调整金额
|
// 提交调整金额
|
||||||
const handleAdjustAmountSubmit = async () => {
|
const handleAdjustAmountSubmit = async () => {
|
||||||
|
await adjustAmountFormRef.value?.validate()
|
||||||
|
startAdjustAmountLoading()
|
||||||
try {
|
try {
|
||||||
await adjustAmountFormRef.value?.validate()
|
|
||||||
await updateCapitalApi({
|
await updateCapitalApi({
|
||||||
target_user_id: adjustUserId.value,
|
target_user_id: adjustUserId.value,
|
||||||
amount: adjustAmountForm.value.adjustAmount,
|
amount: adjustAmountForm.value.adjustAmount,
|
||||||
})
|
})
|
||||||
await getClientList()
|
await getClientList()
|
||||||
adjustAmountVisible.value = false
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('调整金额表单验证失败', err)
|
console.error('调整金额表单验证失败', err)
|
||||||
|
} finally {
|
||||||
|
adjustAmountVisible.value = false
|
||||||
|
stopAdjustAmountLoading()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -522,8 +489,8 @@ const handleAdjustAmountClose = () => {
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
.client{
|
.client {}
|
||||||
}
|
|
||||||
:deep(.el-form-item__content) {
|
:deep(.el-form-item__content) {
|
||||||
margin-left: 0 !important;
|
margin-left: 0 !important;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -54,7 +54,7 @@ export const clientTableColumns = [
|
||||||
{ prop: 'username', label: '用户名', align: 'center' as const },
|
{ prop: 'username', label: '用户名', align: 'center' as const },
|
||||||
{ prop: 'createdTime', label: '注册时间', align: 'center' as const },
|
{ prop: 'createdTime', label: '注册时间', align: 'center' as const },
|
||||||
{ prop: 'agentUsername', label: '所属代理', align: 'center' as const },
|
{ prop: 'agentUsername', label: '所属代理', align: 'center' as const },
|
||||||
{ prop: 'wallet_capital.amount', label: '资金', align: 'center' as const },
|
{ prop: 'wallet_capital.amount', label: '资金', align: 'center' as const, isNumber: true },
|
||||||
{ label: '状态', slotName: 'status', align: 'center' as const },
|
{ label: '状态', slotName: 'status', align: 'center' as const },
|
||||||
{ label: '操作', slotName: 'action', align: 'center' as const },
|
{ label: '操作', slotName: 'action', align: 'center' as const },
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@
|
||||||
:columns="menuTableColumns"
|
:columns="menuTableColumns"
|
||||||
row-key="id"
|
row-key="id"
|
||||||
:tree-props="treeProps"
|
:tree-props="treeProps"
|
||||||
|
:loading="loading"
|
||||||
>
|
>
|
||||||
<template #icon="{ row }">
|
<template #icon="{ row }">
|
||||||
<el-icon v-if="row.icon && menuiconMap[row.icon]">
|
<el-icon v-if="row.icon && menuiconMap[row.icon]">
|
||||||
|
|
@ -71,6 +72,9 @@ defineOptions({
|
||||||
})
|
})
|
||||||
import type { FormInstance } from 'element-plus'
|
import type { FormInstance } from 'element-plus'
|
||||||
import { Plus } from '@element-plus/icons-vue'
|
import { Plus } from '@element-plus/icons-vue'
|
||||||
|
import { usePageLoading } from '@/composables/useLoading'
|
||||||
|
const { loading, startLoading, stopLoading } = usePageLoading()
|
||||||
|
|
||||||
// 组件配置
|
// 组件配置
|
||||||
import MenuTable from '@/components/common/Table.vue'
|
import MenuTable from '@/components/common/Table.vue'
|
||||||
import MenuDialog from '@/components/common/Dialog.vue'
|
import MenuDialog from '@/components/common/Dialog.vue'
|
||||||
|
|
@ -137,6 +141,7 @@ const handleAddMenu = () => {
|
||||||
|
|
||||||
// 获取菜单列表
|
// 获取菜单列表
|
||||||
const fetchMenuList = async () => {
|
const fetchMenuList = async () => {
|
||||||
|
startLoading()
|
||||||
try {
|
try {
|
||||||
const data = await getMenuApi()
|
const data = await getMenuApi()
|
||||||
menuTree.value = data
|
menuTree.value = data
|
||||||
|
|
@ -148,6 +153,8 @@ const fetchMenuList = async () => {
|
||||||
menuFormOptionsMap.value.parent_id = [{ label: '一级菜单', value: '0' }, ...parentNameOptions]
|
menuFormOptionsMap.value.parent_id = [{ label: '一级菜单', value: '0' }, ...parentNameOptions]
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('获取菜单列表失败', err)
|
console.error('获取菜单列表失败', err)
|
||||||
|
} finally {
|
||||||
|
stopLoading()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 页面加载时获取菜单列表
|
// 页面加载时获取菜单列表
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
<!-- 搜索 -->
|
<!-- 搜索 -->
|
||||||
<NoticeSearch
|
<NoticeSearch
|
||||||
:search-form="searchForm"
|
:search-form="searchForm"
|
||||||
|
:buttonLoading="loading"
|
||||||
:search-options="searchOptions"
|
:search-options="searchOptions"
|
||||||
@search="handleSearch"
|
@search="handleSearch"
|
||||||
@reset="handleReset"
|
@reset="handleReset"
|
||||||
|
|
@ -14,7 +15,7 @@
|
||||||
</template>
|
</template>
|
||||||
</NoticeSearch>
|
</NoticeSearch>
|
||||||
<!-- 表格 -->
|
<!-- 表格 -->
|
||||||
<NoticeTable :table-data="noticeTree" :columns="noticeTableColumnsOptions" row-key="id">
|
<NoticeTable :table-data="noticeTree" :columns="noticeTableColumnsOptions" row-key="id" :loading="loading">
|
||||||
<template #status="{ row }">
|
<template #status="{ row }">
|
||||||
<!-- 修正状态显示:1=草稿,2=已发布 -->
|
<!-- 修正状态显示:1=草稿,2=已发布 -->
|
||||||
{{ row.status === 1 ? '草稿' : '已发布' }}
|
{{ row.status === 1 ? '草稿' : '已发布' }}
|
||||||
|
|
@ -55,6 +56,7 @@
|
||||||
:title="dialogTitle"
|
:title="dialogTitle"
|
||||||
:type="dialogType"
|
:type="dialogType"
|
||||||
:show-footer="dialogType !== 'view'"
|
:show-footer="dialogType !== 'view'"
|
||||||
|
:button-loading="submitLoading"
|
||||||
@confirm="handleSubmit"
|
@confirm="handleSubmit"
|
||||||
@cancel="handleCancel"
|
@cancel="handleCancel"
|
||||||
@close="handleClose"
|
@close="handleClose"
|
||||||
|
|
@ -99,6 +101,10 @@
|
||||||
defineOptions({
|
defineOptions({
|
||||||
name: 'Notice'
|
name: 'Notice'
|
||||||
})
|
})
|
||||||
|
import { usePageLoading, useButtonLoading } from '@/composables/useLoading'
|
||||||
|
const { loading, startLoading, stopLoading } = usePageLoading()
|
||||||
|
const { buttonLoading: submitLoading, startButtonLoading: startSubmitLoading, stopButtonLoading: stopSubmitLoading } = useButtonLoading()
|
||||||
|
|
||||||
// 组件
|
// 组件
|
||||||
import NoticeSearch from '@/components/common/Search.vue'
|
import NoticeSearch from '@/components/common/Search.vue'
|
||||||
import NoticeTable from '@/components/common/Table.vue'
|
import NoticeTable from '@/components/common/Table.vue'
|
||||||
|
|
@ -223,6 +229,7 @@ const noticeFormOptionsMap = ref({
|
||||||
*/
|
*/
|
||||||
//获取公告列表
|
//获取公告列表
|
||||||
const getNoticeList = async () => {
|
const getNoticeList = async () => {
|
||||||
|
startLoading()
|
||||||
const params = {
|
const params = {
|
||||||
page: currentPage.value,
|
page: currentPage.value,
|
||||||
page_size: pageSize.value,
|
page_size: pageSize.value,
|
||||||
|
|
@ -231,19 +238,23 @@ const getNoticeList = async () => {
|
||||||
publish_start_time: searchForm.value.startDateTime,
|
publish_start_time: searchForm.value.startDateTime,
|
||||||
publish_end_time: searchForm.value.endDateTime,
|
publish_end_time: searchForm.value.endDateTime,
|
||||||
}
|
}
|
||||||
const data: any = await getNoticeListApi(params)
|
try {
|
||||||
// 表格数据
|
const data: any = await getNoticeListApi(params)
|
||||||
noticeTree.value = data.data.map((item: any) => ({
|
// 表格数据
|
||||||
id: item.id,
|
noticeTree.value = data.data.map((item: any) => ({
|
||||||
noticeName: item.name,
|
id: item.id,
|
||||||
noticeContent: item.content,
|
noticeName: item.name,
|
||||||
publishTime: item.publish_time,
|
noticeContent: item.content,
|
||||||
status: item.status,
|
publishTime: item.publish_time,
|
||||||
}))
|
status: item.status,
|
||||||
// 分页数据
|
}))
|
||||||
total.value = data.total
|
// 分页数据
|
||||||
currentPage.value = data.current_page
|
total.value = data.total
|
||||||
pageSize.value = Number(data.per_page)
|
currentPage.value = data.current_page
|
||||||
|
pageSize.value = Number(data.per_page)
|
||||||
|
} finally {
|
||||||
|
stopLoading()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -337,28 +348,33 @@ const handlePaginationChange = async (page: { currentPage: number; pageSize: num
|
||||||
* @description: 定义弹窗方法
|
* @description: 定义弹窗方法
|
||||||
*/
|
*/
|
||||||
const handleSubmit = async () => {
|
const handleSubmit = async () => {
|
||||||
await noticeFormRef.value.validate()
|
startSubmitLoading()
|
||||||
if (dialogType.value === 'create') {
|
try {
|
||||||
noticeForm.value.noticeContent = valueHtml.value
|
await noticeFormRef.value.validate()
|
||||||
const params = {
|
if (dialogType.value === 'create') {
|
||||||
name: noticeForm.value.noticeName,
|
noticeForm.value.noticeContent = valueHtml.value
|
||||||
content: noticeForm.value.noticeContent,
|
const params = {
|
||||||
status: noticeForm.value.status,
|
name: noticeForm.value.noticeName,
|
||||||
|
content: noticeForm.value.noticeContent,
|
||||||
|
status: noticeForm.value.status,
|
||||||
|
}
|
||||||
|
await createNoticeApi(params)
|
||||||
|
dialogVisible.value = false
|
||||||
|
getNoticeList()
|
||||||
|
} else {
|
||||||
|
noticeForm.value.noticeContent = valueHtml.value
|
||||||
|
const params = {
|
||||||
|
id: noticeForm.value.id,
|
||||||
|
name: noticeForm.value.noticeName,
|
||||||
|
content: noticeForm.value.noticeContent,
|
||||||
|
status: noticeForm.value.status,
|
||||||
|
}
|
||||||
|
await editNoticeApi(params)
|
||||||
|
dialogVisible.value = false
|
||||||
|
getNoticeList()
|
||||||
}
|
}
|
||||||
await createNoticeApi(params)
|
} finally {
|
||||||
dialogVisible.value = false
|
stopSubmitLoading()
|
||||||
getNoticeList()
|
|
||||||
} else {
|
|
||||||
noticeForm.value.noticeContent = valueHtml.value
|
|
||||||
const params = {
|
|
||||||
id: noticeForm.value.id,
|
|
||||||
name: noticeForm.value.noticeName,
|
|
||||||
content: noticeForm.value.noticeContent,
|
|
||||||
status: noticeForm.value.status,
|
|
||||||
}
|
|
||||||
await editNoticeApi(params)
|
|
||||||
dialogVisible.value = false
|
|
||||||
getNoticeList()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@
|
||||||
<el-button type="primary" @click="handleAddRole" v-auth="'roles_create'">新增角色</el-button>
|
<el-button type="primary" @click="handleAddRole" v-auth="'roles_create'">新增角色</el-button>
|
||||||
</div>
|
</div>
|
||||||
<!-- 角色列表表格 -->
|
<!-- 角色列表表格 -->
|
||||||
<RoleTable :table-data="roleTree" :columns="roleTableColumns" row-key="id">
|
<RoleTable :table-data="roleTree" :columns="roleTableColumns" row-key="id" :loading="loading">
|
||||||
<template #status="{ row }">
|
<template #status="{ row }">
|
||||||
<el-switch :model-value="row.status === 1" :active-value="true" :inactive-value="false" active-text="启用"
|
<el-switch :model-value="row.status === 1" :active-value="true" :inactive-value="false" active-text="启用"
|
||||||
inactive-text="禁用" />
|
inactive-text="禁用" />
|
||||||
|
|
@ -32,16 +32,15 @@
|
||||||
<RoleForm :form-data="roleForm" :form-rules="roleFormRules" :form-items="roleFormItemOptions" ref="roleFormRef"
|
<RoleForm :form-data="roleForm" :form-rules="roleFormRules" :form-items="roleFormItemOptions" ref="roleFormRef"
|
||||||
:options-map="roleFormOptionsMap" :dialog-type="dialogType">
|
:options-map="roleFormOptionsMap" :dialog-type="dialogType">
|
||||||
<template #permissions="{ formData }">
|
<template #permissions="{ formData }">
|
||||||
<el-tree ref="permissionTreeRef" :data="permissionTreeData" :props="treeProps" show-checkbox node-key="id"
|
<el-tree v-loading="treeLoading" ref="permissionTreeRef" :data="permissionTreeData" :props="treeProps"
|
||||||
:default-expand-all="true" :check-strictly="false"
|
show-checkbox node-key="id" :default-expand-all="true" :check-strictly="false" class="permission-tree" />
|
||||||
class="permission-tree" />
|
|
||||||
</template>
|
</template>
|
||||||
</RoleForm>
|
</RoleForm>
|
||||||
|
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<div style="flex: auto">
|
<div style="flex: auto">
|
||||||
<el-button @click="handleCancel">取消</el-button>
|
<el-button @click="handleCancel">取消</el-button>
|
||||||
<el-button type="primary" @click="handleSubmit">确定</el-button>
|
<el-button type="primary" :loading="buttonLoading" @click="handleSubmit">确定</el-button>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</el-drawer>
|
</el-drawer>
|
||||||
|
|
@ -54,6 +53,11 @@ defineOptions({
|
||||||
})
|
})
|
||||||
import type { FormInstance, TreeInstance } from 'element-plus'
|
import type { FormInstance, TreeInstance } from 'element-plus'
|
||||||
import { Plus } from '@element-plus/icons-vue'
|
import { Plus } from '@element-plus/icons-vue'
|
||||||
|
import { usePageLoading, useButtonLoading } from '@/composables/useLoading'
|
||||||
|
|
||||||
|
const { loading, startLoading, stopLoading } = usePageLoading()
|
||||||
|
const { loading: treeLoading, startLoading: treeStartLoading, stopLoading: treeStopLoading } = usePageLoading()
|
||||||
|
const { buttonLoading, startButtonLoading, stopButtonLoading } = useButtonLoading()
|
||||||
|
|
||||||
// 组件配置
|
// 组件配置
|
||||||
import RoleTable from '@/components/common/Table.vue'
|
import RoleTable from '@/components/common/Table.vue'
|
||||||
|
|
@ -140,11 +144,14 @@ const filterRoles = (roleList: any[]) => {
|
||||||
|
|
||||||
// 获取角色列表
|
// 获取角色列表
|
||||||
const fetchRoleList = async () => {
|
const fetchRoleList = async () => {
|
||||||
|
startLoading()
|
||||||
try {
|
try {
|
||||||
const data = await getRoleApi()
|
const data = await getRoleApi()
|
||||||
roleTree.value = data
|
roleTree.value = data
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('获取角色列表失败', err)
|
console.error('获取角色列表失败', err)
|
||||||
|
} finally {
|
||||||
|
stopLoading()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -265,7 +272,9 @@ const getParentNodeIds = (checkedKeys: number[], treeData: any[]): number[] => {
|
||||||
const handlePermission = async (row: any) => {
|
const handlePermission = async (row: any) => {
|
||||||
dialogVisible.value = true
|
dialogVisible.value = true
|
||||||
dialogTitle.value = '设置角色权限'
|
dialogTitle.value = '设置角色权限'
|
||||||
|
permissionTreeData.value = []
|
||||||
dialogType.value = 'permissions'
|
dialogType.value = 'permissions'
|
||||||
|
treeStartLoading()
|
||||||
handleDialogType(dialogType.value)
|
handleDialogType(dialogType.value)
|
||||||
permissionIds.value = row.id
|
permissionIds.value = row.id
|
||||||
try {
|
try {
|
||||||
|
|
@ -286,6 +295,8 @@ const handlePermission = async (row: any) => {
|
||||||
permissionTreeRef.value?.setCheckedKeys(childPermissionIds, false)
|
permissionTreeRef.value?.setCheckedKeys(childPermissionIds, false)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('获取角色权限失败', err)
|
console.error('获取角色权限失败', err)
|
||||||
|
} finally {
|
||||||
|
treeStopLoading()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -293,6 +304,7 @@ const handlePermission = async (row: any) => {
|
||||||
@description: 处理弹窗提交/取消/关闭事件
|
@description: 处理弹窗提交/取消/关闭事件
|
||||||
**/
|
**/
|
||||||
const handleSubmit = async () => {
|
const handleSubmit = async () => {
|
||||||
|
startButtonLoading()
|
||||||
console.log('提交菜单表单', roleForm.value.permissions, allPermissions.value)
|
console.log('提交菜单表单', roleForm.value.permissions, allPermissions.value)
|
||||||
try {
|
try {
|
||||||
await roleFormRef.value?.validate()
|
await roleFormRef.value?.validate()
|
||||||
|
|
@ -328,6 +340,8 @@ const handleSubmit = async () => {
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log('表单验证失败')
|
console.log('表单验证失败')
|
||||||
return
|
return
|
||||||
|
} finally {
|
||||||
|
stopButtonLoading()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
<!-- 菜单列表头 -->
|
<!-- 菜单列表头 -->
|
||||||
<MenuHeader :title="menuTitle" :buttons="menuHeaderButtons" @click="handleAddMenu" />
|
<MenuHeader :title="menuTitle" :buttons="menuHeaderButtons" @click="handleAddMenu" />
|
||||||
<!-- 菜单列表表格 -->
|
<!-- 菜单列表表格 -->
|
||||||
<MenuTable :table-data="menuTree" :columns="menuTableColumns" row-key="id">
|
<MenuTable :table-data="menuTree" :columns="menuTableColumns" row-key="id" :loading="loading">
|
||||||
<template #action="{ row }">
|
<template #action="{ row }">
|
||||||
<el-button link type="primary" size="small" @click="handleEditMenu(row)"> 编辑 </el-button>
|
<el-button link type="primary" size="small" @click="handleEditMenu(row)"> 编辑 </el-button>
|
||||||
</template>
|
</template>
|
||||||
|
|
@ -33,6 +33,9 @@ defineOptions({
|
||||||
})
|
})
|
||||||
import type { FormInstance } from 'element-plus'
|
import type { FormInstance } from 'element-plus'
|
||||||
import { Plus } from '@element-plus/icons-vue'
|
import { Plus } from '@element-plus/icons-vue'
|
||||||
|
import { usePageLoading } from '@/composables/useLoading'
|
||||||
|
const { loading, startLoading, stopLoading } = usePageLoading()
|
||||||
|
|
||||||
// 组件配置
|
// 组件配置
|
||||||
import MenuHeader from '@/components/common/Header.vue'
|
import MenuHeader from '@/components/common/Header.vue'
|
||||||
import MenuTable from '@/components/common/Table.vue'
|
import MenuTable from '@/components/common/Table.vue'
|
||||||
|
|
@ -88,11 +91,14 @@ const handleAddMenu = () => {
|
||||||
|
|
||||||
// 获取菜单列表
|
// 获取菜单列表
|
||||||
const fetchSettingList = async () => {
|
const fetchSettingList = async () => {
|
||||||
|
startLoading()
|
||||||
try {
|
try {
|
||||||
const data = await getSettingApi()
|
const data = await getSettingApi()
|
||||||
menuTree.value = data
|
menuTree.value = data
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('获取菜单列表失败', err)
|
console.error('获取菜单列表失败', err)
|
||||||
|
} finally {
|
||||||
|
stopLoading()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 页面加载时获取菜单列表
|
// 页面加载时获取菜单列表
|
||||||
|
|
|
||||||
|
|
@ -1,24 +1,14 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="trade-group table_form-container">
|
<div class="trade-group table_form-container">
|
||||||
<el-form-item label="交易节假日时间设置">
|
<el-form-item label="交易节假日时间设置">
|
||||||
<el-button
|
<el-button style="margin-left: 18px" type="primary" v-auth="'contractVariety_addHoliday'"
|
||||||
style="margin-left: 18px"
|
@click="handleAdd">添加</el-button>
|
||||||
type="primary"
|
<el-button style="margin-left: 18px" type="danger" v-auth="'contractVariety_addHoliday'"
|
||||||
v-auth="'contractVariety_addHoliday'"
|
@click="handleDel">删除</el-button>
|
||||||
@click="handleAdd"
|
|
||||||
>添加</el-button
|
|
||||||
>
|
|
||||||
<el-button
|
|
||||||
style="margin-left: 18px"
|
|
||||||
type="danger"
|
|
||||||
v-auth="'contractVariety_addHoliday'"
|
|
||||||
@click="handleDel"
|
|
||||||
>删除</el-button
|
|
||||||
>
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<!-- 表格 -->
|
<!-- 表格 -->
|
||||||
<div class="table-box">
|
<div class="table-box">
|
||||||
<table>
|
<table v-loading="loading">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>名称</th>
|
<th>名称</th>
|
||||||
|
|
@ -36,33 +26,16 @@
|
||||||
<span v-else>{{ item.name }}</span>
|
<span v-else>{{ item.name }}</span>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<el-date-picker
|
<el-date-picker v-if="item.editStatus" v-model="item.datePicker" type="datetimerange"
|
||||||
v-if="item.editStatus"
|
start-placeholder="休市开始时间" end-placeholder="休市结束时间" format="YYYY-MM-DD HH:mm:ss"
|
||||||
v-model="item.datePicker"
|
date-format="YYYY-MM-DD HH:mm:ss" time-format="YYYY-MM-DD HH:mm:ss"
|
||||||
type="datetimerange"
|
value-format="YYYY-MM-DD HH:mm:ss" />
|
||||||
start-placeholder="休市开始时间"
|
|
||||||
end-placeholder="休市结束时间"
|
|
||||||
format="YYYY-MM-DD HH:mm:ss"
|
|
||||||
date-format="YYYY-MM-DD HH:mm:ss"
|
|
||||||
time-format="YYYY-MM-DD HH:mm:ss"
|
|
||||||
value-format="YYYY-MM-DD HH:mm:ss"
|
|
||||||
/>
|
|
||||||
<span v-else>{{ item.datePicker[0] }} - {{ item.datePicker[1] }}</span>
|
<span v-else>{{ item.datePicker[0] }} - {{ item.datePicker[1] }}</span>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<el-select
|
<el-select multiple placeholder="请选择休市市场" style="width: 240px" v-model="item.groupId"
|
||||||
multiple
|
v-if="item.editStatus">
|
||||||
placeholder="请选择休市市场"
|
<el-option v-for="item in marketList" :key="item.value" :label="item.label" :value="item.value" />
|
||||||
style="width: 240px"
|
|
||||||
v-model="item.groupId"
|
|
||||||
v-if="item.editStatus"
|
|
||||||
>
|
|
||||||
<el-option
|
|
||||||
v-for="item in marketList"
|
|
||||||
:key="item.value"
|
|
||||||
:label="item.label"
|
|
||||||
:value="item.value"
|
|
||||||
/>
|
|
||||||
</el-select>
|
</el-select>
|
||||||
<span>{{
|
<span>{{
|
||||||
(item?.groupId || [])
|
(item?.groupId || [])
|
||||||
|
|
@ -78,34 +51,14 @@
|
||||||
<span v-else>{{ item.description }}</span>
|
<span v-else>{{ item.description }}</span>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<el-button
|
<el-button type="primary" v-if="!item.editStatus" @click="item.editStatus = true"
|
||||||
type="primary"
|
v-auth="'contractVariety_addHoliday'">编辑</el-button>
|
||||||
v-if="!item.editStatus"
|
<el-button type="danger" v-if="!item.editStatus" @click="handleDel(item.id, index)"
|
||||||
@click="item.editStatus = true"
|
v-auth="'contractVariety_addHoliday'">删除</el-button>
|
||||||
v-auth="'contractVariety_addHoliday'"
|
<el-button type="primary" v-if="item.editStatus" @click="submitItem(index)"
|
||||||
>编辑</el-button
|
v-auth="'contractVariety_addHoliday'">确认</el-button>
|
||||||
>
|
<el-button type="danger" v-if="item.editStatus" @click="item.editStatus = false"
|
||||||
<el-button
|
v-auth="'contractVariety_addHoliday'">取消</el-button>
|
||||||
type="danger"
|
|
||||||
v-if="!item.editStatus"
|
|
||||||
@click="handleDel(item.id, index)"
|
|
||||||
v-auth="'contractVariety_addHoliday'"
|
|
||||||
>删除</el-button
|
|
||||||
>
|
|
||||||
<el-button
|
|
||||||
type="primary"
|
|
||||||
v-if="item.editStatus"
|
|
||||||
@click="submitItem(index)"
|
|
||||||
v-auth="'contractVariety_addHoliday'"
|
|
||||||
>确认</el-button
|
|
||||||
>
|
|
||||||
<el-button
|
|
||||||
type="danger"
|
|
||||||
v-if="item.editStatus"
|
|
||||||
@click="item.editStatus = false"
|
|
||||||
v-auth="'contractVariety_addHoliday'"
|
|
||||||
>取消</el-button
|
|
||||||
>
|
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
|
|
@ -123,6 +76,10 @@ import { ref, onMounted } from 'vue'
|
||||||
import { getGroupListApi } from '@/api/modules/trade/group'
|
import { getGroupListApi } from '@/api/modules/trade/group'
|
||||||
import { getHolidayList, addHoliday, editHoliday, delHoliday } from '@/api/modules/trade/time'
|
import { getHolidayList, addHoliday, editHoliday, delHoliday } from '@/api/modules/trade/time'
|
||||||
import { ElMessageBox } from 'element-plus'
|
import { ElMessageBox } from 'element-plus'
|
||||||
|
import { usePageLoading } from '@/composables/useLoading'
|
||||||
|
|
||||||
|
// 按钮 loading
|
||||||
|
const { loading, startLoading, stopLoading } = usePageLoading()
|
||||||
|
|
||||||
type DataItem = {
|
type DataItem = {
|
||||||
id?: number | string
|
id?: number | string
|
||||||
|
|
@ -150,18 +107,21 @@ const getMarketList = async () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
const initDate = () => {
|
const initDate = () => {
|
||||||
getHolidayList().then((res) => {
|
startLoading()
|
||||||
dataList.value = res.map((item: any) => ({
|
try {
|
||||||
id: item.id + '',
|
getHolidayList().then((res) => {
|
||||||
name: item.name,
|
dataList.value = res.map((item: any) => ({
|
||||||
start_time: item.start_time,
|
id: item.id + '',
|
||||||
end_time: item.end_time,
|
name: item.name,
|
||||||
datePicker: [item.start_time, item.end_time],
|
start_time: item.start_time,
|
||||||
groupId: item.group_id,
|
end_time: item.end_time,
|
||||||
description: item.description,
|
datePicker: [item.start_time, item.end_time],
|
||||||
editStatus: false,
|
groupId: item.group_id,
|
||||||
}))
|
description: item.description,
|
||||||
})
|
editStatus: false,
|
||||||
|
}))
|
||||||
|
})
|
||||||
|
} finally { stopLoading() }
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleAdd = () => {
|
const handleAdd = () => {
|
||||||
|
|
@ -223,6 +183,7 @@ onMounted(() => {
|
||||||
.trade-group {
|
.trade-group {
|
||||||
overflow-y: scroll;
|
overflow-y: scroll;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 给 table 及所有 td 加边框 */
|
/* 给 table 及所有 td 加边框 */
|
||||||
table {
|
table {
|
||||||
border-collapse: collapse;
|
border-collapse: collapse;
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,11 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="trade-group table_form-container">
|
<div class="trade-group table_form-container">
|
||||||
<el-form-item label="交易组时间设置">
|
<el-form-item label="交易组时间设置">
|
||||||
<el-button type="primary" @click="addTableItem" v-auth="'contractVariety_createGroup'"
|
<el-button type="primary" @click="addTableItem" v-auth="'contractVariety_createGroup'">添加</el-button>
|
||||||
>添加</el-button
|
|
||||||
>
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<!-- 表格 -->
|
<!-- 表格 -->
|
||||||
<div class="table-box">
|
<div class="table-box">
|
||||||
<table>
|
<table v-loading="loading">
|
||||||
<template v-for="(item, index) in tradeGroupTree" :key="item.id">
|
<template v-for="(item, index) in tradeGroupTree" :key="item.id">
|
||||||
<tr>
|
<tr>
|
||||||
<td style="width: 50px">顺序</td>
|
<td style="width: 50px">顺序</td>
|
||||||
|
|
@ -35,23 +33,13 @@
|
||||||
<td class="time-picker-box">
|
<td class="time-picker-box">
|
||||||
<template v-if="item.editStatus">
|
<template v-if="item.editStatus">
|
||||||
<template v-if="item?.x_time_list">
|
<template v-if="item?.x_time_list">
|
||||||
<el-time-picker
|
<el-time-picker v-for="(time, timeIndex) in item?.x_time_list" :key="timeIndex"
|
||||||
v-for="(time, timeIndex) in item?.x_time_list"
|
v-model="item.x_time_list[timeIndex]" style="width: 180px; flex: 0 0 auto" format="HH:mm:ss"
|
||||||
:key="timeIndex"
|
value-format="HH:mm:ss" :picker-options="{
|
||||||
v-model="item.x_time_list[timeIndex]"
|
|
||||||
style="width: 180px; flex: 0 0 auto"
|
|
||||||
format="HH:mm:ss"
|
|
||||||
value-format="HH:mm:ss"
|
|
||||||
:picker-options="{
|
|
||||||
selectableRange: '09:00:00 - 18:00:00',
|
selectableRange: '09:00:00 - 18:00:00',
|
||||||
}"
|
}" is-range />
|
||||||
is-range
|
|
||||||
/>
|
|
||||||
</template>
|
</template>
|
||||||
<img
|
<img src="@/assets/images/trade/group/add.png" @click="addTime(index, 'x_time_list')" />
|
||||||
src="@/assets/images/trade/group/add.png"
|
|
||||||
@click="addTime(index, 'x_time_list')"
|
|
||||||
/>
|
|
||||||
</template>
|
</template>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<template v-if="item?.x_time_list">
|
<template v-if="item?.x_time_list">
|
||||||
|
|
@ -62,34 +50,14 @@
|
||||||
</template>
|
</template>
|
||||||
</td>
|
</td>
|
||||||
<td rowspan="2" style="width: 140px">
|
<td rowspan="2" style="width: 140px">
|
||||||
<el-button
|
<el-button type="primary" v-if="!item.editStatus" @click="item.editStatus = true"
|
||||||
type="primary"
|
v-auth="'contractVariety_editGroup'">编辑</el-button>
|
||||||
v-if="!item.editStatus"
|
<el-button type="danger" v-if="!item.editStatus" @click="deleteGroup(item.id, index)"
|
||||||
@click="item.editStatus = true"
|
v-auth="'contractVariety_delGroup'">删除</el-button>
|
||||||
v-auth="'contractVariety_editGroup'"
|
<el-button type="primary" v-if="item.editStatus" @click="submitItem(index)"
|
||||||
>编辑</el-button
|
v-auth="'contractVariety_editGroup'">确认</el-button>
|
||||||
>
|
<el-button type="danger" v-if="item.editStatus" @click="item.editStatus = false"
|
||||||
<el-button
|
v-auth="'contractVariety_editGroup'">取消</el-button>
|
||||||
type="danger"
|
|
||||||
v-if="!item.editStatus"
|
|
||||||
@click="deleteGroup(item.id, index)"
|
|
||||||
v-auth="'contractVariety_delGroup'"
|
|
||||||
>删除</el-button
|
|
||||||
>
|
|
||||||
<el-button
|
|
||||||
type="primary"
|
|
||||||
v-if="item.editStatus"
|
|
||||||
@click="submitItem(index)"
|
|
||||||
v-auth="'contractVariety_editGroup'"
|
|
||||||
>确认</el-button
|
|
||||||
>
|
|
||||||
<el-button
|
|
||||||
type="danger"
|
|
||||||
v-if="item.editStatus"
|
|
||||||
@click="item.editStatus = false"
|
|
||||||
v-auth="'contractVariety_editGroup'"
|
|
||||||
>取消</el-button
|
|
||||||
>
|
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
|
|
@ -114,23 +82,13 @@
|
||||||
<td class="time-picker-box">
|
<td class="time-picker-box">
|
||||||
<template v-if="item.editStatus">
|
<template v-if="item.editStatus">
|
||||||
<template v-if="item?.d_time_list">
|
<template v-if="item?.d_time_list">
|
||||||
<el-time-picker
|
<el-time-picker v-for="(time, timeIndex) in item?.d_time_list" :key="timeIndex"
|
||||||
v-for="(time, timeIndex) in item?.d_time_list"
|
v-model="item.d_time_list[timeIndex]" style="width: 180px; flex: 0 0 auto" format="HH:mm:ss"
|
||||||
:key="timeIndex"
|
value-format="HH:mm:ss" :picker-options="{
|
||||||
v-model="item.d_time_list[timeIndex]"
|
|
||||||
style="width: 180px; flex: 0 0 auto"
|
|
||||||
format="HH:mm:ss"
|
|
||||||
value-format="HH:mm:ss"
|
|
||||||
:picker-options="{
|
|
||||||
selectableRange: '09:00:00 - 18:00:00',
|
selectableRange: '09:00:00 - 18:00:00',
|
||||||
}"
|
}" is-range />
|
||||||
is-range
|
|
||||||
/>
|
|
||||||
</template>
|
</template>
|
||||||
<img
|
<img src="@/assets/images/trade/group/add.png" @click="addTime(index, 'd_time_list')" />
|
||||||
src="@/assets/images/trade/group/add.png"
|
|
||||||
@click="addTime(index, 'd_time_list')"
|
|
||||||
/>
|
|
||||||
</template>
|
</template>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<template v-if="item?.d_time_list">
|
<template v-if="item?.d_time_list">
|
||||||
|
|
@ -148,7 +106,10 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import { usePageLoading } from '@/composables/useLoading'
|
||||||
|
|
||||||
|
// 按钮 loading
|
||||||
|
const { loading, startLoading, stopLoading } = usePageLoading()
|
||||||
defineOptions({
|
defineOptions({
|
||||||
name: 'Times'
|
name: 'Times'
|
||||||
})
|
})
|
||||||
|
|
@ -246,6 +207,7 @@ const deleteGroup = (id: number, idx: number) => {
|
||||||
* @description: 定义公共请求数据方法
|
* @description: 定义公共请求数据方法
|
||||||
*/
|
*/
|
||||||
const getGroupList = async () => {
|
const getGroupList = async () => {
|
||||||
|
startLoading()
|
||||||
try {
|
try {
|
||||||
const data = await getGroupListApi()
|
const data = await getGroupListApi()
|
||||||
data.forEach((item: any) => {
|
data.forEach((item: any) => {
|
||||||
|
|
@ -283,6 +245,8 @@ const getGroupList = async () => {
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
console.log(e)
|
console.log(e)
|
||||||
ElMessage.error(e.msg)
|
ElMessage.error(e.msg)
|
||||||
|
} finally {
|
||||||
|
stopLoading()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -298,40 +262,50 @@ onMounted(() => {
|
||||||
.trade-group {
|
.trade-group {
|
||||||
overflow-y: scroll;
|
overflow-y: scroll;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 给 table 及所有 td 加边框 */
|
/* 给 table 及所有 td 加边框 */
|
||||||
table {
|
table {
|
||||||
border-collapse: collapse;
|
border-collapse: collapse;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
table-layout: auto; /* 宽度自适应内容 */
|
table-layout: auto;
|
||||||
|
/* 宽度自适应内容 */
|
||||||
|
|
||||||
.time-picker-box {
|
.time-picker-box {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
gap: 10px;
|
gap: 10px;
|
||||||
|
|
||||||
img {
|
img {
|
||||||
width: 20px;
|
width: 20px;
|
||||||
height: 20px;
|
height: 20px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
td {
|
td {
|
||||||
height: 59px;
|
height: 59px;
|
||||||
border: 1px solid #dcdfe6;
|
border: 1px solid #dcdfe6;
|
||||||
padding: 4px 8px; /* 内边距缩小 */
|
padding: 4px 8px;
|
||||||
|
/* 内边距缩小 */
|
||||||
text-align: center;
|
text-align: center;
|
||||||
font-size: 12px; /* 文字变小 */
|
font-size: 12px;
|
||||||
white-space: nowrap; /* 文字不换行 */
|
/* 文字变小 */
|
||||||
vertical-align: middle; /* 垂直居中 */
|
white-space: nowrap;
|
||||||
|
/* 文字不换行 */
|
||||||
|
vertical-align: middle;
|
||||||
|
/* 垂直居中 */
|
||||||
|
|
||||||
/* 时间选择器容器:两个选择器横排不换行 */
|
/* 时间选择器容器:两个选择器横排不换行 */
|
||||||
:deep(.el-time-picker) {
|
:deep(.el-time-picker) {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
|
|
||||||
.el-range-editor {
|
.el-range-editor {
|
||||||
width: 100px; /* 缩小时间选择器宽度 */
|
width: 100px;
|
||||||
|
/* 缩小时间选择器宽度 */
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.el-range-input {
|
.el-range-input {
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
<!-- 搜索 -->
|
<!-- 搜索 -->
|
||||||
<VarietySearch
|
<VarietySearch
|
||||||
:search-form="searchForm"
|
:search-form="searchForm"
|
||||||
|
:buttonLoading="loading"
|
||||||
:search-options="searchOptions"
|
:search-options="searchOptions"
|
||||||
@search="handleSearch"
|
@search="handleSearch"
|
||||||
@reset="handleReset"
|
@reset="handleReset"
|
||||||
|
|
@ -28,6 +29,7 @@
|
||||||
:columns="varietyTableColumnsOptions"
|
:columns="varietyTableColumnsOptions"
|
||||||
row-key="id"
|
row-key="id"
|
||||||
@row-click="handleRowClick"
|
@row-click="handleRowClick"
|
||||||
|
:loading="loading"
|
||||||
>
|
>
|
||||||
<template #onlineStatus="{ row }">
|
<template #onlineStatus="{ row }">
|
||||||
{{ ['', '上线', '下线'][row.onlineStatus] }}
|
{{ ['', '上线', '下线'][row.onlineStatus] }}
|
||||||
|
|
@ -42,6 +44,7 @@
|
||||||
:visible="dialogVisible"
|
:visible="dialogVisible"
|
||||||
:title="dialogTitle"
|
:title="dialogTitle"
|
||||||
:type="dialogType"
|
:type="dialogType"
|
||||||
|
:button-loading="submitLoading"
|
||||||
@confirm="handleSubmit"
|
@confirm="handleSubmit"
|
||||||
@cancel="handleCancel"
|
@cancel="handleCancel"
|
||||||
@close="handleClose"
|
@close="handleClose"
|
||||||
|
|
@ -94,6 +97,10 @@ defineOptions({
|
||||||
name: 'Variety'
|
name: 'Variety'
|
||||||
})
|
})
|
||||||
// 组件
|
// 组件
|
||||||
|
import { usePageLoading, useButtonLoading } from '@/composables/useLoading'
|
||||||
|
const { loading, startLoading, stopLoading } = usePageLoading()
|
||||||
|
const { buttonLoading: submitLoading, startButtonLoading: startSubmitLoading, stopButtonLoading: stopSubmitLoading } = useButtonLoading()
|
||||||
|
|
||||||
import VarietySearch from '@/components/common/Search.vue'
|
import VarietySearch from '@/components/common/Search.vue'
|
||||||
import VarietyTable from '@/components/common/Table.vue'
|
import VarietyTable from '@/components/common/Table.vue'
|
||||||
import VarietyDialog from '@/components/common/Dialog.vue'
|
import VarietyDialog from '@/components/common/Dialog.vue'
|
||||||
|
|
@ -233,31 +240,36 @@ const typeMap: any = {
|
||||||
|
|
||||||
//获取品种列表
|
//获取品种列表
|
||||||
const getVarietyList = async () => {
|
const getVarietyList = async () => {
|
||||||
|
startLoading()
|
||||||
const params = {
|
const params = {
|
||||||
name: searchForm.value.varietyName,
|
name: searchForm.value.varietyName,
|
||||||
}
|
}
|
||||||
const data = await getVarietyListApi(params)
|
try {
|
||||||
console.log('data', data)
|
const data = await getVarietyListApi(params)
|
||||||
//格式化表格数据
|
console.log('data', data)
|
||||||
varietyTree.value = data.map((item: any) => ({
|
//格式化表格数据
|
||||||
...item,
|
varietyTree.value = data.map((item: any) => ({
|
||||||
id: item.id,
|
...item,
|
||||||
varietyName: item.name,
|
id: item.id,
|
||||||
varietyCode: item.code,
|
varietyName: item.name,
|
||||||
onlineStatus: item.online_status,
|
varietyCode: item.code,
|
||||||
tradeStatus: item.status,
|
onlineStatus: item.online_status,
|
||||||
minPoint: item.point_diff,
|
tradeStatus: item.status,
|
||||||
maxPoint: item.point_diff_max,
|
minPoint: item.point_diff,
|
||||||
contractSize: item.multiplier,
|
maxPoint: item.point_diff_max,
|
||||||
minFlux: item.undulate_min,
|
contractSize: item.multiplier,
|
||||||
unit: item.unit,
|
minFlux: item.undulate_min,
|
||||||
tradeGroup: item.group.name,
|
unit: item.unit,
|
||||||
longStockFee: item.fee_inventory_long,
|
tradeGroup: item.group.name,
|
||||||
shortStockFee: item.fee_inventory_short,
|
longStockFee: item.fee_inventory_long,
|
||||||
profitLevel: item.stop_loss_level,
|
shortStockFee: item.fee_inventory_short,
|
||||||
type: typeMap[item.type],
|
profitLevel: item.stop_loss_level,
|
||||||
image: item.image,
|
type: typeMap[item.type],
|
||||||
}))
|
image: item.image,
|
||||||
|
}))
|
||||||
|
} finally {
|
||||||
|
stopLoading()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取合约品种分组列表
|
// 获取合约品种分组列表
|
||||||
|
|
@ -434,47 +446,52 @@ const beforeUpload = (file: File) => {
|
||||||
* @description: 定义弹窗方法
|
* @description: 定义弹窗方法
|
||||||
*/
|
*/
|
||||||
const handleSubmit = async () => {
|
const handleSubmit = async () => {
|
||||||
await varietyFormRef.value?.validate()
|
startSubmitLoading()
|
||||||
console.log(varietyForm.value)
|
try {
|
||||||
const params = {
|
await varietyFormRef.value?.validate()
|
||||||
id: varietyForm.value.id,
|
console.log(varietyForm.value)
|
||||||
code: varietyForm.value.varietyCode,
|
const params = {
|
||||||
name: varietyForm.value.varietyName,
|
id: varietyForm.value.id,
|
||||||
point_diff: varietyForm.value.minPoint,
|
code: varietyForm.value.varietyCode,
|
||||||
fee_inventory_short: varietyForm.value.shortStockFee,
|
name: varietyForm.value.varietyName,
|
||||||
status: varietyForm.value.tradeStatus,
|
point_diff: varietyForm.value.minPoint,
|
||||||
bail_hedge: varietyForm.value.prepaymentHedge,
|
fee_inventory_short: varietyForm.value.shortStockFee,
|
||||||
bail_percent: varietyForm.value.prepaymentPercent,
|
status: varietyForm.value.tradeStatus,
|
||||||
decimal_place: varietyForm.value.decimalPlaces,
|
bail_hedge: varietyForm.value.prepaymentHedge,
|
||||||
stop_loss_level: varietyForm.value.profitLevel,
|
bail_percent: varietyForm.value.prepaymentPercent,
|
||||||
point_diff_max: varietyForm.value.maxPoint,
|
decimal_place: varietyForm.value.decimalPlaces,
|
||||||
fee_inventory_long: varietyForm.value.longStockFee,
|
stop_loss_level: varietyForm.value.profitLevel,
|
||||||
point_diff_decimal_place: varietyForm.value.pointDecimalPlaces,
|
point_diff_max: varietyForm.value.maxPoint,
|
||||||
unit: varietyForm.value.unit,
|
fee_inventory_long: varietyForm.value.longStockFee,
|
||||||
multiplier: varietyForm.value.contractSize,
|
point_diff_decimal_place: varietyForm.value.pointDecimalPlaces,
|
||||||
undulate_min: varietyForm.value.minFlux,
|
unit: varietyForm.value.unit,
|
||||||
online_status: varietyForm.value.onlineStatus,
|
multiplier: varietyForm.value.contractSize,
|
||||||
type: Number(varietyForm.value.type),
|
undulate_min: varietyForm.value.minFlux,
|
||||||
image: varietyForm.value.imageUrl,
|
online_status: varietyForm.value.onlineStatus,
|
||||||
fee_inventory_time: varietyForm.value.feeInventoryTime,
|
type: Number(varietyForm.value.type),
|
||||||
group_id: varietyForm.value.group_id,
|
image: varietyForm.value.imageUrl,
|
||||||
}
|
fee_inventory_time: varietyForm.value.feeInventoryTime,
|
||||||
console.log(params)
|
group_id: varietyForm.value.group_id,
|
||||||
|
}
|
||||||
if (dialogType.value === 'edit') {
|
|
||||||
console.log(params)
|
console.log(params)
|
||||||
if (params.point_diff_max < params.point_diff)
|
|
||||||
return ElMessage.warning('最大点差不能小于最小点差')
|
if (dialogType.value === 'edit') {
|
||||||
await editVarietyApi({
|
console.log(params)
|
||||||
...params,
|
if (params.point_diff_max < params.point_diff)
|
||||||
is_default: varietyForm.value.isDefault,
|
return ElMessage.warning('最大点差不能小于最小点差')
|
||||||
})
|
await editVarietyApi({
|
||||||
await getVarietyList()
|
...params,
|
||||||
} else {
|
is_default: varietyForm.value.isDefault,
|
||||||
await createVarietyApi({ ...params })
|
})
|
||||||
await getVarietyList()
|
await getVarietyList()
|
||||||
|
} else {
|
||||||
|
await createVarietyApi({ ...params })
|
||||||
|
await getVarietyList()
|
||||||
|
}
|
||||||
|
dialogVisible.value = false
|
||||||
|
} finally {
|
||||||
|
stopSubmitLoading()
|
||||||
}
|
}
|
||||||
dialogVisible.value = false
|
|
||||||
}
|
}
|
||||||
const handleCancel = () => {
|
const handleCancel = () => {
|
||||||
dialogVisible.value = false
|
dialogVisible.value = false
|
||||||
|
|
|
||||||
|
|
@ -33,9 +33,9 @@ export const tableColumns = [
|
||||||
// 交易分组
|
// 交易分组
|
||||||
{ prop: 'tradeGroup', label: '交易分组', align: 'center' as const },
|
{ prop: 'tradeGroup', label: '交易分组', align: 'center' as const },
|
||||||
// 多头库存费
|
// 多头库存费
|
||||||
{ prop: 'longStockFee', label: '多头库存费', align: 'center' as const },
|
{ prop: 'longStockFee', label: '多头库存费', align: 'center' as const, isNumber: true },
|
||||||
// 空头库存费
|
// 空头库存费
|
||||||
{ prop: 'shortStockFee', label: '空头库存费', align: 'center' as const },
|
{ prop: 'shortStockFee', label: '空头库存费', align: 'center' as const, isNumber: true },
|
||||||
// 类型
|
// 类型
|
||||||
{ prop: 'type', label: '类型', align: 'center' as const },
|
{ prop: 'type', label: '类型', align: 'center' as const },
|
||||||
// 止盈水平
|
// 止盈水平
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,7 @@
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</Transition>
|
</Transition>
|
||||||
<el-form-item class="form-submit">
|
<el-form-item class="form-submit">
|
||||||
<el-button type="primary" @click="handleLogin">登录</el-button>
|
<el-button type="primary" @click="handleLogin" :loading="activeTab === 'password' && buttonLoading">登录</el-button>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<router-link to="/user/register" class="to-register">没有账号?去注册</router-link>
|
<router-link to="/user/register" class="to-register">没有账号?去注册</router-link>
|
||||||
</el-form>
|
</el-form>
|
||||||
|
|
@ -74,6 +74,7 @@ import UserTabs from './components/Tabs.vue'
|
||||||
|
|
||||||
//公共方法/store/配置文件
|
//公共方法/store/配置文件
|
||||||
import { useUserStore } from '@/stores/modules/user'
|
import { useUserStore } from '@/stores/modules/user'
|
||||||
|
import { useButtonLoading } from '@/composables/useLoading'
|
||||||
import { setStorage, getStorage } from '@/utils/storage'
|
import { setStorage, getStorage } from '@/utils/storage'
|
||||||
import { md5Encrypt } from '@/utils/crypto'
|
import { md5Encrypt } from '@/utils/crypto'
|
||||||
|
|
||||||
|
|
@ -83,6 +84,9 @@ import { passwordRules, emailRules, phoneRules, codeRules } from './config/rules
|
||||||
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
|
|
||||||
|
// 按钮 loading
|
||||||
|
const { buttonLoading, startButtonLoading, stopButtonLoading } = useButtonLoading()
|
||||||
|
|
||||||
//userText 实例
|
//userText 实例
|
||||||
const userText = ref({
|
const userText = ref({
|
||||||
backText: '',
|
backText: '',
|
||||||
|
|
@ -179,19 +183,26 @@ const handleLogin = async () => {
|
||||||
else if (currentTab === 'password') {
|
else if (currentTab === 'password') {
|
||||||
// 校验密码+验证码
|
// 校验密码+验证码
|
||||||
await loginFormRef.value.validateField(['password', 'code'])
|
await loginFormRef.value.validateField(['password', 'code'])
|
||||||
// 生成device_no并保存到变量(关键修改1)
|
// 开启 loading
|
||||||
const deviceNo = generateTimestampWithRandomNum()
|
startButtonLoading()
|
||||||
// 登录参数
|
try {
|
||||||
const loginParams = {
|
// 生成device_no并保存到变量(关键修改1)
|
||||||
email: loginForm.value.email,
|
const deviceNo = generateTimestampWithRandomNum()
|
||||||
mobile: loginForm.value.countryCode + loginForm.value.phone,
|
// 登录参数
|
||||||
login_type: getStorage('loginType', 'session') === 'email' ? 1 : 2,
|
const loginParams = {
|
||||||
code: loginForm.value.code,
|
email: loginForm.value.email,
|
||||||
password: loginForm.value.password,
|
mobile: loginForm.value.countryCode + loginForm.value.phone,
|
||||||
device_no: deviceNo,
|
login_type: getStorage('loginType', 'session') === 'email' ? 1 : 2,
|
||||||
|
code: loginForm.value.code,
|
||||||
|
password: loginForm.value.password,
|
||||||
|
device_no: deviceNo,
|
||||||
|
}
|
||||||
|
await userStore.login(loginParams)
|
||||||
|
setStorage('device_no', deviceNo)
|
||||||
|
} finally {
|
||||||
|
// 关闭 loading
|
||||||
|
stopButtonLoading()
|
||||||
}
|
}
|
||||||
await userStore.login(loginParams)
|
|
||||||
setStorage('device_no', deviceNo)
|
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('表单校验失败:', error)
|
console.error('表单校验失败:', error)
|
||||||
|
|
|
||||||
|
|
@ -94,7 +94,7 @@
|
||||||
>
|
>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item class="form-submit">
|
<el-form-item class="form-submit">
|
||||||
<el-button type="primary" class="form-btn" @click="handleRegister">注册</el-button>
|
<el-button type="primary" class="form-btn" @click="handleRegister" :loading="buttonLoading">注册</el-button>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<router-link to="/user/login" class="to-login">已有账号?立即登录</router-link>
|
<router-link to="/user/login" class="to-login">已有账号?立即登录</router-link>
|
||||||
</el-form>
|
</el-form>
|
||||||
|
|
@ -118,6 +118,7 @@ import UserCaptcha from './components/Captcha.vue'
|
||||||
import { useUserStore } from '@/stores/modules/user'
|
import { useUserStore } from '@/stores/modules/user'
|
||||||
import { md5Encrypt } from '@/utils/crypto'
|
import { md5Encrypt } from '@/utils/crypto'
|
||||||
import { sendCaptcha, initCaptchaState, clearCaptchaTimer } from '@/utils/sendCaptcha'
|
import { sendCaptcha, initCaptchaState, clearCaptchaTimer } from '@/utils/sendCaptcha'
|
||||||
|
import { useButtonLoading } from '@/composables/useLoading'
|
||||||
|
|
||||||
//用户校验规则
|
//用户校验规则
|
||||||
import { countryOptions } from '@/views/user/config/mock'
|
import { countryOptions } from '@/views/user/config/mock'
|
||||||
|
|
@ -128,6 +129,9 @@ import { useRoute } from 'vue-router'
|
||||||
const userStore = useUserStore()
|
const userStore = useUserStore()
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
|
|
||||||
|
// 按钮 loading
|
||||||
|
const { buttonLoading, startButtonLoading, stopButtonLoading } = useButtonLoading()
|
||||||
|
|
||||||
// UserText 实例
|
// UserText 实例
|
||||||
const userText = ref({
|
const userText = ref({
|
||||||
backText: '',
|
backText: '',
|
||||||
|
|
@ -215,19 +219,25 @@ const handleRegister = async () => {
|
||||||
try {
|
try {
|
||||||
// 提交时再次验证(显示错误提示)
|
// 提交时再次验证(显示错误提示)
|
||||||
await registerFormRef.value.validate()
|
await registerFormRef.value.validate()
|
||||||
|
// 开启 loading
|
||||||
|
startButtonLoading()
|
||||||
|
try {
|
||||||
|
// 注册参数
|
||||||
|
const registerParams = {
|
||||||
|
email: registerForm.value.email,
|
||||||
|
mobile: registerForm.value.countryCode + registerForm.value.phone,
|
||||||
|
reg_type: activeTab.value === 'email' ? 1 : 2,
|
||||||
|
invite_code: registerForm.value.inviteCode,
|
||||||
|
code: registerForm.value.code,
|
||||||
|
password: registerForm.value.password,
|
||||||
|
}
|
||||||
|
|
||||||
// 注册参数
|
// 注册逻辑
|
||||||
const registerParams = {
|
await userStore.register(registerParams)
|
||||||
email: registerForm.value.email,
|
} finally {
|
||||||
mobile: registerForm.value.countryCode + registerForm.value.phone,
|
// 关闭 loading
|
||||||
reg_type: activeTab.value === 'email' ? 1 : 2,
|
stopButtonLoading()
|
||||||
invite_code: registerForm.value.inviteCode,
|
|
||||||
code: registerForm.value.code,
|
|
||||||
password: registerForm.value.password,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 注册逻辑
|
|
||||||
await userStore.register(registerParams)
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('表单校验失败:', error)
|
console.error('表单校验失败:', error)
|
||||||
}
|
}
|
||||||
|
|
@ -239,7 +249,7 @@ onUnmounted(() => {
|
||||||
})
|
})
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
registerForm.value.inviteCode = route.query.invite_code
|
registerForm.value.inviteCode = route.query.invite_code || ''
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue