From 142a38d7d1bb2b24a4ea8415d0d648b217b12fd7 Mon Sep 17 00:00:00 2001 From: imeepos Date: Fri, 26 Sep 2025 22:28:58 +0800 Subject: [PATCH] feat(platforms): refactor platform architecture and update API endpoints - Refactor app.tsx to use new platform factory authorization system - Update TemplateCard to use new URL property names (inputExampleUrl, outputExampleUrl) - Enhance platform factory with authorization support for H5, TT, and WeApp - Add new platform-specific authorization modules for multi-platform support - Update SDK server endpoints to match new API structure - Fix useAd hook factory instantiation timing - Update API base URL for development environment --- src/app.tsx | 37 +++++++++------------ src/components/TemplateCard/index.tsx | 18 +++++----- src/hooks/useAd.ts | 6 ++-- src/platforms/factory.ts | 17 +++++++++- src/platforms/h5/authorize.ts | 47 +++++++++++++++++++++++++++ src/platforms/h5/index.ts | 1 + src/platforms/tt/authorize.ts | 40 +++++++++++++++++++++++ src/platforms/tt/index.ts | 1 + src/platforms/types/authorize.ts | 4 +++ src/platforms/types/index.ts | 1 + src/platforms/weapp.ts | 1 - src/platforms/weapp/authorize.ts | 40 +++++++++++++++++++++++ src/platforms/weapp/index.ts | 1 + src/sdk/sdk-server.ts | 26 +++++++-------- 14 files changed, 190 insertions(+), 50 deletions(-) create mode 100644 src/platforms/h5/authorize.ts create mode 100644 src/platforms/h5/index.ts create mode 100644 src/platforms/tt/authorize.ts create mode 100644 src/platforms/tt/index.ts create mode 100644 src/platforms/types/authorize.ts create mode 100644 src/platforms/types/index.ts create mode 100644 src/platforms/weapp/authorize.ts create mode 100644 src/platforms/weapp/index.ts diff --git a/src/app.tsx b/src/app.tsx index b3fa3b2..2038276 100644 --- a/src/app.tsx +++ b/src/app.tsx @@ -1,36 +1,29 @@ import { PropsWithChildren } from 'react' -import Taro, { useLaunch } from '@tarojs/taro' +import { useLaunch } from '@tarojs/taro' import { Provider } from 'react-redux' import configStore from './store' import './app.css' -import { useServerSdk } from './hooks' +import { createPlatformFactory } from './platforms' const store = configStore() function App({ children }: PropsWithChildren) { - const serverSdk = useServerSdk() - useLaunch(() => { - Taro.login({ - success: async (res) => { - try { - const login = await serverSdk.login({ ...res }) - // 获取accessToken然后存储到本地 - if (login?.tokens?.accessToken) { - serverSdk.setAccessToken(login.tokens.accessToken, login.user.id) - } - } catch (error) { - console.error('Login failed:', error) - } - }, - fail: (error) => { - console.error('Taro.login failed:', error) + useLaunch(async () => { + const authorize = createPlatformFactory().createAuthorize() + + try { + // 检查登录状态,包括OAuth 2.0回调处理 + const isLoggedIn = await authorize.checkLogin() + if (!isLoggedIn) { + // 可以根据需要决定是否自动跳转登录 + await authorize.login() } - }) - console.log('App launched.') + } catch (error) { + console.error('登录检查失败:', error) + } }) - - // children 是将要会渲染的页面 + return ( {children} diff --git a/src/components/TemplateCard/index.tsx b/src/components/TemplateCard/index.tsx index f9bfbef..f5d243b 100644 --- a/src/components/TemplateCard/index.tsx +++ b/src/components/TemplateCard/index.tsx @@ -18,13 +18,13 @@ export default function TemplateCard({ template, onClick }: TemplateCardProps) { // 检测output是否为视频 const isOutputVideo = useMemo(() => { - return /\.(mp4|webm|ogg|mov|avi|mkv|flv)$/i.test(template.outputExample); - }, [template.outputExample]); + return /\.(mp4|webm|ogg|mov|avi|mkv|flv)$/i.test(template.outputExampleUrl); + }, [template.outputExampleUrl]); // 检测input是否为视频 const isInputVideo = useMemo(() => { - return /\.(mp4|webm|ogg|mov|avi|mkv|flv)$/i.test(template.inputExample); - }, [template.inputExample]); + return /\.(mp4|webm|ogg|mov|avi|mkv|flv)$/i.test(template.inputExampleUrl); + }, [template.inputExampleUrl]); const handleClick = () => { if (!isDragging) { @@ -86,10 +86,10 @@ export default function TemplateCard({ template, onClick }: TemplateCardProps) { {isOutputVideo ? ( // 当output是视频时,只显示单个视频 - + @@ -138,7 +138,7 @@ export default function TemplateCard({ template, onClick }: TemplateCardProps) { clipPath: `polygon(${splitPosition}% 0%, 100% 0%, 100% 100%, ${splitPosition}% 100%)`, }} > - + {/* 可拖拽的分割线 */} diff --git a/src/hooks/useAd.ts b/src/hooks/useAd.ts index 5bd08e4..c89626d 100644 --- a/src/hooks/useAd.ts +++ b/src/hooks/useAd.ts @@ -18,17 +18,17 @@ interface UseAdOptions { onClose?: (isEnded: boolean) => void; // 广告关闭回调,传入是否完整观看 } // 创建平台广告实例 -const factory = createPlatformFactory() export function useAd(options?: UseAdOptions): UseAdReturn { + const factory = createPlatformFactory() const [loading, setLoading] = useState(true); const [adAvailable, setAdAvailable] = useState(false); const [adLoaded, setAdLoaded] = useState(false); // 广告是否已加载完成 const adRef = useRef(null); const platform = factory.getPlatform() - + // 检查当前平台是否支持广告 const isAdSupportedPlatform = platform === 'bytedance'; - + useEffect(() => { // 如果当前平台不支持广告,直接设置为不可用状态 if (!isAdSupportedPlatform) { diff --git a/src/platforms/factory.ts b/src/platforms/factory.ts index c662028..e7f1005 100644 --- a/src/platforms/factory.ts +++ b/src/platforms/factory.ts @@ -1,6 +1,10 @@ import { MediaTT, RewardedVideoAdTT, UserInfoTT } from "./tt"; import { Media, RewardedVideoAd, UserInfo } from "./core"; import { MediaWeApp, RewardedVideoAdWeApp, UserInfoWeApp } from "./weapp"; +import { Authorize } from "./types/index"; +import { H5Authorize } from "./h5/index"; +import { TtAuthorize } from "./tt/index"; +import { WeappAuthorize } from "./weapp/index"; /** * 小程序平台全局对象类型声明 @@ -97,6 +101,17 @@ export class PlatformFactory { } } + createAuthorize(): Authorize { + switch (this.platform) { + case 'bytedance': + return new TtAuthorize() + case 'wechat': + return new WeappAuthorize() + default: + return new H5Authorize() + } + } + /** * 获取当前平台类型 * @returns Platform 当前平台 @@ -111,7 +126,7 @@ export class PlatformFactory { * @returns boolean 是否支持 */ static isSupportedPlatform(platform: string): platform is Platform { - return ['tt', 'weapp', 'alipay', 'swan', 'qq'].includes(platform); + return ['tt', 'weapp', 'alipay', 'swan', 'qq', 'h5'].includes(platform); } /** diff --git a/src/platforms/h5/authorize.ts b/src/platforms/h5/authorize.ts new file mode 100644 index 0000000..d852877 --- /dev/null +++ b/src/platforms/h5/authorize.ts @@ -0,0 +1,47 @@ +import { Authorize } from "../types/index"; +import { useServerSdk } from "../../hooks/index"; + +export class H5Authorize extends Authorize { + async checkLogin(): Promise { + // 检查URL中是否有OAuth回调参数 + const urlParams = new URLSearchParams(window.location.search); + const accessToken = urlParams.get('access_token'); + const userId = urlParams.get('user_id'); + if (accessToken && userId) { + // 处理OAuth回调 + try { + const serverSdk = useServerSdk(); + serverSdk.setAccessToken(accessToken, userId); + + // 清理URL参数,避免重复处理 + const newUrl = window.location.pathname; + window.history.replaceState(null, '', newUrl); + + console.log('OAuth登录成功,token已保存'); + return true; + } catch (error) { + console.error('处理OAuth回调失败:', error); + return false; + } + } + + // 如果没有回调参数,检查本地存储的token + try { + const serverSdk = useServerSdk(); + const profile = await serverSdk.profile(); + return !!profile; + } catch (error) { + console.log('本地token无效或已过期'); + return false; + } + } + + async login(): Promise { + const { hostname, protocol, port } = window.location; + let baseUrl = `${protocol}//${hostname}` + if (hostname === 'localhost') { + baseUrl = `${protocol}//${hostname}:${port}` + } + window.location.href = `https://mixvideo-workflow.bowong.cc/auth/google/authorize?redirect_url=${baseUrl}` + } +} \ No newline at end of file diff --git a/src/platforms/h5/index.ts b/src/platforms/h5/index.ts new file mode 100644 index 0000000..4da02a0 --- /dev/null +++ b/src/platforms/h5/index.ts @@ -0,0 +1 @@ +export * from './authorize'; \ No newline at end of file diff --git a/src/platforms/tt/authorize.ts b/src/platforms/tt/authorize.ts new file mode 100644 index 0000000..ca920e9 --- /dev/null +++ b/src/platforms/tt/authorize.ts @@ -0,0 +1,40 @@ +import Taro from "@tarojs/taro"; +import { Authorize } from "../types/index"; +import { useServerSdk } from "../../hooks/index"; + +export class TtAuthorize extends Authorize { + async checkLogin(): Promise { + try { + const serverSdk = useServerSdk(); + const profile = await serverSdk.profile(); + return !!profile; + } catch (error) { + console.log('字节跳动小程序token无效或已过期'); + return false; + } + } + async login(): Promise { + return new Promise((resolve, reject) => { + const serverSdk = useServerSdk() + Taro.login({ + success: async (res) => { + try { + const login = await serverSdk.login({ ...res }) + // 获取accessToken然后存储到本地 + if (login?.tokens?.accessToken) { + serverSdk.setAccessToken(login.tokens.accessToken, login.user.id) + resolve() + return; + } + reject(new Error(`登录失败, access token为空`)) + } catch (error) { + reject(error) + } + }, + fail: (error) => { + reject(error) + } + }) + }) + } +} \ No newline at end of file diff --git a/src/platforms/tt/index.ts b/src/platforms/tt/index.ts new file mode 100644 index 0000000..ef062b7 --- /dev/null +++ b/src/platforms/tt/index.ts @@ -0,0 +1 @@ +export * from './authorize' \ No newline at end of file diff --git a/src/platforms/types/authorize.ts b/src/platforms/types/authorize.ts new file mode 100644 index 0000000..d4e1d47 --- /dev/null +++ b/src/platforms/types/authorize.ts @@ -0,0 +1,4 @@ +export abstract class Authorize { + abstract login(): Promise; + abstract checkLogin(): Promise; +} \ No newline at end of file diff --git a/src/platforms/types/index.ts b/src/platforms/types/index.ts new file mode 100644 index 0000000..ef062b7 --- /dev/null +++ b/src/platforms/types/index.ts @@ -0,0 +1 @@ +export * from './authorize' \ No newline at end of file diff --git a/src/platforms/weapp.ts b/src/platforms/weapp.ts index cfef1bf..02c8460 100644 --- a/src/platforms/weapp.ts +++ b/src/platforms/weapp.ts @@ -291,7 +291,6 @@ export class UserInfoWeApp extends UserInfo { } } - export class MediaWeApp extends Media { downloadFile(url: string): Promise { return new Promise((resolve, reject) => { diff --git a/src/platforms/weapp/authorize.ts b/src/platforms/weapp/authorize.ts new file mode 100644 index 0000000..a16d3cc --- /dev/null +++ b/src/platforms/weapp/authorize.ts @@ -0,0 +1,40 @@ +import Taro from "@tarojs/taro"; +import { Authorize } from "../types/index"; +import { useServerSdk } from "../../hooks/index"; + +export class WeappAuthorize extends Authorize { + async checkLogin(): Promise { + try { + const serverSdk = useServerSdk(); + const profile = await serverSdk.profile(); + return !!profile; + } catch (error) { + console.log('微信小程序token无效或已过期'); + return false; + } + } + async login(): Promise { + return new Promise((resolve, reject) => { + const serverSdk = useServerSdk() + Taro.login({ + success: async (res) => { + try { + const login = await serverSdk.login({ ...res }) + // 获取accessToken然后存储到本地 + if (login?.tokens?.accessToken) { + serverSdk.setAccessToken(login.tokens.accessToken, login.user.id) + resolve() + return; + } + reject(new Error(`登录失败, access token为空`)) + } catch (error) { + reject(error) + } + }, + fail: (error) => { + reject(error) + } + }) + }) + } +} \ No newline at end of file diff --git a/src/platforms/weapp/index.ts b/src/platforms/weapp/index.ts new file mode 100644 index 0000000..ef062b7 --- /dev/null +++ b/src/platforms/weapp/index.ts @@ -0,0 +1 @@ +export * from './authorize' \ No newline at end of file diff --git a/src/sdk/sdk-server.ts b/src/sdk/sdk-server.ts index 0e0be8a..0ff8aae 100644 --- a/src/sdk/sdk-server.ts +++ b/src/sdk/sdk-server.ts @@ -15,8 +15,8 @@ export interface Template { description: string; // 模板详细描述 creditCost: number; // 积分消耗 version: string; // 版本号 - inputExample: string; // 原始图片 - outputExample: string; // 输出图片 + inputExampleUrl: string; // 原始图片 + outputExampleUrl: string; // 输出图片 tags: string[]; // 标签数组 templateType: string; // 模板类型 } @@ -57,7 +57,7 @@ export class SdkServer { private readonly baseUrl: string; private readonly timeout: number; - constructor(url: string = `https://sd2s2bl25ni4n75na2bog.apigateway-cn-beijing.volceapi.com`, timeout: number = 5 * 60 * 1000) { + constructor(url: string = `http://127.0.0.1:8787`, timeout: number = 5 * 60 * 1000) { this.baseUrl = url.endsWith('/') ? url.slice(0, -1) : url; this.timeout = timeout; } @@ -167,8 +167,8 @@ export class SdkServer { * GET / */ async getAllTemplates(): Promise { - const response = await this.request('/api/v1/templates'); - return response.data || []; + const response = await this.request<{ templates: Template[] }>('/templates'); + return response.data.templates || []; } /** @@ -177,7 +177,7 @@ export class SdkServer { */ async getTemplate(templateCode: string): Promise