Complete main UI #37
@@ -11,6 +11,7 @@
|
|||||||
width: 200px;
|
width: 200px;
|
||||||
height: 360px;
|
height: 360px;
|
||||||
flex: 0 0 auto;
|
flex: 0 0 auto;
|
||||||
|
overflow: hidden !important;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
||||||
.common-card {
|
.common-card {
|
||||||
|
|||||||
20
src/assets/css/pages/system/tools/code.scss
Normal file
20
src/assets/css/pages/system/tools/code.scss
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
[data-component=system-tools-code] {
|
||||||
|
padding: 30px;
|
||||||
|
|
||||||
|
.card-box {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.draggable-content {
|
||||||
|
position: fixed;
|
||||||
|
inset-inline-end: 48px;
|
||||||
|
inset-block-end: 48px;
|
||||||
|
|
||||||
|
> * {
|
||||||
|
position: relative;
|
||||||
|
inset-inline-end: 0;
|
||||||
|
inset-block-end: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
8
src/assets/css/pages/system/tools/execute.scss
Normal file
8
src/assets/css/pages/system/tools/execute.scss
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
[data-component=system-tools-execute] {
|
||||||
|
padding: 30px;
|
||||||
|
|
||||||
|
.card-box {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -28,7 +28,7 @@
|
|||||||
position: absolute;
|
position: absolute;
|
||||||
top: 10px;
|
top: 10px;
|
||||||
left: 10px;
|
left: 10px;
|
||||||
width: 6em;
|
width: 8em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.upgrade-bt {
|
.upgrade-bt {
|
||||||
|
|||||||
1
src/assets/svg/execute.svg
Normal file
1
src/assets/svg/execute.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024"><path d="M750.912 505.216L256 198.016c-27.712-17.024-64 4.288-64 36.288v614.4c0 32 36.288 53.312 64 36.288l492.8-307.2c29.888-14.976 29.888-57.6 2.112-72.576z" /></svg>
|
||||||
|
After Width: | Height: | Size: 232 B |
@@ -80,7 +80,8 @@ export const TOOL_ILLEGAL_VERSION = 40050
|
|||||||
export const TOOL_UNDER_REVIEW = 40051
|
export const TOOL_UNDER_REVIEW = 40051
|
||||||
export const TOOL_NOT_UNDER_REVIEW = 40052
|
export const TOOL_NOT_UNDER_REVIEW = 40052
|
||||||
export const TOOL_HAS_UNPUBLISHED_VERSION = 40053
|
export const TOOL_HAS_UNPUBLISHED_VERSION = 40053
|
||||||
export const TOOL_HAS_BEEN_PUBLISHED = 40054
|
export const TOOL_HAS_NOT_BEEN_PUBLISHED = 40054
|
||||||
|
export const TOOL_HAS_BEEN_PUBLISHED = 40055
|
||||||
export const TOOL_SUBMIT_ERROR = 40060
|
export const TOOL_SUBMIT_ERROR = 40060
|
||||||
export const TOOL_CANCEL_ERROR = 40061
|
export const TOOL_CANCEL_ERROR = 40061
|
||||||
|
|
||||||
|
|||||||
25
src/global.d.ts
vendored
25
src/global.d.ts
vendored
@@ -89,6 +89,23 @@ interface LoginParam {
|
|||||||
captchaCode: string
|
captchaCode: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface UserWithInfoVo {
|
||||||
|
id: string
|
||||||
|
username: string
|
||||||
|
verified: boolean
|
||||||
|
locking: boolean
|
||||||
|
expiration: string
|
||||||
|
credentialsExpiration: string
|
||||||
|
enable: boolean
|
||||||
|
currentLoginTime: string
|
||||||
|
currentLoginIp: string
|
||||||
|
lastLoginTime: string
|
||||||
|
lastLoginIp: string
|
||||||
|
createTime: string
|
||||||
|
updateTime: string
|
||||||
|
userInfo: UserInfoVo
|
||||||
|
}
|
||||||
|
|
||||||
interface UserWithPowerInfoVo {
|
interface UserWithPowerInfoVo {
|
||||||
id: string
|
id: string
|
||||||
username: string
|
username: string
|
||||||
@@ -532,7 +549,7 @@ interface ToolVo {
|
|||||||
icon: string
|
icon: string
|
||||||
description: string
|
description: string
|
||||||
base: ToolBaseVo
|
base: ToolBaseVo
|
||||||
author: UserInfoVo
|
author: UserWithInfoVo
|
||||||
ver: string
|
ver: string
|
||||||
keywords: string[]
|
keywords: string[]
|
||||||
categories: ToolCategoryVo[]
|
categories: ToolCategoryVo[]
|
||||||
@@ -570,3 +587,9 @@ interface ToolUpdateParam {
|
|||||||
categories?: string[]
|
categories?: string[]
|
||||||
source?: string
|
source?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface ToolManagementGetParam extends PageParam {
|
||||||
|
searchType?: string
|
||||||
|
searchValue?: string
|
||||||
|
searchRegex?: boolean
|
||||||
|
}
|
||||||
|
|||||||
91
src/pages/System/Tools/Code.tsx
Normal file
91
src/pages/System/Tools/Code.tsx
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
import { r_sys_tool_get_one } from '@/services/system.tsx'
|
||||||
|
import '@/assets/css/pages/system/tools/code.scss'
|
||||||
|
import { DATABASE_NO_RECORD_FOUND, DATABASE_SELECT_SUCCESS } from '@/constants/common.constants.ts'
|
||||||
|
import Playground from '@/components/Playground'
|
||||||
|
import { useState } from 'react'
|
||||||
|
import { IFiles } from '@/components/Playground/shared.ts'
|
||||||
|
import { base64ToFiles } from '@/components/Playground/files.ts'
|
||||||
|
import FitFullscreen from '@/components/common/FitFullscreen.tsx'
|
||||||
|
import Card from '@/components/common/Card.tsx'
|
||||||
|
import Draggable from 'react-draggable'
|
||||||
|
import Icon from '@ant-design/icons'
|
||||||
|
|
||||||
|
const Code = () => {
|
||||||
|
const navigate = useNavigate()
|
||||||
|
const { id } = useParams()
|
||||||
|
const [loading, setLoading] = useState(false)
|
||||||
|
const [files, setFiles] = useState<IFiles>({})
|
||||||
|
const [selectedFileName, setSelectedFileName] = useState('')
|
||||||
|
|
||||||
|
const handleOnRunTool = () => {
|
||||||
|
navigate(`/system/tools/execute/${id}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
const render = (toolVo: ToolVo) => {
|
||||||
|
try {
|
||||||
|
setFiles(base64ToFiles(toolVo.source.data!))
|
||||||
|
setSelectedFileName(toolVo.entryPoint)
|
||||||
|
} catch (e) {
|
||||||
|
void message.error('载入工具失败')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const getTool = () => {
|
||||||
|
if (loading) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
setLoading(true)
|
||||||
|
void message.loading({ content: '加载中……', key: 'LOADING', duration: 0 })
|
||||||
|
|
||||||
|
void r_sys_tool_get_one(id!)
|
||||||
|
.then((res) => {
|
||||||
|
const response = res.data
|
||||||
|
switch (response.code) {
|
||||||
|
case DATABASE_SELECT_SUCCESS:
|
||||||
|
render(response.data!)
|
||||||
|
break
|
||||||
|
case DATABASE_NO_RECORD_FOUND:
|
||||||
|
void message.error('未找到指定工具')
|
||||||
|
setTimeout(() => {
|
||||||
|
navigate(-1)
|
||||||
|
}, 3000)
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
void message.error('获取工具信息失败,请稍后重试')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
setLoading(false)
|
||||||
|
message.destroy('LOADING')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
getTool()
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<FitFullscreen data-component={'system-tools-code'}>
|
||||||
|
<Card>
|
||||||
|
<Playground.CodeEditor
|
||||||
|
readonly
|
||||||
|
files={files}
|
||||||
|
selectedFileName={selectedFileName}
|
||||||
|
onSelectedFileChange={setSelectedFileName}
|
||||||
|
/>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
<Draggable bounds={'#root'}>
|
||||||
|
<div className={'draggable-content'}>
|
||||||
|
<AntdFloatButton
|
||||||
|
type={'primary'}
|
||||||
|
icon={<Icon component={IconOxygenExecute} />}
|
||||||
|
onClick={handleOnRunTool}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</Draggable>
|
||||||
|
</FitFullscreen>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Code
|
||||||
80
src/pages/System/Tools/Execute.tsx
Normal file
80
src/pages/System/Tools/Execute.tsx
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
import FitFullscreen from '@/components/common/FitFullscreen.tsx'
|
||||||
|
import '@/assets/css/pages/system/tools/execute.scss'
|
||||||
|
import { base64ToFiles, base64ToStr, IMPORT_MAP_FILE_NAME } from '@/components/Playground/files.ts'
|
||||||
|
import { IImportMap } from '@/components/Playground/shared.ts'
|
||||||
|
import compiler from '@/components/Playground/compiler.ts'
|
||||||
|
import { DATABASE_NO_RECORD_FOUND, DATABASE_SELECT_SUCCESS } from '@/constants/common.constants.ts'
|
||||||
|
import { r_sys_tool_get_one } from '@/services/system.tsx'
|
||||||
|
import Card from '@/components/common/Card.tsx'
|
||||||
|
import Playground from '@/components/Playground'
|
||||||
|
|
||||||
|
const Execute = () => {
|
||||||
|
const navigate = useNavigate()
|
||||||
|
const { id } = useParams()
|
||||||
|
const [loading, setLoading] = useState(false)
|
||||||
|
const [compiledCode, setCompiledCode] = useState('')
|
||||||
|
|
||||||
|
const render = (toolVo: ToolVo) => {
|
||||||
|
try {
|
||||||
|
const baseDist = base64ToStr(toolVo.base.dist.data!)
|
||||||
|
const files = base64ToFiles(toolVo.source.data!)
|
||||||
|
const importMap = JSON.parse(files[IMPORT_MAP_FILE_NAME].value) as IImportMap
|
||||||
|
|
||||||
|
void compiler
|
||||||
|
.compile(files, importMap, toolVo.entryPoint)
|
||||||
|
.then((result) => {
|
||||||
|
const output = result.outputFiles[0].text
|
||||||
|
setCompiledCode(`${output}\n${baseDist}`)
|
||||||
|
})
|
||||||
|
.catch((reason) => {
|
||||||
|
void message.error(`编译失败:${reason}`)
|
||||||
|
})
|
||||||
|
} catch (e) {
|
||||||
|
void message.error('载入工具失败')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const getTool = () => {
|
||||||
|
if (loading) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
setLoading(true)
|
||||||
|
void message.loading({ content: '加载中……', key: 'LOADING', duration: 0 })
|
||||||
|
|
||||||
|
void r_sys_tool_get_one(id!)
|
||||||
|
.then((res) => {
|
||||||
|
const response = res.data
|
||||||
|
switch (response.code) {
|
||||||
|
case DATABASE_SELECT_SUCCESS:
|
||||||
|
render(response.data!)
|
||||||
|
break
|
||||||
|
case DATABASE_NO_RECORD_FOUND:
|
||||||
|
void message.error('未找到指定工具')
|
||||||
|
setTimeout(() => {
|
||||||
|
navigate(-1)
|
||||||
|
}, 3000)
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
void message.error('获取工具信息失败,请稍后重试')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
setLoading(false)
|
||||||
|
message.destroy('LOADING')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
getTool()
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<FitFullscreen data-component={'system-tools-execute'}>
|
||||||
|
<Card>
|
||||||
|
<Playground.Output.Preview.Render iframeKey={`${id}`} compiledCode={compiledCode} />
|
||||||
|
</Card>
|
||||||
|
</FitFullscreen>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Execute
|
||||||
@@ -1,14 +1,485 @@
|
|||||||
import Playground from '@/components/Playground'
|
import { ChangeEvent, KeyboardEvent } from 'react'
|
||||||
import templates from '@/components/Playground/templates'
|
import {
|
||||||
|
r_sys_tool_delete,
|
||||||
|
r_sys_tool_get,
|
||||||
|
r_sys_tool_off_shelve,
|
||||||
|
r_sys_tool_pass,
|
||||||
|
r_sys_tool_reject
|
||||||
|
} from '@/services/system'
|
||||||
|
import {
|
||||||
|
COLOR_BACKGROUND,
|
||||||
|
COLOR_ERROR_SECONDARY,
|
||||||
|
COLOR_PRODUCTION,
|
||||||
|
DATABASE_DELETE_SUCCESS,
|
||||||
|
DATABASE_SELECT_SUCCESS,
|
||||||
|
DATABASE_UPDATE_SUCCESS,
|
||||||
|
TOOL_NOT_UNDER_REVIEW
|
||||||
|
} from '@/constants/common.constants.ts'
|
||||||
|
import FlexBox from '@/components/common/FlexBox.tsx'
|
||||||
|
import Card from '@/components/common/Card.tsx'
|
||||||
|
import FitFullscreen from '@/components/common/FitFullscreen.tsx'
|
||||||
|
import HideScrollbar from '@/components/common/HideScrollbar.tsx'
|
||||||
|
import Icon from '@ant-design/icons'
|
||||||
|
|
||||||
const Tools = () => {
|
const Tools = () => {
|
||||||
const template = templates['base']
|
const navigate = useNavigate()
|
||||||
return (
|
const [modal, contextHolder] = AntdModal.useModal()
|
||||||
<Playground
|
const [tableParams, setTableParams] = useState<TableParam>({
|
||||||
initFiles={template.files}
|
pagination: {
|
||||||
initTsconfigRaw={JSON.stringify(template.tsconfig, null, 2)}
|
current: 1,
|
||||||
initImportMapRaw={JSON.stringify(template.importMap, null, 2)}
|
pageSize: 20,
|
||||||
|
position: ['bottomCenter'],
|
||||||
|
showTotal: (total, range) =>
|
||||||
|
`第 ${
|
||||||
|
range[0] === range[1] ? `${range[0]}` : `${range[0]}~${range[1]}`
|
||||||
|
} 项 共 ${total} 项`
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const [toolData, setToolData] = useState<ToolVo[]>([])
|
||||||
|
const [isLoading, setIsLoading] = useState(false)
|
||||||
|
const [searchType, setSearchType] = useState('ALL')
|
||||||
|
const [searchValue, setSearchValue] = useState('')
|
||||||
|
const [isUseRegex, setIsUseRegex] = useState(false)
|
||||||
|
const [isRegexLegal, setIsRegexLegal] = useState(true)
|
||||||
|
const [form] = AntdForm.useForm<{ pass: boolean }>()
|
||||||
|
|
||||||
|
const dataColumns: _ColumnsType<ToolVo> = [
|
||||||
|
{
|
||||||
|
dataIndex: 'icon',
|
||||||
|
title: '图标',
|
||||||
|
render: (value) => (
|
||||||
|
<AntdAvatar
|
||||||
|
src={
|
||||||
|
<AntdImage
|
||||||
|
preview={{ mask: <Icon component={IconOxygenEye}></Icon> }}
|
||||||
|
src={`data:image/svg+xml;base64,${value}`}
|
||||||
|
alt={'Avatar'}
|
||||||
/>
|
/>
|
||||||
|
}
|
||||||
|
style={{ background: COLOR_BACKGROUND }}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
width: '0',
|
||||||
|
align: 'center'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '名称',
|
||||||
|
render: (_, record) => (
|
||||||
|
<AntdTooltip title={record.description}>{record.name}</AntdTooltip>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
{ dataIndex: 'toolId', title: '工具 ID' },
|
||||||
|
{ dataIndex: 'ver', title: '版本' },
|
||||||
|
{
|
||||||
|
title: '作者',
|
||||||
|
render: (_, record) => `${record.author.userInfo.nickname}(${record.author.username})`
|
||||||
|
},
|
||||||
|
{
|
||||||
|
dataIndex: 'keywords',
|
||||||
|
title: '关键词',
|
||||||
|
render: (value: string[]) => value.map((item) => <AntdTag>{item}</AntdTag>)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
dataIndex: 'categories',
|
||||||
|
title: '类别',
|
||||||
|
render: (value: { name: string }[]) =>
|
||||||
|
value.map((item) => <AntdTag>{item.name}</AntdTag>)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
dataIndex: 'review',
|
||||||
|
title: '状态',
|
||||||
|
width: '4em',
|
||||||
|
render: (value) => {
|
||||||
|
switch (value) {
|
||||||
|
case 'NONE':
|
||||||
|
return <AntdTag>编码</AntdTag>
|
||||||
|
case 'PROCESSING':
|
||||||
|
return <AntdTag color={'purple'}>审核</AntdTag>
|
||||||
|
case 'REJECT':
|
||||||
|
return <AntdTag color={'yellow'}>驳回</AntdTag>
|
||||||
|
case 'PASS':
|
||||||
|
return <AntdTag color={'green'}>通过</AntdTag>
|
||||||
|
}
|
||||||
|
},
|
||||||
|
filters: [
|
||||||
|
{ text: '编码', value: 'NONE' },
|
||||||
|
{ text: '审核', value: 'PROCESSING' },
|
||||||
|
{ text: '驳回', value: 'REJECT' },
|
||||||
|
{ text: '通过', value: 'PASS' }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '操作',
|
||||||
|
width: '12em',
|
||||||
|
align: 'center',
|
||||||
|
render: (_, record) => (
|
||||||
|
<>
|
||||||
|
<AntdSpace size={'middle'}>
|
||||||
|
<a
|
||||||
|
style={{ color: COLOR_PRODUCTION }}
|
||||||
|
onClick={handleOnViewBtnClick(record)}
|
||||||
|
>
|
||||||
|
查看
|
||||||
|
</a>
|
||||||
|
{record.review === 'PROCESSING' && (
|
||||||
|
<a
|
||||||
|
style={{ color: COLOR_PRODUCTION }}
|
||||||
|
onClick={handleOnReviewBtnClick(record)}
|
||||||
|
>
|
||||||
|
审核
|
||||||
|
</a>
|
||||||
|
)}
|
||||||
|
{record.review === 'PASS' && (
|
||||||
|
<a
|
||||||
|
style={{ color: COLOR_PRODUCTION }}
|
||||||
|
onClick={handleOnOffShelveBtnClick(record)}
|
||||||
|
>
|
||||||
|
下架
|
||||||
|
</a>
|
||||||
|
)}
|
||||||
|
<a
|
||||||
|
style={{ color: COLOR_PRODUCTION }}
|
||||||
|
onClick={handleOnDeleteBtnClick(record)}
|
||||||
|
>
|
||||||
|
删除
|
||||||
|
</a>
|
||||||
|
</AntdSpace>{' '}
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
const handleOnTableChange = (
|
||||||
|
pagination: _TablePaginationConfig,
|
||||||
|
filters: Record<string, _FilterValue | null>,
|
||||||
|
sorter: _SorterResult<ToolVo> | _SorterResult<ToolVo>[]
|
||||||
|
) => {
|
||||||
|
pagination = { ...tableParams.pagination, ...pagination }
|
||||||
|
if (Array.isArray(sorter)) {
|
||||||
|
setTableParams({
|
||||||
|
pagination,
|
||||||
|
filters,
|
||||||
|
sortField: sorter.map((value) => value.field).join(',')
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
setTableParams({
|
||||||
|
pagination,
|
||||||
|
filters,
|
||||||
|
sortField: sorter.field,
|
||||||
|
sortOrder: sorter.order
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pagination.pageSize !== tableParams.pagination?.pageSize) {
|
||||||
|
setToolData([])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleOnViewBtnClick = (value: ToolVo) => {
|
||||||
|
return () => {
|
||||||
|
navigate(`/system/tools/code/${value.id}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleOnReviewBtnClick = (value: ToolVo) => {
|
||||||
|
return () => {
|
||||||
|
form.setFieldValue('pass', undefined)
|
||||||
|
void modal.confirm({
|
||||||
|
title: '审核',
|
||||||
|
content: (
|
||||||
|
<AntdForm form={form}>
|
||||||
|
<AntdForm.Item
|
||||||
|
name={'pass'}
|
||||||
|
style={{ marginTop: 10 }}
|
||||||
|
rules={[{ required: true }]}
|
||||||
|
>
|
||||||
|
<AntdRadio.Group>
|
||||||
|
<AntdRadio value={true}>通过</AntdRadio>
|
||||||
|
<AntdRadio value={false}>驳回</AntdRadio>
|
||||||
|
</AntdRadio.Group>
|
||||||
|
</AntdForm.Item>
|
||||||
|
</AntdForm>
|
||||||
|
),
|
||||||
|
onOk: () =>
|
||||||
|
form.validateFields().then(() => {
|
||||||
|
return new Promise<void>((resolve) => {
|
||||||
|
switch (form.getFieldValue('pass')) {
|
||||||
|
case true:
|
||||||
|
void r_sys_tool_pass(value.id).then((res) => {
|
||||||
|
const response = res.data
|
||||||
|
switch (response.code) {
|
||||||
|
case DATABASE_UPDATE_SUCCESS:
|
||||||
|
void message.success('更新成功')
|
||||||
|
getTool()
|
||||||
|
resolve()
|
||||||
|
break
|
||||||
|
case TOOL_NOT_UNDER_REVIEW:
|
||||||
|
void message.warning('工具处于非审核状态')
|
||||||
|
resolve()
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
void message.error('更新失败,请稍后重试')
|
||||||
|
resolve()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
void r_sys_tool_reject(value.id).then((res) => {
|
||||||
|
const response = res.data
|
||||||
|
switch (response.code) {
|
||||||
|
case DATABASE_UPDATE_SUCCESS:
|
||||||
|
void message.success('更新成功')
|
||||||
|
resolve()
|
||||||
|
break
|
||||||
|
case TOOL_NOT_UNDER_REVIEW:
|
||||||
|
void message.warning('工具处于非审核状态')
|
||||||
|
resolve()
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
void message.error('更新失败,请稍后重试')
|
||||||
|
resolve()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleOnOffShelveBtnClick = (value: ToolVo) => {
|
||||||
|
return () => {
|
||||||
|
modal
|
||||||
|
.confirm({
|
||||||
|
title: '确定下架',
|
||||||
|
content: `确定下架工具 ${value.author.username}:${value.toolId}:${value.ver} 吗?`
|
||||||
|
})
|
||||||
|
.then(
|
||||||
|
(confirmed) => {
|
||||||
|
if (confirmed) {
|
||||||
|
setIsLoading(true)
|
||||||
|
|
||||||
|
void r_sys_tool_off_shelve(value.id)
|
||||||
|
.then((res) => {
|
||||||
|
const response = res.data
|
||||||
|
if (response.code === DATABASE_UPDATE_SUCCESS) {
|
||||||
|
void message.success('下架成功')
|
||||||
|
setTimeout(() => {
|
||||||
|
getTool()
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
void message.error('下架失败,请稍后重试')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
setIsLoading(false)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
() => {}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleOnDeleteBtnClick = (value: ToolVo) => {
|
||||||
|
return () => {
|
||||||
|
modal
|
||||||
|
.confirm({
|
||||||
|
title: '确定删除',
|
||||||
|
content: `确定删除工具 ${value.author.username}:${value.toolId}:${value.ver} 吗?`
|
||||||
|
})
|
||||||
|
.then(
|
||||||
|
(confirmed) => {
|
||||||
|
if (confirmed) {
|
||||||
|
setIsLoading(true)
|
||||||
|
|
||||||
|
void r_sys_tool_delete(value.id)
|
||||||
|
.then((res) => {
|
||||||
|
const response = res.data
|
||||||
|
if (response.code === DATABASE_DELETE_SUCCESS) {
|
||||||
|
void message.success('删除成功')
|
||||||
|
setTimeout(() => {
|
||||||
|
getTool()
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
void message.error('删除失败,请稍后重试')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
setIsLoading(false)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
() => {}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleOnSearchValueChange = (e: ChangeEvent<HTMLInputElement>) => {
|
||||||
|
setSearchValue(e.target.value)
|
||||||
|
|
||||||
|
if (isUseRegex) {
|
||||||
|
try {
|
||||||
|
RegExp(e.target.value)
|
||||||
|
setIsRegexLegal(!(e.target.value.includes('{}') || e.target.value.includes('[]')))
|
||||||
|
} catch (e) {
|
||||||
|
setIsRegexLegal(false)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
setIsRegexLegal(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleOnSearchValueKeyDown = (e: KeyboardEvent) => {
|
||||||
|
if (e.key === 'Enter') {
|
||||||
|
getTool()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleOnSearchTypeChange = (value: string) => {
|
||||||
|
setSearchType(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleOnUseRegexChange = (e: _CheckboxChangeEvent) => {
|
||||||
|
setIsUseRegex(e.target.checked)
|
||||||
|
if (e.target.checked) {
|
||||||
|
try {
|
||||||
|
RegExp(searchValue)
|
||||||
|
setIsRegexLegal(!(searchValue.includes('{}') || searchValue.includes('[]')))
|
||||||
|
} catch (e) {
|
||||||
|
setIsRegexLegal(false)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
setIsRegexLegal(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleOnQueryBtnClick = () => {
|
||||||
|
getTool()
|
||||||
|
}
|
||||||
|
|
||||||
|
const getTool = () => {
|
||||||
|
if (isLoading) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isRegexLegal) {
|
||||||
|
void message.error('非法正则表达式')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
setIsLoading(true)
|
||||||
|
|
||||||
|
void r_sys_tool_get({
|
||||||
|
currentPage: tableParams.pagination?.current,
|
||||||
|
pageSize: tableParams.pagination?.pageSize,
|
||||||
|
sortField:
|
||||||
|
tableParams.sortField && tableParams.sortOrder
|
||||||
|
? (tableParams.sortField as string)
|
||||||
|
: undefined,
|
||||||
|
sortOrder:
|
||||||
|
tableParams.sortField && tableParams.sortOrder ? tableParams.sortOrder : undefined,
|
||||||
|
searchType,
|
||||||
|
searchValue: searchValue.trim().length ? searchValue : undefined,
|
||||||
|
searchRegex: isUseRegex ? isUseRegex : undefined,
|
||||||
|
...tableParams.filters
|
||||||
|
})
|
||||||
|
.then((res) => {
|
||||||
|
const response = res.data
|
||||||
|
switch (response.code) {
|
||||||
|
case DATABASE_SELECT_SUCCESS:
|
||||||
|
setToolData(response.data!.records)
|
||||||
|
setTableParams({
|
||||||
|
...tableParams,
|
||||||
|
pagination: {
|
||||||
|
...tableParams.pagination,
|
||||||
|
total: response.data!.total
|
||||||
|
}
|
||||||
|
})
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
void message.error('获取失败,请稍后重试')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
setIsLoading(false)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
getTool()
|
||||||
|
}, [
|
||||||
|
JSON.stringify(tableParams.filters),
|
||||||
|
JSON.stringify(tableParams.sortField),
|
||||||
|
JSON.stringify(tableParams.sortOrder),
|
||||||
|
JSON.stringify(tableParams.pagination?.pageSize),
|
||||||
|
JSON.stringify(tableParams.pagination?.current)
|
||||||
|
])
|
||||||
|
|
||||||
|
const toolbar = (
|
||||||
|
<FlexBox direction={'horizontal'} gap={10}>
|
||||||
|
<Card style={{ overflow: 'inherit' }}>
|
||||||
|
<AntdInput
|
||||||
|
addonBefore={
|
||||||
|
<AntdSelect
|
||||||
|
value={searchType}
|
||||||
|
onChange={handleOnSearchTypeChange}
|
||||||
|
style={{ width: '6em' }}
|
||||||
|
dropdownStyle={{ textAlign: 'center' }}
|
||||||
|
></AntdSelect>
|
||||||
|
}
|
||||||
|
suffix={
|
||||||
|
<>
|
||||||
|
{!isRegexLegal && (
|
||||||
|
<span style={{ color: COLOR_ERROR_SECONDARY }}>非法表达式</span>
|
||||||
|
)}
|
||||||
|
<AntdCheckbox checked={isUseRegex} onChange={handleOnUseRegexChange}>
|
||||||
|
<AntdTooltip title={'正则表达式'}>.*</AntdTooltip>
|
||||||
|
</AntdCheckbox>
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
allowClear
|
||||||
|
value={searchValue}
|
||||||
|
onChange={handleOnSearchValueChange}
|
||||||
|
onKeyDown={handleOnSearchValueKeyDown}
|
||||||
|
status={isRegexLegal ? undefined : 'error'}
|
||||||
|
/>
|
||||||
|
</Card>
|
||||||
|
<Card style={{ overflow: 'inherit', flex: '0 0 auto' }}>
|
||||||
|
<AntdButton onClick={handleOnQueryBtnClick} type={'primary'}>
|
||||||
|
查询
|
||||||
|
</AntdButton>
|
||||||
|
</Card>
|
||||||
|
</FlexBox>
|
||||||
|
)
|
||||||
|
|
||||||
|
const table = (
|
||||||
|
<Card>
|
||||||
|
<AntdTable
|
||||||
|
dataSource={toolData}
|
||||||
|
columns={dataColumns}
|
||||||
|
pagination={tableParams.pagination}
|
||||||
|
loading={isLoading}
|
||||||
|
onChange={handleOnTableChange}
|
||||||
|
/>
|
||||||
|
</Card>
|
||||||
|
)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<FitFullscreen>
|
||||||
|
<HideScrollbar
|
||||||
|
style={{ padding: 30 }}
|
||||||
|
isShowVerticalScrollbar
|
||||||
|
autoHideWaitingTime={1000}
|
||||||
|
>
|
||||||
|
<FlexBox gap={20}>
|
||||||
|
{toolbar}
|
||||||
|
{table}
|
||||||
|
</FlexBox>
|
||||||
|
</HideScrollbar>
|
||||||
|
</FitFullscreen>
|
||||||
|
{contextHolder}
|
||||||
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ const User = () => {
|
|||||||
const dataColumns: _ColumnsType<UserWithRoleInfoVo> = [
|
const dataColumns: _ColumnsType<UserWithRoleInfoVo> = [
|
||||||
{
|
{
|
||||||
dataIndex: 'username',
|
dataIndex: 'username',
|
||||||
title: '用户',
|
title: '用户名',
|
||||||
render: (value, record) => <AntdTooltip title={record.id}>{value}</AntdTooltip>,
|
render: (value, record) => <AntdTooltip title={record.id}>{value}</AntdTooltip>,
|
||||||
width: '0'
|
width: '0'
|
||||||
},
|
},
|
||||||
@@ -249,7 +249,7 @@ const User = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (pagination.pageSize !== tableParams.pagination?.pageSize) {
|
if (pagination.pageSize !== tableParams.pagination?.pageSize) {
|
||||||
setGroupData([])
|
setUserData([])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -584,7 +584,7 @@ const User = () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleOnSearchNameKeyDown = (e: KeyboardEvent) => {
|
const handleOnSearchValueKeyDown = (e: KeyboardEvent) => {
|
||||||
if (e.key === 'Enter') {
|
if (e.key === 'Enter') {
|
||||||
getUser()
|
getUser()
|
||||||
}
|
}
|
||||||
@@ -936,7 +936,7 @@ const User = () => {
|
|||||||
allowClear
|
allowClear
|
||||||
value={searchValue}
|
value={searchValue}
|
||||||
onChange={handleOnSearchValueChange}
|
onChange={handleOnSearchValueChange}
|
||||||
onKeyDown={handleOnSearchNameKeyDown}
|
onKeyDown={handleOnSearchValueKeyDown}
|
||||||
status={isRegexLegal ? undefined : 'error'}
|
status={isRegexLegal ? undefined : 'error'}
|
||||||
/>
|
/>
|
||||||
</Card>
|
</Card>
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ const SystemFramework = () => {
|
|||||||
>
|
>
|
||||||
{route.children?.map(
|
{route.children?.map(
|
||||||
(subRoute) =>
|
(subRoute) =>
|
||||||
subRoute &&
|
subRoute.menu &&
|
||||||
subRoute.name && (
|
subRoute.name && (
|
||||||
<Sidebar.Item
|
<Sidebar.Item
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ const Create = () => {
|
|||||||
void message.success(
|
void message.success(
|
||||||
`创建工具 ${response.data!.name}<${response.data!.toolId}>:${response.data!.ver} 成功`
|
`创建工具 ${response.data!.name}<${response.data!.toolId}>:${response.data!.ver} 成功`
|
||||||
)
|
)
|
||||||
navigate(`/view/!/${response.data!.toolId}/${response.data!.ver}`)
|
navigate(`/edit/${response.data!.toolId}`)
|
||||||
break
|
break
|
||||||
case DATABASE_DUPLICATE_KEY:
|
case DATABASE_DUPLICATE_KEY:
|
||||||
void message.warning('已存在相同 ID 的应用')
|
void message.warning('已存在相同 ID 的应用')
|
||||||
|
|||||||
@@ -96,11 +96,15 @@ const Edit = () => {
|
|||||||
break
|
break
|
||||||
case TOOL_UNDER_REVIEW:
|
case TOOL_UNDER_REVIEW:
|
||||||
void message.error('保存失败:工具审核中')
|
void message.error('保存失败:工具审核中')
|
||||||
navigate('/')
|
setTimeout(() => {
|
||||||
|
navigate(-1)
|
||||||
|
}, 3000)
|
||||||
break
|
break
|
||||||
case TOOL_HAS_BEEN_PUBLISHED:
|
case TOOL_HAS_BEEN_PUBLISHED:
|
||||||
void message.error('保存失败:工具已发布')
|
void message.error('保存失败:工具已发布')
|
||||||
navigate('/')
|
setTimeout(() => {
|
||||||
|
navigate(-1)
|
||||||
|
}, 3000)
|
||||||
break
|
break
|
||||||
default:
|
default:
|
||||||
void message.error('保存失败,请稍后重试')
|
void message.error('保存失败,请稍后重试')
|
||||||
@@ -158,11 +162,15 @@ const Edit = () => {
|
|||||||
break
|
break
|
||||||
case TOOL_UNDER_REVIEW:
|
case TOOL_UNDER_REVIEW:
|
||||||
void message.error('保存失败:工具审核中')
|
void message.error('保存失败:工具审核中')
|
||||||
navigate('/')
|
setTimeout(() => {
|
||||||
|
navigate(-1)
|
||||||
|
}, 3000)
|
||||||
break
|
break
|
||||||
case TOOL_HAS_BEEN_PUBLISHED:
|
case TOOL_HAS_BEEN_PUBLISHED:
|
||||||
void message.error('保存失败:工具已发布')
|
void message.error('保存失败:工具已发布')
|
||||||
navigate('/')
|
setTimeout(() => {
|
||||||
|
navigate(-1)
|
||||||
|
}, 3000)
|
||||||
break
|
break
|
||||||
default:
|
default:
|
||||||
void message.error('保存失败,请稍后重试')
|
void message.error('保存失败,请稍后重试')
|
||||||
@@ -215,16 +223,22 @@ const Edit = () => {
|
|||||||
break
|
break
|
||||||
case 'PROCESSING':
|
case 'PROCESSING':
|
||||||
void message.warning('工具审核中,请勿修改')
|
void message.warning('工具审核中,请勿修改')
|
||||||
navigate('/')
|
setTimeout(() => {
|
||||||
|
navigate(-1)
|
||||||
|
}, 3000)
|
||||||
break
|
break
|
||||||
default:
|
default:
|
||||||
void message.warning('请先创建新版本后编辑工具')
|
void message.warning('请先创建新版本后编辑工具')
|
||||||
navigate('/')
|
setTimeout(() => {
|
||||||
|
navigate(-1)
|
||||||
|
}, 3000)
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
case DATABASE_NO_RECORD_FOUND:
|
case DATABASE_NO_RECORD_FOUND:
|
||||||
void message.error('未找到指定工具')
|
void message.error('未找到指定工具')
|
||||||
navigate('/')
|
setTimeout(() => {
|
||||||
|
navigate(-1)
|
||||||
|
}, 3000)
|
||||||
break
|
break
|
||||||
default:
|
default:
|
||||||
void message.error('获取工具信息失败,请稍后重试')
|
void message.error('获取工具信息失败,请稍后重试')
|
||||||
|
|||||||
@@ -51,7 +51,9 @@ const View = () => {
|
|||||||
break
|
break
|
||||||
case DATABASE_NO_RECORD_FOUND:
|
case DATABASE_NO_RECORD_FOUND:
|
||||||
void message.error('未找到指定工具')
|
void message.error('未找到指定工具')
|
||||||
navigate('/')
|
setTimeout(() => {
|
||||||
|
navigate(-1)
|
||||||
|
}, 3000)
|
||||||
break
|
break
|
||||||
default:
|
default:
|
||||||
void message.error('获取工具信息失败,请稍后重试')
|
void message.error('获取工具信息失败,请稍后重试')
|
||||||
@@ -65,7 +67,9 @@ const View = () => {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (username === '!' && !getLoginStatus()) {
|
if (username === '!' && !getLoginStatus()) {
|
||||||
navigate('/')
|
setTimeout(() => {
|
||||||
|
navigate(-1)
|
||||||
|
}, 3000)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (username !== '!' && ver) {
|
if (username !== '!' && ver) {
|
||||||
|
|||||||
@@ -284,9 +284,7 @@ const Tools = () => {
|
|||||||
switch (response.code) {
|
switch (response.code) {
|
||||||
case DATABASE_UPDATE_SUCCESS:
|
case DATABASE_UPDATE_SUCCESS:
|
||||||
void message.success('创建新版本成功')
|
void message.success('创建新版本成功')
|
||||||
navigate(
|
navigate(`/edit/${response.data!.toolId}`)
|
||||||
`/view/!/${response.data!.toolId}/${response.data!.ver}`
|
|
||||||
)
|
|
||||||
resolve()
|
resolve()
|
||||||
break
|
break
|
||||||
case TOOL_ILLEGAL_VERSION:
|
case TOOL_ILLEGAL_VERSION:
|
||||||
|
|||||||
@@ -49,6 +49,20 @@ const system: RouteJsonObject[] = [
|
|||||||
menu: true,
|
menu: true,
|
||||||
autoHide: true
|
autoHide: true
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: 'code/:id',
|
||||||
|
absolutePath: '/system/tools/code',
|
||||||
|
id: 'system-tools-code',
|
||||||
|
component: lazy(() => import('@/pages/System/Tools/Code')),
|
||||||
|
name: '查看工具'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'execute/:id',
|
||||||
|
absolutePath: '/system/tools/execute',
|
||||||
|
id: 'system-tools-execute',
|
||||||
|
component: lazy(() => import('@/pages/System/Tools/Execute')),
|
||||||
|
name: '运行工具'
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: 'template',
|
path: 'template',
|
||||||
absolutePath: '/system/tools/template',
|
absolutePath: '/system/tools/template',
|
||||||
|
|||||||
@@ -19,7 +19,8 @@ import {
|
|||||||
URL_SYS_SETTINGS_SENSITIVE,
|
URL_SYS_SETTINGS_SENSITIVE,
|
||||||
URL_SYS_TOOL_CATEGORY,
|
URL_SYS_TOOL_CATEGORY,
|
||||||
URL_SYS_TOOL_BASE,
|
URL_SYS_TOOL_BASE,
|
||||||
URL_SYS_TOOL_TEMPLATE
|
URL_SYS_TOOL_TEMPLATE,
|
||||||
|
URL_SYS_TOOL
|
||||||
} from '@/constants/urls.constants'
|
} from '@/constants/urls.constants'
|
||||||
import request from '@/services/index'
|
import request from '@/services/index'
|
||||||
|
|
||||||
@@ -154,3 +155,16 @@ export const r_sys_tool_template_update = (param: ToolTemplateAddEditParam) =>
|
|||||||
|
|
||||||
export const r_sys_tool_template_delete = (id: string) =>
|
export const r_sys_tool_template_delete = (id: string) =>
|
||||||
request.delete(`${URL_SYS_TOOL_TEMPLATE}/${id}`)
|
request.delete(`${URL_SYS_TOOL_TEMPLATE}/${id}`)
|
||||||
|
|
||||||
|
export const r_sys_tool_get = (param: ToolManagementGetParam) =>
|
||||||
|
request.get<PageVo<ToolVo>>(URL_SYS_TOOL, param)
|
||||||
|
|
||||||
|
export const r_sys_tool_get_one = (id: string) => request.get<ToolVo>(`${URL_SYS_TOOL}/${id}`)
|
||||||
|
|
||||||
|
export const r_sys_tool_pass = (id: string) => request.post<ToolVo>(`${URL_SYS_TOOL}/${id}`)
|
||||||
|
|
||||||
|
export const r_sys_tool_reject = (id: string) => request.put<ToolVo>(`${URL_SYS_TOOL}/${id}`)
|
||||||
|
|
||||||
|
export const r_sys_tool_off_shelve = (id: string) => request.patch<ToolVo>(`${URL_SYS_TOOL}/${id}`)
|
||||||
|
|
||||||
|
export const r_sys_tool_delete = (id: string) => request.delete(`${URL_SYS_TOOL}/${id}`)
|
||||||
|
|||||||
Reference in New Issue
Block a user