Commit 11a9d647 by 肖玉娟

feat:演播室管理 + 赛事管理页面

parent 16d6477e
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'
import { ProCard } from '@ant-design/pro-components'
import ProForm, { ProFormInstance, ProFormText, ProFormTextArea, ProFormTreeSelect } from '@ant-design/pro-form'
import ProForm, { ProFormInstance } from '@ant-design/pro-form'
import styled from 'styled-components'
import { Button, message } from 'antd'
import { useAppDispatch, useAppSelector } from '@/hooks/useStore'
import { useAppDispatch } from '@/hooks/useStore'
import { DelApi, GetListByPageApi } from './common/services'
import { TState } from './common/typing'
import AddUpdate from './components/addUpdate'
import { getinteracts, getStudio } from './store/match'
import DForm from './components/DForm'
import { getStudioModels } from './store/match'
const Match = () => {
const [tab, setTab] = useState('')
const formRef = useRef<ProFormInstance>()
const dispatch = useAppDispatch()
const { files, studios, interacts } = useAppSelector(({ match }) => (match))
const [dataSource, setDataSource] = useState<TState[]>([])
const formRef = useRef<ProFormInstance>()
const [currentId, setCurrentId] = useState<number>(NaN)
const [tab, setTab] = useState<string>('')
const [isModalVisible, setIsModalVisible] = useState<boolean>(false)
const [dataSource, setDataSource] = useState<TState[]>([])
useEffect(() => {
getData()
dispatch(getStudio())
dispatch(getinteracts())
dispatch(getStudioModels())
}, [])
const getData = async () => { // 演播室数据
setDataSource([])
const { data } = await GetListByPageApi({
pageBean: {
pageNum: 0,
......@@ -36,15 +38,16 @@ const Match = () => {
setTab(String(data?.list[0].id))
setDataSource(data?.list)
}
const handleClickOperation = useCallback( // 表格操作
async (type: 'Edit' | 'Del', record: TState) => {
const handleClickOperation = useCallback( // 操作
async (type: 'Edit' | 'Del' | 'Cancel', record: any) => {
switch (type) {
case 'Edit':
setCurrentId(record.id)
setIsModalVisible(true)
break
case 'Del':
try {
const { status } = await DelApi({ id: record.id })
const { status } = await DelApi({ id: Number(record.id) })
if (status !== 200) {
message.error('删除失败')
return
......@@ -56,11 +59,17 @@ const Match = () => {
message.error('删除失败')
}
break
case 'Cancel':
getData()
break
}
}, [dataSource])
const handleUpdateVisible = (value: boolean, type: string) => {
setIsModalVisible(value)
type === 'add' && getData()
if (!value) {
setCurrentId(NaN)
}
}
const data = useMemo(() => {
return dataSource.map((item) => <ProCard.TabPane key={String(item.id)} tab={item?.name}>
......@@ -68,52 +77,24 @@ const Match = () => {
formRef={formRef}
autoFocusFirstInput
submitter={{
searchConfig: {
submitText: '保存'
},
resetButtonProps: { // 配置按钮的属性
style: {
display: 'none' // 隐藏重置按钮
}
},
render: (props: any, doms: any) => {
return [
...doms,
<Button type="primary" key='delete' danger onClick={() => handleClickOperation('Del', item)}>删除</Button>
<div key='operation'>
<Button type="primary" className='button' onClick={() => handleClickOperation('Edit', item)}>编辑</Button>
<Button type="primary" danger onClick={() => handleClickOperation('Del', item)}>删除</Button>
</div>
]
}
}}
initialValues={item}
onFinish={(values: any) => handleClickOperation('Edit', values)}
>
<ProFormText width="md" name="name" label="赛事名称" placeholder="请输入赛事名称" />
<ProFormTextArea width="xl" name="" label="赛事说明" placeholder="请输入赛事说明" />
<ProFormTreeSelect
name="studio"
label="关联演播室"
placeholder="请选择演播室"
allowClear
width="lg"
secondary
request={async () => { return studios }}
fieldProps={files}
/>
<ProFormTreeSelect
name="studio"
label="关联互动模块"
placeholder="请选择互动模块"
allowClear
width="lg"
secondary
request={async () => { return interacts }}
fieldProps={files}
/>
<DForm status={true} />
</ProForm>
</ProCard.TabPane>)
}, [dataSource])
return (
<>
<Wrapper>
<ProCard
tabs={{
type: 'card',
......@@ -127,8 +108,13 @@ const Match = () => {
>
{data}
</ProCard>
<AddUpdate visible={isModalVisible} handleUpdateVisible={handleUpdateVisible} />
</>
<AddUpdate visible={isModalVisible} handleUpdateVisible={handleUpdateVisible} id={currentId} />
</Wrapper>
)
}
export default Match
const Wrapper = styled.div`
.button{
margin-right: 10px;
}
`
import { Get, Post } from '@/utils/request'
import { TMatchList, TMatchUpdate } from './typing'
import { TDelete, TMatchList, TMatchUpdate } from './typing'
/**
* @description 列表查询
......@@ -11,25 +11,31 @@ export const GetListByPageApi = (params: TMatchList): Promise<any> => {
/**
* @description 删除
*/
export const DelApi = (params:{}): Promise<any> => {
return Post('/type/del', { params })
export const DelApi = (params:Partial<TDelete>): Promise<any> => {
return Get('/type/deleteGameType', { params })
}
/**
* @description 修改
*/
export const UpdateApi = (params: Partial<TMatchUpdate>): Promise<any> => {
return Post('/type/update', { params })
return Post('/type/updateGameType', { params })
}
/**
* @description 添加
*/
export const AddApi = (params: Partial<TMatchUpdate>): Promise<any> => {
return Post('/type/add', { params })
return Post('/type/insertGameType', { params })
}
/**
* @description 详情
* @description 获取所有演播室/互动数据
*/
export const GetDetailApi = (id: number): Promise<any> => {
return Get(`/hzy-admin/sys/user/${id}`)
export const getStudiosModels = (): Promise<any> => {
return Get('/type/getAllStudiosGameType')
}
/**
// /**
// * @description 详情
// */
// export const GetDetailApi = (id: number): Promise<any> => {
// return Get(`/hzy-admin/sys/user/${id}`)
// }
......@@ -18,5 +18,8 @@ export type TMatchUpdate = {
createTime: string
updateTime: string
}
export type TDelete = {
id:number
}
export type TState = TMatchUpdate
import { ProFormText, ProFormTextArea, ProFormTreeSelect } from '@ant-design/pro-form'
import { useAppSelector } from '@/hooks/useStore'
type Tprops = {
status: boolean
}
const DForm = ({ status }: Tprops) => {
const { files, studios, models } = useAppSelector(({ match }) => (match))
return (
<>
<ProFormText disabled={status} width="md" name="name" label="赛事名称" placeholder="请输入赛事名称" rules={[{ required: true, message: '请输入赛事名称' }]}/>
<ProFormTextArea disabled={status} width="xl" name="info" label="赛事说明" placeholder="请输入赛事说明" />
<ProFormTreeSelect
disabled={status}
name="studioList"
label="关联演播室"
placeholder="请选择演播室"
allowClear
width="lg"
secondary
fieldProps={files}
request={async () => { return studios }}
rules={[{ required: true, message: '请关联演播室' }]}
/>
<ProFormTreeSelect
disabled={status}
name="modelsList"
label="关联互动模块"
placeholder="请选择互动模块"
allowClear
width="lg"
secondary
fieldProps={files}
request={async () => { return models }}
rules={[{ required: true, message: '请关联互动模块' }]}
/></>
)
}
export default DForm
import { ModalForm, ProFormText, ProFormTreeSelect } from '@ant-design/pro-form'
import { useCallback, useEffect, useState } from 'react'
import { message } from 'antd'
import { ModalForm } from '@ant-design/pro-form'
import { useAppSelector } from '@/hooks/useStore'
import { message } from 'antd'
import { AddApi } from '../common/services'
import { AddApi, GetListByPageApi, UpdateApi } from '../common/services'
import DForm from './DForm'
type TProps = {
visible: boolean,
id: number,
handleUpdateVisible: (value:boolean, type: string) => void
}
const AddUpdate = ({ visible, handleUpdateVisible }:TProps) => {
const title = '创建赛事'
const { files, studios, interacts } = useAppSelector(({ match }) => (match))
const AddUpdate = ({ id, visible, handleUpdateVisible }:TProps) => {
const [title, setTitle] = useState<string>('')
useEffect(() => {
setTitle(() => {
return id ? '编辑赛事' : '创建赛事'
})
}, [visible])
const fetchDetail = useCallback(async () => {
let data:any = {
name: '',
info: '',
studioList: [],
modelsList: []
}
if (id) {
try {
const res = await GetListByPageApi({
id,
pageBean: {
pageNum: 0,
pageSize: 0
}
})
if (res.status !== 200) return
data = res?.data?.list[0]
} catch (error) {
console.log(error)
}
}
return data
}, [id])
const cnacelClick = () => {
handleUpdateVisible(false, '')
}
const okClick = async (values:any) => {
console.log(values, 9999)
const params:any = {}
const params:any = {
name: values.name,
info: values.info,
studioList: values.studioList,
modelsList: values.modelsList
}
try {
if (id) {
params.id = id
}
console.log('params===>', params)
const { status } = await AddApi(params)
const { status } = id ? await UpdateApi(params) : await AddApi(params)
if (status === 200) {
message.success('创建成功')
id ? message.success('编辑成功') : message.success('创建成功')
handleUpdateVisible(false, 'add')
}
} catch (error) {
......@@ -46,29 +82,9 @@ const AddUpdate = ({ visible, handleUpdateVisible }:TProps) => {
onFinish={async (e) => {
okClick(e)
}}
request={fetchDetail}
>
<ProFormText width="md" name="studioName" label="赛事名称" placeholder="请输入演播室名称" />
<ProFormText width="md" name="studioId" label="赛事说明" placeholder="请输入演播室id" />
<ProFormTreeSelect
name="studio"
label="关联演播室"
placeholder="请选择演播室"
allowClear
width="lg"
secondary
request={async () => { return studios }}
fieldProps={files}
/>
<ProFormTreeSelect
name="name"
label="关联互动模块"
placeholder="请选择互动模块"
allowClear
width="lg"
secondary
request={async () => { return interacts }}
fieldProps={files}
/>
<DForm status={false}/>
</ModalForm>
)
}
......
import { createAsyncThunk, createSlice } from '@reduxjs/toolkit'
import { getStudiosModels } from '../common/services'
// import { GetListByPageApi } from '../common/services'
type TMatch = {
data: string
files: object
studios: Array<any> // 演播室数组
interacts: Array<any> // 互动模块数组
models: Array<any> // 互动模块数组
}
const initialState:TMatch = {
const initialState: TMatch = {
data: '',
files: { // TreeSelect组件配置项
showArrow: false,
......@@ -22,54 +26,26 @@ const initialState:TMatch = {
}
},
studios: [], // 演播室数组
interacts: [] // 互动模块数组
models: [] // 互动模块数组
}
export const getStudio = createAsyncThunk('studios', async () => {
// const { data } = await MenuPerApi()
// const data = []
const data:Array<{ label: string, value: string | number }> = [
{
label: 'Node1',
value: 1
},
{
label: 'Node2',
value: 2
}
]
return data
})
export const getinteracts = createAsyncThunk('interacts', async () => {
// const { data } = await MenuPerApi()
// const data = []
const data:Array<{ label: string, value: string | number }> = [
{
label: 'Node1',
value: 1
},
{
label: 'Node2',
value: 2
}
]
export const getStudioModels = createAsyncThunk('studios', async () => {
const { data } = await getStudiosModels()
return data
})
export const { reducer: matchReducer, actions } = createSlice({
name: 'match',
initialState,
reducers: {
setMenus: (state, { payload: any }) => {}
setMenus: (state, { payload: any }) => { }
},
extraReducers: {
[getStudio.pending.type] () { },
[getStudio.rejected.type] () { },
[getStudio.fulfilled.type] (state, { payload }) {
state.studios = payload
},
[getinteracts.pending.type] () {},
[getinteracts.rejected.type] () {},
[getinteracts.fulfilled.type] (state, { payload }) {
state.interacts = payload
[getStudioModels.pending.type] () { },
[getStudioModels.rejected.type] () { },
[getStudioModels.fulfilled.type] (state, { payload }) {
console.log('获取演播室互动', payload)
state.studios = payload.studios
state.models = payload.models
}
}
})
......
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'
import { ProCard, ProFormInstance } from '@ant-design/pro-components'
// import { message } from 'antd'
// import { useAppSelector } from '@/hooks/useStore'
import { ProCard, ProForm, ProFormInstance } from '@ant-design/pro-components'
import styled from 'styled-components'
import { Button, message } from 'antd'
import { DelApi, GetListByPageApi, UpdateApi } from './common/services'
import { DelApi, GetListByPageApi } from './common/services'
import { TState } from './common/typing'
import AddUpdate from './components/addUpdate'
import DForm from './components/DForm'
const Studio = () => {
const [tab, setTab] = useState('')
const formRef = useRef<ProFormInstance>()
const [dataSource, setDataSource] = useState<TState[]>([])
const [currentId, setCurrentId] = useState<number>(NaN)
const [tab, setTab] = useState<string>('')
const [isModalVisible, setIsModalVisible] = useState<boolean>(false)
const [dataSource, setDataSource] = useState<TState[]>([])
useEffect(() => {
getData()
}, [])
const getData = async () => { // 演播室数据
setDataSource([])
const { data } = await GetListByPageApi({
pageBean: {
pageNum: 0,
......@@ -37,22 +36,8 @@ const Studio = () => {
async (type: 'Edit' | 'Del', record: any) => {
switch (type) {
case 'Edit':
try {
const params = {
id: Number(tab),
...record
}
const { status } = await UpdateApi(params)
if (status !== 200) {
message.error('编辑失败')
return
}
message.success('编辑成功')
getData()
} catch (error) {
console.log(error)
message.error('编辑失败')
}
setIsModalVisible(true)
setCurrentId(record.id)
break
case 'Del':
try {
......@@ -73,36 +58,32 @@ const Studio = () => {
const handleUpdateVisible = (value: boolean, type: string) => { // 弹窗状态
setIsModalVisible(value)
type === 'Add' && getData()
if (!value) {
setCurrentId(NaN)
}
}
const data = useMemo(() => {
return dataSource.map((item) => <ProCard.TabPane key={String(item.id)} tab={item?.studioName}>
<DForm
formRef={formRef}
<ProForm formRef={formRef}
autoFocusFirstInput
submitter={{
searchConfig: {
submitText: '保存'
},
resetButtonProps: { // 配置按钮的属性
style: {
display: 'none' // 隐藏重置按钮
}
},
render: (props: any, doms: any) => {
return [
...doms,
<Button type="primary" key='delete' danger onClick={() => handleClickOperation('Del', item)}>删除</Button>
<div key='operation'>
<Button type="primary" className='button' onClick={() => handleClickOperation('Edit', item)}>编辑</Button>
<Button type="primary" danger onClick={() => handleClickOperation('Del', item)}>删除</Button>
</div>
]
}
}}
request={() => { return item }}
onFinish={(values: any) => handleClickOperation('Edit', values)}
/>
initialValues={item}>
<DForm status={true} />
</ProForm>
</ProCard.TabPane>)
}, [dataSource])
return (
<>
<Wrapper>
<ProCard
tabs={{
type: 'card',
......@@ -116,8 +97,13 @@ const Studio = () => {
>
{data}
</ProCard>
<AddUpdate visible={isModalVisible} handleUpdateVisible={handleUpdateVisible} />
</>
<AddUpdate visible={isModalVisible} handleUpdateVisible={handleUpdateVisible} id={currentId} />
</Wrapper>
)
}
export default Studio
const Wrapper = styled.div`
.button{
margin-right: 10px;
}
`
import ProForm, { ProFormDigit, ProFormSelect, ProFormText } from '@ant-design/pro-form'
type Props = any
const DForm = (props:Props) => {
type Tprops = {
status: boolean
}
const DForm = ({ status }: Tprops) => {
return (
<>
<ProForm {...props}>
<ProForm.Group>
<ProFormText width="md" name="studioName" label="演播室名称" placeholder="请输入演播室名称" />
<ProFormDigit width="md" name="studioId" label="演播室id" placeholder="请输入演播室id" />
<ProForm.Group>
<ProFormText disabled={status} width="md" name="studioName" label="演播室名称" placeholder="请输入演播室名称"
rules={[{ required: true, message: '请输入演播室名称' }]} />
<ProFormDigit disabled={status} width="md" name="studioId" label="演播室id" placeholder="请输入演播室id" rules={[{ required: true, message: '请输入演播室id' }]} />
</ProForm.Group>
<ProForm.Group>
<ProFormText width="md" name="ip1" label="主服务ip" placeholder="请输入主服务ip" />
<ProFormText width="md" name="port1" label="主服务器端口" placeholder="请输入主服务器端口" />
<ProFormText disabled={status} width="md" name="ip1" label="主服务ip" placeholder="请输入主服务ip" rules={[{ required: true, message: '请输入主服务ip' }]} />
<ProFormText disabled={status} width="md" name="port1" label="主服务器端口" placeholder="请输入主服务器端口" rules={[{ required: true, message: '请输入主服务器端口' }]} />
</ProForm.Group>
<ProForm.Group>
<ProFormText width="md" name="ip2" label="备服务ip" placeholder="请输入备服务ip" />
<ProFormText width="md" name="port2" label="备服务器端口" placeholder="请输入备服务器端口" />
<ProFormText disabled={status} width="md" name="ip2" label="备服务ip" placeholder="请输入备服务ip" />
<ProFormText disabled={status} width="md" name="port2" label="备服务器端口" placeholder="请输入备服务器端口" />
</ProForm.Group>
<ProForm.Group>
<ProFormText width="md" name="sceneNameS" label="主场景地址" placeholder="请输入主场景地址" />
<ProFormText width="md" name="sceneNameQ" label="备场景地址" placeholder="请输入备场景地址" />
<ProFormText disabled={status} width="md" name="sceneNameS" label="主场景地址" placeholder="请输入主场景地址" rules={[{ required: true, message: '请输入主场景地址' }]} />
<ProFormText disabled={status} width="md" name="sceneNameQ" label="备场景地址" placeholder="请输入备场景地址" />
</ProForm.Group>
<ProForm.Group>
<ProFormSelect
disabled={status}
width="md"
label="弹幕类型"
name="type"
......@@ -32,14 +34,24 @@ const DForm = (props:Props) => {
2: '只保存txt',
3: '发送tcp并存为txt'
}}
rules={[{ required: true, message: '请选择弹幕类型' }]}
/>
<ProFormDigit width="md" name="intervalTime" label="弹幕轮询时间间隔" addonAfter="秒" placeholder="请输入弹幕轮询时间间隔" />
<ProFormDigit disabled={status} width="md" name="intervalTime" label="弹幕轮询时间间隔" addonAfter="秒" placeholder="请输入弹幕轮询时间间隔" />
</ProForm.Group>
<ProForm.Group>
<ProFormDigit width="md" name="bulletChatNums" label="筛选弹幕限制条数" placeholder="请输入筛选弹幕限制数量" />
<ProFormDigit width="md" name="powerTime" label="发电轮询时间间隔" addonAfter="秒" placeholder="请输入发电轮询时间间隔" />
<ProFormSelect
disabled={status}
width="md"
name="bulletChatNums"
label="筛选弹幕限制条数"
options={[
{ label: '6', value: 6 },
{ label: '8', value: 8 }
]}
placeholder="请输入筛选弹幕限制数量"
rules={[{ required: true, message: '请输入筛选弹幕限制条数' }]} />
<ProFormDigit disabled={status} width="md" name="powerTime" label="发电轮询时间间隔" addonAfter="秒" placeholder="请输入发电轮询时间间隔" />
</ProForm.Group>
</ProForm>
</>
)
}
......
import { useCallback } from 'react'
import { useCallback, useEffect, useState } from 'react'
import ProForm, { ModalForm, ProFormDigit, ProFormText, ProFormSelect } from '@ant-design/pro-form'
import { ModalForm } from '@ant-design/pro-form'
import { message } from 'antd'
import { AddApi } from '../common/services'
import { AddApi, GetListByPageApi, UpdateApi } from '../common/services'
import DForm from './DForm'
type TProps = {
id:number,
visible: boolean,
handleUpdateVisible: (value:boolean, type: string) => void
}
const AddUpdate = ({ visible, handleUpdateVisible }:TProps) => {
const title = '创建演播室'
const AddUpdate = ({ id, visible, handleUpdateVisible }:TProps) => {
const [title, setTitle] = useState<string>('')
useEffect(() => {
setTitle(() => {
return id ? '编辑演播室' : '创建演播室'
})
}, [visible])
const fetchDetail = useCallback(async () => {
const data:any = {
let data:any = {
studioName: '', // 演播室名称
studioId: '', // 演播室ids
studioId: '', // 演播室id
ip1: '', // 主服务ip
ip2: '', // 备服务ip
port1: '', // 主服务器端口
......@@ -28,11 +36,26 @@ const AddUpdate = ({ visible, handleUpdateVisible }:TProps) => {
updateTime: '', // 修改时间
type: '', // 弹幕类型
intervalTime: 3, // 弹幕轮询时间间隔
bulletChatNums: 0, // 筛选弹幕限制数量
bulletChatNums: 6, // 筛选弹幕限制数量
powerTime: 3 // 发电时刻开启服务时,默认时间间隔
}
if (id) {
try {
const res = await GetListByPageApi({
id,
pageBean: {
pageNum: 0,
pageSize: 0
}
})
if (res.status !== 200) return
data = res?.data?.list[0]
} catch (error) {
console.log(error)
}
}
return data
}, [])
}, [id])
const cnacelClick = () => {
handleUpdateVisible(false, '')
}
......@@ -49,13 +72,21 @@ const AddUpdate = ({ visible, handleUpdateVisible }:TProps) => {
type: values.type, // 弹幕类型
intervalTime: values.intervalTime, // 弹幕轮询时间间隔
bulletChatNums: values.bulletChatNums, // 筛选弹幕限制数量
powerTime: values.powerTime// 发电时刻开启服务时,默认时间间隔
powerTime: values.powerTime // 发电时刻开启服务时,默认时间间隔
// config: {
// ip1: values.ip1, // 主服务ip
// ip2: values.ip2, // 备服务ip
// port1: values.port1, // 主服务器端口
// port2: values.port2 // 备服务器端口
// }
}
try {
console.log('params===>', params)
const { status } = await AddApi(params)
if (id) {
params.id = id
}
const { status } = id ? await UpdateApi(params) : await AddApi(params)
if (status === 200) {
message.success('创建成功')
id ? message.success('编辑成功') : message.success('创建成功')
handleUpdateVisible(false, 'Add')
}
} catch (error) {
......@@ -76,40 +107,7 @@ const AddUpdate = ({ visible, handleUpdateVisible }:TProps) => {
okClick(e)
}}
request={fetchDetail}>
<ProForm.Group>
<ProFormText width="md" name="studioName" label="演播室名称" placeholder="请输入演播室名称" />
<ProFormDigit width="md" name="studioId" label="演播室id" placeholder="请输入演播室id" />
</ProForm.Group>
<ProForm.Group>
<ProFormText width="md" name="ip1" label="主服务ip" placeholder="请输入主服务ip" />
<ProFormText width="md" name="port1" label="主服务器端口" placeholder="请输入主服务器端口" />
</ProForm.Group>
<ProForm.Group>
<ProFormText width="md" name="ip2" label="备服务ip" placeholder="请输入备服务ip" />
<ProFormText width="md" name="port2" label="备服务器端口" placeholder="请输入备服务器端口" />
</ProForm.Group>
<ProForm.Group>
<ProFormText width="md" name="sceneNameS" label="主场景地址" placeholder="请输入主场景地址" />
<ProFormText width="md" name="sceneNameQ" label="备场景地址" placeholder="请输入备场景地址" />
</ProForm.Group>
<ProForm.Group>
<ProFormSelect
width="md"
label="弹幕类型"
name="type"
placeholder='请选择弹幕类型'
valueEnum={{
1: '入库并存为txt',
2: '只保存txt',
3: '发送tcp并存为txt'
}}
/>
<ProFormDigit width="md" name="intervalTime" label="弹幕轮询时间间隔" addonAfter="秒" placeholder="请输入弹幕轮询时间间隔" />
</ProForm.Group>
<ProForm.Group>
<ProFormDigit width="md" name="bulletChatNums" label="筛选弹幕限制条数" placeholder="请输入筛选弹幕限制数量" />
<ProFormDigit width="md" name="powerTime" label="发电轮询时间间隔" addonAfter="秒" placeholder="请输入发电轮询时间间隔" />
</ProForm.Group>
<DForm status={false}/>
</ModalForm>
)
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment