Commit 96b590a3 by luoqi

fix(web): 修 shadcn 浮层 z 层级(点删除卡死) + 时效移到卡片右上角

🔴 **点客服删除会卡死** —— 根因与上一条下拉看不见同源,但更严重:
   助手窗 fixed z-[60],而 shadcn 给**所有**浮层的默认层级是 z-50。
   · Select/Popover/DropdownMenu/HoverCard:点了有反应(DOM 里 listbox 确实打开),
     但一个选项都看不见;
   · Dialog/AlertDialog:Radix 会给 body 设 pointer-events:none —— **弹窗看不见、
     整页却已经被锁住**,用户看到的就是卡死。实测确认:alertdialog=true、
     overlayZ=50、bodyPE=none。
   两次都**不报任何错**。这次在 components/ui/* **统一修**而不是在调用处打补丁:
   浮层 z ≥ 70(select/popover/dropdown-menu/hover-card),模态 z ≥ 80(dialog/alert-dialog),
   六个文件顶部都写了层级约定,免得下次 re-generate 或新组件又掉回 50。

· 批次时效移到卡片**右上角**,与左边「拟分 N 人」同一层级(它是这一整批的设置);
  文案改成「3 天**后自动退回**」—— 光写"时效"主管不知道到期会发生什么。
· 底部微调区只留人数 + 出处说明(沿用哪次/首次默认/本次指定 + 几条单独设了时效)。

本地实测:点康慧捧的 X → 弹窗正常显示 → 移出本批 → 340/17 位 变 320/16 位 + 「已移除 20」。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
parent 7cfeb862
...@@ -114,14 +114,8 @@ function DaySelect({ ...@@ -114,14 +114,8 @@ function DaySelect({
> >
<SelectValue /> <SelectValue />
</SelectTrigger> </SelectTrigger>
{/* {/* z 层级已在 ui/select.tsx 统一抬到 70(助手窗是 z-60,见那里的层级约定) */}
🔴 `z-[70]` 不是随手加的:助手窗是 `fixed z-[60]`,而 shadcn 的 SelectContent 自带 `z-50`, <SelectContent>
Radix 会把 content 的 z-index **复制到 body 上那层 popper wrapper** —— 于是下拉
以 z-50 渲染在 z-60 的助手窗**底下**:点了有反应(listbox 确实打开了)、但一个选项都看不见。
⚠️ 这类错**不报任何错**,实测才发现(2026-08-03)。凡是在助手窗里用 Radix 浮层的地方,
都要把 z 抬到 60 以上。
*/}
<SelectContent className="z-[70]">
{ASSIGNMENT_EXPIRES_DAYS_PRESETS.map((d) => ( {ASSIGNMENT_EXPIRES_DAYS_PRESETS.map((d) => (
<SelectItem key={d} value={String(d)} className="text-[12px]"> <SelectItem key={d} value={String(d)} className="text-[12px]">
{d} {d}
...@@ -295,6 +289,14 @@ export function AssignmentConfirmSheet({ ...@@ -295,6 +289,14 @@ export function AssignmentConfirmSheet({
{sheet.unplaced} 人分不下去 {sheet.unplaced} 人分不下去
</Badge> </Badge>
)} )}
{/* ⭐ 批次时效放**右上角**:它是"这一整批"的设置,和左边"这一整批多少人"同一层级,
放在底部微调区会让人以为它跟下面的逐条时效是一回事。
⚠️ 文案是「N 天**后自动退回**」而不是光一个「时效」——
主管要知道到期会发生什么(单子回池),不然这个数对他没有意义。 */}
<div className="ml-auto flex flex-none items-center gap-1 text-[10.5px] text-slate-500">
<DaySelect value={expiresInDays} disabled={readOnly} onChange={setExpiresInDays} />
<span>后自动退回</span>
</div>
</div> </div>
{/* ② 按客服(产能视图)—— 这一层是主管真正在看的 */} {/* ② 按客服(产能视图)—— 这一层是主管真正在看的 */}
...@@ -456,19 +458,6 @@ export function AssignmentConfirmSheet({ ...@@ -456,19 +458,6 @@ export function AssignmentConfirmSheet({
{/* ③ 批次级设置 */} {/* ③ 批次级设置 */}
<div className="space-y-1.5 border-t border-slate-100 px-3 py-2"> <div className="space-y-1.5 border-t border-slate-100 px-3 py-2">
<div className="flex items-center gap-2">
<span className="flex-none text-slate-500">时效</span>
<DaySelect value={expiresInDays} disabled={readOnly} onChange={setExpiresInDays} />
{/* ⭐ T14:这个初值哪来的必须当场说清 —— 沿用上次 / 首次默认,信任度不同 */}
<span className="text-[10px] text-slate-400">
{sheet.basis === 'inherited' && sheet.basisFrom
? `沿用 ${sheet.basisFrom.slice(5, 10).replace('-', '/')} 那次`
: sheet.basis === 'explicit'
? '本次指定'
: '首次默认'}
{Object.keys(dayByPlan).length > 0 && ` · ${Object.keys(dayByPlan).length} 条单独设了`}
</span>
</div>
{/* 本批人数:**只读**。改它就是换一批人 —— 卡片不做这种事(要回对话) */} {/* 本批人数:**只读**。改它就是换一批人 —— 卡片不做这种事(要回对话) */}
<div className="flex items-center gap-2 text-[11px] text-slate-500"> <div className="flex items-center gap-2 text-[11px] text-slate-500">
<span className="flex-none">人数</span> <span className="flex-none">人数</span>
...@@ -481,7 +470,15 @@ export function AssignmentConfirmSheet({ ...@@ -481,7 +470,15 @@ export function AssignmentConfirmSheet({
: `要改说「这批 ${sheet.batchSize * 2} 人」`} : `要改说「这批 ${sheet.batchSize * 2} 人」`}
</span> </span>
</div> </div>
{/* ⭐ T14:时效/人数这两个数**哪来的**必须当场说清 —— 沿用上次 / 首次默认,信任度不同 */}
<p className="text-[10.5px] leading-relaxed text-slate-400"> <p className="text-[10.5px] leading-relaxed text-slate-400">
时效{' '}
{sheet.basis === 'inherited' && sheet.basisFrom
? `沿用 ${sheet.basisFrom.slice(5, 10).replace('-', '/')} 那次`
: sheet.basis === 'explicit'
? '为本次指定'
: '为首次默认'}
{Object.keys(dayByPlan).length > 0 && `,其中 ${Object.keys(dayByPlan).length} 条单独设了`};
条目可<span className="font-medium text-slate-500">拖到别的客服</span>名下; 条目可<span className="font-medium text-slate-500">拖到别的客服</span>名下;
换人群 / 改人数回对话让助手重新圈。 换人群 / 改人数回对话让助手重新圈。
</p> </p>
......
'use client'; 'use client';
/**
* 🔴 层级约定(2026-08-03,踩坑后定):**浮层 z ≥ 70,模态 z ≥ 80**。
*
* 助手窗是 `fixed z-[60]`(pet fab 61、数据流粒子 62)。shadcn 默认给浮层 `z-50` ——
* 于是**任何在助手窗里打开的浮层都渲染在它底下**:
* · Select/Popover 类:点了有反应(DOM 里 listbox 确实打开),但一个选项都看不见;
* · Dialog/AlertDialog 类更糟:Radix 会给 body 设 `pointer-events:none`,
* 弹窗看不见、整页却已经被锁住 —— 用户看到的就是**卡死**。
* ⚠️ 这类错**不报任何错**,只能实测发现。⛔ 别把 z 调回 50。
*/
import * as React from 'react'; import * as React from 'react';
import * as AlertDialogPrimitive from '@radix-ui/react-alert-dialog'; import * as AlertDialogPrimitive from '@radix-ui/react-alert-dialog';
import { cn } from '@/lib/utils'; import { cn } from '@/lib/utils';
...@@ -22,7 +32,7 @@ const AlertDialogOverlay = React.forwardRef< ...@@ -22,7 +32,7 @@ const AlertDialogOverlay = React.forwardRef<
<AlertDialogPrimitive.Overlay <AlertDialogPrimitive.Overlay
ref={ref} ref={ref}
className={cn( className={cn(
'fixed inset-0 z-50 bg-black/50 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0', 'fixed inset-0 z-[80] bg-black/50 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0',
className, className,
)} )}
{...props} {...props}
...@@ -39,7 +49,7 @@ const AlertDialogContent = React.forwardRef< ...@@ -39,7 +49,7 @@ const AlertDialogContent = React.forwardRef<
<AlertDialogPrimitive.Content <AlertDialogPrimitive.Content
ref={ref} ref={ref}
className={cn( className={cn(
'fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-md duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg', 'fixed left-[50%] top-[50%] z-[80] grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-md duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg',
className, className,
)} )}
{...props} {...props}
......
'use client'; 'use client';
/**
* 🔴 层级约定(2026-08-03,踩坑后定):**浮层 z ≥ 70,模态 z ≥ 80**。
*
* 助手窗是 `fixed z-[60]`(pet fab 61、数据流粒子 62)。shadcn 默认给浮层 `z-50` ——
* 于是**任何在助手窗里打开的浮层都渲染在它底下**:
* · Select/Popover 类:点了有反应(DOM 里 listbox 确实打开),但一个选项都看不见;
* · Dialog/AlertDialog 类更糟:Radix 会给 body 设 `pointer-events:none`,
* 弹窗看不见、整页却已经被锁住 —— 用户看到的就是**卡死**。
* ⚠️ 这类错**不报任何错**,只能实测发现。⛔ 别把 z 调回 50。
*/
import * as React from 'react'; import * as React from 'react';
import * as DialogPrimitive from '@radix-ui/react-dialog'; import * as DialogPrimitive from '@radix-ui/react-dialog';
import { X } from 'lucide-react'; import { X } from 'lucide-react';
...@@ -23,7 +33,7 @@ const DialogOverlay = React.forwardRef< ...@@ -23,7 +33,7 @@ const DialogOverlay = React.forwardRef<
<DialogPrimitive.Overlay <DialogPrimitive.Overlay
ref={ref} ref={ref}
className={cn( className={cn(
'fixed inset-0 z-50 bg-black/50 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0', 'fixed inset-0 z-[80] bg-black/50 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0',
className, className,
)} )}
{...props} {...props}
...@@ -40,7 +50,7 @@ const DialogContent = React.forwardRef< ...@@ -40,7 +50,7 @@ const DialogContent = React.forwardRef<
<DialogPrimitive.Content <DialogPrimitive.Content
ref={ref} ref={ref}
className={cn( className={cn(
'fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-md duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 sm:rounded-lg', 'fixed left-[50%] top-[50%] z-[80] grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-md duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 sm:rounded-lg',
className, className,
)} )}
{...props} {...props}
......
'use client'; 'use client';
/**
* 🔴 层级约定(2026-08-03,踩坑后定):**浮层 z ≥ 70,模态 z ≥ 80**。
*
* 助手窗是 `fixed z-[60]`(pet fab 61、数据流粒子 62)。shadcn 默认给浮层 `z-50` ——
* 于是**任何在助手窗里打开的浮层都渲染在它底下**:
* · Select/Popover 类:点了有反应(DOM 里 listbox 确实打开),但一个选项都看不见;
* · Dialog/AlertDialog 类更糟:Radix 会给 body 设 `pointer-events:none`,
* 弹窗看不见、整页却已经被锁住 —— 用户看到的就是**卡死**。
* ⚠️ 这类错**不报任何错**,只能实测发现。⛔ 别把 z 调回 50。
*/
import * as React from 'react'; import * as React from 'react';
import * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu'; import * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu';
import { Check, ChevronRight, Circle } from 'lucide-react'; import { Check, ChevronRight, Circle } from 'lucide-react';
...@@ -44,7 +54,7 @@ const DropdownMenuSubContent = React.forwardRef< ...@@ -44,7 +54,7 @@ const DropdownMenuSubContent = React.forwardRef<
<DropdownMenuPrimitive.SubContent <DropdownMenuPrimitive.SubContent
ref={ref} ref={ref}
className={cn( className={cn(
'z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2', 'z-[70] min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
className, className,
)} )}
{...props} {...props}
...@@ -61,7 +71,7 @@ const DropdownMenuContent = React.forwardRef< ...@@ -61,7 +71,7 @@ const DropdownMenuContent = React.forwardRef<
ref={ref} ref={ref}
sideOffset={sideOffset} sideOffset={sideOffset}
className={cn( className={cn(
'z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2', 'z-[70] min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
className, className,
)} )}
{...props} {...props}
......
'use client'; 'use client';
/**
* 🔴 层级约定(2026-08-03,踩坑后定):**浮层 z ≥ 70,模态 z ≥ 80**。
*
* 助手窗是 `fixed z-[60]`(pet fab 61、数据流粒子 62)。shadcn 默认给浮层 `z-50` ——
* 于是**任何在助手窗里打开的浮层都渲染在它底下**:
* · Select/Popover 类:点了有反应(DOM 里 listbox 确实打开),但一个选项都看不见;
* · Dialog/AlertDialog 类更糟:Radix 会给 body 设 `pointer-events:none`,
* 弹窗看不见、整页却已经被锁住 —— 用户看到的就是**卡死**。
* ⚠️ 这类错**不报任何错**,只能实测发现。⛔ 别把 z 调回 50。
*/
import * as React from 'react'; import * as React from 'react';
import * as HoverCardPrimitive from '@radix-ui/react-hover-card'; import * as HoverCardPrimitive from '@radix-ui/react-hover-card';
...@@ -25,7 +35,7 @@ const HoverCardContent = React.forwardRef< ...@@ -25,7 +35,7 @@ const HoverCardContent = React.forwardRef<
sideOffset={sideOffset} sideOffset={sideOffset}
collisionPadding={8} collisionPadding={8}
className={cn( className={cn(
'z-50 w-64 rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-none', 'z-[70] w-64 rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-none',
'data-[state=open]:animate-in data-[state=closed]:animate-out', 'data-[state=open]:animate-in data-[state=closed]:animate-out',
'data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0', 'data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0',
'data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95', 'data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95',
......
'use client'; 'use client';
/**
* 🔴 层级约定(2026-08-03,踩坑后定):**浮层 z ≥ 70,模态 z ≥ 80**。
*
* 助手窗是 `fixed z-[60]`(pet fab 61、数据流粒子 62)。shadcn 默认给浮层 `z-50` ——
* 于是**任何在助手窗里打开的浮层都渲染在它底下**:
* · Select/Popover 类:点了有反应(DOM 里 listbox 确实打开),但一个选项都看不见;
* · Dialog/AlertDialog 类更糟:Radix 会给 body 设 `pointer-events:none`,
* 弹窗看不见、整页却已经被锁住 —— 用户看到的就是**卡死**。
* ⚠️ 这类错**不报任何错**,只能实测发现。⛔ 别把 z 调回 50。
*/
import * as React from 'react'; import * as React from 'react';
import * as PopoverPrimitive from '@radix-ui/react-popover'; import * as PopoverPrimitive from '@radix-ui/react-popover';
import { cn } from '@/lib/utils'; import { cn } from '@/lib/utils';
...@@ -21,7 +31,7 @@ const PopoverContent = React.forwardRef< ...@@ -21,7 +31,7 @@ const PopoverContent = React.forwardRef<
align={align} align={align}
sideOffset={sideOffset} sideOffset={sideOffset}
className={cn( className={cn(
'z-50 w-auto rounded-md border border-slate-100 bg-white p-2 shadow-md outline-none', 'z-[70] w-auto rounded-md border border-slate-100 bg-white p-2 shadow-md outline-none',
// ⚠️ 原先挂的是 shadcn 官方那串 `animate-in fade-in-0 …` —— 它们来自 // ⚠️ 原先挂的是 shadcn 官方那串 `animate-in fade-in-0 …` —— 它们来自
// tailwindcss-animate 插件,**本仓没装**,所以一帧动画都没有(class 写了不报错, // tailwindcss-animate 插件,**本仓没装**,所以一帧动画都没有(class 写了不报错,
// 只是不生效,最难发现的那种)。改用 globals.css 里的原生 keyframes。 // 只是不生效,最难发现的那种)。改用 globals.css 里的原生 keyframes。
......
'use client'; 'use client';
/**
* 🔴 层级约定(2026-08-03,踩坑后定):**浮层 z ≥ 70,模态 z ≥ 80**。
*
* 助手窗是 `fixed z-[60]`(pet fab 61、数据流粒子 62)。shadcn 默认给浮层 `z-50` ——
* 于是**任何在助手窗里打开的浮层都渲染在它底下**:
* · Select/Popover 类:点了有反应(DOM 里 listbox 确实打开),但一个选项都看不见;
* · Dialog/AlertDialog 类更糟:Radix 会给 body 设 `pointer-events:none`,
* 弹窗看不见、整页却已经被锁住 —— 用户看到的就是**卡死**。
* ⚠️ 这类错**不报任何错**,只能实测发现。⛔ 别把 z 调回 50。
*/
import * as React from 'react'; import * as React from 'react';
import * as SelectPrimitive from '@radix-ui/react-select'; import * as SelectPrimitive from '@radix-ui/react-select';
import { Check, ChevronDown } from 'lucide-react'; import { Check, ChevronDown } from 'lucide-react';
...@@ -41,7 +51,7 @@ const SelectContent = React.forwardRef< ...@@ -41,7 +51,7 @@ const SelectContent = React.forwardRef<
<SelectPrimitive.Content <SelectPrimitive.Content
ref={ref} ref={ref}
className={cn( className={cn(
'relative z-50 max-h-96 min-w-[8rem] overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95', 'relative z-[70] max-h-96 min-w-[8rem] overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95',
position === 'popper' && position === 'popper' &&
'data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1', 'data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1',
className, className,
......
...@@ -138,11 +138,17 @@ v1 **轻量**:不核销、不接宿主福利数据,福利就是**话术勾 ...@@ -138,11 +138,17 @@ v1 **轻量**:不核销、不接宿主福利数据,福利就是**话术勾
| 卡片上做 | 回对话做 | | 卡片上做 | 回对话做 |
|---|---| |---|---|
| 逐条改时效(1-7 天) | 换人群(换治疗项 / 温度 / 画像条件) | | 改批次时效(右上角「N 天后自动退回」) | 换人群(换治疗项 / 温度 / 画像条件) |
| 删掉某一条 | 改批次人数 N | | 逐条改时效(1-7 天) | 改批次人数 N |
| 把某一条**拖**给别的客服 | 按客服设本批名额 `maxThisBatch` | | 删掉某一条 | 按客服设本批名额 `maxThisBatch` |
| 把某一条**拖**给别的客服 | |
| 移除某个客服(连同他名下条目) | | | 移除某个客服(连同他名下条目) | |
⚠️ 批次时效放在**卡片右上角**,与左边"拟分 N 人"同一层级 —— 它是"这一整批"的设置。
放在底部微调区会让人以为它跟条目上的逐条时效是一回事。
⚠️ 文案是「N 天**后自动退回**」而不是光一个「时效」:主管要知道到期会发生什么(单子回池),
不然这个数对他没有意义。
⚠️ 这不违 T13「微调只有两项」—— 那条防的是"卡片变成第二个筛选器"。 ⚠️ 这不违 T13「微调只有两项」—— 那条防的是"卡片变成第二个筛选器"。
上面四件都是对**已经算好的结果**做局部修正,不产生新的人群、不重跑落人算法。 上面四件都是对**已经算好的结果**做局部修正,不产生新的人群、不重跑落人算法。
...@@ -153,10 +159,16 @@ v1 **轻量**:不核销、不接宿主福利数据,福利就是**话术勾 ...@@ -153,10 +159,16 @@ v1 **轻量**:不核销、不接宿主福利数据,福利就是**话术勾
必须有二次确认并把这句话写在弹窗里 —— 否则主管以为只是把人从名单上划掉, 必须有二次确认并把这句话写在弹窗里 —— 否则主管以为只是把人从名单上划掉,
回头发现少了 20 个患者。要把这些人交给别人:先拖走,或回对话让助手重出一版。 回头发现少了 20 个患者。要把这些人交给别人:先拖走,或回对话让助手重出一版。
> 🔴 **踩过的坑**:助手窗是 `fixed z-[60]`,而 shadcn 的 `SelectContent` 自带 `z-50`, > 🔴🔴 **踩过两次的坑:z 层级。** 助手窗是 `fixed z-[60]`(fab 61、数据流粒子 62),
> Radix 会把 content 的 z-index **复制到 body 上那层 popper wrapper** —— > 而 shadcn 给**所有**浮层的默认层级是 `z-50` —— 于是任何在助手窗里打开的浮层都在它底下:
> 下拉以 z-50 渲染在助手窗**底下**:点了有反应(listbox 确实打开了)、但一个选项都看不见, >
> **不报任何错**。凡是在助手窗里用 Radix 浮层,z 都要抬到 60 以上。 > | | 症状 |
> |---|---|
> | `Select` / `Popover` / `DropdownMenu` / `HoverCard` | 点了有反应(DOM 里 listbox 确实打开),**一个选项都看不见** |
> | `Dialog` / `AlertDialog` | 更糟:Radix 给 body 设 `pointer-events:none`,弹窗看不见、**整页却已被锁住** —— 用户看到的就是**卡死** |
>
> 两次都**不报任何错**,只能实测发现。已在 `components/ui/*` 统一定死:
> **浮层 z ≥ 70,模态 z ≥ 80**,六个文件顶部都写了这条约定。⛔ 别把 z 调回 50。
> **弯路一**:曾把「客服不能接别人的专属患者」做成**硬约束**(给不下就 unplaced)。 > **弯路一**:曾把「客服不能接别人的专属患者」做成**硬约束**(给不下就 unplaced)。
> 结果在上面那份数据下,「满」和「平」不可能同时成立 —— > 结果在上面那份数据下,「满」和「平」不可能同时成立 ——
......
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