|
@@ -1,395 +1,80 @@
|
|
|
-import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn, UpdateDateColumn, ManyToOne, JoinColumn, OneToMany } from 'typeorm';
|
|
|
|
|
-import { UserEntity } from '../users/user.entity';
|
|
|
|
|
-import { SilverKnowledgeCategory, SilverKnowledgeCategorySchema } from './silver-knowledge-category.entity';
|
|
|
|
|
-import { SilverKnowledgeInteraction } from './silver-knowledge-interaction.entity';
|
|
|
|
|
-import { SilverKnowledgeTagRelation } from './silver-knowledge-tag-relation.entity';
|
|
|
|
|
|
|
+import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn, UpdateDateColumn, ManyToOne, JoinColumn } from 'typeorm';
|
|
|
import { z } from '@hono/zod-openapi';
|
|
import { z } from '@hono/zod-openapi';
|
|
|
-
|
|
|
|
|
-export enum KnowledgeType {
|
|
|
|
|
- ARTICLE = 1, // 文章
|
|
|
|
|
- VIDEO = 2, // 视频
|
|
|
|
|
- DOCUMENT = 3, // 文档
|
|
|
|
|
- COURSE = 4, // 课程
|
|
|
|
|
- EXPERIENCE = 5, // 经验分享
|
|
|
|
|
- CASE = 6, // 案例分享
|
|
|
|
|
- RESEARCH = 7 // 研究报告
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-export enum KnowledgeStatus {
|
|
|
|
|
- DRAFT = 0, // 草稿
|
|
|
|
|
- PUBLISHED = 1, // 已发布
|
|
|
|
|
- HIDDEN = 2, // 已隐藏
|
|
|
|
|
- DELETED = 3, // 已删除
|
|
|
|
|
- REVIEWING = 4 // 审核中
|
|
|
|
|
-}
|
|
|
|
|
|
|
+import { UserEntity } from '../users/user.entity';
|
|
|
|
|
|
|
|
@Entity('silver_knowledges')
|
|
@Entity('silver_knowledges')
|
|
|
export class SilverKnowledge {
|
|
export class SilverKnowledge {
|
|
|
@PrimaryGeneratedColumn({ unsigned: true })
|
|
@PrimaryGeneratedColumn({ unsigned: true })
|
|
|
id!: number;
|
|
id!: number;
|
|
|
|
|
|
|
|
- @Column({ name: 'user_id', type: 'int', unsigned: true })
|
|
|
|
|
- userId!: number;
|
|
|
|
|
-
|
|
|
|
|
- @ManyToOne(() => UserEntity, user => user.silverKnowledges)
|
|
|
|
|
- @JoinColumn({ name: 'user_id' })
|
|
|
|
|
- user!: UserEntity;
|
|
|
|
|
-
|
|
|
|
|
- @Column({ name: 'category_id', type: 'int', unsigned: true, nullable: true })
|
|
|
|
|
- categoryId!: number | null;
|
|
|
|
|
-
|
|
|
|
|
- @ManyToOne(() => SilverKnowledgeCategory, category => category.silverKnowledges)
|
|
|
|
|
- @JoinColumn({ name: 'category_id' })
|
|
|
|
|
- category!: SilverKnowledgeCategory | null;
|
|
|
|
|
-
|
|
|
|
|
@Column({ name: 'title', type: 'varchar', length: 255 })
|
|
@Column({ name: 'title', type: 'varchar', length: 255 })
|
|
|
title!: string;
|
|
title!: string;
|
|
|
|
|
|
|
|
@Column({ name: 'content', type: 'text' })
|
|
@Column({ name: 'content', type: 'text' })
|
|
|
content!: string;
|
|
content!: string;
|
|
|
|
|
|
|
|
- @Column({ name: 'summary', type: 'text', nullable: true })
|
|
|
|
|
- summary!: string | null;
|
|
|
|
|
-
|
|
|
|
|
- @Column({ name: 'type', type: 'tinyint', unsigned: true })
|
|
|
|
|
- type!: KnowledgeType;
|
|
|
|
|
|
|
+ @Column({ name: 'category', type: 'varchar', length: 50 })
|
|
|
|
|
+ category!: string;
|
|
|
|
|
|
|
|
@Column({ name: 'tags', type: 'text', nullable: true })
|
|
@Column({ name: 'tags', type: 'text', nullable: true })
|
|
|
- tags!: string | null; // JSON array of tags
|
|
|
|
|
-
|
|
|
|
|
- @Column({ name: 'cover_image', type: 'varchar', length: 500, nullable: true })
|
|
|
|
|
- coverImage!: string | null;
|
|
|
|
|
|
|
+ tags!: string | null;
|
|
|
|
|
|
|
|
- @Column({ name: 'attachments', type: 'text', nullable: true })
|
|
|
|
|
- attachments!: string | null; // JSON array of attachment URLs
|
|
|
|
|
|
|
+ @Column({ name: 'author', type: 'varchar', length: 100 })
|
|
|
|
|
+ author!: string;
|
|
|
|
|
|
|
|
- @Column({ name: 'status', type: 'tinyint', default: KnowledgeStatus.DRAFT })
|
|
|
|
|
- status!: KnowledgeStatus;
|
|
|
|
|
|
|
+ @Column({ name: 'status', type: 'tinyint', default: 1 })
|
|
|
|
|
+ status!: number; // 1: 发布, 0: 草稿
|
|
|
|
|
|
|
|
- // 统计字段 - 单个知识统计
|
|
|
|
|
- @Column({ name: 'view_count', type: 'int', unsigned: true, default: 0 })
|
|
|
|
|
|
|
+ @Column({ name: 'view_count', type: 'int', default: 0 })
|
|
|
viewCount!: number;
|
|
viewCount!: number;
|
|
|
|
|
|
|
|
- @Column({ name: 'download_count', type: 'int', unsigned: true, default: 0 })
|
|
|
|
|
- downloadCount!: number;
|
|
|
|
|
-
|
|
|
|
|
- @Column({ name: 'like_count', type: 'int', unsigned: true, default: 0 })
|
|
|
|
|
|
|
+ @Column({ name: 'like_count', type: 'int', default: 0 })
|
|
|
likeCount!: number;
|
|
likeCount!: number;
|
|
|
|
|
|
|
|
- @Column({ name: 'comment_count', type: 'int', unsigned: true, default: 0 })
|
|
|
|
|
- commentCount!: number;
|
|
|
|
|
-
|
|
|
|
|
- @Column({ name: 'favorite_count', type: 'int', unsigned: true, default: 0 })
|
|
|
|
|
- favoriteCount!: number;
|
|
|
|
|
-
|
|
|
|
|
- @Column({ name: 'share_count', type: 'int', unsigned: true, default: 0 })
|
|
|
|
|
- shareCount!: number;
|
|
|
|
|
-
|
|
|
|
|
- @Column({ name: 'read_count', type: 'int', unsigned: true, default: 0 })
|
|
|
|
|
- readCount!: number; // 更准确的阅读统计
|
|
|
|
|
-
|
|
|
|
|
- // 推荐和排序
|
|
|
|
|
- @Column({ name: 'is_featured', type: 'tinyint', default: 0 })
|
|
|
|
|
- isFeatured!: number;
|
|
|
|
|
-
|
|
|
|
|
- @Column({ name: 'featured_at', type: 'timestamp', nullable: true })
|
|
|
|
|
- featuredAt!: Date | null;
|
|
|
|
|
-
|
|
|
|
|
- @Column({ name: 'sort_order', type: 'int', default: 0 })
|
|
|
|
|
- sortOrder!: number;
|
|
|
|
|
-
|
|
|
|
|
- // 元数据
|
|
|
|
|
- @Column({ name: 'keywords', type: 'text', nullable: true })
|
|
|
|
|
- keywords!: string | null; // 用于搜索优化的关键词
|
|
|
|
|
-
|
|
|
|
|
- @Column({ name: 'source', type: 'varchar', length: 255, nullable: true })
|
|
|
|
|
- source!: string | null; // 知识来源
|
|
|
|
|
-
|
|
|
|
|
- @Column({ name: 'author', type: 'varchar', length: 100, nullable: true })
|
|
|
|
|
- author!: string | null; // 原作者
|
|
|
|
|
|
|
+ @Column({ name: 'user_id', type: 'int', unsigned: true })
|
|
|
|
|
+ userId!: number;
|
|
|
|
|
|
|
|
- @Column({ name: 'duration', type: 'int', unsigned: true, nullable: true })
|
|
|
|
|
- duration!: number | null; // 视频时长(秒)或阅读时长(分钟)
|
|
|
|
|
|
|
+ @ManyToOne(() => UserEntity)
|
|
|
|
|
+ @JoinColumn({ name: 'user_id' })
|
|
|
|
|
+ user!: UserEntity;
|
|
|
|
|
|
|
|
- // 时间戳
|
|
|
|
|
@CreateDateColumn({ name: 'created_at' })
|
|
@CreateDateColumn({ name: 'created_at' })
|
|
|
createdAt!: Date;
|
|
createdAt!: Date;
|
|
|
|
|
|
|
|
@UpdateDateColumn({ name: 'updated_at' })
|
|
@UpdateDateColumn({ name: 'updated_at' })
|
|
|
updatedAt!: Date;
|
|
updatedAt!: Date;
|
|
|
-
|
|
|
|
|
- @Column({ name: 'published_at', type: 'timestamp', nullable: true })
|
|
|
|
|
- publishedAt!: Date | null;
|
|
|
|
|
-
|
|
|
|
|
- // 用户跟踪
|
|
|
|
|
- @Column({ name: 'created_by', type: 'int', nullable: true })
|
|
|
|
|
- createdBy!: number | null;
|
|
|
|
|
-
|
|
|
|
|
- @Column({ name: 'updated_by', type: 'int', nullable: true })
|
|
|
|
|
- updatedBy!: number | null;
|
|
|
|
|
-
|
|
|
|
|
- @OneToMany(() => SilverKnowledgeInteraction, interaction => interaction.knowledge)
|
|
|
|
|
- silverKnowledgeInteractions!: SilverKnowledgeInteraction[];
|
|
|
|
|
-
|
|
|
|
|
- @OneToMany(() => SilverKnowledgeTagRelation, tagRelation => tagRelation.knowledge)
|
|
|
|
|
- silverKnowledgeTagRelations!: SilverKnowledgeTagRelation[];
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// Zod Schema定义
|
|
// Zod Schema定义
|
|
|
export const SilverKnowledgeSchema = z.object({
|
|
export const SilverKnowledgeSchema = z.object({
|
|
|
- id: z.number().int().positive().openapi({
|
|
|
|
|
- description: '知识ID',
|
|
|
|
|
- example: 1
|
|
|
|
|
- }),
|
|
|
|
|
- userId: z.number().int().positive().openapi({
|
|
|
|
|
- description: '发布用户ID',
|
|
|
|
|
- example: 1
|
|
|
|
|
- }),
|
|
|
|
|
- user: z.object({
|
|
|
|
|
- id: z.number().int().positive(),
|
|
|
|
|
- username: z.string(),
|
|
|
|
|
- nickname: z.string().nullable(),
|
|
|
|
|
- name: z.string().nullable(),
|
|
|
|
|
- avatar: z.string().nullable()
|
|
|
|
|
- }).optional().openapi({
|
|
|
|
|
- description: '发布用户',
|
|
|
|
|
- example: {
|
|
|
|
|
- id: 1,
|
|
|
|
|
- username: 'user123',
|
|
|
|
|
- nickname: '张三'
|
|
|
|
|
- }
|
|
|
|
|
- }),
|
|
|
|
|
- categoryId: z.number().int().positive().optional().nullable().openapi({
|
|
|
|
|
- description: '分类ID',
|
|
|
|
|
- example: 5
|
|
|
|
|
- }),
|
|
|
|
|
- category: SilverKnowledgeCategorySchema.optional().nullable().openapi({
|
|
|
|
|
- description: '知识分类',
|
|
|
|
|
- example: {
|
|
|
|
|
- id: 5,
|
|
|
|
|
- name: '健康养生'
|
|
|
|
|
- }
|
|
|
|
|
- }),
|
|
|
|
|
- title: z.string().max(255).openapi({
|
|
|
|
|
- description: '知识标题',
|
|
|
|
|
- example: '老年人健康饮食指南'
|
|
|
|
|
- }),
|
|
|
|
|
- content: z.string().openapi({
|
|
|
|
|
- description: '知识内容',
|
|
|
|
|
- example: '老年人健康饮食需要注意以下几点...'
|
|
|
|
|
- }),
|
|
|
|
|
- summary: z.string().optional().openapi({
|
|
|
|
|
- description: '知识摘要',
|
|
|
|
|
- example: '本指南详细介绍了老年人健康饮食的科学方法...'
|
|
|
|
|
- }),
|
|
|
|
|
- type: z.coerce.number().int().min(1).max(7).openapi({
|
|
|
|
|
- description: '知识类型 1:文章 2:视频 3:文档 4:课程 5:经验分享 6:案例分享 7:研究报告',
|
|
|
|
|
- example: 1
|
|
|
|
|
- }),
|
|
|
|
|
- tags: z.string().optional().nullable().openapi({
|
|
|
|
|
- description: '标签(JSON数组)',
|
|
|
|
|
- example: '["健康养生", "老年人", "饮食"]'
|
|
|
|
|
- }),
|
|
|
|
|
- coverImage: z.string().max(500).url().optional().nullable().openapi({
|
|
|
|
|
- description: '封面图片URL',
|
|
|
|
|
- example: 'https://example.com/cover.jpg'
|
|
|
|
|
- }),
|
|
|
|
|
- attachments: z.string().optional().nullable().openapi({
|
|
|
|
|
- description: '附件URL(JSON数组)',
|
|
|
|
|
- example: '["https://example.com/attach1.pdf"]'
|
|
|
|
|
- }),
|
|
|
|
|
- status: z.coerce.number().int().min(0).max(4).default(0).openapi({
|
|
|
|
|
- description: '状态 0:草稿 1:已发布 2:已隐藏 3:已删除 4:审核中',
|
|
|
|
|
- example: 1
|
|
|
|
|
- }),
|
|
|
|
|
- viewCount: z.number().int().min(0).default(0).openapi({
|
|
|
|
|
- description: '浏览次数',
|
|
|
|
|
- example: 1234
|
|
|
|
|
- }),
|
|
|
|
|
- downloadCount: z.number().int().min(0).default(0).openapi({
|
|
|
|
|
- description: '下载次数',
|
|
|
|
|
- example: 567
|
|
|
|
|
- }),
|
|
|
|
|
- likeCount: z.number().int().min(0).default(0).openapi({
|
|
|
|
|
- description: '点赞次数',
|
|
|
|
|
- example: 234
|
|
|
|
|
- }),
|
|
|
|
|
- commentCount: z.number().int().min(0).default(0).openapi({
|
|
|
|
|
- description: '评论次数',
|
|
|
|
|
- example: 89
|
|
|
|
|
- }),
|
|
|
|
|
- favoriteCount: z.number().int().min(0).default(0).openapi({
|
|
|
|
|
- description: '收藏次数',
|
|
|
|
|
- example: 156
|
|
|
|
|
- }),
|
|
|
|
|
- shareCount: z.number().int().min(0).default(0).openapi({
|
|
|
|
|
- description: '分享次数',
|
|
|
|
|
- example: 78
|
|
|
|
|
- }),
|
|
|
|
|
- readCount: z.number().int().min(0).default(0).openapi({
|
|
|
|
|
- description: '阅读次数',
|
|
|
|
|
- example: 2345
|
|
|
|
|
- }),
|
|
|
|
|
- isFeatured: z.coerce.number().int().min(0).max(1).default(0).openapi({
|
|
|
|
|
- description: '是否推荐 0:否 1:是',
|
|
|
|
|
- example: 1
|
|
|
|
|
- }),
|
|
|
|
|
- featuredAt: z.date().optional().nullable().openapi({
|
|
|
|
|
- description: '推荐时间',
|
|
|
|
|
- example: '2024-01-01T00:00:00Z'
|
|
|
|
|
- }),
|
|
|
|
|
- sortOrder: z.number().int().default(0).openapi({
|
|
|
|
|
- description: '排序顺序',
|
|
|
|
|
- example: 1
|
|
|
|
|
- }),
|
|
|
|
|
- keywords: z.string().optional().nullable().openapi({
|
|
|
|
|
- description: '搜索关键词',
|
|
|
|
|
- example: '健康,养生,老年人'
|
|
|
|
|
- }),
|
|
|
|
|
- source: z.string().max(255).optional().nullable().openapi({
|
|
|
|
|
- description: '知识来源',
|
|
|
|
|
- example: '中国老年学会'
|
|
|
|
|
- }),
|
|
|
|
|
- author: z.string().max(100).optional().nullable().openapi({
|
|
|
|
|
- description: '原作者',
|
|
|
|
|
- example: '张医生'
|
|
|
|
|
- }),
|
|
|
|
|
- duration: z.number().int().positive().optional().nullable().openapi({
|
|
|
|
|
- description: '时长(秒/分钟)',
|
|
|
|
|
- example: 15
|
|
|
|
|
- }),
|
|
|
|
|
- createdAt: z.date().openapi({
|
|
|
|
|
- description: '创建时间',
|
|
|
|
|
- example: '2024-01-01T00:00:00Z'
|
|
|
|
|
- }),
|
|
|
|
|
- updatedAt: z.date().openapi({
|
|
|
|
|
- description: '更新时间',
|
|
|
|
|
- example: '2024-01-01T00:00:00Z'
|
|
|
|
|
- }),
|
|
|
|
|
- publishedAt: z.date().optional().nullable().openapi({
|
|
|
|
|
- description: '发布时间',
|
|
|
|
|
- example: '2024-01-01T00:00:00Z'
|
|
|
|
|
- })
|
|
|
|
|
|
|
+ id: z.number().int().positive().openapi({ description: '知识ID' }),
|
|
|
|
|
+ title: z.string().max(255).openapi({ description: '知识标题', example: '健康生活小贴士' }),
|
|
|
|
|
+ content: z.string().openapi({ description: '知识内容', example: '今日分享几个健康生活的小技巧...' }),
|
|
|
|
|
+ category: z.string().max(50).openapi({ description: '知识分类', example: '健康养生' }),
|
|
|
|
|
+ tags: z.string().nullable().openapi({ description: '标签,逗号分隔', example: '健康,养生,老年人' }),
|
|
|
|
|
+ author: z.string().max(100).openapi({ description: '作者', example: '张医生' }),
|
|
|
|
|
+ status: z.number().int().min(0).max(1).openapi({ description: '状态(0-草稿,1-发布)', example: 1 }),
|
|
|
|
|
+ viewCount: z.number().int().nonnegative().openapi({ description: '浏览次数', example: 100 }),
|
|
|
|
|
+ likeCount: z.number().int().nonnegative().openapi({ description: '点赞次数', example: 25 }),
|
|
|
|
|
+ userId: z.number().int().positive().openapi({ description: '用户ID', example: 1 }),
|
|
|
|
|
+ createdAt: z.date().openapi({ description: '创建时间', example: '2024-01-01T00:00:00Z' }),
|
|
|
|
|
+ updatedAt: z.date().openapi({ description: '更新时间', example: '2024-01-01T00:00:00Z' })
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
export const CreateSilverKnowledgeDto = z.object({
|
|
export const CreateSilverKnowledgeDto = z.object({
|
|
|
- userId: z.coerce.number().int().positive().openapi({
|
|
|
|
|
- description: '发布用户ID',
|
|
|
|
|
- example: 1
|
|
|
|
|
- }),
|
|
|
|
|
- categoryId: z.number().int().positive().optional().openapi({
|
|
|
|
|
- description: '分类ID',
|
|
|
|
|
- example: 5
|
|
|
|
|
- }),
|
|
|
|
|
- title: z.string().max(255).openapi({
|
|
|
|
|
- description: '知识标题',
|
|
|
|
|
- example: '老年人健康饮食指南'
|
|
|
|
|
- }),
|
|
|
|
|
- content: z.string().openapi({
|
|
|
|
|
- description: '知识内容',
|
|
|
|
|
- example: '老年人健康饮食需要注意以下几点...'
|
|
|
|
|
- }),
|
|
|
|
|
- summary: z.string().optional().openapi({
|
|
|
|
|
- description: '知识摘要',
|
|
|
|
|
- example: '本指南详细介绍了老年人健康饮食的科学方法...'
|
|
|
|
|
- }),
|
|
|
|
|
- type: z.coerce.number().int().min(1).max(7).openapi({
|
|
|
|
|
- description: '知识类型',
|
|
|
|
|
- example: 1
|
|
|
|
|
- }),
|
|
|
|
|
- tags: z.string().optional().openapi({
|
|
|
|
|
- description: '标签(JSON数组)',
|
|
|
|
|
- example: '["健康养生", "老年人", "饮食"]'
|
|
|
|
|
- }),
|
|
|
|
|
- coverImage: z.string().max(500).url().optional().openapi({
|
|
|
|
|
- description: '封面图片URL',
|
|
|
|
|
- example: 'https://example.com/cover.jpg'
|
|
|
|
|
- }),
|
|
|
|
|
- attachments: z.string().optional().openapi({
|
|
|
|
|
- description: '附件URL(JSON数组)',
|
|
|
|
|
- example: '["https://example.com/attach1.pdf"]'
|
|
|
|
|
- }),
|
|
|
|
|
- keywords: z.string().optional().openapi({
|
|
|
|
|
- description: '搜索关键词',
|
|
|
|
|
- example: '健康,养生,老年人'
|
|
|
|
|
- }),
|
|
|
|
|
- source: z.string().max(255).optional().openapi({
|
|
|
|
|
- description: '知识来源',
|
|
|
|
|
- example: '中国老年学会'
|
|
|
|
|
- }),
|
|
|
|
|
- author: z.string().max(100).optional().openapi({
|
|
|
|
|
- description: '原作者',
|
|
|
|
|
- example: '张医生'
|
|
|
|
|
- }),
|
|
|
|
|
- duration: z.number().int().positive().optional().openapi({
|
|
|
|
|
- description: '时长(秒/分钟)',
|
|
|
|
|
- example: 15
|
|
|
|
|
- })
|
|
|
|
|
|
|
+ title: z.string().max(255).openapi({ description: '知识标题', example: '健康生活小贴士' }),
|
|
|
|
|
+ content: z.string().openapi({ description: '知识内容', example: '今日分享几个健康生活的小技巧...' }),
|
|
|
|
|
+ category: z.string().max(50).openapi({ description: '知识分类', example: '健康养生' }),
|
|
|
|
|
+ tags: z.string().nullable().optional().openapi({ description: '标签,逗号分隔', example: '健康,养生,老年人' }),
|
|
|
|
|
+ author: z.string().max(100).openapi({ description: '作者', example: '张医生' }),
|
|
|
|
|
+ status: z.coerce.number().int().min(0).max(1).default(1).openapi({ description: '状态(0-草稿,1-发布)', example: 1 })
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
export const UpdateSilverKnowledgeDto = z.object({
|
|
export const UpdateSilverKnowledgeDto = z.object({
|
|
|
- categoryId: z.number().int().positive().optional().openapi({
|
|
|
|
|
- description: '分类ID',
|
|
|
|
|
- example: 5
|
|
|
|
|
- }),
|
|
|
|
|
- title: z.string().max(255).optional().openapi({
|
|
|
|
|
- description: '知识标题',
|
|
|
|
|
- example: '老年人健康饮食指南'
|
|
|
|
|
- }),
|
|
|
|
|
- content: z.string().optional().openapi({
|
|
|
|
|
- description: '知识内容',
|
|
|
|
|
- example: '老年人健康饮食需要注意以下几点...'
|
|
|
|
|
- }),
|
|
|
|
|
- summary: z.string().optional().openapi({
|
|
|
|
|
- description: '知识摘要',
|
|
|
|
|
- example: '本指南详细介绍了老年人健康饮食的科学方法...'
|
|
|
|
|
- }),
|
|
|
|
|
- type: z.coerce.number().int().min(1).max(7).optional().openapi({
|
|
|
|
|
- description: '知识类型',
|
|
|
|
|
- example: 1
|
|
|
|
|
- }),
|
|
|
|
|
- tags: z.string().optional().openapi({
|
|
|
|
|
- description: '标签(JSON数组)',
|
|
|
|
|
- example: '["健康养生", "老年人", "饮食"]'
|
|
|
|
|
- }),
|
|
|
|
|
- coverImage: z.string().max(500).url().optional().openapi({
|
|
|
|
|
- description: '封面图片URL',
|
|
|
|
|
- example: 'https://example.com/cover.jpg'
|
|
|
|
|
- }),
|
|
|
|
|
- attachments: z.string().optional().openapi({
|
|
|
|
|
- description: '附件URL(JSON数组)',
|
|
|
|
|
- example: '["https://example.com/attach1.pdf"]'
|
|
|
|
|
- }),
|
|
|
|
|
- status: z.coerce.number().int().min(0).max(4).optional().openapi({
|
|
|
|
|
- description: '状态',
|
|
|
|
|
- example: 1
|
|
|
|
|
- }),
|
|
|
|
|
- keywords: z.string().optional().openapi({
|
|
|
|
|
- description: '搜索关键词',
|
|
|
|
|
- example: '健康,养生,老年人'
|
|
|
|
|
- }),
|
|
|
|
|
- source: z.string().max(255).optional().openapi({
|
|
|
|
|
- description: '知识来源',
|
|
|
|
|
- example: '中国老年学会'
|
|
|
|
|
- }),
|
|
|
|
|
- author: z.string().max(100).optional().openapi({
|
|
|
|
|
- description: '原作者',
|
|
|
|
|
- example: '张医生'
|
|
|
|
|
- }),
|
|
|
|
|
- duration: z.number().int().positive().optional().openapi({
|
|
|
|
|
- description: '时长(秒/分钟)',
|
|
|
|
|
- example: 15
|
|
|
|
|
- }),
|
|
|
|
|
- isFeatured: z.coerce.number().int().min(0).max(1).optional().openapi({
|
|
|
|
|
- description: '是否推荐',
|
|
|
|
|
- example: 1
|
|
|
|
|
- }),
|
|
|
|
|
- featuredAt: z.date().optional().nullable().openapi({
|
|
|
|
|
- description: '推荐时间',
|
|
|
|
|
- example: '2024-01-01T00:00:00Z'
|
|
|
|
|
- }),
|
|
|
|
|
- sortOrder: z.number().int().optional().openapi({
|
|
|
|
|
- description: '排序顺序',
|
|
|
|
|
- example: 1
|
|
|
|
|
- })
|
|
|
|
|
|
|
+ title: z.string().max(255).optional().openapi({ description: '知识标题', example: '健康生活小贴士' }),
|
|
|
|
|
+ content: z.string().optional().openapi({ description: '知识内容', example: '今日分享几个健康生活的小技巧...' }),
|
|
|
|
|
+ category: z.string().max(50).optional().openapi({ description: '知识分类', example: '健康养生' }),
|
|
|
|
|
+ tags: z.string().nullable().optional().openapi({ description: '标签,逗号分隔', example: '健康,养生,老年人' }),
|
|
|
|
|
+ author: z.string().max(100).optional().openapi({ description: '作者', example: '张医生' }),
|
|
|
|
|
+ status: z.coerce.number().int().min(0).max(1).optional().openapi({ description: '状态(0-草稿,1-发布)', example: 1 })
|
|
|
});
|
|
});
|