129 lines
3.4 KiB
TypeScript
129 lines
3.4 KiB
TypeScript
/**
|
||
* iframe 与宿主页通信消息类型常量
|
||
*
|
||
* 消息格式:{ type: MESSAGE_TYPE, ...其他字段 }
|
||
* 发送方式:window.parent.postMessage(message, "*")
|
||
*/
|
||
|
||
// 发送给宿主页的消息类型
|
||
export const POST_MESSAGE_TYPES = {
|
||
// 全屏切换
|
||
FULLSCREEN: "fullscreen",
|
||
// 会话是否处于聊天态
|
||
IS_CHATTING: "isChatting",
|
||
// 请求宿主页执行复制
|
||
COPY_TO_CLIPBOARD: "copyToClipboard",
|
||
// 选择预定义 skill
|
||
SELECT_SKILLS: "selectedSkills",
|
||
// 打开 skill 选择对话框
|
||
OPEN_SKILL_DIALOG: "openSkillDialog",
|
||
} as const;
|
||
|
||
// 接收来自宿主页的消息类型
|
||
export const RECEIVE_MESSAGE_TYPES = {
|
||
// 选中的 skill 数据
|
||
SELECTED_SKILL: "selectedSkill",
|
||
// 选中的 skills 数据(数组)
|
||
SELECTED_SKILLS: "selectedSkills",
|
||
} as const;
|
||
|
||
// 消息类型
|
||
export type PostMessageType =
|
||
(typeof POST_MESSAGE_TYPES)[keyof typeof POST_MESSAGE_TYPES];
|
||
export type ReceiveMessageType =
|
||
(typeof RECEIVE_MESSAGE_TYPES)[keyof typeof RECEIVE_MESSAGE_TYPES];
|
||
|
||
// 消息数据类型
|
||
export interface FullscreenMessage {
|
||
type: typeof POST_MESSAGE_TYPES.FULLSCREEN;
|
||
fullscreen: boolean;
|
||
}
|
||
|
||
export interface IsChattingMessage {
|
||
type: typeof POST_MESSAGE_TYPES.IS_CHATTING;
|
||
isChatting: boolean;
|
||
}
|
||
|
||
export interface CopyToClipboardMessage {
|
||
type: typeof POST_MESSAGE_TYPES.COPY_TO_CLIPBOARD;
|
||
text: string;
|
||
}
|
||
|
||
export interface SelectSkillMessage {
|
||
type: typeof POST_MESSAGE_TYPES.SELECT_SKILLS;
|
||
selectedSkills: SelectedSkillPayloadItem[];
|
||
}
|
||
|
||
export interface OpenSkillDialogMessage {
|
||
type: typeof POST_MESSAGE_TYPES.OPEN_SKILL_DIALOG;
|
||
openSkillDialog: true;
|
||
}
|
||
|
||
export interface SelectedSkillMessage {
|
||
type: typeof RECEIVE_MESSAGE_TYPES.SELECTED_SKILL;
|
||
id: string | number;
|
||
title: string;
|
||
}
|
||
|
||
export interface SelectedSkillPayloadItem {
|
||
id: string | number;
|
||
name: string;
|
||
}
|
||
|
||
type UnknownRecord = Record<string, unknown>;
|
||
|
||
function asRecord(value: unknown): UnknownRecord | null {
|
||
if (typeof value !== "object" || value === null) {
|
||
return null;
|
||
}
|
||
return value as UnknownRecord;
|
||
}
|
||
|
||
export function isSelectedSkillMessage(
|
||
value: unknown,
|
||
): value is SelectedSkillMessage {
|
||
const record = asRecord(value);
|
||
if (record?.type !== RECEIVE_MESSAGE_TYPES.SELECTED_SKILL) {
|
||
return false;
|
||
}
|
||
const { id, title } = record;
|
||
const isValidId = typeof id === "string" || typeof id === "number";
|
||
return isValidId && typeof title === "string" && title.trim().length > 0;
|
||
}
|
||
|
||
export function isSelectedSkillsMessage(
|
||
value: unknown,
|
||
): value is SelectSkillMessage {
|
||
const record = asRecord(value);
|
||
if (record?.type !== RECEIVE_MESSAGE_TYPES.SELECTED_SKILLS) {
|
||
return false;
|
||
}
|
||
const selectedSkills = record.selectedSkills;
|
||
if (!Array.isArray(selectedSkills)) {
|
||
return false;
|
||
}
|
||
return selectedSkills.every((item) => {
|
||
const skill = asRecord(item);
|
||
if (!skill) return false;
|
||
const id = skill.id;
|
||
const name = skill.name;
|
||
const isValidId = typeof id === "string" || typeof id === "number";
|
||
return isValidId && typeof name === "string" && name.trim().length > 0;
|
||
});
|
||
}
|
||
|
||
// 发送消息的辅助函数
|
||
export function sendToParent(
|
||
message:
|
||
| FullscreenMessage
|
||
| IsChattingMessage
|
||
| CopyToClipboardMessage
|
||
| SelectSkillMessage
|
||
| OpenSkillDialogMessage,
|
||
): void {
|
||
console.log("[iframe] sendToParent:", message);
|
||
if (window.parent !== window) {
|
||
window.parent.postMessage(message, "*");
|
||
}
|
||
}
|