From ad0907892c1ab5109b402ecbc79dfe11981cf0cc Mon Sep 17 00:00:00 2001 From: FatttSnake Date: Tue, 19 Mar 2024 18:33:40 +0800 Subject: [PATCH] Feat: store - support multiple platforms --- build/resolvers/antd.ts | 6 +- package-lock.json | 6 + package.json | 3 +- src/assets/css/pages/tools/store.scss | 10 +- src/assets/css/pages/tools/user.scss | 10 +- src/assets/svg/browser.svg | 1 + src/assets/svg/desktop.svg | 1 + src/assets/svg/info.svg | 1 + src/assets/svg/mobile.svg | 1 + src/main.tsx | 5 +- src/pages/Tools/Store.tsx | 266 ++++++++++++++++++++------ src/pages/Tools/User.tsx | 229 +++++++++++++++++----- 12 files changed, 429 insertions(+), 110 deletions(-) create mode 100644 src/assets/svg/browser.svg create mode 100644 src/assets/svg/desktop.svg create mode 100644 src/assets/svg/info.svg create mode 100644 src/assets/svg/mobile.svg diff --git a/build/resolvers/antd.ts b/build/resolvers/antd.ts index 0bb5132..4506424 100644 --- a/build/resolvers/antd.ts +++ b/build/resolvers/antd.ts @@ -149,7 +149,10 @@ const matchComponents: IMatcher[] = [ pattern: /^Mentions/, styleDir: 'mentions' }, - + { + pattern: /^QRCode/, + styleDir: 'qr-code' + }, { pattern: /^Step/, styleDir: 'steps' @@ -337,6 +340,7 @@ const primitiveNames = [ 'Rate', 'Result', 'Row', + 'QRCode', 'Select', 'SelectOptGroup', 'SelectOption', diff --git a/package-lock.json b/package-lock.json index fd47514..a47f8f0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,6 +14,7 @@ "@typescript/ata": "^0.9.4", "antd": "^5.13.2", "axios": "^1.6.5", + "custom-protocol-check": "^1.4.0", "dayjs": "^1.11.10", "echarts": "^5.4.3", "esbuild-wasm": "^0.19.12", @@ -2900,6 +2901,11 @@ "resolved": "https://registry.npmmirror.com/csstype/-/csstype-3.1.3.tgz", "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" }, + "node_modules/custom-protocol-check": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/custom-protocol-check/-/custom-protocol-check-1.4.0.tgz", + "integrity": "sha512-eMTyp8AKnE5eo+mKNqG3743eb5ZND5LhBgf9F8BN2tVdhSBnOCHH7me7iTcv0BUDhUW2dBQiHWLWMy776yZW1A==" + }, "node_modules/data-urls": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-5.0.0.tgz", diff --git a/package.json b/package.json index 122f9ac..2e0d431 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,7 @@ "dev": "vite", "dev-host": "vite --host 0.0.0.0", "build": "vite build && npm run typecheck", - "build-test": "vite build --mode testing", + "build-test": "vite build --mode testing && npm run typecheck", "typecheck": "tsc", "clean": "rimraf dist .eslintrc-auto-import.json auto-imports.d.ts", "lint": "eslint src --ext ts,tsx --report-unused-disable-directives --max-warnings 0", @@ -21,6 +21,7 @@ "@typescript/ata": "^0.9.4", "antd": "^5.13.2", "axios": "^1.6.5", + "custom-protocol-check": "^1.4.0", "dayjs": "^1.11.10", "echarts": "^5.4.3", "esbuild-wasm": "^0.19.12", diff --git a/src/assets/css/pages/tools/store.scss b/src/assets/css/pages/tools/store.scss index ffc4ab0..3bffda7 100644 --- a/src/assets/css/pages/tools/store.scss +++ b/src/assets/css/pages/tools/store.scss @@ -99,10 +99,12 @@ } .operation { + display: flex; position: absolute; - top: 6px; + top: 10px; right: 12px; font-size: 1.6em; + gap: 4px; > *:hover { color: constants.$font-secondary-color; @@ -141,4 +143,10 @@ color: constants.$font-secondary-color; } } + + .android-qrcode { + align-items: center; + transform: translateX(-16px); + gap: 20px; + } } diff --git a/src/assets/css/pages/tools/user.scss b/src/assets/css/pages/tools/user.scss index f0d02a1..05f0cc5 100644 --- a/src/assets/css/pages/tools/user.scss +++ b/src/assets/css/pages/tools/user.scss @@ -141,10 +141,12 @@ } .operation { + display: flex; position: absolute; - top: 6px; + top: 10px; right: 12px; font-size: 1.6em; + gap: 4px; > *:hover { color: constants.$font-secondary-color; @@ -185,4 +187,10 @@ } } } + + .android-qrcode { + align-items: center; + transform: translateX(-16px); + gap: 20px; + } } diff --git a/src/assets/svg/browser.svg b/src/assets/svg/browser.svg new file mode 100644 index 0000000..a4f2afe --- /dev/null +++ b/src/assets/svg/browser.svg @@ -0,0 +1 @@ + diff --git a/src/assets/svg/desktop.svg b/src/assets/svg/desktop.svg new file mode 100644 index 0000000..67759d5 --- /dev/null +++ b/src/assets/svg/desktop.svg @@ -0,0 +1 @@ + diff --git a/src/assets/svg/info.svg b/src/assets/svg/info.svg new file mode 100644 index 0000000..d0312db --- /dev/null +++ b/src/assets/svg/info.svg @@ -0,0 +1 @@ + diff --git a/src/assets/svg/mobile.svg b/src/assets/svg/mobile.svg new file mode 100644 index 0000000..e6de593 --- /dev/null +++ b/src/assets/svg/mobile.svg @@ -0,0 +1 @@ + diff --git a/src/main.tsx b/src/main.tsx index c8665a4..84f0207 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -10,7 +10,10 @@ createRoot(document.getElementById('root')!).render( { const navigate = useNavigate() + const [modal, contextHolder] = AntdModal.useModal() const cardRef = useRef(null) useEffect(() => { @@ -53,7 +58,31 @@ const CommonCard = ({ }, [options]) const handleCardOnClick = () => { - url && navigate(url) + if (!checkDesktop() && platform === 'DESKTOP') { + void message.warning('此应用需要桌面端环境,请在桌面端打开') + return + } + if (platform === 'ANDROID') { + void modal.info({ + icon: , + title: 'Android 端', + centered: true, + maskClosable: true, + content: ( + + + 请使用手机端扫描上方二维码 + + ) + }) + return + } + navigate( + `/view/${authorUsername}/${toolId}${platform !== import.meta.env.VITE_PLATFORM ? `?platform=${platform}` : ''}` + ) } const handleOnClickAuthor = (e: MouseEvent) => { @@ -63,50 +92,130 @@ const CommonCard = ({ const handleOnSourceBtnClick = (e: MouseEvent) => { e.stopPropagation() - navigate(`/source/${authorUsername}/${toolId}`) + navigate( + `/source/${authorUsername}/${toolId}${platform !== import.meta.env.VITE_PLATFORM ? `?platform=${platform}` : ''}` + ) + } + + const handleOnAndroidBtnClick = (e: MouseEvent) => { + e.stopPropagation() + void modal.info({ + icon: , + title: 'Android 端', + centered: true, + maskClosable: true, + content: ( + + + 请使用手机端扫描上方二维码 + + ) + }) + } + + const handleOnDesktopBtnClick = (e: MouseEvent) => { + e.stopPropagation() + if (!checkDesktop()) { + void message.loading({ content: '启动桌面端中……', key: 'LOADING', duration: 0 }) + protocolCheck( + `oxygen://openurl/view/${authorUsername}/${toolId}`, + () => { + void message.warning('打开失败,此应用需要桌面端环境,请安装桌面端后重试') + void message.destroy('LOADING') + }, + () => { + void message.destroy('LOADING') + }, + 2000, + () => { + void message.warning('打开失败,此应用需要桌面端环境,请安装桌面端后重试') + void message.destroy('LOADING') + } + ) + return + } + navigate( + `/view/${authorUsername}/${toolId}${platform !== import.meta.env.VITE_PLATFORM ? `?platform=${platform}` : ''}` + ) + } + + const handleOnWebBtnClick = (e: MouseEvent) => { + e.stopPropagation() + navigate( + `/view/${authorUsername}/${toolId}${platform !== import.meta.env.VITE_PLATFORM ? `?platform=${platform}` : ''}` + ) } return ( - - -
{icon}
-
- V{ver} -
-
-
{toolName}
-
{`ID: ${toolId}`}
- {toolDesc &&
{`简介:${toolDesc}`}
} -
-
-
- - } - style={{ background: COLOR_BACKGROUND }} - /> + <> + + +
{icon}
+
+ + {platform.slice(0, 1)}-{ver} +
- -
{authorName}
-
-
-
- - - -
- - +
+
{toolName}
+
{`ID: ${toolId}`}
+ {toolDesc &&
{`简介:${toolDesc}`}
} +
+
+
+ + } + style={{ background: COLOR_BACKGROUND }} + /> +
+ +
{authorName}
+
+
+
+ {platform !== 'ANDROID' && supportPlatform.includes('ANDROID') && ( + + + + )} + {platform === 'DESKTOP' && supportPlatform.includes('WEB') && ( + + + + )} + {platform === 'WEB' && supportPlatform.includes('DESKTOP') && ( + + + + )} + + + +
+ + + {contextHolder} + ) } @@ -231,25 +340,58 @@ const Store = () => {
{!toolData.length &&
未找到任何工具
} - {toolData?.map((value) => ( - + {toolData + ?.reduce((previousValue: ToolVo[], currentValue) => { + if ( + !previousValue.some( + (value) => + value.author.id === currentValue.author.id && + value.toolId === currentValue.toolId + ) + ) { + previousValue.push(currentValue) } - toolName={value.name} - toolId={value.toolId} - toolDesc={value.description} - url={`/view/${value.author.username}/${value.toolId}`} - authorName={value.author.userInfo.nickname} - authorAvatar={value.author.userInfo.avatar} - authorUsername={value.author.username} - ver={value.ver} - /> - ))} + return previousValue + }, []) + .map((item) => { + const tools = toolData.filter( + (value) => + value.author.id === item.author.id && + value.toolId === item.toolId + ) + const webTool = tools.find((value) => value.platform === 'WEB') + const desktopTool = tools.find( + (value) => value.platform === 'DESKTOP' + ) + const androidTool = tools.find( + (value) => value.platform === 'ANDROID' + ) + const firstTool = + (checkDesktop() + ? desktopTool || webTool + : webTool || desktopTool) || androidTool + + return ( + + } + toolName={firstTool!.name} + toolId={firstTool!.toolId} + toolDesc={firstTool!.description} + authorName={firstTool!.author.userInfo.nickname} + authorAvatar={firstTool!.author.userInfo.avatar} + authorUsername={firstTool!.author.username} + ver={firstTool!.ver} + platform={firstTool!.platform} + supportPlatform={tools.map((value) => value.platform)} + /> + ) + })} {hasNextPage && }
diff --git a/src/pages/Tools/User.tsx b/src/pages/Tools/User.tsx index 67d2508..2d1c9e5 100644 --- a/src/pages/Tools/User.tsx +++ b/src/pages/Tools/User.tsx @@ -1,12 +1,15 @@ import { DetailedHTMLProps, HTMLAttributes, MouseEvent, ReactNode } from 'react' import VanillaTilt, { TiltOptions } from 'vanilla-tilt' +import protocolCheck from 'custom-protocol-check' import Icon from '@ant-design/icons' import '@/assets/css/pages/tools/user.scss' import { COLOR_BACKGROUND, + COLOR_MAIN, DATABASE_NO_RECORD_FOUND, DATABASE_SELECT_SUCCESS } from '@/constants/common.constants' +import { checkDesktop } from '@/util/common' import { r_sys_user_info_get_basic } from '@/services/system' import { r_tool_store_get_by_username } from '@/services/tool' import FitFullscreen from '@/components/common/FitFullscreen' @@ -21,9 +24,10 @@ interface CommonCardProps toolId: string toolDesc: string options?: TiltOptions - url: string authorUsername: string ver: string + platform: Platform + supportPlatform: Platform[] } const CommonCard = ({ @@ -41,12 +45,14 @@ const CommonCard = ({ ['max-glare']: 0.3, scale: 1.03 }, - url, authorUsername, ver, + platform, + supportPlatform, ...props }: CommonCardProps) => { const navigate = useNavigate() + const [modal, contextHolder] = AntdModal.useModal() const cardRef = useRef(null) useEffect(() => { @@ -54,38 +60,142 @@ const CommonCard = ({ }, [options]) const handleCardOnClick = () => { - url && navigate(url) + if (!checkDesktop() && platform === 'DESKTOP') { + void message.warning('此应用需要桌面端环境,请在桌面端打开') + return + } + if (platform === 'ANDROID') { + void modal.info({ + icon: , + title: 'Android 端', + centered: true, + maskClosable: true, + content: ( + + + 请使用手机端扫描上方二维码 + + ) + }) + return + } + navigate( + `/view/${authorUsername}/${toolId}${platform !== import.meta.env.VITE_PLATFORM ? `?platform=${platform}` : ''}` + ) } const handleOnSourceBtnClick = (e: MouseEvent) => { e.stopPropagation() - navigate(`/source/${authorUsername}/${toolId}`) + navigate( + `/source/${authorUsername}/${toolId}${platform !== import.meta.env.VITE_PLATFORM ? `?platform=${platform}` : ''}` + ) + } + + const handleOnAndroidBtnClick = (e: MouseEvent) => { + e.stopPropagation() + void modal.info({ + icon: , + title: 'Android 端', + centered: true, + maskClosable: true, + content: ( + + + 请使用手机端扫描上方二维码 + + ) + }) + } + + const handleOnDesktopBtnClick = (e: MouseEvent) => { + e.stopPropagation() + if (!checkDesktop()) { + void message.loading({ content: '启动桌面端中……', key: 'LOADING', duration: 0 }) + protocolCheck( + `oxygen://openurl/view/${authorUsername}/${toolId}`, + () => { + void message.warning('打开失败,此应用需要桌面端环境,请安装桌面端后重试') + void message.destroy('LOADING') + }, + () => { + void message.destroy('LOADING') + }, + 2000, + () => { + void message.warning('打开失败,此应用需要桌面端环境,请安装桌面端后重试') + void message.destroy('LOADING') + } + ) + return + } + navigate( + `/view/${authorUsername}/${toolId}${platform !== import.meta.env.VITE_PLATFORM ? `?platform=${platform}` : ''}` + ) + } + + const handleOnWebBtnClick = (e: MouseEvent) => { + e.stopPropagation() + navigate( + `/view/${authorUsername}/${toolId}${platform !== import.meta.env.VITE_PLATFORM ? `?platform=${platform}` : ''}` + ) } return ( - - -
{icon}
-
- V{ver} -
-
-
{toolName}
-
{`ID: ${toolId}`}
- {toolDesc &&
{`简介:${toolDesc}`}
} -
-
- - - -
-
-
+ <> + + +
{icon}
+
+ + {platform.slice(0, 1)}-{ver} + +
+
+
{toolName}
+
{`ID: ${toolId}`}
+ {toolDesc &&
{`简介:${toolDesc}`}
} +
+
+ {platform !== 'ANDROID' && supportPlatform.includes('ANDROID') && ( + + + + )} + {platform === 'DESKTOP' && supportPlatform.includes('WEB') && ( + + + + )} + {platform === 'WEB' && supportPlatform.includes('DESKTOP') && ( + + + + )} + + + +
+
+
+ {contextHolder} + ) } @@ -266,23 +376,56 @@ const User = () => { {!toolData.length && (
该开发者暂未发布任何工具
)} - {toolData?.map((value) => ( - + {toolData + ?.reduce((previousValue: ToolVo[], currentValue) => { + if ( + !previousValue.some( + (value) => + value.author.id === currentValue.author.id && + value.toolId === currentValue.toolId + ) + ) { + previousValue.push(currentValue) } - toolName={value.name} - toolId={value.toolId} - toolDesc={value.description} - url={`/view/${value.author.username}/${value.toolId}`} - authorUsername={value.author.username} - ver={value.ver} - /> - ))} + return previousValue + }, []) + .map((item) => { + const tools = toolData.filter( + (value) => + value.author.id === item.author.id && + value.toolId === item.toolId + ) + const webTool = tools.find((value) => value.platform === 'WEB') + const desktopTool = tools.find( + (value) => value.platform === 'DESKTOP' + ) + const androidTool = tools.find( + (value) => value.platform === 'ANDROID' + ) + const firstTool = + (checkDesktop() + ? desktopTool || webTool + : webTool || desktopTool) || androidTool + + return ( + + } + toolName={firstTool!.name} + toolId={firstTool!.toolId} + toolDesc={firstTool!.description} + authorUsername={firstTool!.author.username} + ver={firstTool!.ver} + platform={firstTool!.platform} + supportPlatform={tools.map((value) => value.platform)} + /> + ) + })} {hasNextPage && }
-- 2.49.1