节假日,系统设置

This commit is contained in:
Songsl 2026-04-19 15:10:30 +08:00
parent 93893c2918
commit 214bc66b1c
11 changed files with 829 additions and 519 deletions

View File

@ -1,8 +1,8 @@
# 开发环境标识Vite 内置变量,无需修改) # 开发环境标识Vite 内置变量,无需修改)
NODE_ENV = development NODE_ENV = development
# 开发环境接口基础地址(对应你配置的 192.168.10.10:8085/api # 开发环境接口基础地址(对应你配置的 192.168.11.113:8085/api
VITE_API_BASE_URL = http://192.168.10.10:8085/api VITE_API_BASE_URL = http://192.168.11.113:8085/api
# 请求超时时间(毫秒) # 请求超时时间(毫秒)
VITE_REQUEST_TIMEOUT = 10000 VITE_REQUEST_TIMEOUT = 10000

View File

@ -2,7 +2,8 @@ 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 { ElLoading, ElNotification } from 'element-plus'
import { getStorage, setStorage } from '@/utils/storage' import { getStorage, setStorage, removeStorage } from '@/utils/storage'
import router from '../router'
// 定义loading实例类型用于控制loading的显示和关闭 // 定义loading实例类型用于控制loading的显示和关闭
let loadingInstance: ReturnType<typeof ElLoading.service> | null = null let loadingInstance: ReturnType<typeof ElLoading.service> | null = null
@ -14,7 +15,7 @@ const showLoading = () => {
if (requestCount === 0 && !loadingInstance) { if (requestCount === 0 && !loadingInstance) {
loadingInstance = ElLoading.service({ loadingInstance = ElLoading.service({
lock: true, // 锁定屏幕滚动 lock: true, // 锁定屏幕滚动
fullscreen: true // 全屏显示 fullscreen: true, // 全屏显示
}) })
} }
requestCount++ requestCount++
@ -46,7 +47,7 @@ const service = axios.create({
// 3. 请求拦截器:直接使用 axios 内置类型 // 3. 请求拦截器:直接使用 axios 内置类型
const requestInterceptor = (config: InternalAxiosRequestConfig) => { const requestInterceptor = (config: InternalAxiosRequestConfig) => {
console.log('请求配置', config); console.log('请求配置', config)
// 显示loading可通过config配置项控制是否显示比如某些请求不需要loading // 显示loading可通过config配置项控制是否显示比如某些请求不需要loading
if (config.headers?.showLoading !== false) { if (config.headers?.showLoading !== false) {
@ -81,9 +82,9 @@ const responseInterceptor = <T = unknown>(response: AxiosResponse<ApiResponse<T>
if (response.headers['new_token'] !== undefined) { if (response.headers['new_token'] !== undefined) {
setStorage('token', response.headers['new_token'] as string) setStorage('token', response.headers['new_token'] as string)
} }
console.log('响应response', response); console.log('响应response', response)
const { data } = response const { data } = response
console.log('响应数据data', data); console.log('响应数据data', data)
// 判断业务状态码 // 判断业务状态码
if (data.code == 200 || data.code == 0) { if (data.code == 200 || data.code == 0) {
// 仅当业务成功时,才弹成功提示 // 仅当业务成功时,才弹成功提示
@ -91,23 +92,23 @@ const responseInterceptor = <T = unknown>(response: AxiosResponse<ApiResponse<T>
message: data.msg || '操作成功!', message: data.msg || '操作成功!',
type: 'success', type: 'success',
duration: 2000, duration: 2000,
customClass: 'global-notification' customClass: 'global-notification',
}) })
return data.data return data.data
} else { } else {
if (data.code === 1) { switch (data.code) {
// 不弹错误提示,返回带特殊标识的结果 case 1:
// 其他业务失败弹错误提示并拒绝Promise if (!data.msg) {
ElNotification({ data.msg = '未知的错误!'
message: data.msg || '未知的错误!', }
type: 'error', break
duration: 2000, case -101:
customClass: 'global-notification' data.msg = 'token错误'
}) removeStorage('token')
const result = { router.push({ name: 'Login' })
isUserNotExist: true, // 自定义标识,标记“用户不存在” break
} as T default:
return result break;
} }
// 其他业务失败弹错误提示并拒绝Promise // 其他业务失败弹错误提示并拒绝Promise
@ -115,7 +116,7 @@ const responseInterceptor = <T = unknown>(response: AxiosResponse<ApiResponse<T>
message: data.msg || '未知的错误!', message: data.msg || '未知的错误!',
type: 'error', type: 'error',
duration: 2000, duration: 2000,
customClass: 'global-notification' customClass: 'global-notification',
}) })
return Promise.reject(data) return Promise.reject(data)
} }
@ -159,7 +160,7 @@ const responseErrorInterceptor = (error: AxiosError) => {
message: errMsg, message: errMsg,
type: 'error', type: 'error',
duration: 2000, duration: 2000,
customClass: 'global-notification' customClass: 'global-notification',
}) })
return Promise.reject(error) return Promise.reject(error)
} }
@ -170,13 +171,13 @@ service.interceptors.response.use(responseInterceptor, responseErrorInterceptor)
export const request = { export const request = {
get<T = unknown>(url: string, params?: unknown, config?: InternalAxiosRequestConfig): Promise<T> { get<T = unknown>(url: string, params?: unknown, config?: InternalAxiosRequestConfig): Promise<T> {
return service.get<ApiResponse<T>>(url, { params, ...config }).then((res) => { return service.get<ApiResponse<T>>(url, { params, ...config }).then((res) => {
return res as T; return res as T
}); })
}, },
post<T = unknown>(url: string, data?: unknown, config?: InternalAxiosRequestConfig): Promise<T> { post<T = unknown>(url: string, data?: unknown, config?: InternalAxiosRequestConfig): Promise<T> {
return service.post<ApiResponse<T>>(url, data, config).then((res) => { return service.post<ApiResponse<T>>(url, data, config).then((res) => {
return res as T; return res as T
}); })
}, },
} }

View File

@ -0,0 +1,38 @@
import { request } from '@/api';
type SettingFormParams = {
key: string
value: string
description: string
}
type SettingListResponse = SettingFormParams & {
id: number
}
/**
*
* @returns Promise<MenuListResponse>
*/
export async function getSettingApi(): Promise<SettingListResponse[]> {
return request.get<SettingListResponse[]>('/setting/getList')
}
/**
*
* @param params
* @returns Promise<void>
*/
export async function createSettingApi(params: SettingFormParams): Promise<void> {
return request.post<void>('/setting/add', params)
}
/**
*
* @param params id
* @returns Promise<void>
*/
export async function editSettingApi(params: SettingFormParams): Promise<void> {
return request.post<void>('/setting/edit', params)
}

View File

@ -0,0 +1,21 @@
import { request } from '@/api';
// 获取节假日列表
export async function getHolidayList(): Promise<any> {
return request.get<any>('/contractVariety/getHolidayList')
}
// 添加节假日
export async function addHoliday(params: any): Promise<any> {
return request.post<any>('/contractVariety/addHoliday', { ...params })
}
//编辑节假日
export async function editHoliday(params: any): Promise<any> {
return request.post<any>('/contractVariety/editHoliday', { ...params })
}
// 删除节假日
export async function delHoliday(params: any): Promise<any> {
return request.post<any>('/contractVariety/delHoliday', { ...params })
}

View File

@ -38,12 +38,20 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { HomeFilled, List, UserFilled, Platform, BellFilled, GoodsFilled, WarningFilled, Tools } from '@element-plus/icons-vue' import {
HomeFilled,
List,
UserFilled,
Platform,
BellFilled,
GoodsFilled,
WarningFilled,
Tools,
} from '@element-plus/icons-vue'
// //
import { useUserStore } from '@/stores/modules/user' import { useUserStore } from '@/stores/modules/user'
const route = useRoute() const route = useRoute()
const userStore = useUserStore() const userStore = useUserStore()
const menuList = ref<any[]>([]) const menuList = ref<any[]>([])
@ -66,22 +74,20 @@ const iconMap: Record<string, any> = {
BellFilled, BellFilled,
GoodsFilled, GoodsFilled,
WarningFilled, WarningFilled,
Tools Tools,
} }
// //
import type { ElMenuItem } from '@/utils/menuFormat'; import type { ElMenuItem } from '@/utils/menuFormat'
// //
const staticMenuList = ref<ElMenuItem[]>( const staticMenuList = ref<ElMenuItem[]>([
[
// //
{ {
id: 1, id: 1,
label: '首页', label: '首页',
path: 'dashboard', // el-menu-item index="dashboard" path: 'dashboard', // el-menu-item index="dashboard"
icon: 'HomeFilled' // 对应 <HomeFilled /> icon: 'HomeFilled', // <HomeFilled />
}, },
// //
// { // {
@ -110,33 +116,33 @@ const staticMenuList = ref<ElMenuItem[]>(
id: 31, id: 31,
label: '客户管理', label: '客户管理',
path: '/account/client', // index="client" path: '/account/client', // index="client"
icon: '' icon: '',
}, },
{ {
id: 32, id: 32,
label: '代理管理', label: '代理管理',
path: '/account/agentList', // index="3-2" path: '/account/agentList', // index="3-2"
icon: '' icon: '',
}, },
{ {
id: 33, id: 33,
label: '做市商管理', label: '做市商管理',
path: '/account/market-maker', // index="3-3" path: '/account/market-maker', // index="3-3"
icon: '' icon: '',
}, },
{ {
id: 34, id: 34,
label: '档案管理', label: '档案管理',
path: '/account/archives', // index="3-4" path: '/account/archives', // index="3-4"
icon: '' icon: '',
}, },
{ {
id: 35, id: 35,
label: '账号管理', label: '账号管理',
path: '/account/accountDetail', // index="3-5" path: '/account/accountDetail', // index="3-5"
icon: '' icon: '',
}, },
] ],
}, },
// //
{ {
@ -149,46 +155,46 @@ const staticMenuList = ref<ElMenuItem[]>(
id: 41, id: 41,
label: '品种', label: '品种',
path: '/trade/variety', // index="4-1" path: '/trade/variety', // index="4-1"
icon: '' icon: '',
}, },
{ {
id: 42, id: 42,
label: '交易组', label: '交易组',
path: '/trade/group', // index="4-2" path: '/trade/group', // index="4-2"
icon: '' icon: '',
}, },
{ {
id: 43, id: 43,
label: '持仓统计', label: '持仓统计',
path: '/trade/positionStat', // index="4-3" path: '/trade/positionStat', // index="4-3"
icon: '' icon: '',
}, },
{ {
id: 44, id: 44,
label: '历史交易', label: '历史交易',
path: '/trade/historyTrade', // index="4-4" path: '/trade/historyTrade', // index="4-4"
icon: '' icon: '',
}, },
{ {
id: 45, id: 45,
label: '交易软件', label: '交易软件',
path: '/trade/tradeSoftware', // index="4-5" path: '/trade/tradeSoftware', // index="4-5"
icon: '' icon: '',
}, },
{ {
id: 46, id: 46,
label: '交易时间', label: '交易时间',
path: '/trade/time', // index="4-3" path: '/trade/time', // index="4-3"
icon: '' icon: '',
} },
] ],
}, },
// //
{ {
id: 5, id: 5,
label: '公告管理', label: '公告管理',
path: '/notice', // index="5" path: '/notice', // index="5"
icon: 'BellFilled' // 对应 <BellFilled /> icon: 'BellFilled', // <BellFilled />
}, },
// //
{ {
@ -225,19 +231,19 @@ const staticMenuList = ref<ElMenuItem[]>(
id: 64, id: 64,
label: '转账', label: '转账',
path: '/funding/transfer', // index="6-4" path: '/funding/transfer', // index="6-4"
icon: '' icon: '',
}, },
{ {
id: 65, id: 65,
label: '转账明细', label: '转账明细',
path: '/funding/transferDetail', // index="6-5" path: '/funding/transferDetail', // index="6-5"
icon: '' icon: '',
}, },
{ {
id: 66, id: 66,
label: '资金明细', label: '资金明细',
path: '/funding/fundDetail', // index="6-6" path: '/funding/fundDetail', // index="6-6"
icon: '' icon: '',
}, },
// { // {
// id: 66, // id: 66,
@ -257,7 +263,7 @@ const staticMenuList = ref<ElMenuItem[]>(
// path: '/funding/depositChannel', // index="6-8" // path: '/funding/depositChannel', // index="6-8"
// icon: '' // icon: ''
// } // }
] ],
}, },
// //
{ {
@ -270,25 +276,30 @@ const staticMenuList = ref<ElMenuItem[]>(
id: 71, id: 71,
label: '菜单管理', label: '菜单管理',
path: '/system/menu', // index="6-1" index 6-1 path: '/system/menu', // index="6-1" index 6-1
icon: '' icon: '',
}, },
{ {
id: 72, id: 72,
label: '角色管理', label: '角色管理',
path: '/system/role', // index="6-2" index 6-2 path: '/system/role', // index="6-2" index 6-2
icon: '' icon: '',
} },
] {
id: 73,
label: '系统设置',
path: '/system/setting', // index="6-2" index 6-2
icon: '',
},
],
}, },
// //
{ {
id: 8, id: 8,
label: '风控管理', label: '风控管理',
path: '/risk', // index="8" path: '/risk', // index="8"
icon: 'WarningFilled' // 对应 <WarningFilled /> icon: 'WarningFilled', // <WarningFilled />
}, },
// //
// { // {
// id: 9, // id: 9,
@ -337,16 +348,16 @@ const staticMenuList = ref<ElMenuItem[]>(
id: 121, id: 121,
label: '跟单记录', label: '跟单记录',
path: '/personalized/followRecord', // index="12-1" path: '/personalized/followRecord', // index="12-1"
icon: '' icon: '',
}, },
// //
{ {
id: 122, id: 122,
label: '带单记录', label: '带单记录',
path: '/personalized/leadRecord', // index="12-2" path: '/personalized/leadRecord', // index="12-2"
icon: '' icon: '',
}, },
] ],
}, },
// //
{ {
@ -360,23 +371,23 @@ const staticMenuList = ref<ElMenuItem[]>(
id: 132, id: 132,
label: '客户列表', label: '客户列表',
path: '/agent/customerList', // index="13-2" path: '/agent/customerList', // index="13-2"
icon: '' icon: '',
}, },
// //
{ {
id: 133, id: 133,
label: '客户交易订单', label: '客户交易订单',
path: '/agent/customerTradeOrder', // index="13-3" path: '/agent/customerTradeOrder', // index="13-3"
icon: '' icon: '',
}, },
// //
{ {
id: 135, id: 135,
label: '客户资金流水', label: '客户资金流水',
path: '/agent/customerCapitalFlow', // index="13-5" path: '/agent/customerCapitalFlow', // index="13-5"
icon: '' icon: '',
}, },
] ],
}, },
// //
{ {
@ -385,8 +396,7 @@ const staticMenuList = ref<ElMenuItem[]>(
path: 'notification', // index="notification" path: 'notification', // index="notification"
icon: 'NotificationFilled', // <NotificationFilled /> icon: 'NotificationFilled', // <NotificationFilled />
}, },
] ])
)
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
@ -414,9 +424,8 @@ aside {
border: none; border: none;
:deep(.el-menu-item.is-active) { :deep(.el-menu-item.is-active) {
background-color: var(--el-menu-hover-bg-color) background-color: var(--el-menu-hover-bg-color);
} }
} }
} }
</style> </style>

View File

@ -14,39 +14,39 @@ const routes = [
path: 'login', path: 'login',
name: 'Login', name: 'Login',
component: () => import('@/views/user/Login.vue'), component: () => import('@/views/user/Login.vue'),
meta: { isAuthPage: true, title: '登录' } meta: { isAuthPage: true, title: '登录' },
}, },
{ {
path: 'register', path: 'register',
name: 'Register', name: 'Register',
component: () => import('@/views/user/Register.vue'), component: () => import('@/views/user/Register.vue'),
meta: { isAuthPage: true, title: '注册' } meta: { isAuthPage: true, title: '注册' },
}, },
{ {
path: 'forgot-password', path: 'forgot-password',
name: 'ForgotPassword', name: 'ForgotPassword',
component: () => import('@/views/user/ForgotPassword.vue'), component: () => import('@/views/user/ForgotPassword.vue'),
meta: { isAuthPage: true, title: '忘记密码' } meta: { isAuthPage: true, title: '忘记密码' },
}, },
{ {
path: 'change-password', path: 'change-password',
name: 'ChangePassword', name: 'ChangePassword',
component: () => import('@/views/user/ChangePassword.vue'), component: () => import('@/views/user/ChangePassword.vue'),
meta: { requiresAuth: true, title: '修改密码' } meta: { requiresAuth: true, title: '修改密码' },
}, },
{ {
path: 'bind-email', path: 'bind-email',
name: 'BindEmail', name: 'BindEmail',
component: () => import('@/views/user/bindEmail.vue'), component: () => import('@/views/user/bindEmail.vue'),
meta: { requiresAuth: true, title: '绑定邮箱' } meta: { requiresAuth: true, title: '绑定邮箱' },
}, },
{ {
path: 'bind-phone', path: 'bind-phone',
name: 'BindPhone', name: 'BindPhone',
component: () => import('@/views/user/bindPhone.vue'), component: () => import('@/views/user/bindPhone.vue'),
meta: { requiresAuth: true, title: '绑定手机号' } meta: { requiresAuth: true, title: '绑定手机号' },
} },
] ],
}, },
// 带侧边栏布局的核心业务页面 // 带侧边栏布局的核心业务页面
{ {
@ -62,7 +62,7 @@ const routes = [
component: () => import('@/views/dashboard/index.vue'), component: () => import('@/views/dashboard/index.vue'),
meta: { meta: {
title: '首页', // 左侧菜单显示的标题 title: '首页', // 左侧菜单显示的标题
} },
}, },
// 系统管理 // 系统管理
{ {
@ -78,7 +78,7 @@ const routes = [
component: () => import('@/views/system/menu/index.vue'), component: () => import('@/views/system/menu/index.vue'),
meta: { meta: {
title: '菜单管理', // 左侧菜单显示的标题 title: '菜单管理', // 左侧菜单显示的标题
} },
}, },
{ {
path: 'role', path: 'role',
@ -86,9 +86,17 @@ const routes = [
component: () => import('@/views/system/role/index.vue'), component: () => import('@/views/system/role/index.vue'),
meta: { meta: {
title: '角色管理', // 左侧菜单显示的标题 title: '角色管理', // 左侧菜单显示的标题
} },
} },
] {
path: 'setting',
name: 'Setting',
component: () => import('@/views/system/setting/index.vue'),
meta: {
title: '系统设置', // 左侧菜单显示的标题
},
},
],
}, },
//模板配置 //模板配置
{ {
@ -97,7 +105,7 @@ const routes = [
meta: { meta: {
title: '模板配置', // 左侧菜单显示的标题 title: '模板配置', // 左侧菜单显示的标题
}, },
children: [] children: [],
}, },
//账户管理 //账户管理
{ {
@ -113,7 +121,7 @@ const routes = [
component: () => import('@/views/account/client/index.vue'), component: () => import('@/views/account/client/index.vue'),
meta: { meta: {
title: '客户管理', // 左侧菜单显示的标题 title: '客户管理', // 左侧菜单显示的标题
} },
}, },
{ {
path: 'agentList', path: 'agentList',
@ -121,7 +129,7 @@ const routes = [
component: () => import('@/views/account/agentList/index.vue'), component: () => import('@/views/account/agentList/index.vue'),
meta: { meta: {
title: '代理管理', // 左侧菜单显示的标题 title: '代理管理', // 左侧菜单显示的标题
} },
}, },
{ {
path: 'market-maker', path: 'market-maker',
@ -129,7 +137,7 @@ const routes = [
component: () => import('@/views/account/market-maker/index.vue'), component: () => import('@/views/account/market-maker/index.vue'),
meta: { meta: {
title: '做市商管理', // 左侧菜单显示的标题 title: '做市商管理', // 左侧菜单显示的标题
} },
}, },
{ {
path: 'archives', path: 'archives',
@ -137,7 +145,7 @@ const routes = [
component: () => import('@/views/account/archives/index.vue'), component: () => import('@/views/account/archives/index.vue'),
meta: { meta: {
title: '档案管理', // 左侧菜单显示的标题 title: '档案管理', // 左侧菜单显示的标题
} },
}, },
{ {
path: 'accountDetail', path: 'accountDetail',
@ -145,9 +153,9 @@ const routes = [
component: () => import('@/views/account/accountDetail/index.vue'), component: () => import('@/views/account/accountDetail/index.vue'),
meta: { meta: {
title: '账号管理', // 左侧菜单显示的标题 title: '账号管理', // 左侧菜单显示的标题
}
}, },
] },
],
}, },
//交易管理 //交易管理
{ {
@ -163,7 +171,7 @@ const routes = [
component: () => import('@/views/trade/variety/index.vue'), component: () => import('@/views/trade/variety/index.vue'),
meta: { meta: {
title: '品种', // 左侧菜单显示的标题 title: '品种', // 左侧菜单显示的标题
} },
}, },
{ {
path: 'group', path: 'group',
@ -171,7 +179,7 @@ const routes = [
component: () => import('@/views/trade/group/index.vue'), component: () => import('@/views/trade/group/index.vue'),
meta: { meta: {
title: '交易组', // 左侧菜单显示的标题 title: '交易组', // 左侧菜单显示的标题
} },
}, },
{ {
path: 'time', path: 'time',
@ -179,7 +187,7 @@ const routes = [
component: () => import('@/views/trade/time/index.vue'), component: () => import('@/views/trade/time/index.vue'),
meta: { meta: {
title: '交易时间', // 左侧菜单显示的标题 title: '交易时间', // 左侧菜单显示的标题
} },
}, },
{ {
path: 'positionStat', path: 'positionStat',
@ -187,7 +195,7 @@ const routes = [
component: () => import('@/views/trade/positionStat/index.vue'), component: () => import('@/views/trade/positionStat/index.vue'),
meta: { meta: {
title: '持仓统计', // 左侧菜单显示的标题 title: '持仓统计', // 左侧菜单显示的标题
} },
}, },
{ {
path: 'historyTrade', path: 'historyTrade',
@ -195,7 +203,7 @@ const routes = [
component: () => import('@/views/trade/historyTrade/index.vue'), component: () => import('@/views/trade/historyTrade/index.vue'),
meta: { meta: {
title: '历史交易', // 左侧菜单显示的标题 title: '历史交易', // 左侧菜单显示的标题
} },
}, },
{ {
path: 'tradeSoftware', path: 'tradeSoftware',
@ -203,9 +211,9 @@ const routes = [
component: () => import('@/views/trade/tradeSoftware/index.vue'), component: () => import('@/views/trade/tradeSoftware/index.vue'),
meta: { meta: {
title: '交易软件', // 左侧菜单显示的标题 title: '交易软件', // 左侧菜单显示的标题
}
}, },
] },
],
}, },
//公告管理 //公告管理
{ {
@ -230,7 +238,7 @@ const routes = [
component: () => import('@/views/funding/deposit/index.vue'), component: () => import('@/views/funding/deposit/index.vue'),
meta: { meta: {
title: '存款审核', // 左侧菜单显示的标题 title: '存款审核', // 左侧菜单显示的标题
} },
}, },
{ {
path: 'withdrawal', path: 'withdrawal',
@ -238,7 +246,7 @@ const routes = [
component: () => import('@/views/funding/withdrawl/index.vue'), component: () => import('@/views/funding/withdrawl/index.vue'),
meta: { meta: {
title: '取款审核', // 左侧菜单显示的标题 title: '取款审核', // 左侧菜单显示的标题
} },
}, },
{ {
path: 'withdrawalDetail', path: 'withdrawalDetail',
@ -246,7 +254,7 @@ const routes = [
component: () => import('@/views/funding/withdrawalDetail/index.vue'), component: () => import('@/views/funding/withdrawalDetail/index.vue'),
meta: { meta: {
title: '取款明细', // 左侧菜单显示的标题 title: '取款明细', // 左侧菜单显示的标题
} },
}, },
{ {
path: 'depositDetail', path: 'depositDetail',
@ -254,7 +262,7 @@ const routes = [
component: () => import('@/views/funding/depositDetail/index.vue'), component: () => import('@/views/funding/depositDetail/index.vue'),
meta: { meta: {
title: '存款明细', // 左侧菜单显示的标题 title: '存款明细', // 左侧菜单显示的标题
} },
}, },
{ {
path: 'transfer', path: 'transfer',
@ -262,7 +270,7 @@ const routes = [
component: () => import('@/views/funding/transfer/index.vue'), component: () => import('@/views/funding/transfer/index.vue'),
meta: { meta: {
title: '转账', // 左侧菜单显示的标题 title: '转账', // 左侧菜单显示的标题
} },
}, },
{ {
path: 'transferDetail', path: 'transferDetail',
@ -270,7 +278,7 @@ const routes = [
component: () => import('@/views/funding/transferDetail/index.vue'), component: () => import('@/views/funding/transferDetail/index.vue'),
meta: { meta: {
title: '转账明细', // 左侧菜单显示的标题 title: '转账明细', // 左侧菜单显示的标题
} },
}, },
{ {
path: 'capitalFlow', path: 'capitalFlow',
@ -278,7 +286,7 @@ const routes = [
component: () => import('@/views/funding/capitalFlow/index.vue'), component: () => import('@/views/funding/capitalFlow/index.vue'),
meta: { meta: {
title: '资金流水', // 左侧菜单显示的标题 title: '资金流水', // 左侧菜单显示的标题
} },
}, },
{ {
path: 'receiverAccount', path: 'receiverAccount',
@ -286,7 +294,7 @@ const routes = [
component: () => import('@/views/funding/receiverAccount/index.vue'), component: () => import('@/views/funding/receiverAccount/index.vue'),
meta: { meta: {
title: '收款账户列表', // 左侧菜单显示的标题 title: '收款账户列表', // 左侧菜单显示的标题
} },
}, },
{ {
path: 'depositChannel', path: 'depositChannel',
@ -294,7 +302,7 @@ const routes = [
component: () => import('@/views/funding/depositChannel/index.vue'), component: () => import('@/views/funding/depositChannel/index.vue'),
meta: { meta: {
title: '存款渠道列表', // 左侧菜单显示的标题 title: '存款渠道列表', // 左侧菜单显示的标题
} },
}, },
{ {
path: 'fundDetail', path: 'fundDetail',
@ -302,9 +310,9 @@ const routes = [
component: () => import('@/views/funding/fundDetail/index.vue'), component: () => import('@/views/funding/fundDetail/index.vue'),
meta: { meta: {
title: '资金明细', // 左侧菜单显示的标题 title: '资金明细', // 左侧菜单显示的标题
}
}, },
] },
],
}, },
{ {
path: 'risk', path: 'risk',
@ -329,7 +337,7 @@ const routes = [
component: () => import('@/views/personalized/followRecord/index.vue'), component: () => import('@/views/personalized/followRecord/index.vue'),
meta: { meta: {
title: '跟单记录', // 左侧菜单显示的标题 title: '跟单记录', // 左侧菜单显示的标题
} },
}, },
// 带单记录 // 带单记录
{ {
@ -338,9 +346,9 @@ const routes = [
component: () => import('@/views/personalized/leadRecord/index.vue'), component: () => import('@/views/personalized/leadRecord/index.vue'),
meta: { meta: {
title: '带单记录', // 左侧菜单显示的标题 title: '带单记录', // 左侧菜单显示的标题
}
}, },
] },
],
}, },
//代理管理 //代理管理
{ {
@ -357,7 +365,7 @@ const routes = [
component: () => import('@/views/agent/customerList/index.vue'), component: () => import('@/views/agent/customerList/index.vue'),
meta: { meta: {
title: '客户列表', // 左侧菜单显示的标题 title: '客户列表', // 左侧菜单显示的标题
} },
}, },
//客户详情 //客户详情
{ {
@ -366,7 +374,7 @@ const routes = [
component: () => import('@/views/agent/customerDetail/index.vue'), component: () => import('@/views/agent/customerDetail/index.vue'),
meta: { meta: {
title: '客户详情', // 左侧菜单显示的标题 title: '客户详情', // 左侧菜单显示的标题
} },
}, },
//客户交易订单 //客户交易订单
{ {
@ -375,7 +383,7 @@ const routes = [
component: () => import('@/views/agent/customerTradeOrder/index.vue'), component: () => import('@/views/agent/customerTradeOrder/index.vue'),
meta: { meta: {
title: '客户交易订单', // 左侧菜单显示的标题 title: '客户交易订单', // 左侧菜单显示的标题
} },
}, },
//客户资金流水 //客户资金流水
{ {
@ -384,17 +392,17 @@ const routes = [
component: () => import('@/views/agent/customerCapitalFlow/index.vue'), component: () => import('@/views/agent/customerCapitalFlow/index.vue'),
meta: { meta: {
title: '客户资金流水', // 左侧菜单显示的标题 title: '客户资金流水', // 左侧菜单显示的标题
}
}, },
]
}, },
] ],
},
],
}, },
{ {
path: '/:pathMatch(.*)*', path: '/:pathMatch(.*)*',
redirect: '/user/login' // 404 重定向到登录页,避免循环 redirect: '/user/login', // 404 重定向到登录页,避免循环
} },
]; ]
const router = createRouter({ const router = createRouter({
history: createWebHistory(), history: createWebHistory(),

View File

@ -0,0 +1,156 @@
<template>
<div class="system">
<!-- 菜单列表头 -->
<MenuHeader :title="menuTitle" :buttons="menuHeaderButtons" @click="handleAddMenu" />
<!-- 菜单列表表格 -->
<MenuTable :table-data="menuTree" :columns="menuTableColumns" row-key="id">
<template #action="{ row }">
<el-button link type="primary" size="small" @click="handleEditMenu(row)"> 编辑 </el-button>
</template>
</MenuTable>
</div>
<!-- 新增/编辑弹窗 -->
<MenuDialog
:visible="dialogVisible"
:title="dialogTitle"
:type="dialogType"
@confirm="handleSubmit"
@cancel="handleCancel"
@close="handleClose"
>
<MenuForm
:form-data="menuForm"
:form-rules="menuFormRules"
:form-items="menuFormItemOptions"
ref="menuFormRef"
/>
</MenuDialog>
</template>
<script lang="ts" setup>
import type { FormInstance } from 'element-plus'
import { Plus } from '@element-plus/icons-vue'
//
import MenuHeader from '@/components/common/Header.vue'
import MenuTable from '@/components/common/Table.vue'
import MenuDialog from '@/components/common/Dialog.vue'
import MenuForm from '@/components/common/Form.vue'
import { menuTableColumns, menuFormItemOptions } from './options'
import { rules } from './rules'
import { getSettingApi, createSettingApi, editSettingApi } from '@/api/modules/system/setting'
type SettingItem = {
id: number
key: string
value: string
description: string
}
// header
const menuTitle = ref('系统设置')
const menuHeaderButtons = [
{ label: '新增设置', type: 'primary' as const, icon: Plus, key: 'addMenu' },
]
//
const menuTree = ref<SettingItem[]>([])
//
const dialogVisible = ref(false)
const dialogTitle = ref('')
const dialogType = ref('add')
//
const menuForm = ref({
key: '',
value: '',
description: '',
})
const menuFormRef = ref<FormInstance>()
//
const menuFormRules = rules()
/**
@description: 新增菜单
**/
const handleAddMenu = () => {
dialogVisible.value = true
dialogTitle.value = '新增菜单'
menuFormItemOptions[0]!.disabled = false
}
/**
@description: 菜单数据处理
**/
//
const fetchSettingList = async () => {
try {
const data = await getSettingApi()
menuTree.value = data
} catch (err) {
console.error('获取菜单列表失败', err)
}
}
//
onMounted(async () => {
await fetchSettingList()
})
/**
@description: 处理菜单编辑/删除/状态切换
**/
const handleEditMenu = (row: SettingItem) => {
dialogVisible.value = true
menuFormItemOptions[0]!.disabled = true
dialogTitle.value = '编辑菜单'
dialogType.value = 'edit'
menuForm.value = {
...row
}
}
/**
@description: 处理弹窗提交/取消/关闭事件
**/
const handleSubmit = async () => {
console.log('提交菜单表单')
try {
await menuFormRef.value?.validate()
if (dialogType.value === 'add') {
const params = {
key: menuForm.value.key,
value: menuForm.value.value,
description: menuForm.value.description,
}
await createSettingApi(params)
await fetchSettingList()
} else {
await editSettingApi(menuForm.value)
console.log('编辑菜单成功', menuForm.value)
await fetchSettingList()
}
dialogVisible.value = false
} catch (err) {
console.log('表单验证失败', err)
return
}
}
const handleCancel = () => {
dialogVisible.value = false
dialogType.value = 'add'
menuForm.value = {
key: '',
value: '',
description: '',
}
}
const handleClose = () => {
dialogVisible.value = false
dialogType.value = 'add'
menuForm.value = {
key: '',
value: '',
description: '',
}
}
</script>

View File

@ -0,0 +1,19 @@
//定义table配置
export const menuTableColumns = [
{ prop: 'key', label: 'key', align: 'center' as const },
{ prop: 'value', label: 'value', align: 'center' as const },
{ prop: 'description', label: '备注', align: 'center' as const },
{ label: '操作', slotName: 'action', align: 'center' as const },
]
//定义menuForm配置
export const menuFormItemOptions = [
{ prop: 'key', label: 'key', type: 'input' as const, placeholder: '请输入key', disabled: false },
{ prop: 'value', label: 'value', type: 'input' as const, placeholder: '请选择value' },
{
prop: 'description',
label: 'description',
type: 'input' as const,
placeholder: '请选择description',
},
]

View File

@ -0,0 +1,9 @@
import type { FormRules } from 'element-plus'
export const rules = (): FormRules => {
return {
key: [{ required: true, message: '请选择key', trigger: 'blur' }],
value: [{ required: true, message: '请选择value', trigger: 'blur' }],
description: [{ required: true, message: '请选择备注', trigger: 'blur' }],
}
}

View File

@ -1,6 +1,6 @@
<template> <template>
<div class="trade-group"> <div class="trade-group">
<el-form-item label="交易系统时间设置"> <el-form-item label="交易时间设置">
<el-button type="primary" @click="addTableItem">添加</el-button> <el-button type="primary" @click="addTableItem">添加</el-button>
</el-form-item> </el-form-item>
<!-- 表格 --> <!-- 表格 -->

View File

@ -1,6 +1,6 @@
<template> <template>
<div class="trade-group"> <div class="trade-group">
<el-form-item label="交易系统时间设置"> <el-form-item label="交易节假日时间设置">
<el-button style="margin-left: 18px" type="primary" @click="handleAdd">添加</el-button> <el-button style="margin-left: 18px" type="primary" @click="handleAdd">添加</el-button>
<el-button style="margin-left: 18px" type="danger" @click="handleDel">删除</el-button> <el-button style="margin-left: 18px" type="danger" @click="handleDel">删除</el-button>
</el-form-item> </el-form-item>
@ -18,33 +18,43 @@
</thead> </thead>
<tbody> <tbody>
<tr> <tr v-for="(item, index) in dataList" :key="`${item.id}-${index}`">
<td> <td>
<el-input style="width: 80px" /> <el-input v-model="item.name" style="width: 80px" />
</td> </td>
<td> <td>
<el-date-picker <el-date-picker
v-model="item.datePicker"
type="datetimerange" type="datetimerange"
start-placeholder="Start date" start-placeholder="休市开始时间"
end-placeholder="End date" end-placeholder="休市结束时间"
format="YYYY-MM-DD HH:mm:ss" format="YYYY-MM-DD HH:mm:ss"
date-format="YYYY-MM-DD HH:mm:ss" date-format="YYYY-MM-DD HH:mm:ss"
time-format="YYYY-MM-DD HH:mm:ss" time-format="YYYY-MM-DD HH:mm:ss"
value-format="YYYY-MM-DD HH:mm:ss"
/> />
</td> </td>
<td> <td>
<el-select multiple placeholder="Select" style="width: 240px"> <el-select
<el-option :label="1" :value="1" /> multiple
<el-option :label="2" :value="2" /> placeholder="请选择休市市场"
<el-option :label="3" :value="3" /> style="width: 240px"
<el-option :label="4" :value="4" /> v-model="item.groupId"
<el-option :label="5" :value="5" /> >
<el-option
v-for="item in marketList"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select> </el-select>
</td> </td>
<td><el-input style="width: 250px" /></td> <td><el-input style="width: 250px" v-model="item.description" /></td>
<td> <td>
<el-button type="primary" @click="handleAdd">确认</el-button> <el-button type="primary" v-if="!item.editStatus" @click="item.editStatus = true">编辑</el-button>
<el-button type="danger" @click="handleDel">取消</el-button> <el-button type="danger" v-if="!item.editStatus" @click="handleDel(item.id)">删除</el-button>
<el-button type="primary" v-if="item.editStatus" @click="submitItem(index)">确认</el-button>
<el-button type="danger" v-if="item.editStatus" @click="item.editStatus = false">取消</el-button>
</td> </td>
</tr> </tr>
</tbody> </tbody>
@ -54,61 +64,100 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
// import { ref, onMounted } from 'vue'
import { getGroupListApi } from '@/api/modules/trade/group'
import { getHolidayList, addHoliday, editHoliday, delHoliday } from '@/api/modules/trade/time'
import { ElMessageBox } from 'element-plus'
// type DataItem = {
id?: number | string
name: string
start_time?: string
end_time?: string
datePicker: string[]
groupId: number[]
description: string
editStatus: boolean
}
/** const dataList = ref<DataItem[]>([])
* @description: 定义表格数据
*/
/** const marketList = ref<{ label: string; value: number | string }[]>([])
* @description: 定义弹窗数据
*/
const dialogVisible = ref(false)
const dialogTitle = ref('')
const dialogType = ref('')
/** const getMarketList = async () => {
* @description: 定义弹窗表格数据 getGroupListApi().then((res) => {
*/ console.log(res)
const tradeGroupForm = ref({ marketList.value = res.map((item: { name: string; id: number }[]) => ({
// label: item.name,
tradeGroupName: '', value: item.id + '',
// ID }))
exchangeId: '', })
// }
status: 1,
// const initDate = () => {
winterTime: [], getHolidayList().then((res) => {
// dataList.value = res.map((item: any) => ({
summerTime: [], id: item.id + '',
// name: item.name,
sort: 0, start_time: item.start_time,
// ID end_time: item.end_time,
id: '', datePicker: [item.start_time, item.end_time],
}) groupId: item.group_id,
description: item.description,
editStatus: false,
}))
})
}
const handleAdd = () => {
dataList.value.unshift({
name: '',
start_time: '',
end_time: '',
datePicker: [],
groupId: [],
description: '',
editStatus: true,
})
}
const submitItem = (idx: number) => {
const submitObj = {
name: dataList.value[idx]!.name,
start_time: dataList.value[idx]!.datePicker[0],
end_time: dataList.value[idx]!.datePicker[1],
group_id: dataList.value[idx]!.groupId.join(','),
description: dataList.value[idx]!.description,
}
if (dataList.value[idx]!.id) {
editHoliday({id: dataList.value[idx]!.id, ...submitObj}).then(() => {
initDate()
})
} else {
addHoliday(submitObj).then(() => {
initDate()
})
}
}
const handleDel = (id: number | string) => {
ElMessageBox.confirm('确认删除吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
}).then(() => {
delHoliday({id}).then(() => {
initDate()
})
})
}
/** /**
* @description: 页面加载完成需要请求的数据 * @description: 页面加载完成需要请求的数据
*/ */
onMounted(() => {}) onMounted(() => {
getMarketList()
const handleAdd = () => { initDate()
dialogVisible.value = true })
dialogTitle.value = '添加交易组'
dialogType.value = 'add'
tradeGroupForm.value = {
tradeGroupName: '',
winterTime: [],
summerTime: [],
status: 1,
sort: 0,
id: '',
} as any
}
const handleDel = () => {}
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">