@pactor-app/ui 1.42.0 → 1.43.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -148,6 +148,7 @@ __export(components_exports, {
148
148
  RadioGroup: () => RadioGroup2,
149
149
  RailTooltip: () => RailTooltip,
150
150
  Rate: () => Rate,
151
+ RecordingPage: () => RecordingPage,
151
152
  Resizable: () => Resizable,
152
153
  Result: () => Result,
153
154
  RichText: () => RichText,
@@ -540,7 +541,12 @@ var ICONS = {
540
541
  "zoom-in": import_lucide_react2.ZoomIn,
541
542
  "zoom-out": import_lucide_react2.ZoomOut,
542
543
  video: import_lucide_react2.Video,
543
- music: import_lucide_react2.Music
544
+ music: import_lucide_react2.Music,
545
+ // 录音 / 音频场景(spec: chat-page 录音模板):波形、麦克风、播放控制
546
+ "audio-lines": import_lucide_react2.AudioLines,
547
+ mic: import_lucide_react2.Mic,
548
+ play: import_lucide_react2.Play,
549
+ "rotate-cw": import_lucide_react2.RotateCw
544
550
  };
545
551
  function normalizeIconName(name) {
546
552
  return name.replace(/([a-z0-9])([A-Z])/g, "$1-$2").replace(/[_\s]+/g, "-").toLowerCase();
@@ -718,7 +724,7 @@ function AlertDialogOverlay({
718
724
  {
719
725
  "data-slot": "alert-dialog-overlay",
720
726
  className: cn(
721
- "fixed inset-0 z-50 bg-(--overlay-background) data-open:animate-in data-open:fade-in-0 data-closed:animate-out data-closed:fill-mode-forwards data-closed:fade-out-0",
727
+ "fixed inset-0 z-50 bg-(--overlay-background) duration-200 data-open:animate-in data-open:fade-in-0 data-closed:animate-out data-closed:fill-mode-forwards data-closed:fade-out-0",
722
728
  className
723
729
  ),
724
730
  ...props
@@ -4152,7 +4158,7 @@ function DialogOverlay({
4152
4158
  {
4153
4159
  "data-slot": "dialog-overlay",
4154
4160
  className: cn(
4155
- "fixed inset-0 z-50 bg-(--overlay-background) data-open:animate-in data-open:fade-in-0 data-closed:animate-out data-closed:fade-out-0 data-closed:fill-mode-forwards",
4161
+ "fixed inset-0 z-50 bg-(--overlay-background) duration-200 data-open:animate-in data-open:fade-in-0 data-closed:animate-out data-closed:fade-out-0 data-closed:fill-mode-forwards",
4156
4162
  className
4157
4163
  ),
4158
4164
  ...props
@@ -7053,7 +7059,7 @@ function SheetOverlay({
7053
7059
  {
7054
7060
  "data-slot": "sheet-overlay",
7055
7061
  className: cn(
7056
- "fixed inset-0 z-50 bg-(--overlay-background) data-open:animate-in data-open:fade-in-0 data-closed:animate-out data-closed:fill-mode-forwards data-closed:fade-out-0",
7062
+ "fixed inset-0 z-50 bg-(--overlay-background) duration-200 data-open:animate-in data-open:fade-in-0 data-closed:animate-out data-closed:fill-mode-forwards data-closed:fade-out-0",
7057
7063
  className
7058
7064
  ),
7059
7065
  ...props
@@ -14920,6 +14926,7 @@ function ChatPage({
14920
14926
  artifactOpen,
14921
14927
  defaultArtifactOpen = false,
14922
14928
  onArtifactOpenChange,
14929
+ content,
14923
14930
  className,
14924
14931
  style
14925
14932
  }) {
@@ -15173,7 +15180,7 @@ function ChatPage({
15173
15180
  "div",
15174
15181
  {
15175
15182
  "data-slot": "chat-page-menu",
15176
- className: "flex h-full w-[264px] shrink-0 flex-col gap-2 overflow-hidden border-r border-border px-2 py-3",
15183
+ className: "flex h-full w-[250px] shrink-0 flex-col gap-2 overflow-hidden border-r border-border px-2 py-3",
15177
15184
  children: [
15178
15185
  brand ? /* @__PURE__ */ (0, import_jsx_runtime191.jsxs)("div", { className: "flex shrink-0 items-center justify-between px-2", children: [
15179
15186
  /* @__PURE__ */ (0, import_jsx_runtime191.jsxs)("div", { className: "flex flex-col gap-0.5", children: [
@@ -15256,7 +15263,7 @@ function ChatPage({
15256
15263
  ]
15257
15264
  }
15258
15265
  ),
15259
- /* @__PURE__ */ (0, import_jsx_runtime191.jsx)("div", { className: "@container h-full min-w-0 flex-1", children: open || activePanelItem ? /* @__PURE__ */ (0, import_jsx_runtime191.jsxs)(PanelGroup, { orientation: "horizontal", style: { width: "100%", height: "100%" }, children: [
15266
+ /* @__PURE__ */ (0, import_jsx_runtime191.jsx)("div", { className: "@container h-full min-w-0 flex-1", children: content !== void 0 ? renderSlot(content) : open || activePanelItem ? /* @__PURE__ */ (0, import_jsx_runtime191.jsxs)(PanelGroup, { orientation: "horizontal", style: { width: "100%", height: "100%" }, children: [
15260
15267
  /* @__PURE__ */ (0, import_jsx_runtime191.jsx)(Panel, { defaultSize: "62%", children: chatArea }),
15261
15268
  /* @__PURE__ */ (0, import_jsx_runtime191.jsx)(ResizableHandle, { withHandle: true }),
15262
15269
  /* @__PURE__ */ (0, import_jsx_runtime191.jsx)(Panel, { defaultSize: "38%", minSize: "380px", maxSize: "760px", children: activePanelItem ? /* @__PURE__ */ (0, import_jsx_runtime191.jsx)(
@@ -18432,196 +18439,1856 @@ function Login({
18432
18439
  );
18433
18440
  }
18434
18441
 
18435
- // src/components/business/RuleConfig/index.tsx
18436
- var import_lucide_react43 = require("lucide-react");
18442
+ // src/components/business/RecordingPage/index.tsx
18443
+ var import_react81 = require("react");
18444
+
18445
+ // src/components/business/RecordingPage/detail.tsx
18446
+ var import_runtime54 = require("@pactor-app/runtime");
18447
+ var import_react79 = require("react");
18448
+
18449
+ // src/components/business/RecordingPage/insight.tsx
18437
18450
  var import_react76 = require("react");
18451
+
18452
+ // src/components/business/RecordingPage/perspective-dialog.tsx
18438
18453
  var import_jsx_runtime219 = require("react/jsx-runtime");
18439
- var isBlank = (v) => v == null || String(v).trim() === "";
18440
- function isValueMissing(condition) {
18441
- const { opt, value } = condition;
18442
- if (NO_VALUE_OPT.includes(opt)) return false;
18443
- if (opt === "BETWEEN") {
18444
- const [a, b] = normalizeBetweenValue(value);
18445
- return isBlank(a) || isBlank(b);
18446
- }
18447
- if (Array.isArray(value)) return value.length === 0 || value.every(isBlank);
18448
- return isBlank(value);
18449
- }
18450
- function getConditionIssue(condition) {
18451
- const missingValue = isValueMissing(condition);
18452
- const missingScore = condition.score == null || Number.isNaN(condition.score);
18453
- if (!missingValue && !missingScore) return null;
18454
- return { missingValue, missingScore };
18454
+ function RecordingPerspectiveDialog({
18455
+ open,
18456
+ title,
18457
+ hint,
18458
+ value,
18459
+ placeholder,
18460
+ cancelLabel,
18461
+ confirmLabel,
18462
+ onChange,
18463
+ onCancel,
18464
+ onConfirm
18465
+ }) {
18466
+ return /* @__PURE__ */ (0, import_jsx_runtime219.jsx)(
18467
+ Dialog,
18468
+ {
18469
+ open,
18470
+ onOpenChange: (next) => {
18471
+ if (!next) onCancel();
18472
+ },
18473
+ children: /* @__PURE__ */ (0, import_jsx_runtime219.jsxs)(
18474
+ DialogContent,
18475
+ {
18476
+ "data-slot": "recording-perspective-dialog",
18477
+ className: "gap-4 sm:max-w-xl",
18478
+ children: [
18479
+ /* @__PURE__ */ (0, import_jsx_runtime219.jsx)(DialogTitle, { children: title }),
18480
+ hint !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime219.jsx)(DialogDescription, { children: hint }) : null,
18481
+ /* @__PURE__ */ (0, import_jsx_runtime219.jsx)(
18482
+ Textarea2,
18483
+ {
18484
+ value,
18485
+ placeholder,
18486
+ rows: 4,
18487
+ onChange
18488
+ }
18489
+ ),
18490
+ /* @__PURE__ */ (0, import_jsx_runtime219.jsxs)("div", { className: "flex items-center justify-end gap-2", children: [
18491
+ /* @__PURE__ */ (0, import_jsx_runtime219.jsx)(Button2, { text: cancelLabel, onClick: onCancel }),
18492
+ /* @__PURE__ */ (0, import_jsx_runtime219.jsx)(Button2, { text: confirmLabel, variant: "primary", onClick: onConfirm })
18493
+ ] })
18494
+ ]
18495
+ }
18496
+ )
18497
+ }
18498
+ );
18455
18499
  }
18456
- var OPERATOR_VALUES = [
18457
- "GREATER",
18458
- "GREATER_EQUAL",
18459
- "LESS_EQUAL",
18460
- "LESS",
18461
- "EQUAL",
18462
- "IN",
18463
- "NOT_IN",
18464
- "UNEQUAL",
18465
- "LIKE",
18466
- "NULL",
18467
- "HASVAL",
18468
- "NOTNULL",
18469
- "BETWEEN"
18470
- ];
18471
- var NUMERIC_OPT = [
18472
- "GREATER",
18473
- "LESS",
18474
- "LESS_EQUAL",
18475
- "GREATER_EQUAL",
18476
- "UNEQUAL"
18477
- ];
18478
- var NO_VALUE_OPT = ["NULL", "HASVAL", "NOTNULL"];
18479
- var MULTI_VALUE_OPT = ["IN", "NOT_IN"];
18480
- var OPERATOR_LABELS2 = {
18481
- GREATER: "\u5927\u4E8E",
18482
- GREATER_EQUAL: "\u5927\u4E8E\u7B49\u4E8E",
18483
- LESS_EQUAL: "\u5C0F\u4E8E\u7B49\u4E8E",
18484
- LESS: "\u5C0F\u4E8E",
18485
- EQUAL: "\u7B49\u4E8E",
18486
- IN: "\u5305\u542B",
18487
- NOT_IN: "\u4E0D\u5305\u542B",
18488
- UNEQUAL: "\u4E0D\u7B49\u4E8E",
18489
- LIKE: "\u7C7B\u4F3C",
18490
- NULL: "\u4E3A\u7A7A",
18491
- HASVAL: "\u6709\u503C",
18492
- NOTNULL: "\u4E0D\u4E3A\u7A7A",
18493
- BETWEEN: "\u8303\u56F4"
18494
- };
18495
- function operatorLabel2(operator) {
18496
- return OPERATOR_LABELS2[operator] ?? operator;
18500
+
18501
+ // src/components/business/RecordingPage/insight.tsx
18502
+ var import_jsx_runtime220 = require("react/jsx-runtime");
18503
+ function RecordingInsightView({
18504
+ insight,
18505
+ onPerspectiveEdit,
18506
+ onPerspectiveApply,
18507
+ onInsightAction
18508
+ }) {
18509
+ const [dialogOpen, setDialogOpen] = (0, import_react76.useState)(false);
18510
+ const inputControlled = insight.perspectiveInput !== void 0;
18511
+ const [innerInput, setInnerInput] = (0, import_react76.useState)(insight.defaultPerspectiveInput);
18512
+ const committedInput = inputControlled ? insight.perspectiveInput : innerInput;
18513
+ const [draftInput, setDraftInput] = (0, import_react76.useState)(committedInput);
18514
+ const openDialog = () => {
18515
+ setDraftInput(committedInput);
18516
+ setDialogOpen(true);
18517
+ };
18518
+ const confirmDialog = () => {
18519
+ if (!inputControlled) setInnerInput(draftInput);
18520
+ onPerspectiveApply?.(draftInput ?? "");
18521
+ setDialogOpen(false);
18522
+ };
18523
+ return /* @__PURE__ */ (0, import_jsx_runtime220.jsxs)("div", { "data-slot": "recording-insight", className: "flex flex-col gap-6", children: [
18524
+ insight.perspectiveTitle !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime220.jsxs)(
18525
+ "section",
18526
+ {
18527
+ "data-slot": "recording-insight-perspective",
18528
+ className: "flex flex-col gap-2 rounded-lg bg-success/10 p-4",
18529
+ children: [
18530
+ /* @__PURE__ */ (0, import_jsx_runtime220.jsxs)("div", { className: "flex items-center justify-between", children: [
18531
+ /* @__PURE__ */ (0, import_jsx_runtime220.jsxs)("div", { className: "flex min-w-0 items-center gap-2", children: [
18532
+ /* @__PURE__ */ (0, import_jsx_runtime220.jsx)(Icon, { name: "user", size: 16, className: "shrink-0 text-muted-foreground" }),
18533
+ /* @__PURE__ */ (0, import_jsx_runtime220.jsx)(Text, { text: insight.perspectiveTitle, strong: true, className: "truncate" })
18534
+ ] }),
18535
+ insight.perspectiveActionLabel !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime220.jsx)(
18536
+ Button2,
18537
+ {
18538
+ text: insight.perspectiveActionLabel,
18539
+ variant: "link",
18540
+ size: "small",
18541
+ className: "text-success",
18542
+ onClick: () => {
18543
+ onPerspectiveEdit?.();
18544
+ openDialog();
18545
+ }
18546
+ }
18547
+ ) : null
18548
+ ] }),
18549
+ insight.perspectiveHint !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime220.jsx)(Text, { text: insight.perspectiveHint, size: "small", type: "secondary" }) : null
18550
+ ]
18551
+ }
18552
+ ) : null,
18553
+ insight.basics !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime220.jsxs)("section", { className: "flex flex-col gap-3", children: [
18554
+ /* @__PURE__ */ (0, import_jsx_runtime220.jsx)(Text, { text: insight.basicsTitle ?? "\u57FA\u7840\u4FE1\u606F", strong: true, size: "large" }),
18555
+ /* @__PURE__ */ (0, import_jsx_runtime220.jsx)(Text, { text: insight.basics })
18556
+ ] }) : null,
18557
+ insight.chapters !== void 0 && insight.chapters.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime220.jsxs)("section", { className: "flex flex-col gap-3", children: [
18558
+ /* @__PURE__ */ (0, import_jsx_runtime220.jsx)(Text, { text: insight.chaptersTitle ?? "\u7AE0\u8282\u901F\u89C8\u4E0E\u89E3\u8BFB", strong: true, size: "large" }),
18559
+ insight.chapters.map((chapter, index) => /* @__PURE__ */ (0, import_jsx_runtime220.jsxs)(
18560
+ "div",
18561
+ {
18562
+ "data-slot": "recording-insight-chapter",
18563
+ className: "flex flex-col gap-2 rounded-lg border border-border p-4",
18564
+ children: [
18565
+ /* @__PURE__ */ (0, import_jsx_runtime220.jsxs)("div", { className: "flex items-baseline gap-2", children: [
18566
+ chapter.time !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime220.jsx)(Text, { text: chapter.time, size: "small", type: "secondary" }) : null,
18567
+ /* @__PURE__ */ (0, import_jsx_runtime220.jsx)(Text, { text: chapter.title, strong: true, size: "small" })
18568
+ ] }),
18569
+ /* @__PURE__ */ (0, import_jsx_runtime220.jsx)(Text, { text: chapter.content, size: "small" })
18570
+ ]
18571
+ },
18572
+ chapter.time ?? index
18573
+ ))
18574
+ ] }) : null,
18575
+ insight.viewpoints !== void 0 && insight.viewpoints.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime220.jsxs)("section", { className: "flex flex-col gap-3", children: [
18576
+ /* @__PURE__ */ (0, import_jsx_runtime220.jsx)(Text, { text: insight.viewpointsTitle ?? "\u89C2\u70B9\u5206\u6790", strong: true, size: "large" }),
18577
+ insight.viewpoints.map((viewpoint, index) => /* @__PURE__ */ (0, import_jsx_runtime220.jsxs)(
18578
+ "div",
18579
+ {
18580
+ "data-slot": "recording-insight-viewpoint",
18581
+ className: "flex flex-col gap-2 rounded-lg border border-border p-4",
18582
+ children: [
18583
+ /* @__PURE__ */ (0, import_jsx_runtime220.jsxs)("div", { className: "flex items-center justify-between", children: [
18584
+ /* @__PURE__ */ (0, import_jsx_runtime220.jsxs)("div", { className: "flex items-center gap-2", children: [
18585
+ /* @__PURE__ */ (0, import_jsx_runtime220.jsx)(Avatar2, { fallback: viewpoint.avatarText ?? viewpoint.speaker.charAt(0) }),
18586
+ /* @__PURE__ */ (0, import_jsx_runtime220.jsx)(Text, { text: viewpoint.speaker, strong: true, size: "small" })
18587
+ ] }),
18588
+ viewpoint.tag !== "" ? /* @__PURE__ */ (0, import_jsx_runtime220.jsx)(Text, { text: viewpoint.tag ?? "\u81EA\u52A8\u8BC6\u522B", size: "small", type: "secondary" }) : null
18589
+ ] }),
18590
+ /* @__PURE__ */ (0, import_jsx_runtime220.jsxs)("p", { className: "text-sm", children: [
18591
+ viewpoint.label !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime220.jsxs)("strong", { children: [
18592
+ viewpoint.label,
18593
+ "\uFF1A"
18594
+ ] }) : null,
18595
+ viewpoint.content
18596
+ ] })
18597
+ ]
18598
+ },
18599
+ viewpoint.speaker ?? index
18600
+ ))
18601
+ ] }) : null,
18602
+ insight.actions !== void 0 && insight.actions.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime220.jsx)("div", { "data-slot": "recording-insight-actions", className: "flex items-center gap-1", children: insight.actions.map((action) => /* @__PURE__ */ (0, import_jsx_runtime220.jsx)(
18603
+ Button2,
18604
+ {
18605
+ icon: action.icon,
18606
+ variant: "text",
18607
+ size: "small",
18608
+ onClick: () => onInsightAction?.(action.key)
18609
+ },
18610
+ action.key
18611
+ )) }) : null,
18612
+ /* @__PURE__ */ (0, import_jsx_runtime220.jsx)(
18613
+ RecordingPerspectiveDialog,
18614
+ {
18615
+ open: dialogOpen,
18616
+ title: insight.perspectiveDialogTitle ?? "\u4FEE\u6539\u89E3\u8BFB\u8EAB\u4EFD",
18617
+ hint: insight.perspectiveDialogHint ?? "\u7528\u81EA\u7136\u8BED\u8A00\u8BF4\u660E\u4F60\u5728\u672C\u6B21\u4F1A\u8BAE\u4E2D\u7684\u8EAB\u4EFD\u4E0E\u5173\u6CE8\u70B9\u3002",
18618
+ value: draftInput,
18619
+ placeholder: insight.perspectivePlaceholder,
18620
+ cancelLabel: insight.perspectiveCancelLabel ?? "\u53D6\u6D88",
18621
+ confirmLabel: insight.perspectiveConfirmLabel ?? "\u5E94\u7528\u8EAB\u4EFD",
18622
+ onChange: setDraftInput,
18623
+ onCancel: () => setDialogOpen(false),
18624
+ onConfirm: confirmDialog
18625
+ }
18626
+ )
18627
+ ] });
18497
18628
  }
18498
- var _key = 0;
18499
- var nextKey = () => ++_key;
18500
- var defaultCondition = () => ({ key: nextKey(), opt: "EQUAL" });
18501
- function normalizeBetweenValue(value) {
18502
- if (Array.isArray(value)) return [value[0], value[1]];
18503
- if (typeof value === "string" && value.includes(",")) {
18504
- const [a, b] = value.split(",");
18505
- return [a?.trim(), b?.trim()];
18506
- }
18507
- if (value == null || value === "") return [void 0, void 0];
18508
- return [value, void 0];
18629
+
18630
+ // src/components/business/RecordingPage/memory.tsx
18631
+ var import_jsx_runtime221 = require("react/jsx-runtime");
18632
+ function RecordingMemoryView({ memory, onMemoryAction }) {
18633
+ return /* @__PURE__ */ (0, import_jsx_runtime221.jsxs)("div", { "data-slot": "recording-memory", className: "flex flex-col gap-6", children: [
18634
+ (memory.groups ?? []).map((group, groupIndex) => /* @__PURE__ */ (0, import_jsx_runtime221.jsxs)("section", { className: "flex flex-col gap-3", children: [
18635
+ /* @__PURE__ */ (0, import_jsx_runtime221.jsx)(Text, { text: `${group.label} \xB7 ${group.items.length}`, strong: true, size: "large" }),
18636
+ group.items.map((item, index) => /* @__PURE__ */ (0, import_jsx_runtime221.jsxs)(
18637
+ "div",
18638
+ {
18639
+ "data-slot": "recording-memory-item",
18640
+ className: "flex flex-col gap-2 rounded-lg border border-border p-4",
18641
+ children: [
18642
+ /* @__PURE__ */ (0, import_jsx_runtime221.jsx)(Text, { text: item.title, strong: true, size: "small" }),
18643
+ /* @__PURE__ */ (0, import_jsx_runtime221.jsx)(Text, { text: item.content, size: "small" })
18644
+ ]
18645
+ },
18646
+ index
18647
+ ))
18648
+ ] }, group.key ?? group.label ?? groupIndex)),
18649
+ memory.actions !== void 0 && memory.actions.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime221.jsx)("div", { "data-slot": "recording-memory-actions", className: "flex items-center gap-1", children: memory.actions.map((action) => /* @__PURE__ */ (0, import_jsx_runtime221.jsx)(
18650
+ Button2,
18651
+ {
18652
+ icon: action.icon,
18653
+ variant: "text",
18654
+ size: "small",
18655
+ onClick: () => onMemoryAction?.(action.key)
18656
+ },
18657
+ action.key
18658
+ )) }) : null
18659
+ ] });
18509
18660
  }
18510
- function formatConditionValue2(condition) {
18511
- const { opt, value } = condition;
18512
- if (value == null) return "-";
18513
- if (opt === "BETWEEN") {
18514
- const [a, b] = normalizeBetweenValue(value);
18515
- return `${a ?? "-"} ~ ${b ?? "-"}`;
18661
+
18662
+ // src/components/business/RecordingPage/share.tsx
18663
+ var import_react77 = require("react");
18664
+ var import_jsx_runtime222 = require("react/jsx-runtime");
18665
+ function copyText(text) {
18666
+ try {
18667
+ if (typeof navigator !== "undefined" && navigator.clipboard?.writeText) {
18668
+ void navigator.clipboard.writeText(text);
18669
+ return;
18670
+ }
18671
+ const textarea = document.createElement("textarea");
18672
+ textarea.value = text;
18673
+ document.body.appendChild(textarea);
18674
+ textarea.select();
18675
+ document.execCommand?.("copy");
18676
+ textarea.remove();
18677
+ } catch {
18516
18678
  }
18517
- if (Array.isArray(value)) return value.join(", ");
18518
- return String(value);
18519
18679
  }
18520
- function RuleConfig({ value, onChange, disabled, size = "middle" }) {
18521
- const rawConditions = value?.ruleConditions;
18522
- const conditions = (0, import_react76.useMemo)(() => {
18523
- if (!rawConditions?.length) return [defaultCondition()];
18524
- const seen = /* @__PURE__ */ new Set();
18525
- return rawConditions.map((c) => {
18526
- if (c.key != null && !seen.has(c.key)) {
18527
- seen.add(c.key);
18528
- return c;
18529
- }
18530
- const key = nextKey();
18531
- seen.add(key);
18532
- return { ...c, key };
18533
- });
18534
- }, [rawConditions]);
18535
- const initScore = value?.score ?? 1;
18536
- const [scoreText, setScoreText] = (0, import_react76.useState)(String(initScore));
18537
- const lastScoreRef = (0, import_react76.useRef)(value?.score);
18538
- (0, import_react76.useEffect)(() => {
18539
- if (value?.score === lastScoreRef.current) return;
18540
- lastScoreRef.current = value?.score;
18541
- setScoreText(value?.score == null ? "" : String(value.score));
18542
- }, [value?.score]);
18543
- const commitScore = (0, import_react76.useCallback)(
18544
- (score) => {
18545
- lastScoreRef.current = score;
18546
- onChange?.({ score, ruleConditions: conditions });
18547
- },
18548
- [onChange, conditions]
18549
- );
18550
- const normalizeScore = (n) => Math.min(1e3, Math.max(1, Math.round(n)));
18551
- const handleScoreTextChange = (text) => {
18552
- setScoreText(text);
18553
- if (text === "") return;
18554
- const n = Number(text);
18555
- if (Number.isFinite(n) && n >= 1 && n <= 1e3 && Number.isInteger(n)) {
18556
- commitScore(n);
18680
+ function RecordingShare({
18681
+ shareLabel,
18682
+ options,
18683
+ selectedKeys,
18684
+ popoverTitle,
18685
+ cancelLabel,
18686
+ confirmLabel,
18687
+ dialogTitle,
18688
+ link,
18689
+ copyLinkLabel,
18690
+ copiedLabel,
18691
+ mailLabel,
18692
+ systemLabel,
18693
+ onShare,
18694
+ onSelectionCommit,
18695
+ onShareConfirm,
18696
+ onShareChannel
18697
+ }) {
18698
+ const [popoverOpen, setPopoverOpen] = (0, import_react77.useState)(false);
18699
+ const [dialogOpen, setDialogOpen] = (0, import_react77.useState)(false);
18700
+ const [draftKeys, setDraftKeys] = (0, import_react77.useState)(selectedKeys);
18701
+ const [copied, setCopied] = (0, import_react77.useState)(false);
18702
+ const copyLink = () => {
18703
+ if (link !== void 0) {
18704
+ copyText(link);
18705
+ setCopied(true);
18706
+ setTimeout(() => setCopied(false), 1500);
18557
18707
  }
18708
+ onShareChannel?.("copyLink");
18558
18709
  };
18559
- const handleScoreBlur = () => {
18560
- const n = scoreText.trim() === "" ? NaN : Number(scoreText);
18561
- const next = Number.isFinite(n) ? normalizeScore(n) : 1;
18562
- setScoreText(String(next));
18563
- if (next !== lastScoreRef.current) commitScore(next);
18710
+ const openPopover = (next) => {
18711
+ if (next) {
18712
+ setDraftKeys(selectedKeys);
18713
+ onShare?.();
18714
+ }
18715
+ setPopoverOpen(next);
18564
18716
  };
18565
- const update = (0, import_react76.useCallback)(
18566
- (next, nextScore) => onChange?.({
18567
- score: nextScore ?? initScore,
18568
- ruleConditions: next
18569
- }),
18570
- [onChange, initScore]
18571
- );
18572
- const handleOptChange = (key, opt) => {
18573
- update(
18574
- conditions.map(
18575
- (c) => c.key === key ? { ...c, opt, value: opt === "BETWEEN" ? [] : void 0 } : c
18576
- )
18717
+ const toggleOption = (option) => {
18718
+ if (option.disabled === true) return;
18719
+ setDraftKeys(
18720
+ (prev) => prev.includes(option.key) ? prev.filter((key) => key !== option.key) : [...prev, option.key]
18577
18721
  );
18578
18722
  };
18579
- const handleValueChange = (key, val) => {
18580
- update(conditions.map((c) => c.key === key ? { ...c, value: val } : c));
18581
- };
18582
- const handleScoreChange = (key, score) => {
18583
- update(
18584
- conditions.map((c) => c.key === key ? { ...c, score } : c)
18585
- );
18723
+ const confirm = () => {
18724
+ const next = options.filter((option) => draftKeys.includes(option.key)).map((option) => option.key);
18725
+ onSelectionCommit(next);
18726
+ onShareConfirm?.(next);
18727
+ setPopoverOpen(false);
18728
+ setDialogOpen(true);
18586
18729
  };
18587
- const handleAdd = () => update([...conditions, defaultCondition()]);
18588
- const handleDelete = (key) => update(conditions.filter((c) => c.key !== key));
18589
- if (disabled) {
18590
- return /* @__PURE__ */ (0, import_jsx_runtime219.jsxs)("div", { className: "space-y-2 text-sm", children: [
18591
- /* @__PURE__ */ (0, import_jsx_runtime219.jsxs)("div", { className: "flex items-center gap-2 pb-2 border-b", children: [
18592
- /* @__PURE__ */ (0, import_jsx_runtime219.jsx)("span", { className: "text-muted-foreground", children: "\u6743\u91CD" }),
18593
- /* @__PURE__ */ (0, import_jsx_runtime219.jsx)("span", { className: "font-medium", children: initScore })
18594
- ] }),
18595
- conditions.map((condition) => /* @__PURE__ */ (0, import_jsx_runtime219.jsxs)("div", { className: "flex items-center gap-2", children: [
18596
- /* @__PURE__ */ (0, import_jsx_runtime219.jsx)("span", { children: operatorLabel2(condition.opt) }),
18597
- !NO_VALUE_OPT.includes(condition.opt) && /* @__PURE__ */ (0, import_jsx_runtime219.jsx)("span", { className: "font-medium", children: formatConditionValue2(condition) }),
18598
- /* @__PURE__ */ (0, import_jsx_runtime219.jsxs)("span", { className: "text-muted-foreground", children: [
18599
- "\u8BC4\u5206: ",
18600
- condition.score ?? "-"
18601
- ] })
18602
- ] }, condition.key))
18603
- ] });
18604
- }
18605
- return /* @__PURE__ */ (0, import_jsx_runtime219.jsxs)("div", { className: "space-y-2", children: [
18606
- /* @__PURE__ */ (0, import_jsx_runtime219.jsxs)("div", { className: "flex items-center gap-1 pb-2 border-b gap-2", children: [
18607
- /* @__PURE__ */ (0, import_jsx_runtime219.jsx)("span", { className: "text-sm shrink-0", children: "\u6743\u91CD" }),
18608
- /* @__PURE__ */ (0, import_jsx_runtime219.jsx)(
18609
- Input,
18730
+ const trigger = /* @__PURE__ */ (0, import_jsx_runtime222.jsx)(Button2, { text: shareLabel, size: "small" });
18731
+ return /* @__PURE__ */ (0, import_jsx_runtime222.jsxs)(import_jsx_runtime222.Fragment, { children: [
18732
+ /* @__PURE__ */ (0, import_jsx_runtime222.jsxs)(Popover, { open: popoverOpen, onOpenChange: openPopover, children: [
18733
+ /* @__PURE__ */ (0, import_jsx_runtime222.jsx)(
18734
+ PopoverTrigger,
18610
18735
  {
18611
- type: "number",
18612
- className: cn("w-48", CONTROL_SIZE_BOX[size]),
18613
- min: 1,
18614
- max: 1e3,
18615
- step: 1,
18616
- value: scoreText,
18617
- disabled,
18618
- placeholder: "\u8BF7\u8F93\u5165\u6743\u91CD",
18619
- onChange: (e) => handleScoreTextChange(e.target.value),
18620
- onBlur: handleScoreBlur
18736
+ nativeButton: false,
18737
+ render: /* @__PURE__ */ (0, import_jsx_runtime222.jsx)("span", { "data-slot": "recording-share-trigger", className: "inline-flex" }),
18738
+ children: trigger
18621
18739
  }
18622
- )
18740
+ ),
18741
+ /* @__PURE__ */ (0, import_jsx_runtime222.jsxs)(
18742
+ PopoverContent,
18743
+ {
18744
+ align: "end",
18745
+ sideOffset: 8,
18746
+ className: "w-64 p-0",
18747
+ "data-slot": "recording-share-popover",
18748
+ children: [
18749
+ /* @__PURE__ */ (0, import_jsx_runtime222.jsx)("div", { className: "px-4 pt-4 pb-2 text-sm font-semibold", children: popoverTitle }),
18750
+ /* @__PURE__ */ (0, import_jsx_runtime222.jsx)("div", { className: "flex flex-col px-2 pb-2", children: options.map((option) => {
18751
+ const checked = draftKeys.includes(option.key);
18752
+ const disabled = option.disabled === true;
18753
+ return /* @__PURE__ */ (0, import_jsx_runtime222.jsxs)(
18754
+ "button",
18755
+ {
18756
+ type: "button",
18757
+ "data-slot": "recording-share-option",
18758
+ "aria-pressed": checked,
18759
+ disabled,
18760
+ className: cn(
18761
+ "flex w-full items-center gap-2.5 rounded-md px-2 py-2 text-left text-sm",
18762
+ disabled ? "cursor-not-allowed opacity-50" : "cursor-pointer hover:bg-muted"
18763
+ ),
18764
+ onClick: () => toggleOption(option),
18765
+ children: [
18766
+ /* @__PURE__ */ (0, import_jsx_runtime222.jsx)(
18767
+ "span",
18768
+ {
18769
+ className: cn(
18770
+ "flex h-5 w-5 shrink-0 items-center justify-center rounded-full",
18771
+ checked ? "bg-primary text-primary-foreground" : "border border-input"
18772
+ ),
18773
+ children: checked ? /* @__PURE__ */ (0, import_jsx_runtime222.jsx)(Icon, { name: "check", size: 12 }) : null
18774
+ }
18775
+ ),
18776
+ option.label
18777
+ ]
18778
+ },
18779
+ option.key
18780
+ );
18781
+ }) }),
18782
+ /* @__PURE__ */ (0, import_jsx_runtime222.jsxs)("div", { className: "flex items-center justify-end gap-2 border-t border-border px-4 py-3", children: [
18783
+ /* @__PURE__ */ (0, import_jsx_runtime222.jsx)(Button2, { text: cancelLabel, variant: "text", onClick: () => setPopoverOpen(false) }),
18784
+ /* @__PURE__ */ (0, import_jsx_runtime222.jsx)(Button2, { text: confirmLabel, variant: "primary", onClick: confirm })
18785
+ ] })
18786
+ ]
18787
+ }
18788
+ )
18789
+ ] }),
18790
+ /* @__PURE__ */ (0, import_jsx_runtime222.jsx)(Dialog, { open: dialogOpen, onOpenChange: setDialogOpen, children: /* @__PURE__ */ (0, import_jsx_runtime222.jsxs)(DialogContent, { "data-slot": "recording-share-dialog", className: "gap-4 sm:max-w-xl", children: [
18791
+ /* @__PURE__ */ (0, import_jsx_runtime222.jsx)(DialogTitle, { children: dialogTitle }),
18792
+ link !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime222.jsxs)("div", { className: "flex items-center justify-between gap-3 rounded-lg border border-border px-4 py-3", children: [
18793
+ /* @__PURE__ */ (0, import_jsx_runtime222.jsx)("span", { className: "min-w-0 flex-1 truncate text-sm", children: link }),
18794
+ /* @__PURE__ */ (0, import_jsx_runtime222.jsx)(
18795
+ Button2,
18796
+ {
18797
+ text: copied ? copiedLabel : copyLinkLabel,
18798
+ variant: "link",
18799
+ size: "small",
18800
+ onClick: copyLink
18801
+ }
18802
+ )
18803
+ ] }) : null,
18804
+ /* @__PURE__ */ (0, import_jsx_runtime222.jsxs)("div", { className: "grid grid-cols-2 gap-3", children: [
18805
+ /* @__PURE__ */ (0, import_jsx_runtime222.jsx)(
18806
+ Button2,
18807
+ {
18808
+ text: mailLabel,
18809
+ icon: "mail",
18810
+ className: "h-12",
18811
+ onClick: () => onShareChannel?.("mail")
18812
+ }
18813
+ ),
18814
+ /* @__PURE__ */ (0, import_jsx_runtime222.jsx)(
18815
+ Button2,
18816
+ {
18817
+ text: systemLabel,
18818
+ icon: "share",
18819
+ className: "h-12",
18820
+ onClick: () => onShareChannel?.("system")
18821
+ }
18822
+ )
18823
+ ] })
18824
+ ] }) })
18825
+ ] });
18826
+ }
18827
+
18828
+ // src/components/business/RecordingPage/speaker-dialog.tsx
18829
+ var import_jsx_runtime223 = require("react/jsx-runtime");
18830
+ function RecordingSpeakerDialog({
18831
+ open,
18832
+ title,
18833
+ hint,
18834
+ speakers,
18835
+ selectedIndex,
18836
+ customName,
18837
+ inputPlaceholder,
18838
+ applyLabel,
18839
+ onSelect,
18840
+ onInputName,
18841
+ onCancel,
18842
+ onConfirm
18843
+ }) {
18844
+ const canApply = customName.trim() !== "" || selectedIndex >= 0;
18845
+ return /* @__PURE__ */ (0, import_jsx_runtime223.jsx)(
18846
+ Dialog,
18847
+ {
18848
+ open,
18849
+ onOpenChange: (next) => {
18850
+ if (!next) onCancel();
18851
+ },
18852
+ children: /* @__PURE__ */ (0, import_jsx_runtime223.jsxs)(
18853
+ DialogContent,
18854
+ {
18855
+ "data-slot": "recording-speaker-dialog",
18856
+ className: "gap-4 sm:max-w-xl",
18857
+ children: [
18858
+ /* @__PURE__ */ (0, import_jsx_runtime223.jsx)(DialogTitle, { children: title }),
18859
+ hint !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime223.jsx)(DialogDescription, { children: hint }) : null,
18860
+ speakers.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime223.jsx)("div", { className: "flex flex-col divide-y divide-border", children: speakers.map((speaker, index) => {
18861
+ const selected = index === selectedIndex;
18862
+ return /* @__PURE__ */ (0, import_jsx_runtime223.jsxs)(
18863
+ "button",
18864
+ {
18865
+ type: "button",
18866
+ "data-slot": "recording-speaker-option",
18867
+ "aria-pressed": selected,
18868
+ className: cn(
18869
+ "flex w-full cursor-pointer items-center gap-3 px-3 py-3 text-left",
18870
+ selected ? "bg-primary/10" : "hover:bg-muted"
18871
+ ),
18872
+ onClick: () => onSelect(index),
18873
+ children: [
18874
+ /* @__PURE__ */ (0, import_jsx_runtime223.jsx)(Avatar2, { fallback: speaker.avatarText ?? speaker.name.charAt(0) }),
18875
+ /* @__PURE__ */ (0, import_jsx_runtime223.jsxs)("span", { className: "flex min-w-0 flex-1 items-baseline gap-2", children: [
18876
+ /* @__PURE__ */ (0, import_jsx_runtime223.jsx)("span", { className: "text-sm font-medium", children: speaker.name }),
18877
+ speaker.role !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime223.jsx)("span", { className: "truncate text-sm text-muted-foreground", children: speaker.role }) : null
18878
+ ] }),
18879
+ speaker.tag !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime223.jsx)("span", { className: "shrink-0 text-sm text-muted-foreground", children: speaker.tag }) : null
18880
+ ]
18881
+ },
18882
+ `${speaker.name}-${index}`
18883
+ );
18884
+ }) }) : null,
18885
+ /* @__PURE__ */ (0, import_jsx_runtime223.jsx)(
18886
+ Input2,
18887
+ {
18888
+ value: customName,
18889
+ placeholder: inputPlaceholder,
18890
+ onChange: onInputName
18891
+ }
18892
+ ),
18893
+ /* @__PURE__ */ (0, import_jsx_runtime223.jsx)("div", { className: "flex items-center justify-end", children: /* @__PURE__ */ (0, import_jsx_runtime223.jsx)(
18894
+ Button2,
18895
+ {
18896
+ text: applyLabel,
18897
+ variant: "primary",
18898
+ disabled: !canApply,
18899
+ onClick: onConfirm
18900
+ }
18901
+ ) })
18902
+ ]
18903
+ }
18904
+ )
18905
+ }
18906
+ );
18907
+ }
18908
+
18909
+ // src/components/business/RecordingPage/summary.tsx
18910
+ var import_jsx_runtime224 = require("react/jsx-runtime");
18911
+ function MindmapPill({ label, center }) {
18912
+ return /* @__PURE__ */ (0, import_jsx_runtime224.jsx)(
18913
+ "span",
18914
+ {
18915
+ className: cn(
18916
+ "rounded-lg px-4 py-1.5 text-sm",
18917
+ center ? "bg-primary px-5 py-2.5 font-medium text-primary-foreground" : "border border-border bg-background"
18918
+ ),
18919
+ children: label
18920
+ }
18921
+ );
18922
+ }
18923
+ var mindmapLine = /* @__PURE__ */ (0, import_jsx_runtime224.jsx)("div", { className: "h-px w-10 shrink-0", style: { background: "var(--border)" } });
18924
+ function RecordingSummaryView({
18925
+ summary,
18926
+ onMindmapAction,
18927
+ onMaterialClick,
18928
+ selectedTodoIds,
18929
+ onTodoToggle,
18930
+ onSummaryAction
18931
+ }) {
18932
+ return /* @__PURE__ */ (0, import_jsx_runtime224.jsxs)("div", { "data-slot": "recording-summary", className: "flex flex-col gap-6", children: [
18933
+ summary.mindmap ? /* @__PURE__ */ (0, import_jsx_runtime224.jsxs)("section", { className: "rounded-lg border border-border", children: [
18934
+ /* @__PURE__ */ (0, import_jsx_runtime224.jsxs)("div", { className: "flex items-center justify-between px-4 py-3", children: [
18935
+ /* @__PURE__ */ (0, import_jsx_runtime224.jsx)(Text, { text: summary.mindmapTitle ?? "\u601D\u7EF4\u5BFC\u56FE", strong: true }),
18936
+ summary.mindmapActionLabel !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime224.jsx)(
18937
+ Button2,
18938
+ {
18939
+ text: summary.mindmapActionLabel,
18940
+ variant: "link",
18941
+ size: "small",
18942
+ className: "text-success",
18943
+ onClick: () => onMindmapAction?.()
18944
+ }
18945
+ ) : null
18946
+ ] }),
18947
+ /* @__PURE__ */ (0, import_jsx_runtime224.jsxs)("div", { className: "mx-4 mb-4 flex items-center justify-center rounded-lg bg-muted p-8", children: [
18948
+ /* @__PURE__ */ (0, import_jsx_runtime224.jsx)("div", { className: "flex flex-col items-start gap-2", children: (summary.mindmap.left ?? []).map((node) => /* @__PURE__ */ (0, import_jsx_runtime224.jsx)(MindmapPill, { label: node }, node)) }),
18949
+ mindmapLine,
18950
+ /* @__PURE__ */ (0, import_jsx_runtime224.jsx)(MindmapPill, { label: summary.mindmap.center, center: true }),
18951
+ mindmapLine,
18952
+ /* @__PURE__ */ (0, import_jsx_runtime224.jsx)("div", { className: "flex flex-col items-start gap-2", children: (summary.mindmap.right ?? []).map((node) => /* @__PURE__ */ (0, import_jsx_runtime224.jsx)(MindmapPill, { label: node }, node)) })
18953
+ ] })
18954
+ ] }) : null,
18955
+ summary.overview !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime224.jsxs)("section", { className: "flex flex-col gap-3", children: [
18956
+ /* @__PURE__ */ (0, import_jsx_runtime224.jsx)(
18957
+ Text,
18958
+ {
18959
+ text: summary.overviewTitle ?? "\u4F1A\u8BAE\u6982\u51B5",
18960
+ strong: true,
18961
+ size: "large"
18962
+ }
18963
+ ),
18964
+ /* @__PURE__ */ (0, import_jsx_runtime224.jsx)("div", { className: "rounded-lg bg-muted p-4", children: /* @__PURE__ */ (0, import_jsx_runtime224.jsx)(Text, { text: summary.overview }) })
18965
+ ] }) : null,
18966
+ summary.topics !== void 0 && summary.topics.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime224.jsxs)("section", { className: "flex flex-col gap-3", children: [
18967
+ /* @__PURE__ */ (0, import_jsx_runtime224.jsx)(Text, { text: summary.topicsTitle ?? "\u4E3B\u8981\u8BAE\u9898", strong: true, size: "large" }),
18968
+ /* @__PURE__ */ (0, import_jsx_runtime224.jsx)(
18969
+ "div",
18970
+ {
18971
+ className: "grid gap-3",
18972
+ style: { gridTemplateColumns: "1fr 1fr" },
18973
+ children: summary.topics.map((topic, index) => /* @__PURE__ */ (0, import_jsx_runtime224.jsxs)(
18974
+ "div",
18975
+ {
18976
+ className: "flex flex-col gap-2 rounded-lg border border-border p-4",
18977
+ children: [
18978
+ /* @__PURE__ */ (0, import_jsx_runtime224.jsx)(Text, { text: topic.title, strong: true, size: "small" }),
18979
+ /* @__PURE__ */ (0, import_jsx_runtime224.jsx)(Text, { text: topic.content, size: "small" })
18980
+ ]
18981
+ },
18982
+ index
18983
+ ))
18984
+ }
18985
+ )
18986
+ ] }) : null,
18987
+ summary.conclusions !== void 0 && summary.conclusions.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime224.jsxs)("section", { className: "rounded-lg border border-border p-4", children: [
18988
+ /* @__PURE__ */ (0, import_jsx_runtime224.jsx)(
18989
+ Text,
18990
+ {
18991
+ text: summary.conclusionsTitle ?? "\u8BC4\u5BA1\u7ED3\u8BBA\u4E0E\u540E\u7EED\u5B89\u6392",
18992
+ strong: true,
18993
+ size: "small"
18994
+ }
18995
+ ),
18996
+ /* @__PURE__ */ (0, import_jsx_runtime224.jsx)(
18997
+ Table3,
18998
+ {
18999
+ className: "mt-3",
19000
+ columns: [
19001
+ { title: "\u4E8B\u9879", dataIndex: "item" },
19002
+ { title: "\u4F1A\u8BAE\u7ED3\u8BBA", dataIndex: "conclusion" },
19003
+ { title: "\u8D1F\u8D23\u4EBA", dataIndex: "owner" }
19004
+ ],
19005
+ dataSource: summary.conclusions.map((row, index) => ({
19006
+ id: index,
19007
+ ...row
19008
+ }))
19009
+ }
19010
+ )
19011
+ ] }) : null,
19012
+ summary.followUp !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime224.jsxs)("section", { className: "flex flex-col gap-2 rounded-lg border border-border p-4", children: [
19013
+ /* @__PURE__ */ (0, import_jsx_runtime224.jsx)(Text, { text: summary.followUpTitle, strong: true, size: "small" }),
19014
+ /* @__PURE__ */ (0, import_jsx_runtime224.jsx)(Text, { text: summary.followUp, size: "small" })
19015
+ ] }) : null,
19016
+ summary.materials !== void 0 && summary.materials.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime224.jsxs)("section", { className: "flex flex-col gap-3", children: [
19017
+ /* @__PURE__ */ (0, import_jsx_runtime224.jsx)(
19018
+ Text,
19019
+ {
19020
+ text: summary.materialsTitle ?? "\u76F8\u5173\u6750\u6599",
19021
+ strong: true,
19022
+ size: "large"
19023
+ }
19024
+ ),
19025
+ /* @__PURE__ */ (0, import_jsx_runtime224.jsx)("div", { className: "flex flex-col divide-y divide-border rounded-lg border border-border", children: summary.materials.map((material, index) => /* @__PURE__ */ (0, import_jsx_runtime224.jsxs)(
19026
+ "button",
19027
+ {
19028
+ type: "button",
19029
+ "data-slot": "recording-material",
19030
+ className: "flex cursor-pointer items-center gap-2 px-4 py-3 text-left",
19031
+ onClick: () => onMaterialClick?.(material.id ?? index),
19032
+ children: [
19033
+ /* @__PURE__ */ (0, import_jsx_runtime224.jsx)(
19034
+ Icon,
19035
+ {
19036
+ name: material.icon ?? "file-text",
19037
+ size: 16,
19038
+ className: "text-muted-foreground"
19039
+ }
19040
+ ),
19041
+ /* @__PURE__ */ (0, import_jsx_runtime224.jsx)(
19042
+ Text,
19043
+ {
19044
+ text: material.title,
19045
+ size: "small",
19046
+ className: "min-w-0 flex-1 truncate"
19047
+ }
19048
+ ),
19049
+ /* @__PURE__ */ (0, import_jsx_runtime224.jsx)(
19050
+ Text,
19051
+ {
19052
+ text: material.meta,
19053
+ size: "small",
19054
+ type: "secondary",
19055
+ className: "shrink-0"
19056
+ }
19057
+ ),
19058
+ /* @__PURE__ */ (0, import_jsx_runtime224.jsx)(
19059
+ Icon,
19060
+ {
19061
+ name: "chevron-right",
19062
+ size: 14,
19063
+ className: "text-muted-foreground"
19064
+ }
19065
+ )
19066
+ ]
19067
+ },
19068
+ material.id ?? index
19069
+ )) })
19070
+ ] }) : null,
19071
+ summary.todos !== void 0 && summary.todos.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime224.jsxs)("section", { className: "flex flex-col gap-3", children: [
19072
+ /* @__PURE__ */ (0, import_jsx_runtime224.jsx)(Text, { text: summary.todosTitle ?? "\u5F85\u529E\u4E8B\u9879", strong: true, size: "large" }),
19073
+ /* @__PURE__ */ (0, import_jsx_runtime224.jsx)("div", { className: "flex flex-col divide-y divide-border rounded-lg border border-border", children: summary.todos.map((todo, index) => {
19074
+ const todoId = todo.id ?? index;
19075
+ const checked = selectedTodoIds !== void 0 ? selectedTodoIds.includes(todoId) : todo.done === true;
19076
+ return /* @__PURE__ */ (0, import_jsx_runtime224.jsxs)(
19077
+ "button",
19078
+ {
19079
+ type: "button",
19080
+ "data-slot": "recording-todo",
19081
+ "aria-pressed": checked,
19082
+ className: "flex cursor-pointer items-center gap-2 px-4 py-3 text-left",
19083
+ onClick: () => onTodoToggle?.(todoId),
19084
+ children: [
19085
+ checked ? /* @__PURE__ */ (0, import_jsx_runtime224.jsx)(
19086
+ Icon,
19087
+ {
19088
+ name: "check-circle",
19089
+ size: 16,
19090
+ className: "shrink-0 text-success"
19091
+ }
19092
+ ) : /* @__PURE__ */ (0, import_jsx_runtime224.jsx)(
19093
+ "span",
19094
+ {
19095
+ className: "shrink-0 rounded-full border border-border",
19096
+ style: { width: 16, height: 16 }
19097
+ }
19098
+ ),
19099
+ /* @__PURE__ */ (0, import_jsx_runtime224.jsx)(
19100
+ Text,
19101
+ {
19102
+ text: todo.title,
19103
+ size: "small",
19104
+ className: "min-w-0 flex-1 truncate"
19105
+ }
19106
+ ),
19107
+ /* @__PURE__ */ (0, import_jsx_runtime224.jsx)(
19108
+ Text,
19109
+ {
19110
+ text: todo.owner,
19111
+ size: "small",
19112
+ type: "secondary",
19113
+ className: "shrink-0"
19114
+ }
19115
+ )
19116
+ ]
19117
+ },
19118
+ todoId
19119
+ );
19120
+ }) })
19121
+ ] }) : null,
19122
+ summary.actions !== void 0 && summary.actions.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime224.jsx)(
19123
+ "div",
19124
+ {
19125
+ "data-slot": "recording-summary-actions",
19126
+ className: "flex items-center gap-1",
19127
+ children: summary.actions.map((action) => /* @__PURE__ */ (0, import_jsx_runtime224.jsx)(
19128
+ Button2,
19129
+ {
19130
+ icon: action.icon,
19131
+ variant: "text",
19132
+ size: "small",
19133
+ onClick: () => onSummaryAction?.(action.key)
19134
+ },
19135
+ action.key
19136
+ ))
19137
+ }
19138
+ ) : null
19139
+ ] });
19140
+ }
19141
+
19142
+ // src/components/business/RecordingPage/translation.tsx
19143
+ var import_react78 = require("react");
19144
+
19145
+ // src/components/business/RecordingPage/language-dialog.tsx
19146
+ var import_jsx_runtime225 = require("react/jsx-runtime");
19147
+ function LanguageOptionItem({
19148
+ option,
19149
+ selected,
19150
+ onSelect
19151
+ }) {
19152
+ return /* @__PURE__ */ (0, import_jsx_runtime225.jsxs)(
19153
+ "button",
19154
+ {
19155
+ type: "button",
19156
+ "data-slot": "recording-language-option",
19157
+ "aria-pressed": selected,
19158
+ className: cn(
19159
+ "flex w-full cursor-pointer items-center gap-2.5 px-3 py-2.5 text-left text-sm",
19160
+ selected ? "bg-primary/10" : "hover:bg-muted"
19161
+ ),
19162
+ onClick: () => onSelect(option.key),
19163
+ children: [
19164
+ /* @__PURE__ */ (0, import_jsx_runtime225.jsx)(
19165
+ "span",
19166
+ {
19167
+ className: cn(
19168
+ "flex h-4 w-4 shrink-0 items-center justify-center rounded-full border",
19169
+ selected ? "border-primary" : "border-input"
19170
+ ),
19171
+ children: selected ? /* @__PURE__ */ (0, import_jsx_runtime225.jsx)("span", { className: "h-2 w-2 rounded-full bg-primary" }) : null
19172
+ }
19173
+ ),
19174
+ /* @__PURE__ */ (0, import_jsx_runtime225.jsx)("span", { className: cn(selected && "font-medium"), children: option.label })
19175
+ ]
19176
+ }
19177
+ );
19178
+ }
19179
+ function RecordingLanguageDialog({
19180
+ open,
19181
+ title,
19182
+ sourceTitle,
19183
+ targetTitle,
19184
+ sourceLanguages,
19185
+ targetLanguages,
19186
+ source,
19187
+ target,
19188
+ cancelLabel,
19189
+ confirmLabel,
19190
+ onSelectSource,
19191
+ onSelectTarget,
19192
+ onCancel,
19193
+ onConfirm
19194
+ }) {
19195
+ const renderColumn = (columnTitle, options, value, onSelect) => /* @__PURE__ */ (0, import_jsx_runtime225.jsxs)("div", { className: "flex min-w-0 flex-col gap-2", children: [
19196
+ /* @__PURE__ */ (0, import_jsx_runtime225.jsx)("span", { className: "text-sm font-medium", children: columnTitle }),
19197
+ /* @__PURE__ */ (0, import_jsx_runtime225.jsx)("div", { className: "flex flex-col divide-y divide-border", children: options.map((option) => /* @__PURE__ */ (0, import_jsx_runtime225.jsx)(
19198
+ LanguageOptionItem,
19199
+ {
19200
+ option,
19201
+ selected: option.key === value,
19202
+ onSelect
19203
+ },
19204
+ option.key
19205
+ )) })
19206
+ ] });
19207
+ return /* @__PURE__ */ (0, import_jsx_runtime225.jsx)(
19208
+ Dialog,
19209
+ {
19210
+ open,
19211
+ onOpenChange: (next) => {
19212
+ if (!next) onCancel();
19213
+ },
19214
+ children: /* @__PURE__ */ (0, import_jsx_runtime225.jsxs)(
19215
+ DialogContent,
19216
+ {
19217
+ "data-slot": "recording-language-dialog",
19218
+ className: "gap-6 sm:max-w-xl",
19219
+ children: [
19220
+ /* @__PURE__ */ (0, import_jsx_runtime225.jsx)(DialogTitle, { children: title }),
19221
+ /* @__PURE__ */ (0, import_jsx_runtime225.jsxs)("div", { className: "grid grid-cols-2 gap-6", children: [
19222
+ renderColumn(sourceTitle, sourceLanguages, source, onSelectSource),
19223
+ renderColumn(targetTitle, targetLanguages, target, onSelectTarget)
19224
+ ] }),
19225
+ /* @__PURE__ */ (0, import_jsx_runtime225.jsxs)("div", { className: "flex items-center justify-end gap-2", children: [
19226
+ /* @__PURE__ */ (0, import_jsx_runtime225.jsx)(Button2, { text: cancelLabel, onClick: onCancel }),
19227
+ /* @__PURE__ */ (0, import_jsx_runtime225.jsx)(Button2, { text: confirmLabel, variant: "primary", onClick: onConfirm })
19228
+ ] })
19229
+ ]
19230
+ }
19231
+ )
19232
+ }
19233
+ );
19234
+ }
19235
+
19236
+ // src/components/business/RecordingPage/translation.tsx
19237
+ var import_jsx_runtime226 = require("react/jsx-runtime");
19238
+ function RecordingTranslationView({
19239
+ translation,
19240
+ onLanguageClick,
19241
+ onLanguageChange,
19242
+ onTranslationAction
19243
+ }) {
19244
+ const sourceLanguages = translation.sourceLanguages ?? [];
19245
+ const targetLanguages = translation.targetLanguages ?? [];
19246
+ const dialogEnabled = sourceLanguages.length > 0 || targetLanguages.length > 0;
19247
+ const [dialogOpen, setDialogOpen] = (0, import_react78.useState)(false);
19248
+ const sourceControlled = translation.sourceLanguage !== void 0;
19249
+ const targetControlled = translation.targetLanguage !== void 0;
19250
+ const [innerSource, setInnerSource] = (0, import_react78.useState)(
19251
+ translation.defaultSourceLanguage ?? sourceLanguages[0]?.key
19252
+ );
19253
+ const [innerTarget, setInnerTarget] = (0, import_react78.useState)(
19254
+ translation.defaultTargetLanguage ?? targetLanguages[0]?.key
19255
+ );
19256
+ const committedSource = sourceControlled ? translation.sourceLanguage : innerSource;
19257
+ const committedTarget = targetControlled ? translation.targetLanguage : innerTarget;
19258
+ const [draftSource, setDraftSource] = (0, import_react78.useState)(committedSource);
19259
+ const [draftTarget, setDraftTarget] = (0, import_react78.useState)(committedTarget);
19260
+ const openDialog = () => {
19261
+ setDraftSource(committedSource);
19262
+ setDraftTarget(committedTarget);
19263
+ setDialogOpen(true);
19264
+ };
19265
+ const confirmDialog = () => {
19266
+ if (!sourceControlled) setInnerSource(draftSource);
19267
+ if (!targetControlled) setInnerTarget(draftTarget);
19268
+ onLanguageChange?.({
19269
+ source: draftSource,
19270
+ sourceLabel: sourceLanguages.find((item) => item.key === draftSource)?.label,
19271
+ target: draftTarget,
19272
+ targetLabel: targetLanguages.find((item) => item.key === draftTarget)?.label
19273
+ });
19274
+ setDialogOpen(false);
19275
+ };
19276
+ return /* @__PURE__ */ (0, import_jsx_runtime226.jsxs)("div", { "data-slot": "recording-translation", className: "flex flex-col gap-4", children: [
19277
+ translation.languageLabel !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime226.jsx)("div", { children: /* @__PURE__ */ (0, import_jsx_runtime226.jsxs)(
19278
+ "button",
19279
+ {
19280
+ type: "button",
19281
+ "data-slot": "recording-translation-language",
19282
+ className: "inline-flex cursor-pointer items-center gap-1.5 rounded-full bg-primary/10 px-3 py-1.5 text-sm",
19283
+ onClick: () => {
19284
+ onLanguageClick?.();
19285
+ if (dialogEnabled) openDialog();
19286
+ },
19287
+ children: [
19288
+ /* @__PURE__ */ (0, import_jsx_runtime226.jsx)(Icon, { name: "globe", size: 14 }),
19289
+ translation.languageLabel,
19290
+ /* @__PURE__ */ (0, import_jsx_runtime226.jsx)(Icon, { name: "chevron-down", size: 14, className: "text-muted-foreground" })
19291
+ ]
19292
+ }
19293
+ ) }) : null,
19294
+ /* @__PURE__ */ (0, import_jsx_runtime226.jsx)("div", { className: "flex flex-col divide-y divide-border", children: (translation.segments ?? []).map((segment, index) => /* @__PURE__ */ (0, import_jsx_runtime226.jsxs)(
19295
+ "div",
19296
+ {
19297
+ "data-slot": "recording-translation-segment",
19298
+ className: "grid gap-4 py-4",
19299
+ style: { gridTemplateColumns: "1fr 1fr" },
19300
+ children: [
19301
+ /* @__PURE__ */ (0, import_jsx_runtime226.jsxs)("div", { className: "flex min-w-0 flex-col gap-3", children: [
19302
+ /* @__PURE__ */ (0, import_jsx_runtime226.jsxs)("div", { className: "flex items-center gap-2", children: [
19303
+ /* @__PURE__ */ (0, import_jsx_runtime226.jsx)(Avatar2, { fallback: segment.avatarText ?? segment.speaker?.charAt(0) ?? "?" }),
19304
+ /* @__PURE__ */ (0, import_jsx_runtime226.jsx)(Text, { text: segment.speaker, strong: true, size: "small" })
19305
+ ] }),
19306
+ /* @__PURE__ */ (0, import_jsx_runtime226.jsx)(Text, { text: segment.source })
19307
+ ] }),
19308
+ /* @__PURE__ */ (0, import_jsx_runtime226.jsxs)("div", { className: "flex min-w-0 flex-col gap-3", children: [
19309
+ /* @__PURE__ */ (0, import_jsx_runtime226.jsx)(Text, { text: translation.targetLabel ?? "\u8BD1\u6587", strong: true, size: "small" }),
19310
+ /* @__PURE__ */ (0, import_jsx_runtime226.jsx)(Text, { text: segment.target })
19311
+ ] })
19312
+ ]
19313
+ },
19314
+ index
19315
+ )) }),
19316
+ translation.actions !== void 0 && translation.actions.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime226.jsx)("div", { "data-slot": "recording-translation-actions", className: "flex items-center gap-1", children: translation.actions.map((action) => /* @__PURE__ */ (0, import_jsx_runtime226.jsx)(
19317
+ Button2,
19318
+ {
19319
+ icon: action.icon,
19320
+ variant: "text",
19321
+ size: "small",
19322
+ onClick: () => onTranslationAction?.(action.key)
19323
+ },
19324
+ action.key
19325
+ )) }) : null,
19326
+ dialogEnabled ? /* @__PURE__ */ (0, import_jsx_runtime226.jsx)(
19327
+ RecordingLanguageDialog,
19328
+ {
19329
+ open: dialogOpen,
19330
+ title: translation.languageDialogTitle ?? "\u9009\u62E9\u7FFB\u8BD1\u8BED\u8A00",
19331
+ sourceTitle: translation.sourceLanguagesTitle ?? "\u539F\u6587\u8BED\u8A00\u8BC6\u522B",
19332
+ targetTitle: translation.targetLanguagesTitle ?? "\u8BD1\u6587\u8BED\u8A00\u9009\u62E9",
19333
+ sourceLanguages,
19334
+ targetLanguages,
19335
+ source: draftSource,
19336
+ target: draftTarget,
19337
+ cancelLabel: translation.cancelLabel ?? "\u53D6\u6D88",
19338
+ confirmLabel: translation.confirmLabel ?? "\u786E\u5B9A",
19339
+ onSelectSource: setDraftSource,
19340
+ onSelectTarget: setDraftTarget,
19341
+ onCancel: () => setDialogOpen(false),
19342
+ onConfirm: confirmDialog
19343
+ }
19344
+ ) : null
19345
+ ] });
19346
+ }
19347
+
19348
+ // src/components/business/RecordingPage/detail.tsx
19349
+ var import_jsx_runtime227 = require("react/jsx-runtime");
19350
+ function TranscriptSegment({
19351
+ segment,
19352
+ speaker,
19353
+ onRename
19354
+ }) {
19355
+ return /* @__PURE__ */ (0, import_jsx_runtime227.jsxs)("div", { "data-slot": "recording-segment", className: "flex flex-col gap-2", children: [
19356
+ /* @__PURE__ */ (0, import_jsx_runtime227.jsxs)("div", { className: "flex items-center justify-between", children: [
19357
+ /* @__PURE__ */ (0, import_jsx_runtime227.jsxs)("div", { className: "flex items-center gap-2", children: [
19358
+ /* @__PURE__ */ (0, import_jsx_runtime227.jsx)(Avatar2, { fallback: segment.avatarText ?? speaker?.charAt(0) ?? "?" }),
19359
+ /* @__PURE__ */ (0, import_jsx_runtime227.jsx)(Text, { text: speaker, strong: true, size: "small" }),
19360
+ /* @__PURE__ */ (0, import_jsx_runtime227.jsx)(
19361
+ "button",
19362
+ {
19363
+ type: "button",
19364
+ "data-slot": "recording-speaker-edit",
19365
+ "aria-label": "\u4FEE\u6539\u53D1\u8A00\u4EBA",
19366
+ className: "cursor-pointer text-muted-foreground",
19367
+ onClick: () => onRename?.(),
19368
+ children: /* @__PURE__ */ (0, import_jsx_runtime227.jsx)(Icon, { name: "pencil", size: 14 })
19369
+ }
19370
+ )
19371
+ ] }),
19372
+ /* @__PURE__ */ (0, import_jsx_runtime227.jsxs)("div", { className: "flex items-center gap-2", children: [
19373
+ segment.marked ? /* @__PURE__ */ (0, import_jsx_runtime227.jsx)(Badge2, { text: "\u2691 \u5DF2\u6807\u8BB0", variant: "outline" }) : null,
19374
+ /* @__PURE__ */ (0, import_jsx_runtime227.jsx)(Text, { text: segment.time, size: "small", type: "secondary" })
19375
+ ] })
19376
+ ] }),
19377
+ /* @__PURE__ */ (0, import_jsx_runtime227.jsx)(Text, { text: segment.content })
19378
+ ] });
19379
+ }
19380
+ function RecordingDetail({
19381
+ title,
19382
+ meta,
19383
+ editLabel,
19384
+ shareLabel,
19385
+ shareOptions = [],
19386
+ shareSelectedKeys = [],
19387
+ sharePopoverTitle,
19388
+ shareCancelLabel,
19389
+ shareConfirmLabel,
19390
+ shareDialogTitle,
19391
+ shareLink,
19392
+ shareCopyLinkLabel,
19393
+ shareCopiedLabel,
19394
+ shareMailLabel,
19395
+ shareSystemLabel,
19396
+ onShareSelectionCommit,
19397
+ onShareConfirm,
19398
+ onShareChannel,
19399
+ onEdit,
19400
+ onShare,
19401
+ tabs,
19402
+ activeTab,
19403
+ onTabChange,
19404
+ transcriptTabKey,
19405
+ segments,
19406
+ speakers = [],
19407
+ speakerDialogTitle,
19408
+ speakerDialogHint,
19409
+ speakerInputPlaceholder,
19410
+ speakerApplyLabel,
19411
+ onSpeakerChange,
19412
+ summary,
19413
+ summaryTabKey,
19414
+ onMindmapAction,
19415
+ onMaterialClick,
19416
+ selectedTodoIds,
19417
+ onTodoToggle,
19418
+ onSummaryAction,
19419
+ insight,
19420
+ insightTabKey,
19421
+ onPerspectiveEdit,
19422
+ onPerspectiveApply,
19423
+ onInsightAction,
19424
+ memory,
19425
+ memoryTabKey,
19426
+ onMemoryAction,
19427
+ translation,
19428
+ translationTabKey,
19429
+ onLanguageClick,
19430
+ onLanguageChange,
19431
+ onTranslationAction,
19432
+ player,
19433
+ onPlay,
19434
+ onSkipBack,
19435
+ onSkipForward
19436
+ }) {
19437
+ const { renderChildren } = (0, import_runtime54.useRenderer)();
19438
+ const renderSlot = (slot) => (0, import_react79.isValidElement)(slot) || typeof slot !== "object" || slot === null ? slot : renderChildren([slot]);
19439
+ const activeTabItem = tabs.find((tab) => tab.key === activeTab);
19440
+ const [renameIndex, setRenameIndex] = (0, import_react79.useState)(null);
19441
+ const [draftSpeakerIndex, setDraftSpeakerIndex] = (0, import_react79.useState)(-1);
19442
+ const [draftSpeakerName, setDraftSpeakerName] = (0, import_react79.useState)("");
19443
+ const [speakerOverrides, setSpeakerOverrides] = (0, import_react79.useState)({});
19444
+ const speakerSignature = (0, import_react79.useRef)("");
19445
+ (0, import_react79.useEffect)(() => {
19446
+ const signature = JSON.stringify(segments.map((segment) => segment.speaker ?? ""));
19447
+ if (speakerSignature.current !== signature) {
19448
+ speakerSignature.current = signature;
19449
+ setSpeakerOverrides((prev) => Object.keys(prev).length > 0 ? {} : prev);
19450
+ }
19451
+ }, [segments]);
19452
+ const displaySpeaker = (index) => speakerOverrides[index] ?? segments[index]?.speaker;
19453
+ const openRename = (index) => {
19454
+ const current = displaySpeaker(index);
19455
+ setDraftSpeakerIndex(speakers.findIndex((item) => item.name === current));
19456
+ setDraftSpeakerName("");
19457
+ setRenameIndex(index);
19458
+ };
19459
+ const confirmRename = () => {
19460
+ if (renameIndex === null) return;
19461
+ const name = draftSpeakerName.trim() !== "" ? draftSpeakerName.trim() : speakers[draftSpeakerIndex]?.name;
19462
+ if (name === void 0 || name === "") return;
19463
+ const previous = displaySpeaker(renameIndex);
19464
+ setSpeakerOverrides((prev) => ({ ...prev, [renameIndex]: name }));
19465
+ onSpeakerChange?.({ index: renameIndex, previous, name });
19466
+ setRenameIndex(null);
19467
+ };
19468
+ return /* @__PURE__ */ (0, import_jsx_runtime227.jsxs)("div", { "data-slot": "recording-page-detail", className: "flex h-full min-w-0 flex-1 flex-col", children: [
19469
+ /* @__PURE__ */ (0, import_jsx_runtime227.jsxs)("div", { className: "flex shrink-0 items-center justify-between px-6 py-4", children: [
19470
+ /* @__PURE__ */ (0, import_jsx_runtime227.jsxs)("div", { className: "flex min-w-0 flex-col gap-1", children: [
19471
+ /* @__PURE__ */ (0, import_jsx_runtime227.jsx)(Text, { text: title, strong: true, size: "large", className: "truncate" }),
19472
+ meta !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime227.jsx)(Text, { text: meta, size: "small", type: "secondary" }) : null
19473
+ ] }),
19474
+ /* @__PURE__ */ (0, import_jsx_runtime227.jsxs)("div", { className: "flex shrink-0 items-center gap-3", children: [
19475
+ editLabel !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime227.jsx)(Button2, { text: editLabel, variant: "link", size: "small", onClick: () => onEdit?.() }) : null,
19476
+ shareLabel !== void 0 ? shareOptions.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime227.jsx)(
19477
+ RecordingShare,
19478
+ {
19479
+ shareLabel,
19480
+ options: shareOptions,
19481
+ selectedKeys: shareSelectedKeys,
19482
+ popoverTitle: sharePopoverTitle ?? "\u9009\u62E9\u5206\u4EAB\u5185\u5BB9",
19483
+ cancelLabel: shareCancelLabel ?? "\u53D6\u6D88",
19484
+ confirmLabel: shareConfirmLabel ?? "\u786E\u5B9A",
19485
+ dialogTitle: shareDialogTitle ?? "\u5206\u4EAB\u4F1A\u8BAE\u5185\u5BB9",
19486
+ link: shareLink,
19487
+ copyLinkLabel: shareCopyLinkLabel ?? "\u590D\u5236\u94FE\u63A5",
19488
+ copiedLabel: shareCopiedLabel ?? "\u5DF2\u590D\u5236",
19489
+ mailLabel: shareMailLabel ?? "\u90AE\u4EF6",
19490
+ systemLabel: shareSystemLabel ?? "\u7CFB\u7EDF\u5206\u4EAB",
19491
+ onShare,
19492
+ onSelectionCommit: (keys) => onShareSelectionCommit?.(keys),
19493
+ onShareConfirm,
19494
+ onShareChannel
19495
+ }
19496
+ ) : /* @__PURE__ */ (0, import_jsx_runtime227.jsx)(Button2, { text: shareLabel, size: "small", onClick: () => onShare?.() }) : null
19497
+ ] })
19498
+ ] }),
19499
+ tabs.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime227.jsxs)(import_jsx_runtime227.Fragment, { children: [
19500
+ /* @__PURE__ */ (0, import_jsx_runtime227.jsx)("div", { "data-slot": "recording-page-tabs", className: "flex shrink-0 px-6 pt-3", children: /* @__PURE__ */ (0, import_jsx_runtime227.jsx)("div", { className: "flex w-full items-center gap-1 rounded-lg bg-muted p-1", children: tabs.map((tab) => {
19501
+ const active = tab.key === activeTab;
19502
+ return /* @__PURE__ */ (0, import_jsx_runtime227.jsx)(
19503
+ "button",
19504
+ {
19505
+ type: "button",
19506
+ role: "tab",
19507
+ "aria-selected": active,
19508
+ className: cn(
19509
+ "flex-1 cursor-pointer rounded-md px-3 py-1 text-sm",
19510
+ active ? "bg-background shadow-sm" : "text-muted-foreground"
19511
+ ),
19512
+ onClick: () => onTabChange(tab.key),
19513
+ children: tab.label
19514
+ },
19515
+ tab.key
19516
+ );
19517
+ }) }) }),
19518
+ /* @__PURE__ */ (0, import_jsx_runtime227.jsx)(
19519
+ "div",
19520
+ {
19521
+ "data-slot": "recording-page-tab-body",
19522
+ className: "scrollbar-subtle min-h-0 flex-1 overflow-y-auto px-6 py-4",
19523
+ children: activeTabItem?.content !== void 0 ? renderSlot(activeTabItem.content) : activeTabItem?.key === transcriptTabKey ? /* @__PURE__ */ (0, import_jsx_runtime227.jsx)("div", { className: "flex flex-col gap-6", children: segments.map((segment, index) => /* @__PURE__ */ (0, import_jsx_runtime227.jsx)(
19524
+ TranscriptSegment,
19525
+ {
19526
+ segment,
19527
+ speaker: displaySpeaker(index),
19528
+ onRename: () => openRename(index)
19529
+ },
19530
+ segment.time ?? index
19531
+ )) }) : activeTabItem?.key === summaryTabKey && summary !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime227.jsx)(
19532
+ RecordingSummaryView,
19533
+ {
19534
+ summary,
19535
+ onMindmapAction,
19536
+ onMaterialClick,
19537
+ selectedTodoIds,
19538
+ onTodoToggle,
19539
+ onSummaryAction
19540
+ }
19541
+ ) : activeTabItem?.key === insightTabKey && insight !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime227.jsx)(
19542
+ RecordingInsightView,
19543
+ {
19544
+ insight,
19545
+ onPerspectiveEdit,
19546
+ onPerspectiveApply,
19547
+ onInsightAction
19548
+ }
19549
+ ) : activeTabItem?.key === memoryTabKey && memory !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime227.jsx)(RecordingMemoryView, { memory, onMemoryAction }) : activeTabItem?.key === translationTabKey && translation !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime227.jsx)(
19550
+ RecordingTranslationView,
19551
+ {
19552
+ translation,
19553
+ onLanguageClick,
19554
+ onLanguageChange,
19555
+ onTranslationAction
19556
+ }
19557
+ ) : null
19558
+ }
19559
+ )
19560
+ ] }) : null,
19561
+ player !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime227.jsxs)(
19562
+ "div",
19563
+ {
19564
+ "data-slot": "recording-page-player",
19565
+ className: "flex shrink-0 items-center gap-3 border-t border-border px-6 py-3",
19566
+ children: [
19567
+ /* @__PURE__ */ (0, import_jsx_runtime227.jsx)(Button2, { icon: "rotate-ccw", variant: "text", onClick: () => onSkipBack?.() }),
19568
+ /* @__PURE__ */ (0, import_jsx_runtime227.jsx)(
19569
+ Button2,
19570
+ {
19571
+ icon: "play",
19572
+ style: { borderRadius: 999 },
19573
+ onClick: () => onPlay?.()
19574
+ }
19575
+ ),
19576
+ /* @__PURE__ */ (0, import_jsx_runtime227.jsx)(Button2, { icon: "rotate-cw", variant: "text", onClick: () => onSkipForward?.() }),
19577
+ /* @__PURE__ */ (0, import_jsx_runtime227.jsx)(Text, { text: player.currentTime, size: "small", type: "secondary" }),
19578
+ /* @__PURE__ */ (0, import_jsx_runtime227.jsx)(Progress2, { value: player.progress, style: { flex: 1 } }),
19579
+ /* @__PURE__ */ (0, import_jsx_runtime227.jsx)(Text, { text: player.totalTime, size: "small", type: "secondary" })
19580
+ ]
19581
+ }
19582
+ ) : null,
19583
+ /* @__PURE__ */ (0, import_jsx_runtime227.jsx)(
19584
+ RecordingSpeakerDialog,
19585
+ {
19586
+ open: renameIndex !== null,
19587
+ title: speakerDialogTitle ?? "\u4FEE\u6539\u53D1\u8A00\u4EBA",
19588
+ hint: speakerDialogHint ?? "\u9009\u62E9\u53C2\u4F1A\u4FE1\u606F\u3001\u5DF2\u8BC6\u522B\u4EBA\u5458\u6216\u4F60\u66FE\u624B\u52A8\u521B\u5EFA\u7684\u8054\u7CFB\u4EBA\u3002",
19589
+ speakers,
19590
+ selectedIndex: draftSpeakerIndex,
19591
+ customName: draftSpeakerName,
19592
+ inputPlaceholder: speakerInputPlaceholder ?? "\u8F93\u5165\u59D3\u540D",
19593
+ applyLabel: speakerApplyLabel ?? "\u5E94\u7528\u59D3\u540D",
19594
+ onSelect: setDraftSpeakerIndex,
19595
+ onInputName: setDraftSpeakerName,
19596
+ onCancel: () => setRenameIndex(null),
19597
+ onConfirm: confirmRename
19598
+ }
19599
+ )
19600
+ ] });
19601
+ }
19602
+
19603
+ // src/components/business/RecordingPage/list.tsx
19604
+ var import_react80 = require("react");
19605
+ var import_jsx_runtime228 = require("react/jsx-runtime");
19606
+ function RecordingList({
19607
+ listTitle,
19608
+ selectLabel,
19609
+ selectDoneLabel,
19610
+ selectAllLabel,
19611
+ selectedCountText,
19612
+ deleteLabel,
19613
+ deleteConfirmTitle,
19614
+ deleteConfirmText,
19615
+ deleteCancelLabel,
19616
+ deleteConfirmLabel,
19617
+ selecting = false,
19618
+ selectedRecordingIds = [],
19619
+ onEnterSelectMode,
19620
+ onExitSelectMode,
19621
+ onToggleRecordingSelect,
19622
+ onToggleSelectAll,
19623
+ onDeleteSelected,
19624
+ filters,
19625
+ activeFilter,
19626
+ onFilterChange,
19627
+ processingText,
19628
+ processingHint,
19629
+ onProcessingClick,
19630
+ newRecordingLabel,
19631
+ onNewRecording,
19632
+ groups,
19633
+ activeRecordingId,
19634
+ onSelectRecording,
19635
+ listWidth,
19636
+ emptyText
19637
+ }) {
19638
+ const [deleteConfirmOpen, setDeleteConfirmOpen] = (0, import_react80.useState)(false);
19639
+ const renderRecordingItem = (item) => {
19640
+ const active = !selecting && item.id === activeRecordingId;
19641
+ const checked = selecting && selectedRecordingIds.includes(item.id);
19642
+ return /* @__PURE__ */ (0, import_jsx_runtime228.jsxs)(
19643
+ "button",
19644
+ {
19645
+ type: "button",
19646
+ "data-slot": "recording-item",
19647
+ "data-active": active || void 0,
19648
+ "aria-pressed": selecting ? checked : void 0,
19649
+ className: cn(
19650
+ "flex w-full cursor-pointer items-start gap-2 rounded-lg p-2 text-left",
19651
+ active ? "bg-background shadow-sm" : void 0
19652
+ ),
19653
+ onClick: () => selecting ? onToggleRecordingSelect?.(item.id) : onSelectRecording(item.id),
19654
+ children: [
19655
+ selecting ? /* @__PURE__ */ (0, import_jsx_runtime228.jsx)(
19656
+ "span",
19657
+ {
19658
+ className: cn(
19659
+ "mt-0.5 flex h-5 w-5 shrink-0 items-center justify-center rounded-full",
19660
+ checked ? "bg-success text-background" : "border border-border bg-background"
19661
+ ),
19662
+ children: checked ? /* @__PURE__ */ (0, import_jsx_runtime228.jsx)(Icon, { name: "check", size: 12 }) : null
19663
+ }
19664
+ ) : /* @__PURE__ */ (0, import_jsx_runtime228.jsx)(Icon, { name: item.icon ?? "audio-lines", size: 18, className: "mt-0.5 shrink-0" }),
19665
+ /* @__PURE__ */ (0, import_jsx_runtime228.jsxs)("div", { className: "flex min-w-0 flex-1 flex-col gap-1", children: [
19666
+ /* @__PURE__ */ (0, import_jsx_runtime228.jsxs)("div", { className: "flex items-center justify-between gap-2", children: [
19667
+ /* @__PURE__ */ (0, import_jsx_runtime228.jsx)(
19668
+ Text,
19669
+ {
19670
+ text: item.title,
19671
+ size: "small",
19672
+ strong: active || checked,
19673
+ className: "min-w-0 truncate"
19674
+ }
19675
+ ),
19676
+ item.status !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime228.jsx)(
19677
+ Text,
19678
+ {
19679
+ text: item.status,
19680
+ size: "small",
19681
+ type: item.statusType ?? "secondary",
19682
+ className: "shrink-0"
19683
+ }
19684
+ ) : null
19685
+ ] }),
19686
+ /* @__PURE__ */ (0, import_jsx_runtime228.jsxs)("div", { className: "flex items-center justify-between gap-2", children: [
19687
+ /* @__PURE__ */ (0, import_jsx_runtime228.jsx)(Text, { text: item.time, size: "small", type: "secondary" }),
19688
+ /* @__PURE__ */ (0, import_jsx_runtime228.jsx)(Text, { text: item.duration, size: "small", type: "secondary" })
19689
+ ] })
19690
+ ] })
19691
+ ]
19692
+ },
19693
+ item.id
19694
+ );
19695
+ };
19696
+ return /* @__PURE__ */ (0, import_jsx_runtime228.jsxs)(
19697
+ "div",
19698
+ {
19699
+ "data-slot": "recording-page-list",
19700
+ className: "m-3 flex min-h-0 shrink-0 flex-col gap-3 rounded-xl bg-muted p-4",
19701
+ style: { width: listWidth },
19702
+ children: [
19703
+ /* @__PURE__ */ (0, import_jsx_runtime228.jsxs)("div", { className: "flex items-center justify-between", children: [
19704
+ /* @__PURE__ */ (0, import_jsx_runtime228.jsx)(Text, { text: listTitle, strong: true, size: "large" }),
19705
+ selecting ? /* @__PURE__ */ (0, import_jsx_runtime228.jsx)(
19706
+ Button2,
19707
+ {
19708
+ text: selectDoneLabel ?? "\u5B8C\u6210",
19709
+ variant: "link",
19710
+ size: "small",
19711
+ onClick: () => onExitSelectMode?.()
19712
+ }
19713
+ ) : selectLabel !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime228.jsx)(Button2, { text: selectLabel, variant: "link", size: "small", onClick: () => onEnterSelectMode?.() }) : null
19714
+ ] }),
19715
+ selecting ? /* @__PURE__ */ (0, import_jsx_runtime228.jsxs)(
19716
+ "div",
19717
+ {
19718
+ "data-slot": "recording-page-selection-bar",
19719
+ className: "flex items-center justify-between",
19720
+ children: [
19721
+ /* @__PURE__ */ (0, import_jsx_runtime228.jsx)(
19722
+ Text,
19723
+ {
19724
+ text: (selectedCountText ?? "\u5DF2\u9009 {count} \u6761").replace(
19725
+ "{count}",
19726
+ String(selectedRecordingIds.length)
19727
+ ),
19728
+ size: "small",
19729
+ type: "secondary"
19730
+ }
19731
+ ),
19732
+ /* @__PURE__ */ (0, import_jsx_runtime228.jsx)(
19733
+ Button2,
19734
+ {
19735
+ text: selectAllLabel ?? "\u5168\u9009",
19736
+ variant: "link",
19737
+ size: "small",
19738
+ onClick: () => onToggleSelectAll?.()
19739
+ }
19740
+ )
19741
+ ]
19742
+ }
19743
+ ) : null,
19744
+ !selecting && filters.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime228.jsx)("div", { "data-slot": "recording-page-filters", className: "flex gap-2", children: filters.map((filter) => {
19745
+ const active = filter.key === activeFilter;
19746
+ return /* @__PURE__ */ (0, import_jsx_runtime228.jsx)(
19747
+ "button",
19748
+ {
19749
+ type: "button",
19750
+ "data-active": active || void 0,
19751
+ className: cn(
19752
+ "cursor-pointer rounded-full px-3 py-1 text-xs",
19753
+ active ? "bg-primary text-primary-foreground" : "bg-background"
19754
+ ),
19755
+ onClick: () => onFilterChange(filter.key),
19756
+ children: filter.label
19757
+ },
19758
+ filter.key
19759
+ );
19760
+ }) }) : null,
19761
+ !selecting && processingText !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime228.jsxs)(
19762
+ "button",
19763
+ {
19764
+ type: "button",
19765
+ "data-slot": "recording-page-processing",
19766
+ className: "flex cursor-pointer items-center gap-2 rounded-lg bg-background p-3 text-left",
19767
+ onClick: () => onProcessingClick?.(),
19768
+ children: [
19769
+ /* @__PURE__ */ (0, import_jsx_runtime228.jsx)(Icon, { name: "audio-lines", size: 18 }),
19770
+ /* @__PURE__ */ (0, import_jsx_runtime228.jsxs)("div", { className: "flex flex-1 flex-col", children: [
19771
+ /* @__PURE__ */ (0, import_jsx_runtime228.jsx)(Text, { text: processingText, size: "small", strong: true }),
19772
+ processingHint !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime228.jsx)(Text, { text: processingHint, size: "small", type: "secondary" }) : null
19773
+ ] }),
19774
+ /* @__PURE__ */ (0, import_jsx_runtime228.jsx)(Icon, { name: "chevron-right", size: 16, className: "text-muted-foreground" })
19775
+ ]
19776
+ }
19777
+ ) : null,
19778
+ !selecting && newRecordingLabel !== null && newRecordingLabel !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime228.jsx)(
19779
+ Button2,
19780
+ {
19781
+ text: newRecordingLabel,
19782
+ icon: "mic",
19783
+ variant: "primary",
19784
+ className: "w-full",
19785
+ onClick: () => onNewRecording?.()
19786
+ }
19787
+ ) : null,
19788
+ /* @__PURE__ */ (0, import_jsx_runtime228.jsx)(
19789
+ "div",
19790
+ {
19791
+ "data-slot": "recording-page-groups",
19792
+ className: "scrollbar-subtle flex min-h-0 flex-1 flex-col gap-3 overflow-y-auto",
19793
+ children: groups.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime228.jsx)(Empty2, { title: emptyText }) : groups.map((group, groupIndex) => /* @__PURE__ */ (0, import_jsx_runtime228.jsxs)("div", { className: "flex flex-col gap-1", children: [
19794
+ /* @__PURE__ */ (0, import_jsx_runtime228.jsx)(Text, { text: group.label, size: "small", type: "secondary", className: "px-1" }),
19795
+ group.items.map(renderRecordingItem)
19796
+ ] }, group.key ?? group.label ?? groupIndex))
19797
+ }
19798
+ ),
19799
+ selecting ? /* @__PURE__ */ (0, import_jsx_runtime228.jsxs)(import_jsx_runtime228.Fragment, { children: [
19800
+ /* @__PURE__ */ (0, import_jsx_runtime228.jsx)(
19801
+ Button2,
19802
+ {
19803
+ text: deleteLabel ?? "\u5220\u9664",
19804
+ variant: "primary",
19805
+ danger: true,
19806
+ className: "w-full shrink-0",
19807
+ onClick: () => setDeleteConfirmOpen(true)
19808
+ }
19809
+ ),
19810
+ /* @__PURE__ */ (0, import_jsx_runtime228.jsx)(AlertDialog, { open: deleteConfirmOpen, onOpenChange: setDeleteConfirmOpen, children: /* @__PURE__ */ (0, import_jsx_runtime228.jsxs)(AlertDialogContent, { "data-slot": "recording-delete-confirm", children: [
19811
+ /* @__PURE__ */ (0, import_jsx_runtime228.jsxs)(AlertDialogHeader, { children: [
19812
+ /* @__PURE__ */ (0, import_jsx_runtime228.jsx)(AlertDialogTitle, { children: deleteConfirmTitle ?? "\u5220\u9664\u5F55\u97F3" }),
19813
+ /* @__PURE__ */ (0, import_jsx_runtime228.jsx)(AlertDialogDescription, { children: (deleteConfirmText ?? "\u786E\u5B9A\u5220\u9664\u9009\u4E2D\u7684 {count} \u6761\u5F55\u97F3\u5417\uFF1F\u5220\u9664\u540E\u4E0D\u53EF\u6062\u590D\u3002").replace("{count}", String(selectedRecordingIds.length)) })
19814
+ ] }),
19815
+ /* @__PURE__ */ (0, import_jsx_runtime228.jsxs)(AlertDialogFooter, { children: [
19816
+ /* @__PURE__ */ (0, import_jsx_runtime228.jsx)(AlertDialogCancel, { children: deleteCancelLabel ?? "\u53D6\u6D88" }),
19817
+ /* @__PURE__ */ (0, import_jsx_runtime228.jsx)(
19818
+ AlertDialogAction,
19819
+ {
19820
+ variant: "destructive",
19821
+ onClick: () => onDeleteSelected?.(),
19822
+ children: deleteConfirmLabel ?? "\u5220\u9664"
19823
+ }
19824
+ )
19825
+ ] })
19826
+ ] }) })
19827
+ ] }) : null
19828
+ ]
19829
+ }
19830
+ );
19831
+ }
19832
+
19833
+ // src/components/business/RecordingPage/index.tsx
19834
+ var import_jsx_runtime229 = require("react/jsx-runtime");
19835
+ function RecordingPage({
19836
+ listTitle = "\u5F55\u97F3\u8BB0\u5F55\u5217\u8868",
19837
+ selectLabel,
19838
+ selectDoneLabel,
19839
+ selectAllLabel,
19840
+ selectedCountText,
19841
+ deleteLabel,
19842
+ deleteConfirmTitle,
19843
+ deleteConfirmText,
19844
+ deleteCancelLabel,
19845
+ deleteConfirmLabel,
19846
+ selectedRecordingIds,
19847
+ defaultSelectedRecordingIds,
19848
+ onRecordingSelectionChange,
19849
+ onDeleteRecordings,
19850
+ onSelectClick,
19851
+ filters = [],
19852
+ activeFilterKey,
19853
+ defaultActiveFilterKey,
19854
+ onFilterChange,
19855
+ processingText,
19856
+ processingHint,
19857
+ onProcessingClick,
19858
+ newRecordingLabel = "\u5F00\u59CB\u65B0\u5F55\u97F3",
19859
+ onNewRecording,
19860
+ groups = [],
19861
+ activeRecordingId,
19862
+ defaultActiveRecordingId,
19863
+ onSelectRecording,
19864
+ listWidth = 300,
19865
+ emptyText = "\u6682\u65E0\u5F55\u97F3",
19866
+ title,
19867
+ meta,
19868
+ editLabel,
19869
+ shareLabel,
19870
+ shareOptions,
19871
+ shareSelectedKeys,
19872
+ defaultShareSelectedKeys,
19873
+ sharePopoverTitle,
19874
+ shareCancelLabel,
19875
+ shareConfirmLabel,
19876
+ shareDialogTitle,
19877
+ shareLink,
19878
+ shareCopyLinkLabel,
19879
+ shareCopiedLabel,
19880
+ shareMailLabel,
19881
+ shareSystemLabel,
19882
+ onShareConfirm,
19883
+ onShareChannel,
19884
+ onEdit,
19885
+ onShare,
19886
+ tabs = [],
19887
+ activeTabKey,
19888
+ defaultActiveTabKey,
19889
+ onTabChange,
19890
+ transcriptTabKey = "transcript",
19891
+ segments = [],
19892
+ speakers,
19893
+ speakerDialogTitle,
19894
+ speakerDialogHint,
19895
+ speakerInputPlaceholder,
19896
+ speakerApplyLabel,
19897
+ onSpeakerChange,
19898
+ summary,
19899
+ summaryTabKey = "summary",
19900
+ onMindmapAction,
19901
+ onMaterialClick,
19902
+ onTodoClick,
19903
+ selectedTodoIds,
19904
+ defaultSelectedTodoIds,
19905
+ onTodoSelectionChange,
19906
+ onSummaryAction,
19907
+ insight,
19908
+ insightTabKey = "ai",
19909
+ onPerspectiveEdit,
19910
+ onPerspectiveApply,
19911
+ onInsightAction,
19912
+ memory,
19913
+ memoryTabKey = "knowledge",
19914
+ onMemoryAction,
19915
+ translation,
19916
+ translationTabKey = "translation",
19917
+ onLanguageClick,
19918
+ onLanguageChange,
19919
+ onTranslationAction,
19920
+ player,
19921
+ onPlay,
19922
+ onSkipBack,
19923
+ onSkipForward,
19924
+ className,
19925
+ style
19926
+ }) {
19927
+ const filterControlled = activeFilterKey !== void 0;
19928
+ const [innerFilter, setInnerFilter] = (0, import_react81.useState)(
19929
+ defaultActiveFilterKey ?? filters[0]?.key
19930
+ );
19931
+ const activeFilter = filterControlled ? activeFilterKey : innerFilter;
19932
+ const setActiveFilter = (next) => {
19933
+ if (!filterControlled) setInnerFilter(next);
19934
+ onFilterChange?.(next);
19935
+ };
19936
+ const recControlled = activeRecordingId !== void 0;
19937
+ const [innerRec, setInnerRec] = (0, import_react81.useState)(defaultActiveRecordingId);
19938
+ const activeRec = recControlled ? activeRecordingId : innerRec;
19939
+ const setActiveRec = (next) => {
19940
+ if (!recControlled) setInnerRec(next);
19941
+ onSelectRecording?.(next);
19942
+ };
19943
+ const tabControlled = activeTabKey !== void 0;
19944
+ const [innerTab, setInnerTab] = (0, import_react81.useState)(defaultActiveTabKey ?? tabs[0]?.key);
19945
+ const activeTab = tabControlled ? activeTabKey : innerTab;
19946
+ const setActiveTab = (next) => {
19947
+ if (!tabControlled) setInnerTab(next);
19948
+ onTabChange?.(next);
19949
+ };
19950
+ const todoControlled = selectedTodoIds !== void 0;
19951
+ const [innerTodos, setInnerTodos] = (0, import_react81.useState)(
19952
+ () => defaultSelectedTodoIds ?? (summary?.todos ?? []).flatMap(
19953
+ (todo, index) => todo.done === true ? [todo.id ?? index] : []
19954
+ )
19955
+ );
19956
+ const selectedTodos = todoControlled ? selectedTodoIds : innerTodos;
19957
+ const toggleTodo = (id) => {
19958
+ const next = selectedTodos.includes(id) ? selectedTodos.filter((item) => item !== id) : [...selectedTodos, id];
19959
+ if (!todoControlled) setInnerTodos(next);
19960
+ onTodoClick?.(id);
19961
+ onTodoSelectionChange?.(next);
19962
+ };
19963
+ const shareControlled = shareSelectedKeys !== void 0;
19964
+ const [innerShareKeys, setInnerShareKeys] = (0, import_react81.useState)(
19965
+ () => defaultShareSelectedKeys ?? (shareOptions ?? []).map((option) => option.key)
19966
+ );
19967
+ const shareKeys = shareControlled ? shareSelectedKeys : innerShareKeys;
19968
+ const commitShareKeys = (next) => {
19969
+ if (!shareControlled) setInnerShareKeys(next);
19970
+ };
19971
+ const [selecting, setSelecting] = (0, import_react81.useState)(false);
19972
+ const recSelControlled = selectedRecordingIds !== void 0;
19973
+ const [innerSelectedRecs, setInnerSelectedRecs] = (0, import_react81.useState)(
19974
+ () => defaultSelectedRecordingIds ?? []
19975
+ );
19976
+ const selectedRecs = recSelControlled ? selectedRecordingIds : innerSelectedRecs;
19977
+ const commitSelectedRecs = (next) => {
19978
+ if (!recSelControlled) setInnerSelectedRecs(next);
19979
+ onRecordingSelectionChange?.(next);
19980
+ };
19981
+ const allRecordingIds = groups.flatMap((group) => group.items.map((item) => item.id));
19982
+ const toggleRecordingSelect = (id) => {
19983
+ commitSelectedRecs(
19984
+ selectedRecs.includes(id) ? selectedRecs.filter((item) => item !== id) : [...selectedRecs, id]
19985
+ );
19986
+ };
19987
+ const toggleSelectAll = () => {
19988
+ commitSelectedRecs(
19989
+ selectedRecs.length === allRecordingIds.length ? [] : allRecordingIds
19990
+ );
19991
+ };
19992
+ return /* @__PURE__ */ (0, import_jsx_runtime229.jsxs)(
19993
+ "div",
19994
+ {
19995
+ "data-slot": "recording-page",
19996
+ className: cn("flex h-full w-full min-h-0 items-stretch", className),
19997
+ style,
19998
+ children: [
19999
+ /* @__PURE__ */ (0, import_jsx_runtime229.jsx)(
20000
+ RecordingList,
20001
+ {
20002
+ listTitle,
20003
+ selectLabel,
20004
+ selectDoneLabel,
20005
+ selectAllLabel,
20006
+ selectedCountText,
20007
+ deleteLabel,
20008
+ deleteConfirmTitle,
20009
+ deleteConfirmText,
20010
+ deleteCancelLabel,
20011
+ deleteConfirmLabel,
20012
+ selecting,
20013
+ selectedRecordingIds: selectedRecs,
20014
+ onEnterSelectMode: () => {
20015
+ setSelecting(true);
20016
+ onSelectClick?.();
20017
+ },
20018
+ onExitSelectMode: () => setSelecting(false),
20019
+ onToggleRecordingSelect: toggleRecordingSelect,
20020
+ onToggleSelectAll: toggleSelectAll,
20021
+ onDeleteSelected: () => onDeleteRecordings?.(selectedRecs),
20022
+ filters,
20023
+ activeFilter,
20024
+ onFilterChange: setActiveFilter,
20025
+ processingText,
20026
+ processingHint,
20027
+ onProcessingClick,
20028
+ newRecordingLabel,
20029
+ onNewRecording,
20030
+ groups,
20031
+ activeRecordingId: activeRec,
20032
+ onSelectRecording: setActiveRec,
20033
+ listWidth,
20034
+ emptyText
20035
+ }
20036
+ ),
20037
+ /* @__PURE__ */ (0, import_jsx_runtime229.jsx)(
20038
+ RecordingDetail,
20039
+ {
20040
+ title,
20041
+ meta,
20042
+ editLabel,
20043
+ shareLabel,
20044
+ shareOptions,
20045
+ shareSelectedKeys: shareKeys,
20046
+ sharePopoverTitle,
20047
+ shareCancelLabel,
20048
+ shareConfirmLabel,
20049
+ shareDialogTitle,
20050
+ shareLink,
20051
+ shareCopyLinkLabel,
20052
+ shareCopiedLabel,
20053
+ shareMailLabel,
20054
+ shareSystemLabel,
20055
+ onShareSelectionCommit: commitShareKeys,
20056
+ onShareConfirm,
20057
+ onShareChannel,
20058
+ onEdit,
20059
+ onShare,
20060
+ tabs,
20061
+ activeTab,
20062
+ onTabChange: setActiveTab,
20063
+ transcriptTabKey,
20064
+ segments,
20065
+ speakers,
20066
+ speakerDialogTitle,
20067
+ speakerDialogHint,
20068
+ speakerInputPlaceholder,
20069
+ speakerApplyLabel,
20070
+ onSpeakerChange,
20071
+ summary,
20072
+ summaryTabKey,
20073
+ onMindmapAction,
20074
+ onMaterialClick,
20075
+ selectedTodoIds: selectedTodos,
20076
+ onTodoToggle: toggleTodo,
20077
+ onSummaryAction,
20078
+ insight,
20079
+ insightTabKey,
20080
+ onPerspectiveEdit,
20081
+ onPerspectiveApply,
20082
+ onInsightAction,
20083
+ memory,
20084
+ memoryTabKey,
20085
+ onMemoryAction,
20086
+ translation,
20087
+ translationTabKey,
20088
+ onLanguageClick,
20089
+ onLanguageChange,
20090
+ onTranslationAction,
20091
+ player,
20092
+ onPlay,
20093
+ onSkipBack,
20094
+ onSkipForward
20095
+ }
20096
+ )
20097
+ ]
20098
+ }
20099
+ );
20100
+ }
20101
+
20102
+ // src/components/business/RuleConfig/index.tsx
20103
+ var import_lucide_react43 = require("lucide-react");
20104
+ var import_react82 = require("react");
20105
+ var import_jsx_runtime230 = require("react/jsx-runtime");
20106
+ var isBlank = (v) => v == null || String(v).trim() === "";
20107
+ function isValueMissing(condition) {
20108
+ const { opt, value } = condition;
20109
+ if (NO_VALUE_OPT.includes(opt)) return false;
20110
+ if (opt === "BETWEEN") {
20111
+ const [a, b] = normalizeBetweenValue(value);
20112
+ return isBlank(a) || isBlank(b);
20113
+ }
20114
+ if (Array.isArray(value)) return value.length === 0 || value.every(isBlank);
20115
+ return isBlank(value);
20116
+ }
20117
+ function getConditionIssue(condition) {
20118
+ const missingValue = isValueMissing(condition);
20119
+ const missingScore = condition.score == null || Number.isNaN(condition.score);
20120
+ if (!missingValue && !missingScore) return null;
20121
+ return { missingValue, missingScore };
20122
+ }
20123
+ var OPERATOR_VALUES = [
20124
+ "GREATER",
20125
+ "GREATER_EQUAL",
20126
+ "LESS_EQUAL",
20127
+ "LESS",
20128
+ "EQUAL",
20129
+ "IN",
20130
+ "NOT_IN",
20131
+ "UNEQUAL",
20132
+ "LIKE",
20133
+ "NULL",
20134
+ "HASVAL",
20135
+ "NOTNULL",
20136
+ "BETWEEN"
20137
+ ];
20138
+ var NUMERIC_OPT = [
20139
+ "GREATER",
20140
+ "LESS",
20141
+ "LESS_EQUAL",
20142
+ "GREATER_EQUAL",
20143
+ "UNEQUAL"
20144
+ ];
20145
+ var NO_VALUE_OPT = ["NULL", "HASVAL", "NOTNULL"];
20146
+ var MULTI_VALUE_OPT = ["IN", "NOT_IN"];
20147
+ var OPERATOR_LABELS2 = {
20148
+ GREATER: "\u5927\u4E8E",
20149
+ GREATER_EQUAL: "\u5927\u4E8E\u7B49\u4E8E",
20150
+ LESS_EQUAL: "\u5C0F\u4E8E\u7B49\u4E8E",
20151
+ LESS: "\u5C0F\u4E8E",
20152
+ EQUAL: "\u7B49\u4E8E",
20153
+ IN: "\u5305\u542B",
20154
+ NOT_IN: "\u4E0D\u5305\u542B",
20155
+ UNEQUAL: "\u4E0D\u7B49\u4E8E",
20156
+ LIKE: "\u7C7B\u4F3C",
20157
+ NULL: "\u4E3A\u7A7A",
20158
+ HASVAL: "\u6709\u503C",
20159
+ NOTNULL: "\u4E0D\u4E3A\u7A7A",
20160
+ BETWEEN: "\u8303\u56F4"
20161
+ };
20162
+ function operatorLabel2(operator) {
20163
+ return OPERATOR_LABELS2[operator] ?? operator;
20164
+ }
20165
+ var _key = 0;
20166
+ var nextKey = () => ++_key;
20167
+ var defaultCondition = () => ({ key: nextKey(), opt: "EQUAL" });
20168
+ function normalizeBetweenValue(value) {
20169
+ if (Array.isArray(value)) return [value[0], value[1]];
20170
+ if (typeof value === "string" && value.includes(",")) {
20171
+ const [a, b] = value.split(",");
20172
+ return [a?.trim(), b?.trim()];
20173
+ }
20174
+ if (value == null || value === "") return [void 0, void 0];
20175
+ return [value, void 0];
20176
+ }
20177
+ function formatConditionValue2(condition) {
20178
+ const { opt, value } = condition;
20179
+ if (value == null) return "-";
20180
+ if (opt === "BETWEEN") {
20181
+ const [a, b] = normalizeBetweenValue(value);
20182
+ return `${a ?? "-"} ~ ${b ?? "-"}`;
20183
+ }
20184
+ if (Array.isArray(value)) return value.join(", ");
20185
+ return String(value);
20186
+ }
20187
+ function RuleConfig({ value, onChange, disabled, size = "middle" }) {
20188
+ const rawConditions = value?.ruleConditions;
20189
+ const conditions = (0, import_react82.useMemo)(() => {
20190
+ if (!rawConditions?.length) return [defaultCondition()];
20191
+ const seen = /* @__PURE__ */ new Set();
20192
+ return rawConditions.map((c) => {
20193
+ if (c.key != null && !seen.has(c.key)) {
20194
+ seen.add(c.key);
20195
+ return c;
20196
+ }
20197
+ const key = nextKey();
20198
+ seen.add(key);
20199
+ return { ...c, key };
20200
+ });
20201
+ }, [rawConditions]);
20202
+ const initScore = value?.score ?? 1;
20203
+ const [scoreText, setScoreText] = (0, import_react82.useState)(String(initScore));
20204
+ const lastScoreRef = (0, import_react82.useRef)(value?.score);
20205
+ (0, import_react82.useEffect)(() => {
20206
+ if (value?.score === lastScoreRef.current) return;
20207
+ lastScoreRef.current = value?.score;
20208
+ setScoreText(value?.score == null ? "" : String(value.score));
20209
+ }, [value?.score]);
20210
+ const commitScore = (0, import_react82.useCallback)(
20211
+ (score) => {
20212
+ lastScoreRef.current = score;
20213
+ onChange?.({ score, ruleConditions: conditions });
20214
+ },
20215
+ [onChange, conditions]
20216
+ );
20217
+ const normalizeScore = (n) => Math.min(1e3, Math.max(1, Math.round(n)));
20218
+ const handleScoreTextChange = (text) => {
20219
+ setScoreText(text);
20220
+ if (text === "") return;
20221
+ const n = Number(text);
20222
+ if (Number.isFinite(n) && n >= 1 && n <= 1e3 && Number.isInteger(n)) {
20223
+ commitScore(n);
20224
+ }
20225
+ };
20226
+ const handleScoreBlur = () => {
20227
+ const n = scoreText.trim() === "" ? NaN : Number(scoreText);
20228
+ const next = Number.isFinite(n) ? normalizeScore(n) : 1;
20229
+ setScoreText(String(next));
20230
+ if (next !== lastScoreRef.current) commitScore(next);
20231
+ };
20232
+ const update = (0, import_react82.useCallback)(
20233
+ (next, nextScore) => onChange?.({
20234
+ score: nextScore ?? initScore,
20235
+ ruleConditions: next
20236
+ }),
20237
+ [onChange, initScore]
20238
+ );
20239
+ const handleOptChange = (key, opt) => {
20240
+ update(
20241
+ conditions.map(
20242
+ (c) => c.key === key ? { ...c, opt, value: opt === "BETWEEN" ? [] : void 0 } : c
20243
+ )
20244
+ );
20245
+ };
20246
+ const handleValueChange = (key, val) => {
20247
+ update(conditions.map((c) => c.key === key ? { ...c, value: val } : c));
20248
+ };
20249
+ const handleScoreChange = (key, score) => {
20250
+ update(
20251
+ conditions.map((c) => c.key === key ? { ...c, score } : c)
20252
+ );
20253
+ };
20254
+ const handleAdd = () => update([...conditions, defaultCondition()]);
20255
+ const handleDelete = (key) => update(conditions.filter((c) => c.key !== key));
20256
+ if (disabled) {
20257
+ return /* @__PURE__ */ (0, import_jsx_runtime230.jsxs)("div", { className: "space-y-2 text-sm", children: [
20258
+ /* @__PURE__ */ (0, import_jsx_runtime230.jsxs)("div", { className: "flex items-center gap-2 pb-2 border-b", children: [
20259
+ /* @__PURE__ */ (0, import_jsx_runtime230.jsx)("span", { className: "text-muted-foreground", children: "\u6743\u91CD" }),
20260
+ /* @__PURE__ */ (0, import_jsx_runtime230.jsx)("span", { className: "font-medium", children: initScore })
20261
+ ] }),
20262
+ conditions.map((condition) => /* @__PURE__ */ (0, import_jsx_runtime230.jsxs)("div", { className: "flex items-center gap-2", children: [
20263
+ /* @__PURE__ */ (0, import_jsx_runtime230.jsx)("span", { children: operatorLabel2(condition.opt) }),
20264
+ !NO_VALUE_OPT.includes(condition.opt) && /* @__PURE__ */ (0, import_jsx_runtime230.jsx)("span", { className: "font-medium", children: formatConditionValue2(condition) }),
20265
+ /* @__PURE__ */ (0, import_jsx_runtime230.jsxs)("span", { className: "text-muted-foreground", children: [
20266
+ "\u8BC4\u5206: ",
20267
+ condition.score ?? "-"
20268
+ ] })
20269
+ ] }, condition.key))
20270
+ ] });
20271
+ }
20272
+ return /* @__PURE__ */ (0, import_jsx_runtime230.jsxs)("div", { className: "space-y-2", children: [
20273
+ /* @__PURE__ */ (0, import_jsx_runtime230.jsxs)("div", { className: "flex items-center gap-1 pb-2 border-b gap-2", children: [
20274
+ /* @__PURE__ */ (0, import_jsx_runtime230.jsx)("span", { className: "text-sm shrink-0", children: "\u6743\u91CD" }),
20275
+ /* @__PURE__ */ (0, import_jsx_runtime230.jsx)(
20276
+ Input,
20277
+ {
20278
+ type: "number",
20279
+ className: cn("w-48", CONTROL_SIZE_BOX[size]),
20280
+ min: 1,
20281
+ max: 1e3,
20282
+ step: 1,
20283
+ value: scoreText,
20284
+ disabled,
20285
+ placeholder: "\u8BF7\u8F93\u5165\u6743\u91CD",
20286
+ onChange: (e) => handleScoreTextChange(e.target.value),
20287
+ onBlur: handleScoreBlur
20288
+ }
20289
+ )
18623
20290
  ] }),
18624
- conditions.map((condition) => /* @__PURE__ */ (0, import_jsx_runtime219.jsx)(
20291
+ conditions.map((condition) => /* @__PURE__ */ (0, import_jsx_runtime230.jsx)(
18625
20292
  ConditionRow2,
18626
20293
  {
18627
20294
  condition,
@@ -18636,7 +20303,7 @@ function RuleConfig({ value, onChange, disabled, size = "middle" }) {
18636
20303
  },
18637
20304
  condition.key
18638
20305
  )),
18639
- !disabled && /* @__PURE__ */ (0, import_jsx_runtime219.jsxs)(
20306
+ !disabled && /* @__PURE__ */ (0, import_jsx_runtime230.jsxs)(
18640
20307
  Button,
18641
20308
  {
18642
20309
  type: "button",
@@ -18645,7 +20312,7 @@ function RuleConfig({ value, onChange, disabled, size = "middle" }) {
18645
20312
  className: "h-auto p-0 text-sm mt-1",
18646
20313
  onClick: handleAdd,
18647
20314
  children: [
18648
- /* @__PURE__ */ (0, import_jsx_runtime219.jsx)(import_lucide_react43.Plus, { className: "h-3.5 w-3.5" }),
20315
+ /* @__PURE__ */ (0, import_jsx_runtime230.jsx)(import_lucide_react43.Plus, { className: "h-3.5 w-3.5" }),
18649
20316
  "\u6DFB\u52A0\u6761\u4EF6"
18650
20317
  ]
18651
20318
  }
@@ -18666,9 +20333,9 @@ function ConditionRow2({
18666
20333
  const { opt, value, score } = condition;
18667
20334
  const missingValue = !disabled && !!issue?.missingValue;
18668
20335
  const missingScore = !disabled && !!issue?.missingScore;
18669
- return /* @__PURE__ */ (0, import_jsx_runtime219.jsxs)("div", { className: "space-y-1", children: [
18670
- /* @__PURE__ */ (0, import_jsx_runtime219.jsxs)("div", { className: "flex items-center gap-2", children: [
18671
- /* @__PURE__ */ (0, import_jsx_runtime219.jsxs)(
20336
+ return /* @__PURE__ */ (0, import_jsx_runtime230.jsxs)("div", { className: "space-y-1", children: [
20337
+ /* @__PURE__ */ (0, import_jsx_runtime230.jsxs)("div", { className: "flex items-center gap-2", children: [
20338
+ /* @__PURE__ */ (0, import_jsx_runtime230.jsxs)(
18672
20339
  Select,
18673
20340
  {
18674
20341
  items: OPERATOR_VALUES.map((op) => ({
@@ -18679,23 +20346,23 @@ function ConditionRow2({
18679
20346
  onValueChange: (v) => onOptChange(v),
18680
20347
  disabled,
18681
20348
  children: [
18682
- /* @__PURE__ */ (0, import_jsx_runtime219.jsx)(
20349
+ /* @__PURE__ */ (0, import_jsx_runtime230.jsx)(
18683
20350
  SelectTrigger,
18684
20351
  {
18685
20352
  size: CONTROL_SIZE_SELECT_ATTR[size],
18686
20353
  className: cn("w-36 shrink-0", CONTROL_SIZE_TRIGGER_TEXT[size]),
18687
- children: /* @__PURE__ */ (0, import_jsx_runtime219.jsx)(SelectValue, {})
20354
+ children: /* @__PURE__ */ (0, import_jsx_runtime230.jsx)(SelectValue, {})
18688
20355
  }
18689
20356
  ),
18690
- /* @__PURE__ */ (0, import_jsx_runtime219.jsx)(SelectContent, { children: OPERATOR_VALUES.map((op) => /* @__PURE__ */ (0, import_jsx_runtime219.jsx)(SelectItem, { value: op, children: operatorLabel2(op) }, op)) })
20357
+ /* @__PURE__ */ (0, import_jsx_runtime230.jsx)(SelectContent, { children: OPERATOR_VALUES.map((op) => /* @__PURE__ */ (0, import_jsx_runtime230.jsx)(SelectItem, { value: op, children: operatorLabel2(op) }, op)) })
18691
20358
  ]
18692
20359
  }
18693
20360
  ),
18694
- !NO_VALUE_OPT.includes(opt) && /* @__PURE__ */ (0, import_jsx_runtime219.jsx)(
20361
+ !NO_VALUE_OPT.includes(opt) && /* @__PURE__ */ (0, import_jsx_runtime230.jsx)(
18695
20362
  "div",
18696
20363
  {
18697
20364
  className: "w-[30%]" + (missingValue ? " [&_input]:border-destructive" : ""),
18698
- children: /* @__PURE__ */ (0, import_jsx_runtime219.jsx)(
20365
+ children: /* @__PURE__ */ (0, import_jsx_runtime230.jsx)(
18699
20366
  ValueInput,
18700
20367
  {
18701
20368
  opt,
@@ -18707,7 +20374,7 @@ function ConditionRow2({
18707
20374
  )
18708
20375
  }
18709
20376
  ),
18710
- /* @__PURE__ */ (0, import_jsx_runtime219.jsx)(
20377
+ /* @__PURE__ */ (0, import_jsx_runtime230.jsx)(
18711
20378
  Input,
18712
20379
  {
18713
20380
  type: "number",
@@ -18725,7 +20392,7 @@ function ConditionRow2({
18725
20392
  )
18726
20393
  }
18727
20394
  ),
18728
- showDelete && !disabled && /* @__PURE__ */ (0, import_jsx_runtime219.jsx)(
20395
+ showDelete && !disabled && /* @__PURE__ */ (0, import_jsx_runtime230.jsx)(
18729
20396
  Button,
18730
20397
  {
18731
20398
  type: "button",
@@ -18733,11 +20400,11 @@ function ConditionRow2({
18733
20400
  size: "icon",
18734
20401
  className: "h-8 w-8 shrink-0 text-muted-foreground hover:text-destructive",
18735
20402
  onClick: onDelete,
18736
- children: /* @__PURE__ */ (0, import_jsx_runtime219.jsx)(import_lucide_react43.Trash2, { className: "h-4 w-4" })
20403
+ children: /* @__PURE__ */ (0, import_jsx_runtime230.jsx)(import_lucide_react43.Trash2, { className: "h-4 w-4" })
18737
20404
  }
18738
20405
  )
18739
20406
  ] }),
18740
- !disabled && issue && /* @__PURE__ */ (0, import_jsx_runtime219.jsx)("p", { className: "text-xs text-destructive", children: [
20407
+ !disabled && issue && /* @__PURE__ */ (0, import_jsx_runtime230.jsx)("p", { className: "text-xs text-destructive", children: [
18741
20408
  missingValue ? "\u8BF7\u586B\u5199\u53D6\u503C" : null,
18742
20409
  missingScore ? "\u8BF7\u586B\u5199\u8BC4\u5206" : null
18743
20410
  ].filter(Boolean).join("\uFF1B") })
@@ -18749,8 +20416,8 @@ function ValueInput({ opt, value, disabled, size, onChange }) {
18749
20416
  }
18750
20417
  if (opt === "BETWEEN") {
18751
20418
  const [v1, v2] = normalizeBetweenValue(value);
18752
- return /* @__PURE__ */ (0, import_jsx_runtime219.jsxs)("div", { className: "flex items-center gap-2", children: [
18753
- /* @__PURE__ */ (0, import_jsx_runtime219.jsx)(
20419
+ return /* @__PURE__ */ (0, import_jsx_runtime230.jsxs)("div", { className: "flex items-center gap-2", children: [
20420
+ /* @__PURE__ */ (0, import_jsx_runtime230.jsx)(
18754
20421
  Input,
18755
20422
  {
18756
20423
  type: "number",
@@ -18760,8 +20427,8 @@ function ValueInput({ opt, value, disabled, size, onChange }) {
18760
20427
  onChange: (e) => onChange([e.target.valueAsNumber, v2])
18761
20428
  }
18762
20429
  ),
18763
- /* @__PURE__ */ (0, import_jsx_runtime219.jsx)("span", { className: "text-muted-foreground text-sm shrink-0", children: "~" }),
18764
- /* @__PURE__ */ (0, import_jsx_runtime219.jsx)(
20430
+ /* @__PURE__ */ (0, import_jsx_runtime230.jsx)("span", { className: "text-muted-foreground text-sm shrink-0", children: "~" }),
20431
+ /* @__PURE__ */ (0, import_jsx_runtime230.jsx)(
18765
20432
  Input,
18766
20433
  {
18767
20434
  type: "number",
@@ -18774,7 +20441,7 @@ function ValueInput({ opt, value, disabled, size, onChange }) {
18774
20441
  ] });
18775
20442
  }
18776
20443
  if (MULTI_VALUE_OPT.includes(opt)) {
18777
- return /* @__PURE__ */ (0, import_jsx_runtime219.jsx)(
20444
+ return /* @__PURE__ */ (0, import_jsx_runtime230.jsx)(
18778
20445
  TagInput,
18779
20446
  {
18780
20447
  value: value ?? [],
@@ -18785,7 +20452,7 @@ function ValueInput({ opt, value, disabled, size, onChange }) {
18785
20452
  );
18786
20453
  }
18787
20454
  if (NUMERIC_OPT.includes(opt)) {
18788
- return /* @__PURE__ */ (0, import_jsx_runtime219.jsx)(
20455
+ return /* @__PURE__ */ (0, import_jsx_runtime230.jsx)(
18789
20456
  Input,
18790
20457
  {
18791
20458
  type: "number",
@@ -18796,7 +20463,7 @@ function ValueInput({ opt, value, disabled, size, onChange }) {
18796
20463
  }
18797
20464
  );
18798
20465
  }
18799
- return /* @__PURE__ */ (0, import_jsx_runtime219.jsx)(
20466
+ return /* @__PURE__ */ (0, import_jsx_runtime230.jsx)(
18800
20467
  Input,
18801
20468
  {
18802
20469
  type: "text",
@@ -18813,7 +20480,7 @@ function TagInput({
18813
20480
  size,
18814
20481
  onChange
18815
20482
  }) {
18816
- const [input, setInput] = (0, import_react76.useState)("");
20483
+ const [input, setInput] = (0, import_react82.useState)("");
18817
20484
  const addTag = () => {
18818
20485
  const tag = input.trim();
18819
20486
  if (tag && !value.includes(tag)) {
@@ -18822,7 +20489,7 @@ function TagInput({
18822
20489
  setInput("");
18823
20490
  };
18824
20491
  const removeTag = (tag) => onChange(value.filter((t) => t !== tag));
18825
- return /* @__PURE__ */ (0, import_jsx_runtime219.jsxs)(
20492
+ return /* @__PURE__ */ (0, import_jsx_runtime230.jsxs)(
18826
20493
  "div",
18827
20494
  {
18828
20495
  className: cn(
@@ -18831,9 +20498,9 @@ function TagInput({
18831
20498
  ),
18832
20499
  children: [
18833
20500
  " ",
18834
- value.map((tag) => /* @__PURE__ */ (0, import_jsx_runtime219.jsxs)(Badge, { variant: "secondary", className: "gap-1 pr-1", children: [
20501
+ value.map((tag) => /* @__PURE__ */ (0, import_jsx_runtime230.jsxs)(Badge, { variant: "secondary", className: "gap-1 pr-1", children: [
18835
20502
  tag,
18836
- !disabled && /* @__PURE__ */ (0, import_jsx_runtime219.jsx)(
20503
+ !disabled && /* @__PURE__ */ (0, import_jsx_runtime230.jsx)(
18837
20504
  "button",
18838
20505
  {
18839
20506
  type: "button",
@@ -18843,7 +20510,7 @@ function TagInput({
18843
20510
  }
18844
20511
  )
18845
20512
  ] }, tag)),
18846
- !disabled && /* @__PURE__ */ (0, import_jsx_runtime219.jsx)(
20513
+ !disabled && /* @__PURE__ */ (0, import_jsx_runtime230.jsx)(
18847
20514
  "input",
18848
20515
  {
18849
20516
  className: "flex-1 min-w-16 bg-transparent outline-none placeholder:text-muted-foreground",
@@ -18864,8 +20531,8 @@ function TagInput({
18864
20531
  }
18865
20532
 
18866
20533
  // src/components/business/RuleExpression/index.tsx
18867
- var import_react77 = require("react");
18868
- var import_jsx_runtime220 = require("react/jsx-runtime");
20534
+ var import_react83 = require("react");
20535
+ var import_jsx_runtime231 = require("react/jsx-runtime");
18869
20536
  function trailingWord(text) {
18870
20537
  const m = text.match(/[\w一-龥]+$/u);
18871
20538
  return m ? m[0] : "";
@@ -19003,11 +20670,11 @@ function RuleExpression({
19003
20670
  id,
19004
20671
  className
19005
20672
  }) {
19006
- const editorRef = (0, import_react77.useRef)(null);
19007
- const [focused, setFocused] = (0, import_react77.useState)(false);
19008
- const [activeIndex, setActiveIndex] = (0, import_react77.useState)(0);
19009
- const [matchText, setMatchText] = (0, import_react77.useState)("");
19010
- const lastEmittedRef = (0, import_react77.useRef)(null);
20673
+ const editorRef = (0, import_react83.useRef)(null);
20674
+ const [focused, setFocused] = (0, import_react83.useState)(false);
20675
+ const [activeIndex, setActiveIndex] = (0, import_react83.useState)(0);
20676
+ const [matchText, setMatchText] = (0, import_react83.useState)("");
20677
+ const lastEmittedRef = (0, import_react83.useRef)(null);
19011
20678
  const matched = matchText ? options.filter((o) => o.label.toLowerCase().includes(matchText.toLowerCase())) : [];
19012
20679
  const showSuggestions = focused && !disabled && matched.length > 0;
19013
20680
  const emitTokens = (tokens) => {
@@ -19052,7 +20719,7 @@ function RuleExpression({
19052
20719
  else ed.appendChild(document.createTextNode(t.text));
19053
20720
  }
19054
20721
  };
19055
- (0, import_react77.useLayoutEffect)(() => {
20722
+ (0, import_react83.useLayoutEffect)(() => {
19056
20723
  const sig = JSON.stringify(value ?? null);
19057
20724
  if (sig !== lastEmittedRef.current) {
19058
20725
  rebuild(seedTokens(value, options));
@@ -19155,7 +20822,7 @@ function RuleExpression({
19155
20822
  e.preventDefault();
19156
20823
  }
19157
20824
  };
19158
- return /* @__PURE__ */ (0, import_jsx_runtime220.jsxs)(
20825
+ return /* @__PURE__ */ (0, import_jsx_runtime231.jsxs)(
19159
20826
  "div",
19160
20827
  {
19161
20828
  className: cn("relative", className),
@@ -19165,7 +20832,7 @@ function RuleExpression({
19165
20832
  }
19166
20833
  },
19167
20834
  children: [
19168
- /* @__PURE__ */ (0, import_jsx_runtime220.jsx)(
20835
+ /* @__PURE__ */ (0, import_jsx_runtime231.jsx)(
19169
20836
  "div",
19170
20837
  {
19171
20838
  ref: editorRef,
@@ -19201,13 +20868,13 @@ function RuleExpression({
19201
20868
  }
19202
20869
  }
19203
20870
  ),
19204
- showSuggestions && /* @__PURE__ */ (0, import_jsx_runtime220.jsx)(
20871
+ showSuggestions && /* @__PURE__ */ (0, import_jsx_runtime231.jsx)(
19205
20872
  "ul",
19206
20873
  {
19207
20874
  role: "list",
19208
20875
  className: "absolute left-0 top-full z-50 mt-1 max-h-60 w-full overflow-auto rounded-md border bg-popover p-1 shadow-md",
19209
20876
  onMouseDown: (e) => e.preventDefault(),
19210
- children: matched.map((opt, index) => /* @__PURE__ */ (0, import_jsx_runtime220.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime220.jsx)(
20877
+ children: matched.map((opt, index) => /* @__PURE__ */ (0, import_jsx_runtime231.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime231.jsx)(
19211
20878
  "button",
19212
20879
  {
19213
20880
  type: "button",
@@ -19228,8 +20895,8 @@ function RuleExpression({
19228
20895
  }
19229
20896
 
19230
20897
  // src/components/business/ScriptEditor/index.tsx
19231
- var import_react78 = require("react");
19232
- var import_jsx_runtime221 = require("react/jsx-runtime");
20898
+ var import_react84 = require("react");
20899
+ var import_jsx_runtime232 = require("react/jsx-runtime");
19233
20900
  function escapeHtml(text) {
19234
20901
  return text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
19235
20902
  }
@@ -19296,12 +20963,12 @@ function ScriptEditor({
19296
20963
  height = 160,
19297
20964
  className
19298
20965
  }) {
19299
- const containerRef = (0, import_react78.useRef)(null);
19300
- const editorRef = (0, import_react78.useRef)(null);
19301
- const onChangeRef = (0, import_react78.useRef)(onChange);
20966
+ const containerRef = (0, import_react84.useRef)(null);
20967
+ const editorRef = (0, import_react84.useRef)(null);
20968
+ const onChangeRef = (0, import_react84.useRef)(onChange);
19302
20969
  onChangeRef.current = onChange;
19303
- const [isEmpty2, setIsEmpty] = (0, import_react78.useState)(!value);
19304
- (0, import_react78.useEffect)(() => {
20970
+ const [isEmpty2, setIsEmpty] = (0, import_react84.useState)(!value);
20971
+ (0, import_react84.useEffect)(() => {
19305
20972
  let disposed = false;
19306
20973
  (async () => {
19307
20974
  const ace = await import("ace-builds");
@@ -19339,7 +21006,7 @@ function ScriptEditor({
19339
21006
  editorRef.current = null;
19340
21007
  };
19341
21008
  }, []);
19342
- (0, import_react78.useEffect)(() => {
21009
+ (0, import_react84.useEffect)(() => {
19343
21010
  const editor = editorRef.current;
19344
21011
  if (!editor) return;
19345
21012
  const next = value ?? "";
@@ -19348,15 +21015,15 @@ function ScriptEditor({
19348
21015
  setIsEmpty(next === "");
19349
21016
  }
19350
21017
  }, [value]);
19351
- (0, import_react78.useEffect)(() => {
21018
+ (0, import_react84.useEffect)(() => {
19352
21019
  editorRef.current?.setOptions({
19353
21020
  enableBasicAutocompletion: [buildScriptCompletions(functions, variables)]
19354
21021
  });
19355
21022
  }, [functions, variables]);
19356
- (0, import_react78.useEffect)(() => {
21023
+ (0, import_react84.useEffect)(() => {
19357
21024
  editorRef.current?.setReadOnly(readonly ?? false);
19358
21025
  }, [readonly]);
19359
- return /* @__PURE__ */ (0, import_jsx_runtime221.jsxs)(
21026
+ return /* @__PURE__ */ (0, import_jsx_runtime232.jsxs)(
19360
21027
  "div",
19361
21028
  {
19362
21029
  className: cn(
@@ -19365,15 +21032,15 @@ function ScriptEditor({
19365
21032
  className
19366
21033
  ),
19367
21034
  children: [
19368
- /* @__PURE__ */ (0, import_jsx_runtime221.jsx)("div", { ref: containerRef, id, style: { height }, className: "w-full" }),
19369
- isEmpty2 && placeholder && /* @__PURE__ */ (0, import_jsx_runtime221.jsx)("div", { className: "absolute top-0 left-0 px-3 py-2 text-sm text-muted-foreground pointer-events-none z-10", children: placeholder })
21035
+ /* @__PURE__ */ (0, import_jsx_runtime232.jsx)("div", { ref: containerRef, id, style: { height }, className: "w-full" }),
21036
+ isEmpty2 && placeholder && /* @__PURE__ */ (0, import_jsx_runtime232.jsx)("div", { className: "absolute top-0 left-0 px-3 py-2 text-sm text-muted-foreground pointer-events-none z-10", children: placeholder })
19370
21037
  ]
19371
21038
  }
19372
21039
  );
19373
21040
  }
19374
21041
 
19375
21042
  // src/components/business/SiteFooter/index.tsx
19376
- var import_jsx_runtime222 = require("react/jsx-runtime");
21043
+ var import_jsx_runtime233 = require("react/jsx-runtime");
19377
21044
  function SiteFooter({
19378
21045
  brand,
19379
21046
  groups,
@@ -19385,7 +21052,7 @@ function SiteFooter({
19385
21052
  }) {
19386
21053
  const renderLink = (link) => {
19387
21054
  if (link.href) {
19388
- return /* @__PURE__ */ (0, import_jsx_runtime222.jsx)(
21055
+ return /* @__PURE__ */ (0, import_jsx_runtime233.jsx)(
19389
21056
  Link2,
19390
21057
  {
19391
21058
  href: link.href,
@@ -19394,7 +21061,7 @@ function SiteFooter({
19394
21061
  }
19395
21062
  );
19396
21063
  }
19397
- return /* @__PURE__ */ (0, import_jsx_runtime222.jsx)(
21064
+ return /* @__PURE__ */ (0, import_jsx_runtime233.jsx)(
19398
21065
  "button",
19399
21066
  {
19400
21067
  type: "button",
@@ -19411,22 +21078,22 @@ function SiteFooter({
19411
21078
  if (!hasBrand && !hasGroups && !hasBottom) {
19412
21079
  return null;
19413
21080
  }
19414
- return /* @__PURE__ */ (0, import_jsx_runtime222.jsxs)(
21081
+ return /* @__PURE__ */ (0, import_jsx_runtime233.jsxs)(
19415
21082
  "footer",
19416
21083
  {
19417
21084
  "data-slot": "site-footer",
19418
21085
  className: cn("border-t bg-muted/40", className),
19419
21086
  style,
19420
21087
  children: [
19421
- hasBrand || hasGroups ? /* @__PURE__ */ (0, import_jsx_runtime222.jsxs)(
21088
+ hasBrand || hasGroups ? /* @__PURE__ */ (0, import_jsx_runtime233.jsxs)(
19422
21089
  "div",
19423
21090
  {
19424
21091
  "data-slot": "site-footer-main",
19425
21092
  className: "mx-auto flex w-full max-w-6xl flex-col gap-8 px-6 py-10 md:flex-row md:justify-between",
19426
21093
  children: [
19427
- hasBrand ? /* @__PURE__ */ (0, import_jsx_runtime222.jsxs)("div", { "data-slot": "site-footer-brand", className: "flex max-w-xs flex-col gap-3", children: [
19428
- brand.logo || brand.name ? /* @__PURE__ */ (0, import_jsx_runtime222.jsxs)("div", { className: "flex items-center gap-2", children: [
19429
- brand.logo ? /* @__PURE__ */ (0, import_jsx_runtime222.jsx)(
21094
+ hasBrand ? /* @__PURE__ */ (0, import_jsx_runtime233.jsxs)("div", { "data-slot": "site-footer-brand", className: "flex max-w-xs flex-col gap-3", children: [
21095
+ brand.logo || brand.name ? /* @__PURE__ */ (0, import_jsx_runtime233.jsxs)("div", { className: "flex items-center gap-2", children: [
21096
+ brand.logo ? /* @__PURE__ */ (0, import_jsx_runtime233.jsx)(
19430
21097
  "img",
19431
21098
  {
19432
21099
  src: brand.logo,
@@ -19434,23 +21101,23 @@ function SiteFooter({
19434
21101
  className: "size-8 rounded-md object-contain"
19435
21102
  }
19436
21103
  ) : null,
19437
- brand.name ? /* @__PURE__ */ (0, import_jsx_runtime222.jsx)("span", { className: "text-base font-semibold", children: brand.name }) : null
21104
+ brand.name ? /* @__PURE__ */ (0, import_jsx_runtime233.jsx)("span", { className: "text-base font-semibold", children: brand.name }) : null
19438
21105
  ] }) : null,
19439
- brand.description ? /* @__PURE__ */ (0, import_jsx_runtime222.jsx)("p", { className: "text-sm leading-relaxed text-muted-foreground", children: brand.description }) : null
21106
+ brand.description ? /* @__PURE__ */ (0, import_jsx_runtime233.jsx)("p", { className: "text-sm leading-relaxed text-muted-foreground", children: brand.description }) : null
19440
21107
  ] }) : null,
19441
- hasGroups ? /* @__PURE__ */ (0, import_jsx_runtime222.jsx)(
21108
+ hasGroups ? /* @__PURE__ */ (0, import_jsx_runtime233.jsx)(
19442
21109
  "div",
19443
21110
  {
19444
21111
  "data-slot": "site-footer-groups",
19445
21112
  className: "grid flex-1 grid-cols-2 gap-8 sm:grid-cols-3 md:justify-items-end",
19446
- children: groups.map((group) => /* @__PURE__ */ (0, import_jsx_runtime222.jsxs)(
21113
+ children: groups.map((group) => /* @__PURE__ */ (0, import_jsx_runtime233.jsxs)(
19447
21114
  "div",
19448
21115
  {
19449
21116
  "data-slot": "site-footer-group",
19450
21117
  className: "flex min-w-24 flex-col gap-3",
19451
21118
  children: [
19452
- /* @__PURE__ */ (0, import_jsx_runtime222.jsx)("span", { className: "text-sm font-medium", children: group.title }),
19453
- /* @__PURE__ */ (0, import_jsx_runtime222.jsx)("div", { className: "flex flex-col gap-2", children: group.links.map((link) => /* @__PURE__ */ (0, import_jsx_runtime222.jsx)("div", { children: renderLink(link) }, link.text)) })
21119
+ /* @__PURE__ */ (0, import_jsx_runtime233.jsx)("span", { className: "text-sm font-medium", children: group.title }),
21120
+ /* @__PURE__ */ (0, import_jsx_runtime233.jsx)("div", { className: "flex flex-col gap-2", children: group.links.map((link) => /* @__PURE__ */ (0, import_jsx_runtime233.jsx)("div", { children: renderLink(link) }, link.text)) })
19454
21121
  ]
19455
21122
  },
19456
21123
  group.title
@@ -19460,9 +21127,9 @@ function SiteFooter({
19460
21127
  ]
19461
21128
  }
19462
21129
  ) : null,
19463
- hasBottom ? /* @__PURE__ */ (0, import_jsx_runtime222.jsx)("div", { "data-slot": "site-footer-bottom", className: "border-t", children: /* @__PURE__ */ (0, import_jsx_runtime222.jsxs)("div", { className: "mx-auto flex w-full max-w-6xl flex-col items-center gap-2 px-6 py-4 text-xs text-muted-foreground sm:flex-row sm:justify-between", children: [
19464
- copyright ? /* @__PURE__ */ (0, import_jsx_runtime222.jsx)("span", { children: copyright }) : /* @__PURE__ */ (0, import_jsx_runtime222.jsx)("span", {}),
19465
- bottomLinks && bottomLinks.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime222.jsx)("div", { "data-slot": "site-footer-bottom-links", className: "flex items-center gap-4", children: bottomLinks.map((link) => /* @__PURE__ */ (0, import_jsx_runtime222.jsx)("div", { children: renderLink(link) }, link.text)) }) : null
21130
+ hasBottom ? /* @__PURE__ */ (0, import_jsx_runtime233.jsx)("div", { "data-slot": "site-footer-bottom", className: "border-t", children: /* @__PURE__ */ (0, import_jsx_runtime233.jsxs)("div", { className: "mx-auto flex w-full max-w-6xl flex-col items-center gap-2 px-6 py-4 text-xs text-muted-foreground sm:flex-row sm:justify-between", children: [
21131
+ copyright ? /* @__PURE__ */ (0, import_jsx_runtime233.jsx)("span", { children: copyright }) : /* @__PURE__ */ (0, import_jsx_runtime233.jsx)("span", {}),
21132
+ bottomLinks && bottomLinks.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime233.jsx)("div", { "data-slot": "site-footer-bottom-links", className: "flex items-center gap-4", children: bottomLinks.map((link) => /* @__PURE__ */ (0, import_jsx_runtime233.jsx)("div", { children: renderLink(link) }, link.text)) }) : null
19466
21133
  ] }) }) : null
19467
21134
  ]
19468
21135
  }
@@ -19642,6 +21309,7 @@ var builtinComponents = {
19642
21309
  Login,
19643
21310
  EntityCard,
19644
21311
  CardList,
21312
+ RecordingPage,
19645
21313
  SiteFooter,
19646
21314
  // 业务表单类组件(value/onChange 受控;DSL 用 props.value + events.onChange 读写 ${event})
19647
21315
  SearchableSelect,
@@ -19781,6 +21449,7 @@ function createComponentRegistry() {
19781
21449
  RadioGroup,
19782
21450
  RailTooltip,
19783
21451
  Rate,
21452
+ RecordingPage,
19784
21453
  Resizable,
19785
21454
  Result,
19786
21455
  RichText,