feat(font): 新增字体设置并统一医护端与患者端文书字体
This commit is contained in:
@@ -0,0 +1,54 @@
|
||||
/** Immutable font descriptor shared by clinical and patient document renderers. */
|
||||
export interface DocumentFont {
|
||||
id: string;
|
||||
name: string;
|
||||
regularSha256: string;
|
||||
boldSha256: string | null;
|
||||
}
|
||||
|
||||
const loaded = new Map<string, Promise<string>>();
|
||||
|
||||
export function loadDocumentFont(
|
||||
font: DocumentFont | null,
|
||||
apiBase: string,
|
||||
): Promise<string> {
|
||||
if (!font) return Promise.resolve("");
|
||||
const key = `${apiBase}:${font.id}:${font.regularSha256}:${font.boldSha256 ?? ""}`;
|
||||
const existing = loaded.get(key);
|
||||
if (existing) return existing;
|
||||
const family = `Medisign-${font.regularSha256}-${font.boldSha256 ?? "regular"}`;
|
||||
const load = async () => {
|
||||
const descriptors = [
|
||||
{ sha: font.regularSha256, weight: "400" },
|
||||
{ sha: font.boldSha256 ?? font.regularSha256, weight: "700" },
|
||||
];
|
||||
const faces = await Promise.all(
|
||||
descriptors.map(async ({ sha, weight }) => {
|
||||
const url = `${apiBase.replace(/\/$/, "")}/v1/document-fonts/${encodeURIComponent(font.id)}/${sha}.ttf`;
|
||||
const response = await fetch(url, {
|
||||
signal: AbortSignal.timeout(30000),
|
||||
});
|
||||
if (!response.ok)
|
||||
throw new Error("文书字体加载失败,请重试或联系管理员。");
|
||||
const bytes = await response.arrayBuffer();
|
||||
// The URL names an immutable digest; verify before registering the face.
|
||||
if (globalThis.crypto?.subtle) {
|
||||
const digest = await crypto.subtle.digest("SHA-256", bytes);
|
||||
const actual = Array.from(new Uint8Array(digest), (byte) =>
|
||||
byte.toString(16).padStart(2, "0"),
|
||||
).join("");
|
||||
if (actual !== sha) throw new Error("文书字体校验失败。");
|
||||
}
|
||||
return new FontFace(family, bytes, { weight }).load();
|
||||
}),
|
||||
);
|
||||
for (const face of faces) document.fonts.add(face);
|
||||
return `"${family}"`;
|
||||
};
|
||||
const promise = load().catch((error: unknown) => {
|
||||
loaded.delete(key);
|
||||
throw error;
|
||||
});
|
||||
loaded.set(key, promise);
|
||||
return promise;
|
||||
}
|
||||
Reference in New Issue
Block a user