Feat: all - support multiple platforms

This commit is contained in:
2024-03-18 17:23:31 +08:00
parent f985a2f750
commit 4b1a3fbc01
23 changed files with 487 additions and 92 deletions

View File

@@ -42,9 +42,11 @@ const Create = () => {
switch (response.code) {
case DATABASE_INSERT_SUCCESS:
void message.success(
`创建工具 ${response.data!.name}<${response.data!.toolId}>:${response.data!.ver} 成功`
`创建工具 ${response.data!.name}<${response.data!.toolId}:${response.data!.platform.slice(0, 1)}${response.data!.platform.slice(1).toLowerCase()}:${response.data!.ver}> 成功`
)
navigate(
`/edit/${response.data!.toolId}${response.data!.platform !== import.meta.env.VITE_PLATFORM ? `?platform=${response.data!.platform}` : ''}`
)
navigate(`/edit/${response.data!.toolId}`)
break
case DATABASE_DUPLICATE_KEY:
void message.warning('已存在相同 ID 的应用')
@@ -82,6 +84,30 @@ const Create = () => {
return false
}
const handleOnPlatformChange = (value: string) => {
setLoadingTemplate(true)
void r_tool_template_get({
platform: value
})
.then((res) => {
const response = res.data
switch (response.code) {
case DATABASE_SELECT_SUCCESS:
setTemplateData(response.data!)
response.data?.length
? form.setFieldValue('templateId', response.data?.[0].id)
: form.setFieldValue('templateId', null)
response.data?.length && handleOnTemplateChange(response.data?.[0].id)
break
default:
void message.error('获取模板列表失败,请稍后重试')
}
})
.finally(() => {
setLoadingTemplate(false)
})
}
const handleOnTemplateChange = (value: string) => {
setPreviewTemplate(value)
if (templateDetailData[value]) {
@@ -110,6 +136,7 @@ const Create = () => {
if (!template) {
return
}
setCompiledCode('')
try {
const baseDist = base64ToStr(template.base.dist.data!)
const files = base64ToFiles(template.source.data!)
@@ -123,6 +150,7 @@ const Create = () => {
})
.catch((reason) => {
void message.error(`编译失败:${reason}`)
setCompiledCode(baseDist)
})
} catch (e) {
void message.error(`载入模板 ${templateDetailData[previewTemplate].name} 失败`)
@@ -140,22 +168,7 @@ const Create = () => {
}, [form, formValues?.keywords])
useEffect(() => {
setLoadingTemplate(true)
setLoadingCategory(true)
void r_tool_template_get()
.then((res) => {
const response = res.data
switch (response.code) {
case DATABASE_SELECT_SUCCESS:
setTemplateData(response.data!)
break
default:
void message.error('获取模板列表失败,请稍后重试')
}
})
.finally(() => {
setLoadingTemplate(false)
})
void r_tool_category_get()
.then((res) => {
const response = res.data
@@ -254,6 +267,24 @@ const Create = () => {
placeholder={'请输入工具 ID'}
/>
</AntdForm.Item>
<AntdForm.Item
label={'平台'}
name={'platform'}
rules={[{ required: true }]}
>
<AntdSelect
placeholder={'请选择平台'}
onChange={handleOnPlatformChange}
>
<AntdSelect.Option key={'WEB'}>Web</AntdSelect.Option>
<AntdSelect.Option key={'DESKTOP'}>
Desktop
</AntdSelect.Option>
<AntdSelect.Option key={'ANDROID'}>
Android
</AntdSelect.Option>
</AntdSelect>
</AntdForm.Item>
<AntdForm.Item label={'简介'} name={'description'}>
<AntdInput.TextArea
autoSize={{ minRows: 6, maxRows: 6 }}
@@ -344,11 +375,13 @@ const Create = () => {
<FlexBox></FlexBox>
</Card>
<Card className={'preview'}>
{compiledCode && (
{compiledCode ? (
<Playground.Output.Preview.Render
iframeKey={previewTemplate}
compiledCode={compiledCode}
/>
) : (
<span className={'no-preview'}></span>
)}
</Card>
</FlexBox>

View File

@@ -26,6 +26,9 @@ import Card from '@/components/common/Card'
const Edit = () => {
const navigate = useNavigate()
const { toolId } = useParams()
const [searchParams] = useSearchParams({
platform: import.meta.env.VITE_PLATFORM
})
const [form] = AntdForm.useForm<ToolUpdateParam>()
const formValues = AntdForm.useWatch([], form)
const [loading, setLoading] = useState(false)
@@ -98,13 +101,13 @@ const Edit = () => {
case TOOL_UNDER_REVIEW:
void message.error('保存失败:工具审核中')
setTimeout(() => {
navigate(-1)
navigate('/')
}, 3000)
break
case TOOL_HAS_BEEN_PUBLISHED:
void message.error('保存失败:工具已发布')
setTimeout(() => {
navigate(-1)
navigate('/')
}, 3000)
break
default:
@@ -164,13 +167,13 @@ const Edit = () => {
case TOOL_UNDER_REVIEW:
void message.error('保存失败:工具审核中')
setTimeout(() => {
navigate(-1)
navigate('/')
}, 3000)
break
case TOOL_HAS_BEEN_PUBLISHED:
void message.error('保存失败:工具已发布')
setTimeout(() => {
navigate(-1)
navigate('/')
}, 3000)
break
default:
@@ -211,7 +214,7 @@ const Edit = () => {
setLoading(true)
void message.loading({ content: '加载中……', key: 'LOADING', duration: 0 })
void r_tool_detail('!', toolId!, 'latest')
void r_tool_detail('!', toolId!, 'latest', searchParams.get('platform') as Platform)
.then((res) => {
const response = res.data
switch (response.code) {
@@ -225,20 +228,20 @@ const Edit = () => {
case 'PROCESSING':
void message.warning('工具审核中,请勿修改')
setTimeout(() => {
navigate(-1)
navigate('/')
}, 3000)
break
default:
void message.warning('请先创建新版本后编辑工具')
setTimeout(() => {
navigate(-1)
navigate('/')
}, 3000)
}
break
case DATABASE_NO_RECORD_FOUND:
void message.error('未找到指定工具')
setTimeout(() => {
navigate(-1)
navigate('/')
}, 3000)
break
default:
@@ -301,6 +304,10 @@ const Edit = () => {
}, [formValues])
useEffect(() => {
if (!['WEB', 'DESKTOP', 'ANDROID'].includes(searchParams.get('platform')!)) {
navigate('/')
return
}
getTool()
}, [])

View File

@@ -11,6 +11,9 @@ import { getLoginStatus } from '@/util/auth'
const Source = () => {
const navigate = useNavigate()
const { username, toolId, ver } = useParams()
const [searchParams] = useSearchParams({
platform: import.meta.env.VITE_PLATFORM
})
const [loading, setLoading] = useState(false)
const [files, setFiles] = useState<IFiles>({})
const [selectedFileName, setSelectedFileName] = useState('')
@@ -31,7 +34,12 @@ const Source = () => {
setLoading(true)
void message.loading({ content: '加载中……', key: 'LOADING', duration: 0 })
void r_tool_detail(username!, toolId!, ver || 'latest')
void r_tool_detail(
username!,
toolId!,
ver || 'latest',
searchParams.get('platform') as Platform
)
.then((res) => {
const response = res.data
switch (response.code) {
@@ -41,7 +49,7 @@ const Source = () => {
case DATABASE_NO_RECORD_FOUND:
void message.error('未找到指定工具')
setTimeout(() => {
navigate(-1)
navigate('/')
}, 3000)
break
default:
@@ -57,7 +65,7 @@ const Source = () => {
useEffect(() => {
if (username === '!' && !getLoginStatus()) {
setTimeout(() => {
navigate(-1)
navigate('/')
}, 3000)
return
}
@@ -69,6 +77,10 @@ const Source = () => {
navigate(`/source/!/${toolId}/latest`)
return
}
if (!['WEB', 'DESKTOP', 'ANDROID'].includes(searchParams.get('platform')!)) {
navigate('/')
return
}
getTool()
}, [])

View File

@@ -159,7 +159,7 @@ const User = () => {
case DATABASE_NO_RECORD_FOUND:
void message.warning('用户不存在')
setTimeout(() => {
navigate(-1)
navigate('/')
}, 3000)
break
default:

View File

@@ -12,6 +12,9 @@ import Card from '@/components/common/Card'
const View = () => {
const navigate = useNavigate()
const { username, toolId, ver } = useParams()
const [searchParams] = useSearchParams({
platform: import.meta.env.VITE_PLATFORM
})
const [loading, setLoading] = useState(false)
const [compiledCode, setCompiledCode] = useState('')
@@ -52,7 +55,12 @@ const View = () => {
setLoading(true)
void message.loading({ content: '加载中……', key: 'LOADING', duration: 0 })
void r_tool_detail(username!, toolId!, ver || 'latest')
void r_tool_detail(
username!,
toolId!,
ver || 'latest',
searchParams.get('platform') as Platform
)
.then((res) => {
const response = res.data
switch (response.code) {
@@ -62,7 +70,7 @@ const View = () => {
case DATABASE_NO_RECORD_FOUND:
void message.error('未找到指定工具')
setTimeout(() => {
navigate(-1)
navigate('/')
}, 3000)
break
default:
@@ -78,7 +86,7 @@ const View = () => {
useEffect(() => {
if (username === '!' && !getLoginStatus()) {
setTimeout(() => {
navigate(-1)
navigate('/')
}, 3000)
return
}
@@ -90,6 +98,10 @@ const View = () => {
navigate(`/view/!/${toolId}/latest`)
return
}
if (!['WEB', 'DESKTOP', 'ANDROID'].includes(searchParams.get('platform')!)) {
navigate('/')
return
}
getTool()
}, [])

View File

@@ -14,6 +14,7 @@ import {
TOOL_SUBMIT_SUCCESS,
TOOL_UNDER_REVIEW
} from '@/constants/common.constants'
import { checkDesktop } from '@/util/common'
import { getLoginStatus } from '@/util/auth'
import {
r_tool_cancel,
@@ -138,18 +139,30 @@ const ToolCard = ({ tools, onDelete, onUpgrade, onSubmit, onCancel }: ToolCardPr
const navigate = useNavigate()
const [selectedTool, setSelectedTool] = useState(tools[0])
const handleOnVersionChange = (value: string) => {
setSelectedTool(tools.find((item) => item.id === value)!)
const handleOnVersionChange = (value: (string | number)[]) => {
setSelectedTool(tools.find((item) => item.id === value[1])!)
}
const handleOnOpenTool = () => {
navigate(`/view/!/${selectedTool.toolId}/${selectedTool.ver}`)
if (checkDesktop() || selectedTool.platform !== 'DESKTOP') {
navigate(
`/view/!/${selectedTool.toolId}/${selectedTool.ver}${selectedTool.platform !== import.meta.env.VITE_PLATFORM ? `?platform=${selectedTool.platform}` : ''}`
)
} else {
void message.warning('此应用需要桌面端环境,请在桌面端打开')
}
}
const handleOnEditTool = () => {
if (['NONE', 'REJECT'].includes(selectedTool.review)) {
return () => {
navigate(`/edit/${tools[0].toolId}`)
if (checkDesktop() || selectedTool.platform !== 'DESKTOP') {
navigate(
`/edit/${selectedTool.toolId}${selectedTool.platform !== import.meta.env.VITE_PLATFORM ? `?platform=${selectedTool.platform}` : ''}`
)
} else {
void message.warning('此应用需要桌面端环境,请在桌面端编辑')
}
}
}
return undefined
@@ -158,7 +171,9 @@ const ToolCard = ({ tools, onDelete, onUpgrade, onSubmit, onCancel }: ToolCardPr
const handleOnSourceTool = () => {
if (selectedTool.review === 'PASS') {
return () => {
navigate(`/source/!/${selectedTool.toolId}/${selectedTool.ver}`)
navigate(
`/source/!/${selectedTool.toolId}/${selectedTool.ver}${selectedTool.platform !== import.meta.env.VITE_PLATFORM ? `?platform=${selectedTool.platform}` : ''}`
)
}
}
return undefined
@@ -190,6 +205,55 @@ const ToolCard = ({ tools, onDelete, onUpgrade, onSubmit, onCancel }: ToolCardPr
onUpgrade?.(selectedTool)
}
const toolsGroupByPlatform = (tools: ToolVo[]) => {
interface Node {
label: string
value: string
children?: Node[]
}
const temp: Node[] = []
tools.forEach((value) => {
if (!temp.length) {
temp.push({
label: `${value.platform.slice(0, 1)}${value.platform.slice(1).toLowerCase()}`,
value: value.platform,
children: [
{
label: `${value.ver}${value.review !== 'PASS' ? '*' : ''}`,
value: value.id
}
]
})
} else {
if (
!temp.some((platform, platformIndex) => {
if (platform.value === value.platform) {
temp[platformIndex].children!.push({
label: `${value.ver}${value.review !== 'PASS' ? '*' : ''}`,
value: value.id
})
return true
}
return false
})
) {
temp.push({
label: `${value.platform.slice(0, 1)}${value.platform.slice(1).toLowerCase()}`,
value: value.platform,
children: [
{
label: `${value.ver}${value.review !== 'PASS' ? '*' : ''}`,
value: value.id
}
]
})
}
}
})
return temp
}
return (
<CommonCard
icon={<img src={`data:image/svg+xml;base64,${selectedTool.icon}`} alt={'Icon'} />}
@@ -202,15 +266,17 @@ const ToolCard = ({ tools, onDelete, onUpgrade, onSubmit, onCancel }: ToolCardPr
onCancelReview={handleOnCancelReview()}
onDelete={handleOnDeleteTool}
>
<AntdSelect
<AntdCascader
className={'version-select'}
size={'small'}
value={selectedTool.id}
allowClear={false}
value={[
tools.find((value) => value.id === selectedTool.id)!.platform,
selectedTool.id
]}
displayRender={(label: string[]) => `${label[0].slice(0, 1)}-${label[1]}`}
onChange={handleOnVersionChange}
options={tools.map((value) => ({
value: value.id,
label: `${value.ver}${value.review !== 'PASS' ? '*' : ''}`
}))}
options={toolsGroupByPlatform(tools)}
/>
{tools.every((value) => value.review === 'PASS') && (
<AntdTooltip title={'更新'}>
@@ -237,7 +303,7 @@ const Tools = () => {
.confirm({
title: '删除',
maskClosable: true,
content: `确定删除工具 ${tool.name}:${tool.ver} 吗?`
content: `确定删除工具 ${tool.toolId}:${tool.platform.slice(0, 1)}${tool.platform.slice(1).toLowerCase()}:${tool.ver} 吗?`
})
.then(
(confirmed) => {
@@ -313,14 +379,22 @@ const Tools = () => {
() => {
return new Promise<void>((resolve, reject) => {
void r_tool_upgrade({
toolId: upgradeForm.getFieldValue('toolId') as string,
ver: upgradeForm.getFieldValue('ver') as string
toolId: tool.toolId,
ver: upgradeForm.getFieldValue('ver') as string,
platform: tool.platform
}).then((res) => {
const response = res.data
switch (response.code) {
case DATABASE_UPDATE_SUCCESS:
void message.success('创建新版本成功')
navigate(`/edit/${response.data!.toolId}`)
if (
checkDesktop() ||
response.data!.platform !== 'DESKTOP'
) {
navigate(
`/edit/${response.data!.toolId}${response.data!.platform !== import.meta.env.VITE_PLATFORM ? `?platform=${response.data!.platform}` : ''}`
)
}
resolve()
break
case TOOL_ILLEGAL_VERSION: