96 lines
2.3 KiB
TypeScript
96 lines
2.3 KiB
TypeScript
export const NOTICE_STATUS_VALUES = ["draft", "published", "retracted"] as const;
|
|
export type NoticeStatus = (typeof NOTICE_STATUS_VALUES)[number];
|
|
|
|
export const NOTICE_STATUS_LABELS: Record<NoticeStatus, string> = {
|
|
draft: "草稿",
|
|
published: "已发布",
|
|
retracted: "已撤回",
|
|
};
|
|
|
|
export type Notice = {
|
|
id: string;
|
|
organizationId: string;
|
|
title: string;
|
|
content: string;
|
|
audience: string;
|
|
status: NoticeStatus;
|
|
publishedAt?: string;
|
|
createdByAccountId?: string;
|
|
createdByName?: string;
|
|
updatedByAccountId?: string;
|
|
updatedByName?: string;
|
|
readCount: number;
|
|
hasRead: boolean;
|
|
createdAt: string;
|
|
updatedAt: string;
|
|
};
|
|
|
|
export type NoticeCenterData = {
|
|
metrics: {
|
|
published: number;
|
|
drafts: number;
|
|
unread: number;
|
|
retracted: number;
|
|
};
|
|
notices: Notice[];
|
|
};
|
|
|
|
export type NoticeInput = {
|
|
title: string;
|
|
content: string;
|
|
audience: string;
|
|
status: NoticeStatus;
|
|
};
|
|
|
|
type ValidationSuccess<T> = {
|
|
success: true;
|
|
data: T;
|
|
};
|
|
|
|
type ValidationFailure = {
|
|
success: false;
|
|
reason: string;
|
|
};
|
|
|
|
export type ValidationResult<T> = ValidationSuccess<T> | ValidationFailure;
|
|
|
|
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
}
|
|
|
|
function readString(source: Record<string, unknown>, key: string): string {
|
|
const value = source[key];
|
|
return typeof value === "string" ? value.trim() : "";
|
|
}
|
|
|
|
function readEnum<T extends string>(value: unknown, values: readonly T[]): T | null {
|
|
return typeof value === "string" ? values.find((item) => item === value) ?? null : null;
|
|
}
|
|
|
|
export function validateNoticeInput(value: unknown): ValidationResult<NoticeInput> {
|
|
if (!isRecord(value)) {
|
|
return { success: false, reason: "请求数据格式无效" };
|
|
}
|
|
|
|
const title = readString(value, "title");
|
|
const content = readString(value, "content");
|
|
if (!title || !content) {
|
|
return { success: false, reason: "公告标题和内容不能为空" };
|
|
}
|
|
|
|
const status = readEnum(value.status, NOTICE_STATUS_VALUES);
|
|
if (!status) {
|
|
return { success: false, reason: "公告状态无效" };
|
|
}
|
|
|
|
return {
|
|
success: true,
|
|
data: {
|
|
title,
|
|
content,
|
|
audience: readString(value, "audience") || "全体员工",
|
|
status,
|
|
},
|
|
};
|
|
}
|