| 1 | import { AccountType, createZodDto } from '@yikart/common' |
| 2 | import { z } from 'zod' |
| 3 | import { ChannelPaginationMetadataVoSchema } from './platform-pagination.vo' |
| 4 | import { |
| 5 | AuthType, |
| 6 | ChannelEngagementFunctionName, |
| 7 | ChannelEngagementTargetType, |
| 8 | CompletionStrategy, |
| 9 | EditorType, |
| 10 | PlatformStatus, |
| 11 | PublishContentMode, |
| 12 | PublishOptionValueType, |
| 13 | } from './platforms.interface' |
| 14 | |
| 15 | export const LocaleTextSchema = z.object({ |
| 16 | 'en-US': z.string().describe('英文文案'), |
| 17 | 'zh-CN': z.string().describe('中文文案'), |
| 18 | }) |
| 19 | |
| 20 | const PlatformContentLimitsVoSchema = z.object({ |
| 21 | modes: z.array(z.enum(PublishContentMode)).describe('支持的发布内容模式'), |
| 22 | maxTitleLength: z.number().optional().describe('标题最大长度'), |
| 23 | maxBodyLength: z.number().optional().describe('正文最大长度'), |
| 24 | maxTotalTextLength: z.number().optional().describe('最终发布文本最大长度'), |
| 25 | maxMediaCount: z.number().optional().describe('媒体最大数量'), |
| 26 | maxImages: z.number().optional().describe('图片最大数量'), |
| 27 | maxVideos: z.number().optional().describe('视频最大数量'), |
| 28 | }) |
| 29 | |
| 30 | const PlatformMediaRulesVoSchema = z.object({ |
| 31 | imageFormats: z.array(z.string()).optional().describe('图片格式'), |
| 32 | videoFormats: z.array(z.string()).optional().describe('视频格式'), |
| 33 | maxImageSize: z.number().optional().describe('图片最大字节数'), |
| 34 | maxVideoSize: z.number().optional().describe('视频最大字节数'), |
| 35 | minVideoDuration: z.number().optional().describe('视频最小秒数'), |
| 36 | maxVideoDuration: z.number().optional().describe('视频最大秒数'), |
| 37 | minImageWidth: z.number().optional().describe('图片最小宽度'), |
| 38 | minImageHeight: z.number().optional().describe('图片最小高度'), |
| 39 | maxImageWidth: z.number().optional().describe('图片最大宽度'), |
| 40 | maxImageHeight: z.number().optional().describe('图片最大高度'), |
| 41 | aspectRatio: z.object({ |
| 42 | min: z.number().optional().describe('最小宽高比'), |
| 43 | max: z.number().optional().describe('最大宽高比'), |
| 44 | }).optional().describe('宽高比限制'), |
| 45 | }) |
| 46 | |
| 47 | const TopicCapabilityVoSchema = z.object({ |
| 48 | supported: z.boolean().describe('是否支持话题'), |
| 49 | nativeField: z.boolean().optional().describe('是否使用平台原生话题字段'), |
| 50 | maxCount: z.number().optional().describe('话题最大数量'), |
| 51 | maxTotalLength: z.number().optional().describe('话题序列化后的最大总长度'), |
| 52 | }) |
| 53 | |
| 54 | const JsonSchemaVoSchema = z.record(z.string(), z.unknown()).describe('发布选项 JSON Schema') |
| 55 | |
| 56 | const PlatformAuthCapabilitiesVoSchema = z.object({ |
| 57 | supported: z.boolean().describe('是否支持授权'), |
| 58 | revoke: z.boolean().describe('是否支持取消授权'), |
| 59 | selectableAccounts: z.boolean().describe('是否支持授权后选择子账号'), |
| 60 | refreshAccountAccess: z.boolean().describe('是否支持刷新子账号访问凭证'), |
| 61 | }) |
| 62 | |
| 63 | const PlatformEmptyAccountHintVoSchema = z.object({ |
| 64 | title: LocaleTextSchema.describe('空账号提示标题'), |
| 65 | description: LocaleTextSchema.describe('空账号提示描述'), |
| 66 | action: z.object({ |
| 67 | label: LocaleTextSchema.describe('操作按钮文案'), |
| 68 | url: z.url().describe('操作链接'), |
| 69 | }).optional().describe('操作按钮'), |
| 70 | }) |
| 71 | |
| 72 | const PlatformPublishCapabilitiesVoSchema = z.object({ |
| 73 | supported: z.boolean().describe('是否支持服务端发布'), |
| 74 | cancel: z.boolean().describe('是否支持取消平台侧发布'), |
| 75 | update: z.boolean().describe('是否支持更新已发布内容'), |
| 76 | verify: z.boolean().describe('是否支持发布结果验证'), |
| 77 | finalize: z.boolean().describe('是否支持发布后轮询或收尾'), |
| 78 | scheduleByPlatform: z.boolean().describe('是否支持平台原生定时发布'), |
| 79 | optionSources: z.boolean().describe('是否支持动态发布选项'), |
| 80 | completionStrategy: z.enum(CompletionStrategy).optional().describe('发布完成策略'), |
| 81 | }) |
| 82 | |
| 83 | const PlatformAnalyticsCapabilitiesVoSchema = z.object({ |
| 84 | account: z.boolean().describe('是否支持账号数据分析'), |
| 85 | work: z.boolean().describe('是否支持作品数据分析'), |
| 86 | }) |
| 87 | |
| 88 | const ChannelEngagementOperationParametersVoSchema = z.object({ |
| 89 | querySchema: JsonSchemaVoSchema.describe('Query 参数 JSON Schema'), |
| 90 | bodySchema: JsonSchemaVoSchema.optional().describe('Body 参数 JSON Schema'), |
| 91 | dataSchema: JsonSchemaVoSchema.optional().describe('函数 data 参数 JSON Schema'), |
| 92 | }) |
| 93 | |
| 94 | const PlatformEngagementCapabilitiesVoSchema = z.object({ |
| 95 | comments: z.object({ |
| 96 | list: z.object({ |
| 97 | supported: z.boolean().describe('是否支持评论列表'), |
| 98 | pagination: ChannelPaginationMetadataVoSchema.describe('评论列表分页能力'), |
| 99 | parameters: ChannelEngagementOperationParametersVoSchema.describe('评论列表参数'), |
| 100 | }).describe('评论列表能力'), |
| 101 | create: z.object({ |
| 102 | supported: z.boolean().describe('是否支持创建评论'), |
| 103 | parameters: ChannelEngagementOperationParametersVoSchema.describe('创建评论参数'), |
| 104 | }).describe('创建评论能力'), |
| 105 | }).describe('评论能力'), |
| 106 | functions: z.array(z.object({ |
| 107 | name: z.enum(ChannelEngagementFunctionName).describe('互动函数名称'), |
| 108 | label: LocaleTextSchema.describe('函数展示文案'), |
| 109 | target: z.enum(ChannelEngagementTargetType).describe('互动目标类型'), |
| 110 | parameters: z.object({ |
| 111 | querySchema: JsonSchemaVoSchema.describe('Query 参数 JSON Schema'), |
| 112 | bodySchema: JsonSchemaVoSchema.describe('Body 参数 JSON Schema'), |
| 113 | dataSchema: JsonSchemaVoSchema.describe('函数 data 参数 JSON Schema'), |
| 114 | }).describe('函数参数'), |
| 115 | })).describe('平台支持的互动函数'), |
| 116 | }) |
| 117 | |
| 118 | const PlatformWorkCapabilitiesVoSchema = z.object({ |
| 119 | listWorks: z.boolean().describe('是否支持账号作品列表'), |
| 120 | listWorksPagination: ChannelPaginationMetadataVoSchema.describe('账号作品列表分页能力'), |
| 121 | getLinkInfo: z.boolean().describe('是否支持解析作品链接'), |
| 122 | getDetail: z.boolean().describe('是否支持作品详情'), |
| 123 | verifyOwnership: z.boolean().describe('是否支持作品归属校验'), |
| 124 | }) |
| 125 | |
| 126 | const PlatformBrowseCapabilitiesVoSchema = z.object({ |
| 127 | search: z.boolean().describe('是否支持搜索浏览'), |
| 128 | getDetail: z.boolean().describe('是否支持浏览详情'), |
| 129 | }) |
| 130 | |
| 131 | const PlatformWebhookCapabilitiesVoSchema = z.object({ |
| 132 | supported: z.boolean().describe('是否支持 webhook'), |
| 133 | }) |
| 134 | |
| 135 | const PlatformCapabilitiesVoSchema = z.object({ |
| 136 | auth: PlatformAuthCapabilitiesVoSchema.describe('授权能力'), |
| 137 | publish: PlatformPublishCapabilitiesVoSchema.describe('发布能力'), |
| 138 | analytics: PlatformAnalyticsCapabilitiesVoSchema.describe('数据分析能力'), |
| 139 | engagement: PlatformEngagementCapabilitiesVoSchema.describe('互动能力'), |
| 140 | work: PlatformWorkCapabilitiesVoSchema.describe('作品能力'), |
| 141 | browse: PlatformBrowseCapabilitiesVoSchema.describe('浏览能力'), |
| 142 | webhook: PlatformWebhookCapabilitiesVoSchema.describe('Webhook 能力'), |
| 143 | }) |
| 144 | |
| 145 | export const PlatformMetadataVoSchema = z.object({ |
| 146 | platform: z.enum(AccountType).describe('平台'), |
| 147 | displayName: LocaleTextSchema.describe('展示名'), |
| 148 | logoUrl: z.url().describe('平台 logo URL'), |
| 149 | authType: z.enum(AuthType).describe('授权类型'), |
| 150 | authInstructions: LocaleTextSchema.optional().describe('授权操作提示语'), |
| 151 | emptyAccountHint: PlatformEmptyAccountHintVoSchema.optional().describe('空账号引导提示'), |
| 152 | editor: z.enum(EditorType).describe('编辑器类型'), |
| 153 | contentLimits: PlatformContentLimitsVoSchema.describe('内容限制'), |
| 154 | mediaRules: PlatformMediaRulesVoSchema.describe('媒体规则'), |
| 155 | topic: TopicCapabilityVoSchema.describe('话题能力'), |
| 156 | capabilities: PlatformCapabilitiesVoSchema.describe('平台操作能力'), |
| 157 | optionSchema: JsonSchemaVoSchema.describe('发布选项 JSON Schema'), |
| 158 | defaultOption: z.record(z.string(), z.unknown()).optional().describe('默认发布选项'), |
| 159 | status: z.enum(PlatformStatus).describe('平台状态'), |
| 160 | }) |
| 161 | |
| 162 | export class PlatformMetadataVo extends createZodDto(PlatformMetadataVoSchema) {} |
| 163 | |
| 164 | interface PublishOptionValueItemVo { |
| 165 | value: string |
| 166 | label: string |
| 167 | description?: string |
| 168 | disabled?: boolean |
| 169 | children?: PublishOptionValueItemVo[] |
| 170 | extra?: Record<string, unknown> |
| 171 | } |
| 172 | |
| 173 | export const PublishOptionSourceVoSchema = z.object({ |
| 174 | field: z.string().describe('发布选项字段'), |
| 175 | label: z.string().describe('展示名称'), |
| 176 | description: z.string().optional().describe('说明'), |
| 177 | valueType: z.enum(PublishOptionValueType).describe('取值结构'), |
| 178 | requiresAccount: z.boolean().describe('是否需要账号授权'), |
| 179 | filterSchema: JsonSchemaVoSchema.optional().describe('过滤条件 schema'), |
| 180 | createSchema: JsonSchemaVoSchema.optional().describe('创建参数 schema'), |
| 181 | }) |
| 182 | |
| 183 | export class PublishOptionSourceVo extends createZodDto(PublishOptionSourceVoSchema, 'PublishOptionSourceVo') {} |
| 184 | |
| 185 | export const PublishOptionValueItemVoSchema: z.ZodType<PublishOptionValueItemVo> = z.lazy(() => z.object({ |
| 186 | value: z.string().describe('选项值'), |
| 187 | label: z.string().describe('展示名称'), |
| 188 | description: z.string().optional().describe('说明'), |
| 189 | disabled: z.boolean().optional().describe('是否禁用'), |
| 190 | children: z.array(PublishOptionValueItemVoSchema).optional().describe('子选项'), |
| 191 | extra: z.record(z.string(), z.unknown()).optional().describe('平台原始补充字段'), |
| 192 | })) |
| 193 | |
| 194 | export const PublishOptionValuesVoSchema = z.object({ |
| 195 | field: z.string().describe('发布选项字段'), |
| 196 | valueType: z.enum(PublishOptionValueType).describe('取值结构'), |
| 197 | items: z.array(PublishOptionValueItemVoSchema).describe('选项列表'), |
| 198 | }) |
| 199 | |
| 200 | export class PublishOptionValuesVo extends createZodDto(PublishOptionValuesVoSchema, 'PublishOptionValuesVo') {} |
| 201 | |
| 202 | export const PublishOptionCreatedValueVoSchema = z.object({ |
| 203 | field: z.string().describe('发布选项字段'), |
| 204 | valueType: z.enum(PublishOptionValueType).describe('取值结构'), |
| 205 | item: PublishOptionValueItemVoSchema.describe('创建后的选项'), |
| 206 | }) |
| 207 | |
| 208 | export class PublishOptionCreatedValueVo extends createZodDto( |
| 209 | PublishOptionCreatedValueVoSchema, |
| 210 | 'PublishOptionCreatedValueVo', |
| 211 | ) {} |
| 212 |