Add tool view page
This commit is contained in:
@@ -28,6 +28,14 @@
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
left: 10px;
|
||||
width: 6em;
|
||||
}
|
||||
|
||||
.upgrade-bt {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
right: 10px;
|
||||
font-size: 1.8em;
|
||||
}
|
||||
|
||||
.icon {
|
||||
@@ -61,7 +69,7 @@
|
||||
|
||||
& > :not(:first-child) {
|
||||
.info {
|
||||
transform: translateY(20px);
|
||||
transform: translateY(40px);
|
||||
transition: all 0.1s ease;
|
||||
}
|
||||
|
||||
|
||||
8
src/assets/css/pages/tools/view.scss
Normal file
8
src/assets/css/pages/tools/view.scss
Normal file
@@ -0,0 +1,8 @@
|
||||
[data-component=tools-view] {
|
||||
padding: 30px;
|
||||
|
||||
.card-box {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
1
src/assets/svg/upgrade.svg
Normal file
1
src/assets/svg/upgrade.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024"><path d="M837.008696 338.365217 583.234783 84.591304c-24.486957-24.486957-66.782609-24.486957-91.269565 0L235.965217 338.365217c-17.808696 17.808696-24.486957 46.747826-13.356522 71.234783 11.130435 24.486957 33.391304 40.069565 60.104348 40.069565l91.269565 0L373.982609 645.565217l46.747826 0L420.730435 402.921739l-135.791304 0c-11.130435 0-15.582609-8.904348-17.808696-11.130435-2.226087-2.226087-4.452174-13.356522 4.452174-20.034783L523.130435 115.756522C527.582609 113.530435 532.034783 111.304348 536.486957 111.304348s8.904348 2.226087 13.356522 4.452174l256 256c8.904348 8.904348 4.452174 17.808696 4.452174 20.034783-2.226087 2.226087-6.678261 11.130435-17.808696 11.130435l-135.791304 0 0 289.391304c0 2.226087-2.226087 2.226087-2.226087 2.226087L373.982609 694.53913l0 46.747826 278.26087 0c26.713043 0 48.973913-22.26087 48.973913-48.973913L701.217391 449.669565l91.269565 0c26.713043 0 48.973913-15.582609 60.104348-40.069565C861.495652 385.113043 857.043478 358.4 837.008696 338.365217L837.008696 338.365217zM837.008696 338.365217M714.573913 839.234783c0 15.582609-11.130435 26.713043-26.713043 26.713043L394.017391 865.947826c-15.582609 0-26.713043-11.130435-26.713043-26.713043l0 0c0-15.582609 11.130435-26.713043 26.713043-26.713043l293.843478 0C703.443478 812.521739 714.573913 823.652174 714.573913 839.234783L714.573913 839.234783 714.573913 839.234783zM714.573913 839.234783M670.052174 946.086957c0 11.130435-8.904348 22.26087-20.034783 22.26087l-220.382609 0c-11.130435 0-20.034783-8.904348-20.034783-22.26087l0 0c0-11.130435 8.904348-22.26087 20.034783-22.26087l220.382609 0C661.147826 923.826087 670.052174 934.956522 670.052174 946.086957L670.052174 946.086957 670.052174 946.086957zM670.052174 946.086957" /></svg>
|
||||
|
After Width: | Height: | Size: 1.8 KiB |
@@ -74,6 +74,8 @@ export const DATABASE_EXECUTE_ERROR = 30050
|
||||
export const DATABASE_DUPLICATE_KEY = 30051
|
||||
export const DATABASE_NO_RECORD_FOUND = 30052
|
||||
|
||||
export const TOOL_ILLEGAL_VERSION = 40050
|
||||
|
||||
export const API_AVATAR_SUCCESS = 50100
|
||||
export const API_AVATAR_ERROR = 50150
|
||||
|
||||
|
||||
10
src/global.d.ts
vendored
10
src/global.d.ts
vendored
@@ -531,15 +531,16 @@ interface ToolVo {
|
||||
toolId: string
|
||||
icon: string
|
||||
description: string
|
||||
baseId: string
|
||||
base: ToolBaseVo
|
||||
author: UserInfoVo
|
||||
ver: string
|
||||
keywords: string[]
|
||||
categories: ToolCategoryVo[]
|
||||
source: ToolDataVo
|
||||
dist: ToolDataVo
|
||||
entryPoint: string
|
||||
publish: string
|
||||
review: number
|
||||
review: 'NONE' | 'PASS' | 'REJECT'
|
||||
createTime: string
|
||||
updateTime: string
|
||||
}
|
||||
@@ -554,3 +555,8 @@ interface ToolCreateParam {
|
||||
keywords: string[]
|
||||
categories: string[]
|
||||
}
|
||||
|
||||
interface ToolUpgradeParam {
|
||||
toolId: string
|
||||
ver: string
|
||||
}
|
||||
|
||||
@@ -11,9 +11,9 @@ import {
|
||||
r_tool_template_get,
|
||||
r_tool_template_get_one
|
||||
} from '@/services/tool'
|
||||
import compiler from '@/components/Playground/compiler'
|
||||
import { IImportMap } from '@/components/Playground/shared'
|
||||
import { base64ToFiles, base64ToStr, IMPORT_MAP_FILE_NAME } from '@/components/Playground/files'
|
||||
import compiler from '@/components/Playground/compiler'
|
||||
import FlexBox from '@/components/common/FlexBox'
|
||||
import Card from '@/components/common/Card'
|
||||
import FitFullscreen from '@/components/common/FitFullscreen'
|
||||
@@ -21,6 +21,7 @@ import HideScrollbar from '@/components/common/HideScrollbar'
|
||||
import Playground from '@/components/Playground'
|
||||
|
||||
const Create = () => {
|
||||
const navigate = useNavigate()
|
||||
const [form] = AntdForm.useForm<ToolCreateParam>()
|
||||
const formValues = AntdForm.useWatch([], form)
|
||||
const [templateData, setTemplateData] = useState<ToolTemplateVo[]>()
|
||||
@@ -43,9 +44,10 @@ const Create = () => {
|
||||
void message.success(
|
||||
`创建工具 ${response.data!.name}<${response.data!.toolId}>:${response.data!.ver} 成功`
|
||||
)
|
||||
navigate(`/view/!/${response.data!.toolId}/${response.data!.ver}`)
|
||||
break
|
||||
case DATABASE_DUPLICATE_KEY:
|
||||
void message.warning('已存在相同 ID 相同版本或未发布版本的应用')
|
||||
void message.warning('已存在相同 ID 的应用')
|
||||
setCreating(false)
|
||||
break
|
||||
default:
|
||||
|
||||
@@ -1,11 +1,39 @@
|
||||
import { r_tool_detail } from '@/services/tool.tsx'
|
||||
import { DATABASE_NO_RECORD_FOUND, DATABASE_SELECT_SUCCESS } from '@/constants/common.constants.ts'
|
||||
import { getLoginStatus } from '@/util/auth.tsx'
|
||||
import '@/assets/css/pages/tools/view.scss'
|
||||
import { DATABASE_NO_RECORD_FOUND, DATABASE_SELECT_SUCCESS } from '@/constants/common.constants'
|
||||
import { getLoginStatus } from '@/util/auth'
|
||||
import { r_tool_detail } from '@/services/tool'
|
||||
import compiler from '@/components/Playground/compiler'
|
||||
import { IImportMap } from '@/components/Playground/shared'
|
||||
import { base64ToFiles, base64ToStr, IMPORT_MAP_FILE_NAME } from '@/components/Playground/files'
|
||||
import FitFullscreen from '@/components/common/FitFullscreen'
|
||||
import Playground from '@/components/Playground'
|
||||
import Card from '@/components/common/Card'
|
||||
|
||||
const View = () => {
|
||||
const navigate = useNavigate()
|
||||
const [loading, setLoading] = useState(false)
|
||||
const { username, toolId, ver } = useParams()
|
||||
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) {
|
||||
@@ -19,7 +47,7 @@ const View = () => {
|
||||
const response = res.data
|
||||
switch (response.code) {
|
||||
case DATABASE_SELECT_SUCCESS:
|
||||
console.log(response.data)
|
||||
render(response.data!)
|
||||
break
|
||||
case DATABASE_NO_RECORD_FOUND:
|
||||
void message.error('未找到指定工具')
|
||||
@@ -52,9 +80,14 @@ const View = () => {
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<>
|
||||
{username}:{toolId}:{ver}
|
||||
</>
|
||||
<FitFullscreen data-component={'tools-view'}>
|
||||
<Card>
|
||||
<Playground.Output.Preview.Render
|
||||
iframeKey={`${username}:${toolId}:${ver}`}
|
||||
compiledCode={compiledCode}
|
||||
/>
|
||||
</Card>
|
||||
</FitFullscreen>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,15 +1,19 @@
|
||||
import { DetailedHTMLProps, HTMLAttributes, ReactNode, useState } from 'react'
|
||||
import { DetailedHTMLProps, HTMLAttributes, ReactNode } from 'react'
|
||||
import Icon from '@ant-design/icons'
|
||||
import VanillaTilt, { TiltOptions } from 'vanilla-tilt'
|
||||
import '@/assets/css/pages/tools/index.scss'
|
||||
import {
|
||||
DATABASE_DELETE_SUCCESS,
|
||||
DATABASE_SELECT_SUCCESS,
|
||||
DATABASE_UPDATE_SUCCESS,
|
||||
TOOL_ILLEGAL_VERSION
|
||||
} from '@/constants/common.constants'
|
||||
import { getLoginStatus } from '@/util/auth'
|
||||
import { r_tool_delete, r_tool_get, r_tool_upgrade } from '@/services/tool'
|
||||
import FitFullscreen from '@/components/common/FitFullscreen'
|
||||
import HideScrollbar from '@/components/common/HideScrollbar'
|
||||
import FlexBox from '@/components/common/FlexBox'
|
||||
import Card from '@/components/common/Card'
|
||||
import { r_tool_get } from '@/services/tool.tsx'
|
||||
import { DATABASE_SELECT_SUCCESS } from '@/constants/common.constants.ts'
|
||||
import { getLoginStatus } from '@/util/auth.tsx'
|
||||
import { useNavigate } from 'react-router'
|
||||
|
||||
interface CommonCardProps
|
||||
extends DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement> {
|
||||
@@ -79,13 +83,13 @@ const CommonCard = ({
|
||||
{onEdit && (
|
||||
<div className={'edit'}>
|
||||
<AntdButton.Group size={'small'}>
|
||||
<AntdButton>编辑</AntdButton>
|
||||
{onPublish && <AntdButton>发布</AntdButton>}
|
||||
<AntdButton onClick={onEdit}>编辑</AntdButton>
|
||||
{onPublish && <AntdButton onClick={onPublish}>发布</AntdButton>}
|
||||
</AntdButton.Group>
|
||||
</div>
|
||||
)}
|
||||
{onDelete && (
|
||||
<AntdButton size={'small'} danger>
|
||||
<AntdButton size={'small'} danger onClick={onDelete}>
|
||||
删除
|
||||
</AntdButton>
|
||||
)}
|
||||
@@ -98,9 +102,11 @@ const CommonCard = ({
|
||||
|
||||
interface ToolCardProps {
|
||||
tools: ToolVo[]
|
||||
onDelete?: (tool: ToolVo) => void
|
||||
onUpgrade?: (tool: ToolVo) => void
|
||||
}
|
||||
|
||||
const ToolCard = ({ tools }: ToolCardProps) => {
|
||||
const ToolCard = ({ tools, onDelete, onUpgrade }: ToolCardProps) => {
|
||||
const navigate = useNavigate()
|
||||
const [selectedTool, setSelectedTool] = useState(tools[0])
|
||||
|
||||
@@ -112,11 +118,25 @@ const ToolCard = ({ tools }: ToolCardProps) => {
|
||||
navigate(`/view/!/${selectedTool.toolId}/${selectedTool.ver}`)
|
||||
}
|
||||
|
||||
const handleOnEditTool = () => {}
|
||||
const handleOnEditTool = () => {
|
||||
if (selectedTool.publish === '0') {
|
||||
return () => {}
|
||||
}
|
||||
}
|
||||
|
||||
const handleOnPublishTool = () => {}
|
||||
const handleOnPublishTool = () => {
|
||||
if (selectedTool.publish === '0') {
|
||||
return () => {}
|
||||
}
|
||||
}
|
||||
|
||||
const handleOnDeleteTool = () => {}
|
||||
const handleOnDeleteTool = () => {
|
||||
onDelete?.(selectedTool)
|
||||
}
|
||||
|
||||
const handleOnUpgradeTool = () => {
|
||||
onUpgrade?.(selectedTool)
|
||||
}
|
||||
|
||||
return (
|
||||
<CommonCard
|
||||
@@ -124,8 +144,8 @@ const ToolCard = ({ tools }: ToolCardProps) => {
|
||||
toolName={selectedTool.name}
|
||||
toolId={selectedTool.toolId}
|
||||
onOpen={handleOnOpenTool}
|
||||
onEdit={handleOnEditTool}
|
||||
onPublish={handleOnPublishTool}
|
||||
onEdit={handleOnEditTool()}
|
||||
onPublish={handleOnPublishTool()}
|
||||
onDelete={handleOnDeleteTool}
|
||||
>
|
||||
<AntdSelect
|
||||
@@ -138,13 +158,121 @@ const ToolCard = ({ tools }: ToolCardProps) => {
|
||||
label: `${value.ver}${value.publish === '0' ? '*' : ''}`
|
||||
}))}
|
||||
/>
|
||||
{tools.every((value) => value.publish !== '0') && (
|
||||
<AntdTooltip title={'更新'}>
|
||||
<Icon
|
||||
component={IconOxygenUpgrade}
|
||||
className={'upgrade-bt'}
|
||||
onClick={handleOnUpgradeTool}
|
||||
/>
|
||||
</AntdTooltip>
|
||||
)}
|
||||
</CommonCard>
|
||||
)
|
||||
}
|
||||
|
||||
const Tools = () => {
|
||||
const navigate = useNavigate()
|
||||
const [modal, contextHolder] = AntdModal.useModal()
|
||||
const [loading, setLoading] = useState(false)
|
||||
const [toolData, setToolData] = useState<ToolVo[]>()
|
||||
const [upgradeForm] = AntdForm.useForm<ToolUpgradeParam>()
|
||||
|
||||
const handleOnDeleteTool = (tool: ToolVo) => {
|
||||
modal
|
||||
.confirm({
|
||||
title: '确定删除',
|
||||
content: `确定删除工具 ${tool.name}:${tool.ver} 吗?`
|
||||
})
|
||||
.then(
|
||||
(confirmed) => {
|
||||
if (confirmed) {
|
||||
setLoading(true)
|
||||
|
||||
void r_tool_delete(tool.id)
|
||||
.then((res) => {
|
||||
const response = res.data
|
||||
if (response.code === DATABASE_DELETE_SUCCESS) {
|
||||
void message.success('删除成功')
|
||||
getTool()
|
||||
} else {
|
||||
void message.error('删除失败,请稍后重试')
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
setLoading(false)
|
||||
})
|
||||
}
|
||||
},
|
||||
() => {}
|
||||
)
|
||||
}
|
||||
|
||||
const handleOnUpgradeTool = (tool: ToolVo) => {
|
||||
void modal.confirm({
|
||||
title: '更新应用',
|
||||
content: (
|
||||
<>
|
||||
<AntdForm form={upgradeForm}>
|
||||
<AntdForm.Item
|
||||
initialValue={tool.toolId}
|
||||
name={'toolId'}
|
||||
label={'工具 ID'}
|
||||
style={{ marginTop: 10 }}
|
||||
>
|
||||
<AntdInput disabled />
|
||||
</AntdForm.Item>
|
||||
<AntdForm.Item
|
||||
name={'ver'}
|
||||
label={'版本'}
|
||||
rules={[
|
||||
{ required: true },
|
||||
{
|
||||
pattern: /^\d+\.\d+\.\d+$/,
|
||||
message: `格式必须为 '<数字>.<数字>.<数字>', eg. 1.0.3`
|
||||
}
|
||||
]}
|
||||
>
|
||||
<AntdInput maxLength={10} showCount placeholder={'请输入版本'} />
|
||||
</AntdForm.Item>
|
||||
</AntdForm>
|
||||
</>
|
||||
),
|
||||
onOk: () =>
|
||||
upgradeForm.validateFields().then(
|
||||
() => {
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
void r_tool_upgrade({
|
||||
toolId: upgradeForm.getFieldValue('toolId') as string,
|
||||
ver: upgradeForm.getFieldValue('ver') as string
|
||||
}).then((res) => {
|
||||
const response = res.data
|
||||
switch (response.code) {
|
||||
case DATABASE_UPDATE_SUCCESS:
|
||||
void message.success('创建新版本成功')
|
||||
const toolVo = response.data!
|
||||
navigate(`/view/!/${toolVo.toolId}/${toolVo.ver}`)
|
||||
resolve()
|
||||
break
|
||||
case TOOL_ILLEGAL_VERSION:
|
||||
void message.error('版本有误,请重新输入')
|
||||
reject()
|
||||
break
|
||||
default:
|
||||
void message.error('更新失败,请稍后重试')
|
||||
reject()
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
() => {
|
||||
return new Promise((_, reject) => {
|
||||
reject('未输入版本')
|
||||
})
|
||||
}
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
const getTool = () => {
|
||||
if (loading) {
|
||||
@@ -195,10 +323,18 @@ const Tools = () => {
|
||||
result[item.toolId].push(item)
|
||||
return result
|
||||
}, {})
|
||||
).map((value, index) => <ToolCard key={index} tools={value} />)}
|
||||
).map((value) => (
|
||||
<ToolCard
|
||||
key={JSON.stringify(value)}
|
||||
tools={value}
|
||||
onDelete={handleOnDeleteTool}
|
||||
onUpgrade={handleOnUpgradeTool}
|
||||
/>
|
||||
))}
|
||||
</FlexBox>
|
||||
</HideScrollbar>
|
||||
</FitFullscreen>
|
||||
{contextHolder}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -15,7 +15,11 @@ export const r_tool_category_get = () => request.get<ToolCategoryVo[]>(URL_TOOL_
|
||||
|
||||
export const r_tool_create = (param: ToolCreateParam) => request.post<ToolVo>(URL_TOOL, param)
|
||||
|
||||
export const r_tool_upgrade = (param: ToolUpgradeParam) => request.patch<ToolVo>(URL_TOOL, param)
|
||||
|
||||
export const r_tool_get = () => request.get<ToolVo[]>(URL_TOOL)
|
||||
|
||||
export const r_tool_detail = (username: string, toolId: string, ver: string) =>
|
||||
request.get<ToolVo>(`${URL_TOOL_DETAIL}/${username}/${toolId}/${ver}`)
|
||||
|
||||
export const r_tool_delete = (id: string) => request.delete(`${URL_TOOL}/${id}`)
|
||||
|
||||
Reference in New Issue
Block a user