Commit 951fb26d by luoqi

feat(web): 宿主槽位跳转一律新开标签页,不再顶掉当前页

业务约定:客户档案 / 病历 / 预约等宿主页面「打开新页,不在当前页面做跳转」。

原来四处槽位跳转全用 `_top` —— PAC 嵌在宿主 iframe 里时会把整个宿主页顶掉,
客服看完档案回不到刚才的工单(召回上下文、已填的通话结果全丢)。

四处统一收口到 action-url.ts 的两个出口,免得以后再各写各的 target:
  a 标签  → HOST_LINK_PROPS (target=_blank + rel=noopener noreferrer)
  JS 派发 → openHostUrl()

覆盖:VIEW_PATIENT(原始档案)、VIEW_MEDICAL_RECORD(原始病历)、
CREATE_APPOINTMENT(新建预约)、OPEN_POTENTIAL_TREATMENT / OPEN_RETURN_VISIT
的 URL 模式(postMessage 模式不涉及跳转,不动)。

本地实测:两个 a 标签渲染成 target="_blank" rel="noopener noreferrer";
新建预约走 openHostUrl 打开宿主页。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
parent b5fdb1b9
......@@ -28,7 +28,7 @@ import { IdentityCluster } from '@/components/identity-cluster';
import { isEmbedded } from '@/lib/embed';
import { hostActionMode, openHostAction } from '@/lib/host-message';
import { CloseOpportunityDialog } from './close-opportunity-dialog';
import { resolveActionUrl } from '@/lib/action-url';
import { resolveActionUrl, openHostUrl, HOST_LINK_PROPS } from '@/lib/action-url';
import {
cn,
formatGender,
......@@ -433,8 +433,8 @@ export function PlanDetailApp({
showToast('amber', '未配置新建预约', '请在宿主管理页配置 actionUrls.CREATE_APPOINTMENT');
return;
}
window.open(url, '_top');
showToast('emerald', '已打开宿主预约页', '带上患者 id');
openHostUrl(url);
showToast('emerald', '已在新标签页打开宿主预约页', '带上患者 id');
};
// ── 宠物引导 1:话术已生成 + 在本患者页停留 15s → 发话引导给话术打「是否好用」评价 ──
......@@ -1339,8 +1339,7 @@ function IdentityCard({
{originalArchiveUrl ? (
<a
href={originalArchiveUrl}
target="_top"
rel="noopener"
{...HOST_LINK_PROPS}
className="text-[10.5px] text-teal-700 hover:underline"
>
原始档案 →
......@@ -1909,8 +1908,7 @@ function TreatmentHistoryCard({
// 宿主电子病历原文(占位插槽)—— 替换原「详情」时间轴抽屉
<a
href={emrUrl}
target="_top"
rel="noopener"
{...HOST_LINK_PROPS}
className="text-[10.5px] text-teal-700 hover:underline"
>
原始病历 →
......
......@@ -37,3 +37,19 @@ export function resolveActionUrl(
const tpl = actionTemplate(key);
return tpl ? fillActionUrl(tpl, ctx) : undefined;
}
/**
* ⭐ 宿主槽位跳转一律**新开标签页** —— 所有槽位统一,别再各写各的 target。
*
* 2026-07-29 业务约定:客户档案 / 病历 / 预约等宿主页面「打开新页,不在当前页面做跳转」。
* 原来用的是 `_top`:PAC 嵌在宿主 iframe 里时会把**整个宿主页顶掉**,客服看完档案回不到
* 刚才的工单(召回上下文、已填的通话结果全丢)。新标签页则两边都在。
*
* 用 a 标签的地方用 HOST_LINK_PROPS,用 JS 派发的地方用 openHostUrl(),两条路同一口径。
* `noopener`:新页拿不到 window.opener,防宿主页被反向导航(tabnabbing)。
*/
export const HOST_LINK_PROPS = { target: '_blank', rel: 'noopener noreferrer' } as const;
export function openHostUrl(url: string): void {
window.open(url, '_blank', 'noopener,noreferrer');
}
......@@ -2,7 +2,7 @@
import { toast } from 'sonner';
import { useAuthStore } from '@/stores/auth-store';
import { fillActionUrl } from '@/lib/action-url';
import { fillActionUrl, openHostUrl } from '@/lib/action-url';
/**
* 宿主动作派发(潜在治疗 / 回访)—— 模式由 actionUrls[key] 的值形态决定:
......@@ -63,7 +63,7 @@ export function openHostAction(
return false;
}
if (mode === 'url') {
window.open(fillActionUrl(raw, ctx), '_top');
openHostUrl(fillActionUrl(raw, ctx));
return true;
}
// 信封:source + type + action + payload(契约约定;无 version / doctorId / meta)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment