@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.
@@ -2,7 +2,7 @@ import {
2
2
  Icon,
3
3
  Menu,
4
4
  Sidebar
5
- } from "./chunk-PWXXEJ4J.js";
5
+ } from "./chunk-QIOYKSN4.js";
6
6
  import {
7
7
  Alert,
8
8
  AlertDescription,
@@ -140,7 +140,7 @@ import {
140
140
  Typography,
141
141
  navigationMenuTriggerStyle,
142
142
  toast
143
- } from "./chunk-XMWIT53K.js";
143
+ } from "./chunk-T3TGKYAB.js";
144
144
  import {
145
145
  Dialog,
146
146
  DialogContent,
@@ -153,7 +153,7 @@ import {
153
153
  DrawerFooter,
154
154
  DrawerHeader,
155
155
  DrawerTitle
156
- } from "./chunk-HAOAXDTW.js";
156
+ } from "./chunk-YVHPJHW3.js";
157
157
  import {
158
158
  Accordion,
159
159
  AccordionContent,
@@ -176,7 +176,7 @@ import {
176
176
  Tooltip,
177
177
  TooltipContent,
178
178
  TooltipTrigger
179
- } from "./chunk-IBMIQXOM.js";
179
+ } from "./chunk-7OBUSV5S.js";
180
180
  import {
181
181
  Button,
182
182
  buttonVariants,
@@ -10623,6 +10623,7 @@ function ChatPage({
10623
10623
  artifactOpen,
10624
10624
  defaultArtifactOpen = false,
10625
10625
  onArtifactOpenChange,
10626
+ content,
10626
10627
  className,
10627
10628
  style
10628
10629
  }) {
@@ -10876,7 +10877,7 @@ function ChatPage({
10876
10877
  "div",
10877
10878
  {
10878
10879
  "data-slot": "chat-page-menu",
10879
- className: "flex h-full w-[264px] shrink-0 flex-col gap-2 overflow-hidden border-r border-border px-2 py-3",
10880
+ className: "flex h-full w-[250px] shrink-0 flex-col gap-2 overflow-hidden border-r border-border px-2 py-3",
10880
10881
  children: [
10881
10882
  brand ? /* @__PURE__ */ jsxs92("div", { className: "flex shrink-0 items-center justify-between px-2", children: [
10882
10883
  /* @__PURE__ */ jsxs92("div", { className: "flex flex-col gap-0.5", children: [
@@ -10959,7 +10960,7 @@ function ChatPage({
10959
10960
  ]
10960
10961
  }
10961
10962
  ),
10962
- /* @__PURE__ */ jsx133("div", { className: "@container h-full min-w-0 flex-1", children: open || activePanelItem ? /* @__PURE__ */ jsxs92(PanelGroup, { orientation: "horizontal", style: { width: "100%", height: "100%" }, children: [
10963
+ /* @__PURE__ */ jsx133("div", { className: "@container h-full min-w-0 flex-1", children: content !== void 0 ? renderSlot(content) : open || activePanelItem ? /* @__PURE__ */ jsxs92(PanelGroup, { orientation: "horizontal", style: { width: "100%", height: "100%" }, children: [
10963
10964
  /* @__PURE__ */ jsx133(Panel, { defaultSize: "62%", children: chatArea }),
10964
10965
  /* @__PURE__ */ jsx133(ResizableHandle, { withHandle: true }),
10965
10966
  /* @__PURE__ */ jsx133(Panel, { defaultSize: "38%", minSize: "380px", maxSize: "760px", children: activePanelItem ? /* @__PURE__ */ jsx133(
@@ -14156,196 +14157,1856 @@ function Login({
14156
14157
  );
14157
14158
  }
14158
14159
 
14159
- // src/components/business/RuleConfig/index.tsx
14160
- import { Plus as Plus2, Trash2 } from "lucide-react";
14161
- import { useCallback as useCallback5, useEffect as useEffect43, useMemo as useMemo11, useRef as useRef16, useState as useState51 } from "react";
14160
+ // src/components/business/RecordingPage/index.tsx
14161
+ import { useState as useState56 } from "react";
14162
+
14163
+ // src/components/business/RecordingPage/detail.tsx
14164
+ import { useRenderer as useRenderer22 } from "@pactor-app/runtime";
14165
+ import { isValidElement as isValidElement4, useEffect as useEffect43, useRef as useRef16, useState as useState54 } from "react";
14166
+
14167
+ // src/components/business/RecordingPage/insight.tsx
14168
+ import { useState as useState51 } from "react";
14169
+
14170
+ // src/components/business/RecordingPage/perspective-dialog.tsx
14162
14171
  import { jsx as jsx161, jsxs as jsxs103 } from "react/jsx-runtime";
14163
- var isBlank = (v) => v == null || String(v).trim() === "";
14164
- function isValueMissing(condition) {
14165
- const { opt, value } = condition;
14166
- if (NO_VALUE_OPT.includes(opt)) return false;
14167
- if (opt === "BETWEEN") {
14168
- const [a, b] = normalizeBetweenValue(value);
14169
- return isBlank(a) || isBlank(b);
14170
- }
14171
- if (Array.isArray(value)) return value.length === 0 || value.every(isBlank);
14172
- return isBlank(value);
14173
- }
14174
- function getConditionIssue(condition) {
14175
- const missingValue = isValueMissing(condition);
14176
- const missingScore = condition.score == null || Number.isNaN(condition.score);
14177
- if (!missingValue && !missingScore) return null;
14178
- return { missingValue, missingScore };
14172
+ function RecordingPerspectiveDialog({
14173
+ open,
14174
+ title,
14175
+ hint,
14176
+ value,
14177
+ placeholder,
14178
+ cancelLabel,
14179
+ confirmLabel,
14180
+ onChange,
14181
+ onCancel,
14182
+ onConfirm
14183
+ }) {
14184
+ return /* @__PURE__ */ jsx161(
14185
+ Dialog,
14186
+ {
14187
+ open,
14188
+ onOpenChange: (next) => {
14189
+ if (!next) onCancel();
14190
+ },
14191
+ children: /* @__PURE__ */ jsxs103(
14192
+ DialogContent,
14193
+ {
14194
+ "data-slot": "recording-perspective-dialog",
14195
+ className: "gap-4 sm:max-w-xl",
14196
+ children: [
14197
+ /* @__PURE__ */ jsx161(DialogTitle, { children: title }),
14198
+ hint !== void 0 ? /* @__PURE__ */ jsx161(DialogDescription, { children: hint }) : null,
14199
+ /* @__PURE__ */ jsx161(
14200
+ Textarea2,
14201
+ {
14202
+ value,
14203
+ placeholder,
14204
+ rows: 4,
14205
+ onChange
14206
+ }
14207
+ ),
14208
+ /* @__PURE__ */ jsxs103("div", { className: "flex items-center justify-end gap-2", children: [
14209
+ /* @__PURE__ */ jsx161(Button2, { text: cancelLabel, onClick: onCancel }),
14210
+ /* @__PURE__ */ jsx161(Button2, { text: confirmLabel, variant: "primary", onClick: onConfirm })
14211
+ ] })
14212
+ ]
14213
+ }
14214
+ )
14215
+ }
14216
+ );
14179
14217
  }
14180
- var OPERATOR_VALUES = [
14181
- "GREATER",
14182
- "GREATER_EQUAL",
14183
- "LESS_EQUAL",
14184
- "LESS",
14185
- "EQUAL",
14186
- "IN",
14187
- "NOT_IN",
14188
- "UNEQUAL",
14189
- "LIKE",
14190
- "NULL",
14191
- "HASVAL",
14192
- "NOTNULL",
14193
- "BETWEEN"
14194
- ];
14195
- var NUMERIC_OPT = [
14196
- "GREATER",
14197
- "LESS",
14198
- "LESS_EQUAL",
14199
- "GREATER_EQUAL",
14200
- "UNEQUAL"
14201
- ];
14202
- var NO_VALUE_OPT = ["NULL", "HASVAL", "NOTNULL"];
14203
- var MULTI_VALUE_OPT = ["IN", "NOT_IN"];
14204
- var OPERATOR_LABELS2 = {
14205
- GREATER: "\u5927\u4E8E",
14206
- GREATER_EQUAL: "\u5927\u4E8E\u7B49\u4E8E",
14207
- LESS_EQUAL: "\u5C0F\u4E8E\u7B49\u4E8E",
14208
- LESS: "\u5C0F\u4E8E",
14209
- EQUAL: "\u7B49\u4E8E",
14210
- IN: "\u5305\u542B",
14211
- NOT_IN: "\u4E0D\u5305\u542B",
14212
- UNEQUAL: "\u4E0D\u7B49\u4E8E",
14213
- LIKE: "\u7C7B\u4F3C",
14214
- NULL: "\u4E3A\u7A7A",
14215
- HASVAL: "\u6709\u503C",
14216
- NOTNULL: "\u4E0D\u4E3A\u7A7A",
14217
- BETWEEN: "\u8303\u56F4"
14218
- };
14219
- function operatorLabel2(operator) {
14220
- return OPERATOR_LABELS2[operator] ?? operator;
14218
+
14219
+ // src/components/business/RecordingPage/insight.tsx
14220
+ import { jsx as jsx162, jsxs as jsxs104 } from "react/jsx-runtime";
14221
+ function RecordingInsightView({
14222
+ insight,
14223
+ onPerspectiveEdit,
14224
+ onPerspectiveApply,
14225
+ onInsightAction
14226
+ }) {
14227
+ const [dialogOpen, setDialogOpen] = useState51(false);
14228
+ const inputControlled = insight.perspectiveInput !== void 0;
14229
+ const [innerInput, setInnerInput] = useState51(insight.defaultPerspectiveInput);
14230
+ const committedInput = inputControlled ? insight.perspectiveInput : innerInput;
14231
+ const [draftInput, setDraftInput] = useState51(committedInput);
14232
+ const openDialog = () => {
14233
+ setDraftInput(committedInput);
14234
+ setDialogOpen(true);
14235
+ };
14236
+ const confirmDialog = () => {
14237
+ if (!inputControlled) setInnerInput(draftInput);
14238
+ onPerspectiveApply?.(draftInput ?? "");
14239
+ setDialogOpen(false);
14240
+ };
14241
+ return /* @__PURE__ */ jsxs104("div", { "data-slot": "recording-insight", className: "flex flex-col gap-6", children: [
14242
+ insight.perspectiveTitle !== void 0 ? /* @__PURE__ */ jsxs104(
14243
+ "section",
14244
+ {
14245
+ "data-slot": "recording-insight-perspective",
14246
+ className: "flex flex-col gap-2 rounded-lg bg-success/10 p-4",
14247
+ children: [
14248
+ /* @__PURE__ */ jsxs104("div", { className: "flex items-center justify-between", children: [
14249
+ /* @__PURE__ */ jsxs104("div", { className: "flex min-w-0 items-center gap-2", children: [
14250
+ /* @__PURE__ */ jsx162(Icon, { name: "user", size: 16, className: "shrink-0 text-muted-foreground" }),
14251
+ /* @__PURE__ */ jsx162(Text, { text: insight.perspectiveTitle, strong: true, className: "truncate" })
14252
+ ] }),
14253
+ insight.perspectiveActionLabel !== void 0 ? /* @__PURE__ */ jsx162(
14254
+ Button2,
14255
+ {
14256
+ text: insight.perspectiveActionLabel,
14257
+ variant: "link",
14258
+ size: "small",
14259
+ className: "text-success",
14260
+ onClick: () => {
14261
+ onPerspectiveEdit?.();
14262
+ openDialog();
14263
+ }
14264
+ }
14265
+ ) : null
14266
+ ] }),
14267
+ insight.perspectiveHint !== void 0 ? /* @__PURE__ */ jsx162(Text, { text: insight.perspectiveHint, size: "small", type: "secondary" }) : null
14268
+ ]
14269
+ }
14270
+ ) : null,
14271
+ insight.basics !== void 0 ? /* @__PURE__ */ jsxs104("section", { className: "flex flex-col gap-3", children: [
14272
+ /* @__PURE__ */ jsx162(Text, { text: insight.basicsTitle ?? "\u57FA\u7840\u4FE1\u606F", strong: true, size: "large" }),
14273
+ /* @__PURE__ */ jsx162(Text, { text: insight.basics })
14274
+ ] }) : null,
14275
+ insight.chapters !== void 0 && insight.chapters.length > 0 ? /* @__PURE__ */ jsxs104("section", { className: "flex flex-col gap-3", children: [
14276
+ /* @__PURE__ */ jsx162(Text, { text: insight.chaptersTitle ?? "\u7AE0\u8282\u901F\u89C8\u4E0E\u89E3\u8BFB", strong: true, size: "large" }),
14277
+ insight.chapters.map((chapter, index) => /* @__PURE__ */ jsxs104(
14278
+ "div",
14279
+ {
14280
+ "data-slot": "recording-insight-chapter",
14281
+ className: "flex flex-col gap-2 rounded-lg border border-border p-4",
14282
+ children: [
14283
+ /* @__PURE__ */ jsxs104("div", { className: "flex items-baseline gap-2", children: [
14284
+ chapter.time !== void 0 ? /* @__PURE__ */ jsx162(Text, { text: chapter.time, size: "small", type: "secondary" }) : null,
14285
+ /* @__PURE__ */ jsx162(Text, { text: chapter.title, strong: true, size: "small" })
14286
+ ] }),
14287
+ /* @__PURE__ */ jsx162(Text, { text: chapter.content, size: "small" })
14288
+ ]
14289
+ },
14290
+ chapter.time ?? index
14291
+ ))
14292
+ ] }) : null,
14293
+ insight.viewpoints !== void 0 && insight.viewpoints.length > 0 ? /* @__PURE__ */ jsxs104("section", { className: "flex flex-col gap-3", children: [
14294
+ /* @__PURE__ */ jsx162(Text, { text: insight.viewpointsTitle ?? "\u89C2\u70B9\u5206\u6790", strong: true, size: "large" }),
14295
+ insight.viewpoints.map((viewpoint, index) => /* @__PURE__ */ jsxs104(
14296
+ "div",
14297
+ {
14298
+ "data-slot": "recording-insight-viewpoint",
14299
+ className: "flex flex-col gap-2 rounded-lg border border-border p-4",
14300
+ children: [
14301
+ /* @__PURE__ */ jsxs104("div", { className: "flex items-center justify-between", children: [
14302
+ /* @__PURE__ */ jsxs104("div", { className: "flex items-center gap-2", children: [
14303
+ /* @__PURE__ */ jsx162(Avatar2, { fallback: viewpoint.avatarText ?? viewpoint.speaker.charAt(0) }),
14304
+ /* @__PURE__ */ jsx162(Text, { text: viewpoint.speaker, strong: true, size: "small" })
14305
+ ] }),
14306
+ viewpoint.tag !== "" ? /* @__PURE__ */ jsx162(Text, { text: viewpoint.tag ?? "\u81EA\u52A8\u8BC6\u522B", size: "small", type: "secondary" }) : null
14307
+ ] }),
14308
+ /* @__PURE__ */ jsxs104("p", { className: "text-sm", children: [
14309
+ viewpoint.label !== void 0 ? /* @__PURE__ */ jsxs104("strong", { children: [
14310
+ viewpoint.label,
14311
+ "\uFF1A"
14312
+ ] }) : null,
14313
+ viewpoint.content
14314
+ ] })
14315
+ ]
14316
+ },
14317
+ viewpoint.speaker ?? index
14318
+ ))
14319
+ ] }) : null,
14320
+ insight.actions !== void 0 && insight.actions.length > 0 ? /* @__PURE__ */ jsx162("div", { "data-slot": "recording-insight-actions", className: "flex items-center gap-1", children: insight.actions.map((action) => /* @__PURE__ */ jsx162(
14321
+ Button2,
14322
+ {
14323
+ icon: action.icon,
14324
+ variant: "text",
14325
+ size: "small",
14326
+ onClick: () => onInsightAction?.(action.key)
14327
+ },
14328
+ action.key
14329
+ )) }) : null,
14330
+ /* @__PURE__ */ jsx162(
14331
+ RecordingPerspectiveDialog,
14332
+ {
14333
+ open: dialogOpen,
14334
+ title: insight.perspectiveDialogTitle ?? "\u4FEE\u6539\u89E3\u8BFB\u8EAB\u4EFD",
14335
+ 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",
14336
+ value: draftInput,
14337
+ placeholder: insight.perspectivePlaceholder,
14338
+ cancelLabel: insight.perspectiveCancelLabel ?? "\u53D6\u6D88",
14339
+ confirmLabel: insight.perspectiveConfirmLabel ?? "\u5E94\u7528\u8EAB\u4EFD",
14340
+ onChange: setDraftInput,
14341
+ onCancel: () => setDialogOpen(false),
14342
+ onConfirm: confirmDialog
14343
+ }
14344
+ )
14345
+ ] });
14221
14346
  }
14222
- var _key = 0;
14223
- var nextKey = () => ++_key;
14224
- var defaultCondition = () => ({ key: nextKey(), opt: "EQUAL" });
14225
- function normalizeBetweenValue(value) {
14226
- if (Array.isArray(value)) return [value[0], value[1]];
14227
- if (typeof value === "string" && value.includes(",")) {
14228
- const [a, b] = value.split(",");
14229
- return [a?.trim(), b?.trim()];
14230
- }
14231
- if (value == null || value === "") return [void 0, void 0];
14232
- return [value, void 0];
14347
+
14348
+ // src/components/business/RecordingPage/memory.tsx
14349
+ import { jsx as jsx163, jsxs as jsxs105 } from "react/jsx-runtime";
14350
+ function RecordingMemoryView({ memory, onMemoryAction }) {
14351
+ return /* @__PURE__ */ jsxs105("div", { "data-slot": "recording-memory", className: "flex flex-col gap-6", children: [
14352
+ (memory.groups ?? []).map((group, groupIndex) => /* @__PURE__ */ jsxs105("section", { className: "flex flex-col gap-3", children: [
14353
+ /* @__PURE__ */ jsx163(Text, { text: `${group.label} \xB7 ${group.items.length}`, strong: true, size: "large" }),
14354
+ group.items.map((item, index) => /* @__PURE__ */ jsxs105(
14355
+ "div",
14356
+ {
14357
+ "data-slot": "recording-memory-item",
14358
+ className: "flex flex-col gap-2 rounded-lg border border-border p-4",
14359
+ children: [
14360
+ /* @__PURE__ */ jsx163(Text, { text: item.title, strong: true, size: "small" }),
14361
+ /* @__PURE__ */ jsx163(Text, { text: item.content, size: "small" })
14362
+ ]
14363
+ },
14364
+ index
14365
+ ))
14366
+ ] }, group.key ?? group.label ?? groupIndex)),
14367
+ memory.actions !== void 0 && memory.actions.length > 0 ? /* @__PURE__ */ jsx163("div", { "data-slot": "recording-memory-actions", className: "flex items-center gap-1", children: memory.actions.map((action) => /* @__PURE__ */ jsx163(
14368
+ Button2,
14369
+ {
14370
+ icon: action.icon,
14371
+ variant: "text",
14372
+ size: "small",
14373
+ onClick: () => onMemoryAction?.(action.key)
14374
+ },
14375
+ action.key
14376
+ )) }) : null
14377
+ ] });
14233
14378
  }
14234
- function formatConditionValue2(condition) {
14235
- const { opt, value } = condition;
14236
- if (value == null) return "-";
14237
- if (opt === "BETWEEN") {
14238
- const [a, b] = normalizeBetweenValue(value);
14239
- return `${a ?? "-"} ~ ${b ?? "-"}`;
14379
+
14380
+ // src/components/business/RecordingPage/share.tsx
14381
+ import { useState as useState52 } from "react";
14382
+ import { Fragment as Fragment19, jsx as jsx164, jsxs as jsxs106 } from "react/jsx-runtime";
14383
+ function copyText(text) {
14384
+ try {
14385
+ if (typeof navigator !== "undefined" && navigator.clipboard?.writeText) {
14386
+ void navigator.clipboard.writeText(text);
14387
+ return;
14388
+ }
14389
+ const textarea = document.createElement("textarea");
14390
+ textarea.value = text;
14391
+ document.body.appendChild(textarea);
14392
+ textarea.select();
14393
+ document.execCommand?.("copy");
14394
+ textarea.remove();
14395
+ } catch {
14240
14396
  }
14241
- if (Array.isArray(value)) return value.join(", ");
14242
- return String(value);
14243
14397
  }
14244
- function RuleConfig({ value, onChange, disabled, size = "middle" }) {
14245
- const rawConditions = value?.ruleConditions;
14246
- const conditions = useMemo11(() => {
14247
- if (!rawConditions?.length) return [defaultCondition()];
14248
- const seen = /* @__PURE__ */ new Set();
14249
- return rawConditions.map((c) => {
14250
- if (c.key != null && !seen.has(c.key)) {
14251
- seen.add(c.key);
14252
- return c;
14253
- }
14254
- const key = nextKey();
14255
- seen.add(key);
14256
- return { ...c, key };
14257
- });
14258
- }, [rawConditions]);
14259
- const initScore = value?.score ?? 1;
14260
- const [scoreText, setScoreText] = useState51(String(initScore));
14261
- const lastScoreRef = useRef16(value?.score);
14262
- useEffect43(() => {
14263
- if (value?.score === lastScoreRef.current) return;
14264
- lastScoreRef.current = value?.score;
14265
- setScoreText(value?.score == null ? "" : String(value.score));
14266
- }, [value?.score]);
14267
- const commitScore = useCallback5(
14268
- (score) => {
14269
- lastScoreRef.current = score;
14270
- onChange?.({ score, ruleConditions: conditions });
14271
- },
14272
- [onChange, conditions]
14273
- );
14274
- const normalizeScore = (n) => Math.min(1e3, Math.max(1, Math.round(n)));
14275
- const handleScoreTextChange = (text) => {
14276
- setScoreText(text);
14277
- if (text === "") return;
14278
- const n = Number(text);
14279
- if (Number.isFinite(n) && n >= 1 && n <= 1e3 && Number.isInteger(n)) {
14280
- commitScore(n);
14398
+ function RecordingShare({
14399
+ shareLabel,
14400
+ options,
14401
+ selectedKeys,
14402
+ popoverTitle,
14403
+ cancelLabel,
14404
+ confirmLabel,
14405
+ dialogTitle,
14406
+ link,
14407
+ copyLinkLabel,
14408
+ copiedLabel,
14409
+ mailLabel,
14410
+ systemLabel,
14411
+ onShare,
14412
+ onSelectionCommit,
14413
+ onShareConfirm,
14414
+ onShareChannel
14415
+ }) {
14416
+ const [popoverOpen, setPopoverOpen] = useState52(false);
14417
+ const [dialogOpen, setDialogOpen] = useState52(false);
14418
+ const [draftKeys, setDraftKeys] = useState52(selectedKeys);
14419
+ const [copied, setCopied] = useState52(false);
14420
+ const copyLink = () => {
14421
+ if (link !== void 0) {
14422
+ copyText(link);
14423
+ setCopied(true);
14424
+ setTimeout(() => setCopied(false), 1500);
14281
14425
  }
14426
+ onShareChannel?.("copyLink");
14282
14427
  };
14283
- const handleScoreBlur = () => {
14284
- const n = scoreText.trim() === "" ? NaN : Number(scoreText);
14285
- const next = Number.isFinite(n) ? normalizeScore(n) : 1;
14286
- setScoreText(String(next));
14287
- if (next !== lastScoreRef.current) commitScore(next);
14428
+ const openPopover = (next) => {
14429
+ if (next) {
14430
+ setDraftKeys(selectedKeys);
14431
+ onShare?.();
14432
+ }
14433
+ setPopoverOpen(next);
14288
14434
  };
14289
- const update = useCallback5(
14290
- (next, nextScore) => onChange?.({
14291
- score: nextScore ?? initScore,
14292
- ruleConditions: next
14293
- }),
14294
- [onChange, initScore]
14295
- );
14296
- const handleOptChange = (key, opt) => {
14297
- update(
14298
- conditions.map(
14299
- (c) => c.key === key ? { ...c, opt, value: opt === "BETWEEN" ? [] : void 0 } : c
14300
- )
14435
+ const toggleOption = (option) => {
14436
+ if (option.disabled === true) return;
14437
+ setDraftKeys(
14438
+ (prev) => prev.includes(option.key) ? prev.filter((key) => key !== option.key) : [...prev, option.key]
14301
14439
  );
14302
14440
  };
14303
- const handleValueChange = (key, val) => {
14304
- update(conditions.map((c) => c.key === key ? { ...c, value: val } : c));
14305
- };
14306
- const handleScoreChange = (key, score) => {
14307
- update(
14308
- conditions.map((c) => c.key === key ? { ...c, score } : c)
14309
- );
14441
+ const confirm = () => {
14442
+ const next = options.filter((option) => draftKeys.includes(option.key)).map((option) => option.key);
14443
+ onSelectionCommit(next);
14444
+ onShareConfirm?.(next);
14445
+ setPopoverOpen(false);
14446
+ setDialogOpen(true);
14310
14447
  };
14311
- const handleAdd = () => update([...conditions, defaultCondition()]);
14312
- const handleDelete = (key) => update(conditions.filter((c) => c.key !== key));
14313
- if (disabled) {
14314
- return /* @__PURE__ */ jsxs103("div", { className: "space-y-2 text-sm", children: [
14315
- /* @__PURE__ */ jsxs103("div", { className: "flex items-center gap-2 pb-2 border-b", children: [
14316
- /* @__PURE__ */ jsx161("span", { className: "text-muted-foreground", children: "\u6743\u91CD" }),
14317
- /* @__PURE__ */ jsx161("span", { className: "font-medium", children: initScore })
14318
- ] }),
14319
- conditions.map((condition) => /* @__PURE__ */ jsxs103("div", { className: "flex items-center gap-2", children: [
14320
- /* @__PURE__ */ jsx161("span", { children: operatorLabel2(condition.opt) }),
14321
- !NO_VALUE_OPT.includes(condition.opt) && /* @__PURE__ */ jsx161("span", { className: "font-medium", children: formatConditionValue2(condition) }),
14322
- /* @__PURE__ */ jsxs103("span", { className: "text-muted-foreground", children: [
14323
- "\u8BC4\u5206: ",
14324
- condition.score ?? "-"
14325
- ] })
14326
- ] }, condition.key))
14327
- ] });
14328
- }
14329
- return /* @__PURE__ */ jsxs103("div", { className: "space-y-2", children: [
14330
- /* @__PURE__ */ jsxs103("div", { className: "flex items-center gap-1 pb-2 border-b gap-2", children: [
14331
- /* @__PURE__ */ jsx161("span", { className: "text-sm shrink-0", children: "\u6743\u91CD" }),
14332
- /* @__PURE__ */ jsx161(
14333
- Input,
14448
+ const trigger = /* @__PURE__ */ jsx164(Button2, { text: shareLabel, size: "small" });
14449
+ return /* @__PURE__ */ jsxs106(Fragment19, { children: [
14450
+ /* @__PURE__ */ jsxs106(Popover, { open: popoverOpen, onOpenChange: openPopover, children: [
14451
+ /* @__PURE__ */ jsx164(
14452
+ PopoverTrigger,
14334
14453
  {
14335
- type: "number",
14336
- className: cn("w-48", CONTROL_SIZE_BOX[size]),
14337
- min: 1,
14338
- max: 1e3,
14339
- step: 1,
14340
- value: scoreText,
14341
- disabled,
14342
- placeholder: "\u8BF7\u8F93\u5165\u6743\u91CD",
14343
- onChange: (e) => handleScoreTextChange(e.target.value),
14344
- onBlur: handleScoreBlur
14454
+ nativeButton: false,
14455
+ render: /* @__PURE__ */ jsx164("span", { "data-slot": "recording-share-trigger", className: "inline-flex" }),
14456
+ children: trigger
14457
+ }
14458
+ ),
14459
+ /* @__PURE__ */ jsxs106(
14460
+ PopoverContent,
14461
+ {
14462
+ align: "end",
14463
+ sideOffset: 8,
14464
+ className: "w-64 p-0",
14465
+ "data-slot": "recording-share-popover",
14466
+ children: [
14467
+ /* @__PURE__ */ jsx164("div", { className: "px-4 pt-4 pb-2 text-sm font-semibold", children: popoverTitle }),
14468
+ /* @__PURE__ */ jsx164("div", { className: "flex flex-col px-2 pb-2", children: options.map((option) => {
14469
+ const checked = draftKeys.includes(option.key);
14470
+ const disabled = option.disabled === true;
14471
+ return /* @__PURE__ */ jsxs106(
14472
+ "button",
14473
+ {
14474
+ type: "button",
14475
+ "data-slot": "recording-share-option",
14476
+ "aria-pressed": checked,
14477
+ disabled,
14478
+ className: cn(
14479
+ "flex w-full items-center gap-2.5 rounded-md px-2 py-2 text-left text-sm",
14480
+ disabled ? "cursor-not-allowed opacity-50" : "cursor-pointer hover:bg-muted"
14481
+ ),
14482
+ onClick: () => toggleOption(option),
14483
+ children: [
14484
+ /* @__PURE__ */ jsx164(
14485
+ "span",
14486
+ {
14487
+ className: cn(
14488
+ "flex h-5 w-5 shrink-0 items-center justify-center rounded-full",
14489
+ checked ? "bg-primary text-primary-foreground" : "border border-input"
14490
+ ),
14491
+ children: checked ? /* @__PURE__ */ jsx164(Icon, { name: "check", size: 12 }) : null
14492
+ }
14493
+ ),
14494
+ option.label
14495
+ ]
14496
+ },
14497
+ option.key
14498
+ );
14499
+ }) }),
14500
+ /* @__PURE__ */ jsxs106("div", { className: "flex items-center justify-end gap-2 border-t border-border px-4 py-3", children: [
14501
+ /* @__PURE__ */ jsx164(Button2, { text: cancelLabel, variant: "text", onClick: () => setPopoverOpen(false) }),
14502
+ /* @__PURE__ */ jsx164(Button2, { text: confirmLabel, variant: "primary", onClick: confirm })
14503
+ ] })
14504
+ ]
14505
+ }
14506
+ )
14507
+ ] }),
14508
+ /* @__PURE__ */ jsx164(Dialog, { open: dialogOpen, onOpenChange: setDialogOpen, children: /* @__PURE__ */ jsxs106(DialogContent, { "data-slot": "recording-share-dialog", className: "gap-4 sm:max-w-xl", children: [
14509
+ /* @__PURE__ */ jsx164(DialogTitle, { children: dialogTitle }),
14510
+ link !== void 0 ? /* @__PURE__ */ jsxs106("div", { className: "flex items-center justify-between gap-3 rounded-lg border border-border px-4 py-3", children: [
14511
+ /* @__PURE__ */ jsx164("span", { className: "min-w-0 flex-1 truncate text-sm", children: link }),
14512
+ /* @__PURE__ */ jsx164(
14513
+ Button2,
14514
+ {
14515
+ text: copied ? copiedLabel : copyLinkLabel,
14516
+ variant: "link",
14517
+ size: "small",
14518
+ onClick: copyLink
14519
+ }
14520
+ )
14521
+ ] }) : null,
14522
+ /* @__PURE__ */ jsxs106("div", { className: "grid grid-cols-2 gap-3", children: [
14523
+ /* @__PURE__ */ jsx164(
14524
+ Button2,
14525
+ {
14526
+ text: mailLabel,
14527
+ icon: "mail",
14528
+ className: "h-12",
14529
+ onClick: () => onShareChannel?.("mail")
14530
+ }
14531
+ ),
14532
+ /* @__PURE__ */ jsx164(
14533
+ Button2,
14534
+ {
14535
+ text: systemLabel,
14536
+ icon: "share",
14537
+ className: "h-12",
14538
+ onClick: () => onShareChannel?.("system")
14539
+ }
14540
+ )
14541
+ ] })
14542
+ ] }) })
14543
+ ] });
14544
+ }
14545
+
14546
+ // src/components/business/RecordingPage/speaker-dialog.tsx
14547
+ import { jsx as jsx165, jsxs as jsxs107 } from "react/jsx-runtime";
14548
+ function RecordingSpeakerDialog({
14549
+ open,
14550
+ title,
14551
+ hint,
14552
+ speakers,
14553
+ selectedIndex,
14554
+ customName,
14555
+ inputPlaceholder,
14556
+ applyLabel,
14557
+ onSelect,
14558
+ onInputName,
14559
+ onCancel,
14560
+ onConfirm
14561
+ }) {
14562
+ const canApply = customName.trim() !== "" || selectedIndex >= 0;
14563
+ return /* @__PURE__ */ jsx165(
14564
+ Dialog,
14565
+ {
14566
+ open,
14567
+ onOpenChange: (next) => {
14568
+ if (!next) onCancel();
14569
+ },
14570
+ children: /* @__PURE__ */ jsxs107(
14571
+ DialogContent,
14572
+ {
14573
+ "data-slot": "recording-speaker-dialog",
14574
+ className: "gap-4 sm:max-w-xl",
14575
+ children: [
14576
+ /* @__PURE__ */ jsx165(DialogTitle, { children: title }),
14577
+ hint !== void 0 ? /* @__PURE__ */ jsx165(DialogDescription, { children: hint }) : null,
14578
+ speakers.length > 0 ? /* @__PURE__ */ jsx165("div", { className: "flex flex-col divide-y divide-border", children: speakers.map((speaker, index) => {
14579
+ const selected = index === selectedIndex;
14580
+ return /* @__PURE__ */ jsxs107(
14581
+ "button",
14582
+ {
14583
+ type: "button",
14584
+ "data-slot": "recording-speaker-option",
14585
+ "aria-pressed": selected,
14586
+ className: cn(
14587
+ "flex w-full cursor-pointer items-center gap-3 px-3 py-3 text-left",
14588
+ selected ? "bg-primary/10" : "hover:bg-muted"
14589
+ ),
14590
+ onClick: () => onSelect(index),
14591
+ children: [
14592
+ /* @__PURE__ */ jsx165(Avatar2, { fallback: speaker.avatarText ?? speaker.name.charAt(0) }),
14593
+ /* @__PURE__ */ jsxs107("span", { className: "flex min-w-0 flex-1 items-baseline gap-2", children: [
14594
+ /* @__PURE__ */ jsx165("span", { className: "text-sm font-medium", children: speaker.name }),
14595
+ speaker.role !== void 0 ? /* @__PURE__ */ jsx165("span", { className: "truncate text-sm text-muted-foreground", children: speaker.role }) : null
14596
+ ] }),
14597
+ speaker.tag !== void 0 ? /* @__PURE__ */ jsx165("span", { className: "shrink-0 text-sm text-muted-foreground", children: speaker.tag }) : null
14598
+ ]
14599
+ },
14600
+ `${speaker.name}-${index}`
14601
+ );
14602
+ }) }) : null,
14603
+ /* @__PURE__ */ jsx165(
14604
+ Input2,
14605
+ {
14606
+ value: customName,
14607
+ placeholder: inputPlaceholder,
14608
+ onChange: onInputName
14609
+ }
14610
+ ),
14611
+ /* @__PURE__ */ jsx165("div", { className: "flex items-center justify-end", children: /* @__PURE__ */ jsx165(
14612
+ Button2,
14613
+ {
14614
+ text: applyLabel,
14615
+ variant: "primary",
14616
+ disabled: !canApply,
14617
+ onClick: onConfirm
14618
+ }
14619
+ ) })
14620
+ ]
14621
+ }
14622
+ )
14623
+ }
14624
+ );
14625
+ }
14626
+
14627
+ // src/components/business/RecordingPage/summary.tsx
14628
+ import { jsx as jsx166, jsxs as jsxs108 } from "react/jsx-runtime";
14629
+ function MindmapPill({ label, center }) {
14630
+ return /* @__PURE__ */ jsx166(
14631
+ "span",
14632
+ {
14633
+ className: cn(
14634
+ "rounded-lg px-4 py-1.5 text-sm",
14635
+ center ? "bg-primary px-5 py-2.5 font-medium text-primary-foreground" : "border border-border bg-background"
14636
+ ),
14637
+ children: label
14638
+ }
14639
+ );
14640
+ }
14641
+ var mindmapLine = /* @__PURE__ */ jsx166("div", { className: "h-px w-10 shrink-0", style: { background: "var(--border)" } });
14642
+ function RecordingSummaryView({
14643
+ summary,
14644
+ onMindmapAction,
14645
+ onMaterialClick,
14646
+ selectedTodoIds,
14647
+ onTodoToggle,
14648
+ onSummaryAction
14649
+ }) {
14650
+ return /* @__PURE__ */ jsxs108("div", { "data-slot": "recording-summary", className: "flex flex-col gap-6", children: [
14651
+ summary.mindmap ? /* @__PURE__ */ jsxs108("section", { className: "rounded-lg border border-border", children: [
14652
+ /* @__PURE__ */ jsxs108("div", { className: "flex items-center justify-between px-4 py-3", children: [
14653
+ /* @__PURE__ */ jsx166(Text, { text: summary.mindmapTitle ?? "\u601D\u7EF4\u5BFC\u56FE", strong: true }),
14654
+ summary.mindmapActionLabel !== void 0 ? /* @__PURE__ */ jsx166(
14655
+ Button2,
14656
+ {
14657
+ text: summary.mindmapActionLabel,
14658
+ variant: "link",
14659
+ size: "small",
14660
+ className: "text-success",
14661
+ onClick: () => onMindmapAction?.()
14662
+ }
14663
+ ) : null
14664
+ ] }),
14665
+ /* @__PURE__ */ jsxs108("div", { className: "mx-4 mb-4 flex items-center justify-center rounded-lg bg-muted p-8", children: [
14666
+ /* @__PURE__ */ jsx166("div", { className: "flex flex-col items-start gap-2", children: (summary.mindmap.left ?? []).map((node) => /* @__PURE__ */ jsx166(MindmapPill, { label: node }, node)) }),
14667
+ mindmapLine,
14668
+ /* @__PURE__ */ jsx166(MindmapPill, { label: summary.mindmap.center, center: true }),
14669
+ mindmapLine,
14670
+ /* @__PURE__ */ jsx166("div", { className: "flex flex-col items-start gap-2", children: (summary.mindmap.right ?? []).map((node) => /* @__PURE__ */ jsx166(MindmapPill, { label: node }, node)) })
14671
+ ] })
14672
+ ] }) : null,
14673
+ summary.overview !== void 0 ? /* @__PURE__ */ jsxs108("section", { className: "flex flex-col gap-3", children: [
14674
+ /* @__PURE__ */ jsx166(
14675
+ Text,
14676
+ {
14677
+ text: summary.overviewTitle ?? "\u4F1A\u8BAE\u6982\u51B5",
14678
+ strong: true,
14679
+ size: "large"
14680
+ }
14681
+ ),
14682
+ /* @__PURE__ */ jsx166("div", { className: "rounded-lg bg-muted p-4", children: /* @__PURE__ */ jsx166(Text, { text: summary.overview }) })
14683
+ ] }) : null,
14684
+ summary.topics !== void 0 && summary.topics.length > 0 ? /* @__PURE__ */ jsxs108("section", { className: "flex flex-col gap-3", children: [
14685
+ /* @__PURE__ */ jsx166(Text, { text: summary.topicsTitle ?? "\u4E3B\u8981\u8BAE\u9898", strong: true, size: "large" }),
14686
+ /* @__PURE__ */ jsx166(
14687
+ "div",
14688
+ {
14689
+ className: "grid gap-3",
14690
+ style: { gridTemplateColumns: "1fr 1fr" },
14691
+ children: summary.topics.map((topic, index) => /* @__PURE__ */ jsxs108(
14692
+ "div",
14693
+ {
14694
+ className: "flex flex-col gap-2 rounded-lg border border-border p-4",
14695
+ children: [
14696
+ /* @__PURE__ */ jsx166(Text, { text: topic.title, strong: true, size: "small" }),
14697
+ /* @__PURE__ */ jsx166(Text, { text: topic.content, size: "small" })
14698
+ ]
14699
+ },
14700
+ index
14701
+ ))
14702
+ }
14703
+ )
14704
+ ] }) : null,
14705
+ summary.conclusions !== void 0 && summary.conclusions.length > 0 ? /* @__PURE__ */ jsxs108("section", { className: "rounded-lg border border-border p-4", children: [
14706
+ /* @__PURE__ */ jsx166(
14707
+ Text,
14708
+ {
14709
+ text: summary.conclusionsTitle ?? "\u8BC4\u5BA1\u7ED3\u8BBA\u4E0E\u540E\u7EED\u5B89\u6392",
14710
+ strong: true,
14711
+ size: "small"
14712
+ }
14713
+ ),
14714
+ /* @__PURE__ */ jsx166(
14715
+ Table2,
14716
+ {
14717
+ className: "mt-3",
14718
+ columns: [
14719
+ { title: "\u4E8B\u9879", dataIndex: "item" },
14720
+ { title: "\u4F1A\u8BAE\u7ED3\u8BBA", dataIndex: "conclusion" },
14721
+ { title: "\u8D1F\u8D23\u4EBA", dataIndex: "owner" }
14722
+ ],
14723
+ dataSource: summary.conclusions.map((row, index) => ({
14724
+ id: index,
14725
+ ...row
14726
+ }))
14727
+ }
14728
+ )
14729
+ ] }) : null,
14730
+ summary.followUp !== void 0 ? /* @__PURE__ */ jsxs108("section", { className: "flex flex-col gap-2 rounded-lg border border-border p-4", children: [
14731
+ /* @__PURE__ */ jsx166(Text, { text: summary.followUpTitle, strong: true, size: "small" }),
14732
+ /* @__PURE__ */ jsx166(Text, { text: summary.followUp, size: "small" })
14733
+ ] }) : null,
14734
+ summary.materials !== void 0 && summary.materials.length > 0 ? /* @__PURE__ */ jsxs108("section", { className: "flex flex-col gap-3", children: [
14735
+ /* @__PURE__ */ jsx166(
14736
+ Text,
14737
+ {
14738
+ text: summary.materialsTitle ?? "\u76F8\u5173\u6750\u6599",
14739
+ strong: true,
14740
+ size: "large"
14741
+ }
14742
+ ),
14743
+ /* @__PURE__ */ jsx166("div", { className: "flex flex-col divide-y divide-border rounded-lg border border-border", children: summary.materials.map((material, index) => /* @__PURE__ */ jsxs108(
14744
+ "button",
14745
+ {
14746
+ type: "button",
14747
+ "data-slot": "recording-material",
14748
+ className: "flex cursor-pointer items-center gap-2 px-4 py-3 text-left",
14749
+ onClick: () => onMaterialClick?.(material.id ?? index),
14750
+ children: [
14751
+ /* @__PURE__ */ jsx166(
14752
+ Icon,
14753
+ {
14754
+ name: material.icon ?? "file-text",
14755
+ size: 16,
14756
+ className: "text-muted-foreground"
14757
+ }
14758
+ ),
14759
+ /* @__PURE__ */ jsx166(
14760
+ Text,
14761
+ {
14762
+ text: material.title,
14763
+ size: "small",
14764
+ className: "min-w-0 flex-1 truncate"
14765
+ }
14766
+ ),
14767
+ /* @__PURE__ */ jsx166(
14768
+ Text,
14769
+ {
14770
+ text: material.meta,
14771
+ size: "small",
14772
+ type: "secondary",
14773
+ className: "shrink-0"
14774
+ }
14775
+ ),
14776
+ /* @__PURE__ */ jsx166(
14777
+ Icon,
14778
+ {
14779
+ name: "chevron-right",
14780
+ size: 14,
14781
+ className: "text-muted-foreground"
14782
+ }
14783
+ )
14784
+ ]
14785
+ },
14786
+ material.id ?? index
14787
+ )) })
14788
+ ] }) : null,
14789
+ summary.todos !== void 0 && summary.todos.length > 0 ? /* @__PURE__ */ jsxs108("section", { className: "flex flex-col gap-3", children: [
14790
+ /* @__PURE__ */ jsx166(Text, { text: summary.todosTitle ?? "\u5F85\u529E\u4E8B\u9879", strong: true, size: "large" }),
14791
+ /* @__PURE__ */ jsx166("div", { className: "flex flex-col divide-y divide-border rounded-lg border border-border", children: summary.todos.map((todo, index) => {
14792
+ const todoId = todo.id ?? index;
14793
+ const checked = selectedTodoIds !== void 0 ? selectedTodoIds.includes(todoId) : todo.done === true;
14794
+ return /* @__PURE__ */ jsxs108(
14795
+ "button",
14796
+ {
14797
+ type: "button",
14798
+ "data-slot": "recording-todo",
14799
+ "aria-pressed": checked,
14800
+ className: "flex cursor-pointer items-center gap-2 px-4 py-3 text-left",
14801
+ onClick: () => onTodoToggle?.(todoId),
14802
+ children: [
14803
+ checked ? /* @__PURE__ */ jsx166(
14804
+ Icon,
14805
+ {
14806
+ name: "check-circle",
14807
+ size: 16,
14808
+ className: "shrink-0 text-success"
14809
+ }
14810
+ ) : /* @__PURE__ */ jsx166(
14811
+ "span",
14812
+ {
14813
+ className: "shrink-0 rounded-full border border-border",
14814
+ style: { width: 16, height: 16 }
14815
+ }
14816
+ ),
14817
+ /* @__PURE__ */ jsx166(
14818
+ Text,
14819
+ {
14820
+ text: todo.title,
14821
+ size: "small",
14822
+ className: "min-w-0 flex-1 truncate"
14823
+ }
14824
+ ),
14825
+ /* @__PURE__ */ jsx166(
14826
+ Text,
14827
+ {
14828
+ text: todo.owner,
14829
+ size: "small",
14830
+ type: "secondary",
14831
+ className: "shrink-0"
14832
+ }
14833
+ )
14834
+ ]
14835
+ },
14836
+ todoId
14837
+ );
14838
+ }) })
14839
+ ] }) : null,
14840
+ summary.actions !== void 0 && summary.actions.length > 0 ? /* @__PURE__ */ jsx166(
14841
+ "div",
14842
+ {
14843
+ "data-slot": "recording-summary-actions",
14844
+ className: "flex items-center gap-1",
14845
+ children: summary.actions.map((action) => /* @__PURE__ */ jsx166(
14846
+ Button2,
14847
+ {
14848
+ icon: action.icon,
14849
+ variant: "text",
14850
+ size: "small",
14851
+ onClick: () => onSummaryAction?.(action.key)
14852
+ },
14853
+ action.key
14854
+ ))
14855
+ }
14856
+ ) : null
14857
+ ] });
14858
+ }
14859
+
14860
+ // src/components/business/RecordingPage/translation.tsx
14861
+ import { useState as useState53 } from "react";
14862
+
14863
+ // src/components/business/RecordingPage/language-dialog.tsx
14864
+ import { jsx as jsx167, jsxs as jsxs109 } from "react/jsx-runtime";
14865
+ function LanguageOptionItem({
14866
+ option,
14867
+ selected,
14868
+ onSelect
14869
+ }) {
14870
+ return /* @__PURE__ */ jsxs109(
14871
+ "button",
14872
+ {
14873
+ type: "button",
14874
+ "data-slot": "recording-language-option",
14875
+ "aria-pressed": selected,
14876
+ className: cn(
14877
+ "flex w-full cursor-pointer items-center gap-2.5 px-3 py-2.5 text-left text-sm",
14878
+ selected ? "bg-primary/10" : "hover:bg-muted"
14879
+ ),
14880
+ onClick: () => onSelect(option.key),
14881
+ children: [
14882
+ /* @__PURE__ */ jsx167(
14883
+ "span",
14884
+ {
14885
+ className: cn(
14886
+ "flex h-4 w-4 shrink-0 items-center justify-center rounded-full border",
14887
+ selected ? "border-primary" : "border-input"
14888
+ ),
14889
+ children: selected ? /* @__PURE__ */ jsx167("span", { className: "h-2 w-2 rounded-full bg-primary" }) : null
14890
+ }
14891
+ ),
14892
+ /* @__PURE__ */ jsx167("span", { className: cn(selected && "font-medium"), children: option.label })
14893
+ ]
14894
+ }
14895
+ );
14896
+ }
14897
+ function RecordingLanguageDialog({
14898
+ open,
14899
+ title,
14900
+ sourceTitle,
14901
+ targetTitle,
14902
+ sourceLanguages,
14903
+ targetLanguages,
14904
+ source,
14905
+ target,
14906
+ cancelLabel,
14907
+ confirmLabel,
14908
+ onSelectSource,
14909
+ onSelectTarget,
14910
+ onCancel,
14911
+ onConfirm
14912
+ }) {
14913
+ const renderColumn = (columnTitle, options, value, onSelect) => /* @__PURE__ */ jsxs109("div", { className: "flex min-w-0 flex-col gap-2", children: [
14914
+ /* @__PURE__ */ jsx167("span", { className: "text-sm font-medium", children: columnTitle }),
14915
+ /* @__PURE__ */ jsx167("div", { className: "flex flex-col divide-y divide-border", children: options.map((option) => /* @__PURE__ */ jsx167(
14916
+ LanguageOptionItem,
14917
+ {
14918
+ option,
14919
+ selected: option.key === value,
14920
+ onSelect
14921
+ },
14922
+ option.key
14923
+ )) })
14924
+ ] });
14925
+ return /* @__PURE__ */ jsx167(
14926
+ Dialog,
14927
+ {
14928
+ open,
14929
+ onOpenChange: (next) => {
14930
+ if (!next) onCancel();
14931
+ },
14932
+ children: /* @__PURE__ */ jsxs109(
14933
+ DialogContent,
14934
+ {
14935
+ "data-slot": "recording-language-dialog",
14936
+ className: "gap-6 sm:max-w-xl",
14937
+ children: [
14938
+ /* @__PURE__ */ jsx167(DialogTitle, { children: title }),
14939
+ /* @__PURE__ */ jsxs109("div", { className: "grid grid-cols-2 gap-6", children: [
14940
+ renderColumn(sourceTitle, sourceLanguages, source, onSelectSource),
14941
+ renderColumn(targetTitle, targetLanguages, target, onSelectTarget)
14942
+ ] }),
14943
+ /* @__PURE__ */ jsxs109("div", { className: "flex items-center justify-end gap-2", children: [
14944
+ /* @__PURE__ */ jsx167(Button2, { text: cancelLabel, onClick: onCancel }),
14945
+ /* @__PURE__ */ jsx167(Button2, { text: confirmLabel, variant: "primary", onClick: onConfirm })
14946
+ ] })
14947
+ ]
14948
+ }
14949
+ )
14950
+ }
14951
+ );
14952
+ }
14953
+
14954
+ // src/components/business/RecordingPage/translation.tsx
14955
+ import { jsx as jsx168, jsxs as jsxs110 } from "react/jsx-runtime";
14956
+ function RecordingTranslationView({
14957
+ translation,
14958
+ onLanguageClick,
14959
+ onLanguageChange,
14960
+ onTranslationAction
14961
+ }) {
14962
+ const sourceLanguages = translation.sourceLanguages ?? [];
14963
+ const targetLanguages = translation.targetLanguages ?? [];
14964
+ const dialogEnabled = sourceLanguages.length > 0 || targetLanguages.length > 0;
14965
+ const [dialogOpen, setDialogOpen] = useState53(false);
14966
+ const sourceControlled = translation.sourceLanguage !== void 0;
14967
+ const targetControlled = translation.targetLanguage !== void 0;
14968
+ const [innerSource, setInnerSource] = useState53(
14969
+ translation.defaultSourceLanguage ?? sourceLanguages[0]?.key
14970
+ );
14971
+ const [innerTarget, setInnerTarget] = useState53(
14972
+ translation.defaultTargetLanguage ?? targetLanguages[0]?.key
14973
+ );
14974
+ const committedSource = sourceControlled ? translation.sourceLanguage : innerSource;
14975
+ const committedTarget = targetControlled ? translation.targetLanguage : innerTarget;
14976
+ const [draftSource, setDraftSource] = useState53(committedSource);
14977
+ const [draftTarget, setDraftTarget] = useState53(committedTarget);
14978
+ const openDialog = () => {
14979
+ setDraftSource(committedSource);
14980
+ setDraftTarget(committedTarget);
14981
+ setDialogOpen(true);
14982
+ };
14983
+ const confirmDialog = () => {
14984
+ if (!sourceControlled) setInnerSource(draftSource);
14985
+ if (!targetControlled) setInnerTarget(draftTarget);
14986
+ onLanguageChange?.({
14987
+ source: draftSource,
14988
+ sourceLabel: sourceLanguages.find((item) => item.key === draftSource)?.label,
14989
+ target: draftTarget,
14990
+ targetLabel: targetLanguages.find((item) => item.key === draftTarget)?.label
14991
+ });
14992
+ setDialogOpen(false);
14993
+ };
14994
+ return /* @__PURE__ */ jsxs110("div", { "data-slot": "recording-translation", className: "flex flex-col gap-4", children: [
14995
+ translation.languageLabel !== void 0 ? /* @__PURE__ */ jsx168("div", { children: /* @__PURE__ */ jsxs110(
14996
+ "button",
14997
+ {
14998
+ type: "button",
14999
+ "data-slot": "recording-translation-language",
15000
+ className: "inline-flex cursor-pointer items-center gap-1.5 rounded-full bg-primary/10 px-3 py-1.5 text-sm",
15001
+ onClick: () => {
15002
+ onLanguageClick?.();
15003
+ if (dialogEnabled) openDialog();
15004
+ },
15005
+ children: [
15006
+ /* @__PURE__ */ jsx168(Icon, { name: "globe", size: 14 }),
15007
+ translation.languageLabel,
15008
+ /* @__PURE__ */ jsx168(Icon, { name: "chevron-down", size: 14, className: "text-muted-foreground" })
15009
+ ]
15010
+ }
15011
+ ) }) : null,
15012
+ /* @__PURE__ */ jsx168("div", { className: "flex flex-col divide-y divide-border", children: (translation.segments ?? []).map((segment, index) => /* @__PURE__ */ jsxs110(
15013
+ "div",
15014
+ {
15015
+ "data-slot": "recording-translation-segment",
15016
+ className: "grid gap-4 py-4",
15017
+ style: { gridTemplateColumns: "1fr 1fr" },
15018
+ children: [
15019
+ /* @__PURE__ */ jsxs110("div", { className: "flex min-w-0 flex-col gap-3", children: [
15020
+ /* @__PURE__ */ jsxs110("div", { className: "flex items-center gap-2", children: [
15021
+ /* @__PURE__ */ jsx168(Avatar2, { fallback: segment.avatarText ?? segment.speaker?.charAt(0) ?? "?" }),
15022
+ /* @__PURE__ */ jsx168(Text, { text: segment.speaker, strong: true, size: "small" })
15023
+ ] }),
15024
+ /* @__PURE__ */ jsx168(Text, { text: segment.source })
15025
+ ] }),
15026
+ /* @__PURE__ */ jsxs110("div", { className: "flex min-w-0 flex-col gap-3", children: [
15027
+ /* @__PURE__ */ jsx168(Text, { text: translation.targetLabel ?? "\u8BD1\u6587", strong: true, size: "small" }),
15028
+ /* @__PURE__ */ jsx168(Text, { text: segment.target })
15029
+ ] })
15030
+ ]
15031
+ },
15032
+ index
15033
+ )) }),
15034
+ translation.actions !== void 0 && translation.actions.length > 0 ? /* @__PURE__ */ jsx168("div", { "data-slot": "recording-translation-actions", className: "flex items-center gap-1", children: translation.actions.map((action) => /* @__PURE__ */ jsx168(
15035
+ Button2,
15036
+ {
15037
+ icon: action.icon,
15038
+ variant: "text",
15039
+ size: "small",
15040
+ onClick: () => onTranslationAction?.(action.key)
15041
+ },
15042
+ action.key
15043
+ )) }) : null,
15044
+ dialogEnabled ? /* @__PURE__ */ jsx168(
15045
+ RecordingLanguageDialog,
15046
+ {
15047
+ open: dialogOpen,
15048
+ title: translation.languageDialogTitle ?? "\u9009\u62E9\u7FFB\u8BD1\u8BED\u8A00",
15049
+ sourceTitle: translation.sourceLanguagesTitle ?? "\u539F\u6587\u8BED\u8A00\u8BC6\u522B",
15050
+ targetTitle: translation.targetLanguagesTitle ?? "\u8BD1\u6587\u8BED\u8A00\u9009\u62E9",
15051
+ sourceLanguages,
15052
+ targetLanguages,
15053
+ source: draftSource,
15054
+ target: draftTarget,
15055
+ cancelLabel: translation.cancelLabel ?? "\u53D6\u6D88",
15056
+ confirmLabel: translation.confirmLabel ?? "\u786E\u5B9A",
15057
+ onSelectSource: setDraftSource,
15058
+ onSelectTarget: setDraftTarget,
15059
+ onCancel: () => setDialogOpen(false),
15060
+ onConfirm: confirmDialog
15061
+ }
15062
+ ) : null
15063
+ ] });
15064
+ }
15065
+
15066
+ // src/components/business/RecordingPage/detail.tsx
15067
+ import { Fragment as Fragment20, jsx as jsx169, jsxs as jsxs111 } from "react/jsx-runtime";
15068
+ function TranscriptSegment({
15069
+ segment,
15070
+ speaker,
15071
+ onRename
15072
+ }) {
15073
+ return /* @__PURE__ */ jsxs111("div", { "data-slot": "recording-segment", className: "flex flex-col gap-2", children: [
15074
+ /* @__PURE__ */ jsxs111("div", { className: "flex items-center justify-between", children: [
15075
+ /* @__PURE__ */ jsxs111("div", { className: "flex items-center gap-2", children: [
15076
+ /* @__PURE__ */ jsx169(Avatar2, { fallback: segment.avatarText ?? speaker?.charAt(0) ?? "?" }),
15077
+ /* @__PURE__ */ jsx169(Text, { text: speaker, strong: true, size: "small" }),
15078
+ /* @__PURE__ */ jsx169(
15079
+ "button",
15080
+ {
15081
+ type: "button",
15082
+ "data-slot": "recording-speaker-edit",
15083
+ "aria-label": "\u4FEE\u6539\u53D1\u8A00\u4EBA",
15084
+ className: "cursor-pointer text-muted-foreground",
15085
+ onClick: () => onRename?.(),
15086
+ children: /* @__PURE__ */ jsx169(Icon, { name: "pencil", size: 14 })
15087
+ }
15088
+ )
15089
+ ] }),
15090
+ /* @__PURE__ */ jsxs111("div", { className: "flex items-center gap-2", children: [
15091
+ segment.marked ? /* @__PURE__ */ jsx169(Badge2, { text: "\u2691 \u5DF2\u6807\u8BB0", variant: "outline" }) : null,
15092
+ /* @__PURE__ */ jsx169(Text, { text: segment.time, size: "small", type: "secondary" })
15093
+ ] })
15094
+ ] }),
15095
+ /* @__PURE__ */ jsx169(Text, { text: segment.content })
15096
+ ] });
15097
+ }
15098
+ function RecordingDetail({
15099
+ title,
15100
+ meta,
15101
+ editLabel,
15102
+ shareLabel,
15103
+ shareOptions = [],
15104
+ shareSelectedKeys = [],
15105
+ sharePopoverTitle,
15106
+ shareCancelLabel,
15107
+ shareConfirmLabel,
15108
+ shareDialogTitle,
15109
+ shareLink,
15110
+ shareCopyLinkLabel,
15111
+ shareCopiedLabel,
15112
+ shareMailLabel,
15113
+ shareSystemLabel,
15114
+ onShareSelectionCommit,
15115
+ onShareConfirm,
15116
+ onShareChannel,
15117
+ onEdit,
15118
+ onShare,
15119
+ tabs,
15120
+ activeTab,
15121
+ onTabChange,
15122
+ transcriptTabKey,
15123
+ segments,
15124
+ speakers = [],
15125
+ speakerDialogTitle,
15126
+ speakerDialogHint,
15127
+ speakerInputPlaceholder,
15128
+ speakerApplyLabel,
15129
+ onSpeakerChange,
15130
+ summary,
15131
+ summaryTabKey,
15132
+ onMindmapAction,
15133
+ onMaterialClick,
15134
+ selectedTodoIds,
15135
+ onTodoToggle,
15136
+ onSummaryAction,
15137
+ insight,
15138
+ insightTabKey,
15139
+ onPerspectiveEdit,
15140
+ onPerspectiveApply,
15141
+ onInsightAction,
15142
+ memory,
15143
+ memoryTabKey,
15144
+ onMemoryAction,
15145
+ translation,
15146
+ translationTabKey,
15147
+ onLanguageClick,
15148
+ onLanguageChange,
15149
+ onTranslationAction,
15150
+ player,
15151
+ onPlay,
15152
+ onSkipBack,
15153
+ onSkipForward
15154
+ }) {
15155
+ const { renderChildren } = useRenderer22();
15156
+ const renderSlot = (slot) => isValidElement4(slot) || typeof slot !== "object" || slot === null ? slot : renderChildren([slot]);
15157
+ const activeTabItem = tabs.find((tab) => tab.key === activeTab);
15158
+ const [renameIndex, setRenameIndex] = useState54(null);
15159
+ const [draftSpeakerIndex, setDraftSpeakerIndex] = useState54(-1);
15160
+ const [draftSpeakerName, setDraftSpeakerName] = useState54("");
15161
+ const [speakerOverrides, setSpeakerOverrides] = useState54({});
15162
+ const speakerSignature = useRef16("");
15163
+ useEffect43(() => {
15164
+ const signature = JSON.stringify(segments.map((segment) => segment.speaker ?? ""));
15165
+ if (speakerSignature.current !== signature) {
15166
+ speakerSignature.current = signature;
15167
+ setSpeakerOverrides((prev) => Object.keys(prev).length > 0 ? {} : prev);
15168
+ }
15169
+ }, [segments]);
15170
+ const displaySpeaker = (index) => speakerOverrides[index] ?? segments[index]?.speaker;
15171
+ const openRename = (index) => {
15172
+ const current = displaySpeaker(index);
15173
+ setDraftSpeakerIndex(speakers.findIndex((item) => item.name === current));
15174
+ setDraftSpeakerName("");
15175
+ setRenameIndex(index);
15176
+ };
15177
+ const confirmRename = () => {
15178
+ if (renameIndex === null) return;
15179
+ const name = draftSpeakerName.trim() !== "" ? draftSpeakerName.trim() : speakers[draftSpeakerIndex]?.name;
15180
+ if (name === void 0 || name === "") return;
15181
+ const previous = displaySpeaker(renameIndex);
15182
+ setSpeakerOverrides((prev) => ({ ...prev, [renameIndex]: name }));
15183
+ onSpeakerChange?.({ index: renameIndex, previous, name });
15184
+ setRenameIndex(null);
15185
+ };
15186
+ return /* @__PURE__ */ jsxs111("div", { "data-slot": "recording-page-detail", className: "flex h-full min-w-0 flex-1 flex-col", children: [
15187
+ /* @__PURE__ */ jsxs111("div", { className: "flex shrink-0 items-center justify-between px-6 py-4", children: [
15188
+ /* @__PURE__ */ jsxs111("div", { className: "flex min-w-0 flex-col gap-1", children: [
15189
+ /* @__PURE__ */ jsx169(Text, { text: title, strong: true, size: "large", className: "truncate" }),
15190
+ meta !== void 0 ? /* @__PURE__ */ jsx169(Text, { text: meta, size: "small", type: "secondary" }) : null
15191
+ ] }),
15192
+ /* @__PURE__ */ jsxs111("div", { className: "flex shrink-0 items-center gap-3", children: [
15193
+ editLabel !== void 0 ? /* @__PURE__ */ jsx169(Button2, { text: editLabel, variant: "link", size: "small", onClick: () => onEdit?.() }) : null,
15194
+ shareLabel !== void 0 ? shareOptions.length > 0 ? /* @__PURE__ */ jsx169(
15195
+ RecordingShare,
15196
+ {
15197
+ shareLabel,
15198
+ options: shareOptions,
15199
+ selectedKeys: shareSelectedKeys,
15200
+ popoverTitle: sharePopoverTitle ?? "\u9009\u62E9\u5206\u4EAB\u5185\u5BB9",
15201
+ cancelLabel: shareCancelLabel ?? "\u53D6\u6D88",
15202
+ confirmLabel: shareConfirmLabel ?? "\u786E\u5B9A",
15203
+ dialogTitle: shareDialogTitle ?? "\u5206\u4EAB\u4F1A\u8BAE\u5185\u5BB9",
15204
+ link: shareLink,
15205
+ copyLinkLabel: shareCopyLinkLabel ?? "\u590D\u5236\u94FE\u63A5",
15206
+ copiedLabel: shareCopiedLabel ?? "\u5DF2\u590D\u5236",
15207
+ mailLabel: shareMailLabel ?? "\u90AE\u4EF6",
15208
+ systemLabel: shareSystemLabel ?? "\u7CFB\u7EDF\u5206\u4EAB",
15209
+ onShare,
15210
+ onSelectionCommit: (keys) => onShareSelectionCommit?.(keys),
15211
+ onShareConfirm,
15212
+ onShareChannel
15213
+ }
15214
+ ) : /* @__PURE__ */ jsx169(Button2, { text: shareLabel, size: "small", onClick: () => onShare?.() }) : null
15215
+ ] })
15216
+ ] }),
15217
+ tabs.length > 0 ? /* @__PURE__ */ jsxs111(Fragment20, { children: [
15218
+ /* @__PURE__ */ jsx169("div", { "data-slot": "recording-page-tabs", className: "flex shrink-0 px-6 pt-3", children: /* @__PURE__ */ jsx169("div", { className: "flex w-full items-center gap-1 rounded-lg bg-muted p-1", children: tabs.map((tab) => {
15219
+ const active = tab.key === activeTab;
15220
+ return /* @__PURE__ */ jsx169(
15221
+ "button",
15222
+ {
15223
+ type: "button",
15224
+ role: "tab",
15225
+ "aria-selected": active,
15226
+ className: cn(
15227
+ "flex-1 cursor-pointer rounded-md px-3 py-1 text-sm",
15228
+ active ? "bg-background shadow-sm" : "text-muted-foreground"
15229
+ ),
15230
+ onClick: () => onTabChange(tab.key),
15231
+ children: tab.label
15232
+ },
15233
+ tab.key
15234
+ );
15235
+ }) }) }),
15236
+ /* @__PURE__ */ jsx169(
15237
+ "div",
15238
+ {
15239
+ "data-slot": "recording-page-tab-body",
15240
+ className: "scrollbar-subtle min-h-0 flex-1 overflow-y-auto px-6 py-4",
15241
+ children: activeTabItem?.content !== void 0 ? renderSlot(activeTabItem.content) : activeTabItem?.key === transcriptTabKey ? /* @__PURE__ */ jsx169("div", { className: "flex flex-col gap-6", children: segments.map((segment, index) => /* @__PURE__ */ jsx169(
15242
+ TranscriptSegment,
15243
+ {
15244
+ segment,
15245
+ speaker: displaySpeaker(index),
15246
+ onRename: () => openRename(index)
15247
+ },
15248
+ segment.time ?? index
15249
+ )) }) : activeTabItem?.key === summaryTabKey && summary !== void 0 ? /* @__PURE__ */ jsx169(
15250
+ RecordingSummaryView,
15251
+ {
15252
+ summary,
15253
+ onMindmapAction,
15254
+ onMaterialClick,
15255
+ selectedTodoIds,
15256
+ onTodoToggle,
15257
+ onSummaryAction
15258
+ }
15259
+ ) : activeTabItem?.key === insightTabKey && insight !== void 0 ? /* @__PURE__ */ jsx169(
15260
+ RecordingInsightView,
15261
+ {
15262
+ insight,
15263
+ onPerspectiveEdit,
15264
+ onPerspectiveApply,
15265
+ onInsightAction
15266
+ }
15267
+ ) : activeTabItem?.key === memoryTabKey && memory !== void 0 ? /* @__PURE__ */ jsx169(RecordingMemoryView, { memory, onMemoryAction }) : activeTabItem?.key === translationTabKey && translation !== void 0 ? /* @__PURE__ */ jsx169(
15268
+ RecordingTranslationView,
15269
+ {
15270
+ translation,
15271
+ onLanguageClick,
15272
+ onLanguageChange,
15273
+ onTranslationAction
15274
+ }
15275
+ ) : null
15276
+ }
15277
+ )
15278
+ ] }) : null,
15279
+ player !== void 0 ? /* @__PURE__ */ jsxs111(
15280
+ "div",
15281
+ {
15282
+ "data-slot": "recording-page-player",
15283
+ className: "flex shrink-0 items-center gap-3 border-t border-border px-6 py-3",
15284
+ children: [
15285
+ /* @__PURE__ */ jsx169(Button2, { icon: "rotate-ccw", variant: "text", onClick: () => onSkipBack?.() }),
15286
+ /* @__PURE__ */ jsx169(
15287
+ Button2,
15288
+ {
15289
+ icon: "play",
15290
+ style: { borderRadius: 999 },
15291
+ onClick: () => onPlay?.()
15292
+ }
15293
+ ),
15294
+ /* @__PURE__ */ jsx169(Button2, { icon: "rotate-cw", variant: "text", onClick: () => onSkipForward?.() }),
15295
+ /* @__PURE__ */ jsx169(Text, { text: player.currentTime, size: "small", type: "secondary" }),
15296
+ /* @__PURE__ */ jsx169(Progress2, { value: player.progress, style: { flex: 1 } }),
15297
+ /* @__PURE__ */ jsx169(Text, { text: player.totalTime, size: "small", type: "secondary" })
15298
+ ]
15299
+ }
15300
+ ) : null,
15301
+ /* @__PURE__ */ jsx169(
15302
+ RecordingSpeakerDialog,
15303
+ {
15304
+ open: renameIndex !== null,
15305
+ title: speakerDialogTitle ?? "\u4FEE\u6539\u53D1\u8A00\u4EBA",
15306
+ 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",
15307
+ speakers,
15308
+ selectedIndex: draftSpeakerIndex,
15309
+ customName: draftSpeakerName,
15310
+ inputPlaceholder: speakerInputPlaceholder ?? "\u8F93\u5165\u59D3\u540D",
15311
+ applyLabel: speakerApplyLabel ?? "\u5E94\u7528\u59D3\u540D",
15312
+ onSelect: setDraftSpeakerIndex,
15313
+ onInputName: setDraftSpeakerName,
15314
+ onCancel: () => setRenameIndex(null),
15315
+ onConfirm: confirmRename
15316
+ }
15317
+ )
15318
+ ] });
15319
+ }
15320
+
15321
+ // src/components/business/RecordingPage/list.tsx
15322
+ import { useState as useState55 } from "react";
15323
+ import { Fragment as Fragment21, jsx as jsx170, jsxs as jsxs112 } from "react/jsx-runtime";
15324
+ function RecordingList({
15325
+ listTitle,
15326
+ selectLabel,
15327
+ selectDoneLabel,
15328
+ selectAllLabel,
15329
+ selectedCountText,
15330
+ deleteLabel,
15331
+ deleteConfirmTitle,
15332
+ deleteConfirmText,
15333
+ deleteCancelLabel,
15334
+ deleteConfirmLabel,
15335
+ selecting = false,
15336
+ selectedRecordingIds = [],
15337
+ onEnterSelectMode,
15338
+ onExitSelectMode,
15339
+ onToggleRecordingSelect,
15340
+ onToggleSelectAll,
15341
+ onDeleteSelected,
15342
+ filters,
15343
+ activeFilter,
15344
+ onFilterChange,
15345
+ processingText,
15346
+ processingHint,
15347
+ onProcessingClick,
15348
+ newRecordingLabel,
15349
+ onNewRecording,
15350
+ groups,
15351
+ activeRecordingId,
15352
+ onSelectRecording,
15353
+ listWidth,
15354
+ emptyText
15355
+ }) {
15356
+ const [deleteConfirmOpen, setDeleteConfirmOpen] = useState55(false);
15357
+ const renderRecordingItem = (item) => {
15358
+ const active = !selecting && item.id === activeRecordingId;
15359
+ const checked = selecting && selectedRecordingIds.includes(item.id);
15360
+ return /* @__PURE__ */ jsxs112(
15361
+ "button",
15362
+ {
15363
+ type: "button",
15364
+ "data-slot": "recording-item",
15365
+ "data-active": active || void 0,
15366
+ "aria-pressed": selecting ? checked : void 0,
15367
+ className: cn(
15368
+ "flex w-full cursor-pointer items-start gap-2 rounded-lg p-2 text-left",
15369
+ active ? "bg-background shadow-sm" : void 0
15370
+ ),
15371
+ onClick: () => selecting ? onToggleRecordingSelect?.(item.id) : onSelectRecording(item.id),
15372
+ children: [
15373
+ selecting ? /* @__PURE__ */ jsx170(
15374
+ "span",
15375
+ {
15376
+ className: cn(
15377
+ "mt-0.5 flex h-5 w-5 shrink-0 items-center justify-center rounded-full",
15378
+ checked ? "bg-success text-background" : "border border-border bg-background"
15379
+ ),
15380
+ children: checked ? /* @__PURE__ */ jsx170(Icon, { name: "check", size: 12 }) : null
15381
+ }
15382
+ ) : /* @__PURE__ */ jsx170(Icon, { name: item.icon ?? "audio-lines", size: 18, className: "mt-0.5 shrink-0" }),
15383
+ /* @__PURE__ */ jsxs112("div", { className: "flex min-w-0 flex-1 flex-col gap-1", children: [
15384
+ /* @__PURE__ */ jsxs112("div", { className: "flex items-center justify-between gap-2", children: [
15385
+ /* @__PURE__ */ jsx170(
15386
+ Text,
15387
+ {
15388
+ text: item.title,
15389
+ size: "small",
15390
+ strong: active || checked,
15391
+ className: "min-w-0 truncate"
15392
+ }
15393
+ ),
15394
+ item.status !== void 0 ? /* @__PURE__ */ jsx170(
15395
+ Text,
15396
+ {
15397
+ text: item.status,
15398
+ size: "small",
15399
+ type: item.statusType ?? "secondary",
15400
+ className: "shrink-0"
15401
+ }
15402
+ ) : null
15403
+ ] }),
15404
+ /* @__PURE__ */ jsxs112("div", { className: "flex items-center justify-between gap-2", children: [
15405
+ /* @__PURE__ */ jsx170(Text, { text: item.time, size: "small", type: "secondary" }),
15406
+ /* @__PURE__ */ jsx170(Text, { text: item.duration, size: "small", type: "secondary" })
15407
+ ] })
15408
+ ] })
15409
+ ]
15410
+ },
15411
+ item.id
15412
+ );
15413
+ };
15414
+ return /* @__PURE__ */ jsxs112(
15415
+ "div",
15416
+ {
15417
+ "data-slot": "recording-page-list",
15418
+ className: "m-3 flex min-h-0 shrink-0 flex-col gap-3 rounded-xl bg-muted p-4",
15419
+ style: { width: listWidth },
15420
+ children: [
15421
+ /* @__PURE__ */ jsxs112("div", { className: "flex items-center justify-between", children: [
15422
+ /* @__PURE__ */ jsx170(Text, { text: listTitle, strong: true, size: "large" }),
15423
+ selecting ? /* @__PURE__ */ jsx170(
15424
+ Button2,
15425
+ {
15426
+ text: selectDoneLabel ?? "\u5B8C\u6210",
15427
+ variant: "link",
15428
+ size: "small",
15429
+ onClick: () => onExitSelectMode?.()
15430
+ }
15431
+ ) : selectLabel !== void 0 ? /* @__PURE__ */ jsx170(Button2, { text: selectLabel, variant: "link", size: "small", onClick: () => onEnterSelectMode?.() }) : null
15432
+ ] }),
15433
+ selecting ? /* @__PURE__ */ jsxs112(
15434
+ "div",
15435
+ {
15436
+ "data-slot": "recording-page-selection-bar",
15437
+ className: "flex items-center justify-between",
15438
+ children: [
15439
+ /* @__PURE__ */ jsx170(
15440
+ Text,
15441
+ {
15442
+ text: (selectedCountText ?? "\u5DF2\u9009 {count} \u6761").replace(
15443
+ "{count}",
15444
+ String(selectedRecordingIds.length)
15445
+ ),
15446
+ size: "small",
15447
+ type: "secondary"
15448
+ }
15449
+ ),
15450
+ /* @__PURE__ */ jsx170(
15451
+ Button2,
15452
+ {
15453
+ text: selectAllLabel ?? "\u5168\u9009",
15454
+ variant: "link",
15455
+ size: "small",
15456
+ onClick: () => onToggleSelectAll?.()
15457
+ }
15458
+ )
15459
+ ]
15460
+ }
15461
+ ) : null,
15462
+ !selecting && filters.length > 0 ? /* @__PURE__ */ jsx170("div", { "data-slot": "recording-page-filters", className: "flex gap-2", children: filters.map((filter) => {
15463
+ const active = filter.key === activeFilter;
15464
+ return /* @__PURE__ */ jsx170(
15465
+ "button",
15466
+ {
15467
+ type: "button",
15468
+ "data-active": active || void 0,
15469
+ className: cn(
15470
+ "cursor-pointer rounded-full px-3 py-1 text-xs",
15471
+ active ? "bg-primary text-primary-foreground" : "bg-background"
15472
+ ),
15473
+ onClick: () => onFilterChange(filter.key),
15474
+ children: filter.label
15475
+ },
15476
+ filter.key
15477
+ );
15478
+ }) }) : null,
15479
+ !selecting && processingText !== void 0 ? /* @__PURE__ */ jsxs112(
15480
+ "button",
15481
+ {
15482
+ type: "button",
15483
+ "data-slot": "recording-page-processing",
15484
+ className: "flex cursor-pointer items-center gap-2 rounded-lg bg-background p-3 text-left",
15485
+ onClick: () => onProcessingClick?.(),
15486
+ children: [
15487
+ /* @__PURE__ */ jsx170(Icon, { name: "audio-lines", size: 18 }),
15488
+ /* @__PURE__ */ jsxs112("div", { className: "flex flex-1 flex-col", children: [
15489
+ /* @__PURE__ */ jsx170(Text, { text: processingText, size: "small", strong: true }),
15490
+ processingHint !== void 0 ? /* @__PURE__ */ jsx170(Text, { text: processingHint, size: "small", type: "secondary" }) : null
15491
+ ] }),
15492
+ /* @__PURE__ */ jsx170(Icon, { name: "chevron-right", size: 16, className: "text-muted-foreground" })
15493
+ ]
15494
+ }
15495
+ ) : null,
15496
+ !selecting && newRecordingLabel !== null && newRecordingLabel !== void 0 ? /* @__PURE__ */ jsx170(
15497
+ Button2,
15498
+ {
15499
+ text: newRecordingLabel,
15500
+ icon: "mic",
15501
+ variant: "primary",
15502
+ className: "w-full",
15503
+ onClick: () => onNewRecording?.()
15504
+ }
15505
+ ) : null,
15506
+ /* @__PURE__ */ jsx170(
15507
+ "div",
15508
+ {
15509
+ "data-slot": "recording-page-groups",
15510
+ className: "scrollbar-subtle flex min-h-0 flex-1 flex-col gap-3 overflow-y-auto",
15511
+ children: groups.length === 0 ? /* @__PURE__ */ jsx170(Empty2, { title: emptyText }) : groups.map((group, groupIndex) => /* @__PURE__ */ jsxs112("div", { className: "flex flex-col gap-1", children: [
15512
+ /* @__PURE__ */ jsx170(Text, { text: group.label, size: "small", type: "secondary", className: "px-1" }),
15513
+ group.items.map(renderRecordingItem)
15514
+ ] }, group.key ?? group.label ?? groupIndex))
15515
+ }
15516
+ ),
15517
+ selecting ? /* @__PURE__ */ jsxs112(Fragment21, { children: [
15518
+ /* @__PURE__ */ jsx170(
15519
+ Button2,
15520
+ {
15521
+ text: deleteLabel ?? "\u5220\u9664",
15522
+ variant: "primary",
15523
+ danger: true,
15524
+ className: "w-full shrink-0",
15525
+ onClick: () => setDeleteConfirmOpen(true)
15526
+ }
15527
+ ),
15528
+ /* @__PURE__ */ jsx170(AlertDialog, { open: deleteConfirmOpen, onOpenChange: setDeleteConfirmOpen, children: /* @__PURE__ */ jsxs112(AlertDialogContent, { "data-slot": "recording-delete-confirm", children: [
15529
+ /* @__PURE__ */ jsxs112(AlertDialogHeader, { children: [
15530
+ /* @__PURE__ */ jsx170(AlertDialogTitle, { children: deleteConfirmTitle ?? "\u5220\u9664\u5F55\u97F3" }),
15531
+ /* @__PURE__ */ jsx170(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)) })
15532
+ ] }),
15533
+ /* @__PURE__ */ jsxs112(AlertDialogFooter, { children: [
15534
+ /* @__PURE__ */ jsx170(AlertDialogCancel, { children: deleteCancelLabel ?? "\u53D6\u6D88" }),
15535
+ /* @__PURE__ */ jsx170(
15536
+ AlertDialogAction,
15537
+ {
15538
+ variant: "destructive",
15539
+ onClick: () => onDeleteSelected?.(),
15540
+ children: deleteConfirmLabel ?? "\u5220\u9664"
15541
+ }
15542
+ )
15543
+ ] })
15544
+ ] }) })
15545
+ ] }) : null
15546
+ ]
15547
+ }
15548
+ );
15549
+ }
15550
+
15551
+ // src/components/business/RecordingPage/index.tsx
15552
+ import { jsx as jsx171, jsxs as jsxs113 } from "react/jsx-runtime";
15553
+ function RecordingPage({
15554
+ listTitle = "\u5F55\u97F3\u8BB0\u5F55\u5217\u8868",
15555
+ selectLabel,
15556
+ selectDoneLabel,
15557
+ selectAllLabel,
15558
+ selectedCountText,
15559
+ deleteLabel,
15560
+ deleteConfirmTitle,
15561
+ deleteConfirmText,
15562
+ deleteCancelLabel,
15563
+ deleteConfirmLabel,
15564
+ selectedRecordingIds,
15565
+ defaultSelectedRecordingIds,
15566
+ onRecordingSelectionChange,
15567
+ onDeleteRecordings,
15568
+ onSelectClick,
15569
+ filters = [],
15570
+ activeFilterKey,
15571
+ defaultActiveFilterKey,
15572
+ onFilterChange,
15573
+ processingText,
15574
+ processingHint,
15575
+ onProcessingClick,
15576
+ newRecordingLabel = "\u5F00\u59CB\u65B0\u5F55\u97F3",
15577
+ onNewRecording,
15578
+ groups = [],
15579
+ activeRecordingId,
15580
+ defaultActiveRecordingId,
15581
+ onSelectRecording,
15582
+ listWidth = 300,
15583
+ emptyText = "\u6682\u65E0\u5F55\u97F3",
15584
+ title,
15585
+ meta,
15586
+ editLabel,
15587
+ shareLabel,
15588
+ shareOptions,
15589
+ shareSelectedKeys,
15590
+ defaultShareSelectedKeys,
15591
+ sharePopoverTitle,
15592
+ shareCancelLabel,
15593
+ shareConfirmLabel,
15594
+ shareDialogTitle,
15595
+ shareLink,
15596
+ shareCopyLinkLabel,
15597
+ shareCopiedLabel,
15598
+ shareMailLabel,
15599
+ shareSystemLabel,
15600
+ onShareConfirm,
15601
+ onShareChannel,
15602
+ onEdit,
15603
+ onShare,
15604
+ tabs = [],
15605
+ activeTabKey,
15606
+ defaultActiveTabKey,
15607
+ onTabChange,
15608
+ transcriptTabKey = "transcript",
15609
+ segments = [],
15610
+ speakers,
15611
+ speakerDialogTitle,
15612
+ speakerDialogHint,
15613
+ speakerInputPlaceholder,
15614
+ speakerApplyLabel,
15615
+ onSpeakerChange,
15616
+ summary,
15617
+ summaryTabKey = "summary",
15618
+ onMindmapAction,
15619
+ onMaterialClick,
15620
+ onTodoClick,
15621
+ selectedTodoIds,
15622
+ defaultSelectedTodoIds,
15623
+ onTodoSelectionChange,
15624
+ onSummaryAction,
15625
+ insight,
15626
+ insightTabKey = "ai",
15627
+ onPerspectiveEdit,
15628
+ onPerspectiveApply,
15629
+ onInsightAction,
15630
+ memory,
15631
+ memoryTabKey = "knowledge",
15632
+ onMemoryAction,
15633
+ translation,
15634
+ translationTabKey = "translation",
15635
+ onLanguageClick,
15636
+ onLanguageChange,
15637
+ onTranslationAction,
15638
+ player,
15639
+ onPlay,
15640
+ onSkipBack,
15641
+ onSkipForward,
15642
+ className,
15643
+ style
15644
+ }) {
15645
+ const filterControlled = activeFilterKey !== void 0;
15646
+ const [innerFilter, setInnerFilter] = useState56(
15647
+ defaultActiveFilterKey ?? filters[0]?.key
15648
+ );
15649
+ const activeFilter = filterControlled ? activeFilterKey : innerFilter;
15650
+ const setActiveFilter = (next) => {
15651
+ if (!filterControlled) setInnerFilter(next);
15652
+ onFilterChange?.(next);
15653
+ };
15654
+ const recControlled = activeRecordingId !== void 0;
15655
+ const [innerRec, setInnerRec] = useState56(defaultActiveRecordingId);
15656
+ const activeRec = recControlled ? activeRecordingId : innerRec;
15657
+ const setActiveRec = (next) => {
15658
+ if (!recControlled) setInnerRec(next);
15659
+ onSelectRecording?.(next);
15660
+ };
15661
+ const tabControlled = activeTabKey !== void 0;
15662
+ const [innerTab, setInnerTab] = useState56(defaultActiveTabKey ?? tabs[0]?.key);
15663
+ const activeTab = tabControlled ? activeTabKey : innerTab;
15664
+ const setActiveTab = (next) => {
15665
+ if (!tabControlled) setInnerTab(next);
15666
+ onTabChange?.(next);
15667
+ };
15668
+ const todoControlled = selectedTodoIds !== void 0;
15669
+ const [innerTodos, setInnerTodos] = useState56(
15670
+ () => defaultSelectedTodoIds ?? (summary?.todos ?? []).flatMap(
15671
+ (todo, index) => todo.done === true ? [todo.id ?? index] : []
15672
+ )
15673
+ );
15674
+ const selectedTodos = todoControlled ? selectedTodoIds : innerTodos;
15675
+ const toggleTodo = (id) => {
15676
+ const next = selectedTodos.includes(id) ? selectedTodos.filter((item) => item !== id) : [...selectedTodos, id];
15677
+ if (!todoControlled) setInnerTodos(next);
15678
+ onTodoClick?.(id);
15679
+ onTodoSelectionChange?.(next);
15680
+ };
15681
+ const shareControlled = shareSelectedKeys !== void 0;
15682
+ const [innerShareKeys, setInnerShareKeys] = useState56(
15683
+ () => defaultShareSelectedKeys ?? (shareOptions ?? []).map((option) => option.key)
15684
+ );
15685
+ const shareKeys = shareControlled ? shareSelectedKeys : innerShareKeys;
15686
+ const commitShareKeys = (next) => {
15687
+ if (!shareControlled) setInnerShareKeys(next);
15688
+ };
15689
+ const [selecting, setSelecting] = useState56(false);
15690
+ const recSelControlled = selectedRecordingIds !== void 0;
15691
+ const [innerSelectedRecs, setInnerSelectedRecs] = useState56(
15692
+ () => defaultSelectedRecordingIds ?? []
15693
+ );
15694
+ const selectedRecs = recSelControlled ? selectedRecordingIds : innerSelectedRecs;
15695
+ const commitSelectedRecs = (next) => {
15696
+ if (!recSelControlled) setInnerSelectedRecs(next);
15697
+ onRecordingSelectionChange?.(next);
15698
+ };
15699
+ const allRecordingIds = groups.flatMap((group) => group.items.map((item) => item.id));
15700
+ const toggleRecordingSelect = (id) => {
15701
+ commitSelectedRecs(
15702
+ selectedRecs.includes(id) ? selectedRecs.filter((item) => item !== id) : [...selectedRecs, id]
15703
+ );
15704
+ };
15705
+ const toggleSelectAll = () => {
15706
+ commitSelectedRecs(
15707
+ selectedRecs.length === allRecordingIds.length ? [] : allRecordingIds
15708
+ );
15709
+ };
15710
+ return /* @__PURE__ */ jsxs113(
15711
+ "div",
15712
+ {
15713
+ "data-slot": "recording-page",
15714
+ className: cn("flex h-full w-full min-h-0 items-stretch", className),
15715
+ style,
15716
+ children: [
15717
+ /* @__PURE__ */ jsx171(
15718
+ RecordingList,
15719
+ {
15720
+ listTitle,
15721
+ selectLabel,
15722
+ selectDoneLabel,
15723
+ selectAllLabel,
15724
+ selectedCountText,
15725
+ deleteLabel,
15726
+ deleteConfirmTitle,
15727
+ deleteConfirmText,
15728
+ deleteCancelLabel,
15729
+ deleteConfirmLabel,
15730
+ selecting,
15731
+ selectedRecordingIds: selectedRecs,
15732
+ onEnterSelectMode: () => {
15733
+ setSelecting(true);
15734
+ onSelectClick?.();
15735
+ },
15736
+ onExitSelectMode: () => setSelecting(false),
15737
+ onToggleRecordingSelect: toggleRecordingSelect,
15738
+ onToggleSelectAll: toggleSelectAll,
15739
+ onDeleteSelected: () => onDeleteRecordings?.(selectedRecs),
15740
+ filters,
15741
+ activeFilter,
15742
+ onFilterChange: setActiveFilter,
15743
+ processingText,
15744
+ processingHint,
15745
+ onProcessingClick,
15746
+ newRecordingLabel,
15747
+ onNewRecording,
15748
+ groups,
15749
+ activeRecordingId: activeRec,
15750
+ onSelectRecording: setActiveRec,
15751
+ listWidth,
15752
+ emptyText
15753
+ }
15754
+ ),
15755
+ /* @__PURE__ */ jsx171(
15756
+ RecordingDetail,
15757
+ {
15758
+ title,
15759
+ meta,
15760
+ editLabel,
15761
+ shareLabel,
15762
+ shareOptions,
15763
+ shareSelectedKeys: shareKeys,
15764
+ sharePopoverTitle,
15765
+ shareCancelLabel,
15766
+ shareConfirmLabel,
15767
+ shareDialogTitle,
15768
+ shareLink,
15769
+ shareCopyLinkLabel,
15770
+ shareCopiedLabel,
15771
+ shareMailLabel,
15772
+ shareSystemLabel,
15773
+ onShareSelectionCommit: commitShareKeys,
15774
+ onShareConfirm,
15775
+ onShareChannel,
15776
+ onEdit,
15777
+ onShare,
15778
+ tabs,
15779
+ activeTab,
15780
+ onTabChange: setActiveTab,
15781
+ transcriptTabKey,
15782
+ segments,
15783
+ speakers,
15784
+ speakerDialogTitle,
15785
+ speakerDialogHint,
15786
+ speakerInputPlaceholder,
15787
+ speakerApplyLabel,
15788
+ onSpeakerChange,
15789
+ summary,
15790
+ summaryTabKey,
15791
+ onMindmapAction,
15792
+ onMaterialClick,
15793
+ selectedTodoIds: selectedTodos,
15794
+ onTodoToggle: toggleTodo,
15795
+ onSummaryAction,
15796
+ insight,
15797
+ insightTabKey,
15798
+ onPerspectiveEdit,
15799
+ onPerspectiveApply,
15800
+ onInsightAction,
15801
+ memory,
15802
+ memoryTabKey,
15803
+ onMemoryAction,
15804
+ translation,
15805
+ translationTabKey,
15806
+ onLanguageClick,
15807
+ onLanguageChange,
15808
+ onTranslationAction,
15809
+ player,
15810
+ onPlay,
15811
+ onSkipBack,
15812
+ onSkipForward
15813
+ }
15814
+ )
15815
+ ]
15816
+ }
15817
+ );
15818
+ }
15819
+
15820
+ // src/components/business/RuleConfig/index.tsx
15821
+ import { Plus as Plus2, Trash2 } from "lucide-react";
15822
+ import { useCallback as useCallback5, useEffect as useEffect44, useMemo as useMemo11, useRef as useRef17, useState as useState57 } from "react";
15823
+ import { jsx as jsx172, jsxs as jsxs114 } from "react/jsx-runtime";
15824
+ var isBlank = (v) => v == null || String(v).trim() === "";
15825
+ function isValueMissing(condition) {
15826
+ const { opt, value } = condition;
15827
+ if (NO_VALUE_OPT.includes(opt)) return false;
15828
+ if (opt === "BETWEEN") {
15829
+ const [a, b] = normalizeBetweenValue(value);
15830
+ return isBlank(a) || isBlank(b);
15831
+ }
15832
+ if (Array.isArray(value)) return value.length === 0 || value.every(isBlank);
15833
+ return isBlank(value);
15834
+ }
15835
+ function getConditionIssue(condition) {
15836
+ const missingValue = isValueMissing(condition);
15837
+ const missingScore = condition.score == null || Number.isNaN(condition.score);
15838
+ if (!missingValue && !missingScore) return null;
15839
+ return { missingValue, missingScore };
15840
+ }
15841
+ var OPERATOR_VALUES = [
15842
+ "GREATER",
15843
+ "GREATER_EQUAL",
15844
+ "LESS_EQUAL",
15845
+ "LESS",
15846
+ "EQUAL",
15847
+ "IN",
15848
+ "NOT_IN",
15849
+ "UNEQUAL",
15850
+ "LIKE",
15851
+ "NULL",
15852
+ "HASVAL",
15853
+ "NOTNULL",
15854
+ "BETWEEN"
15855
+ ];
15856
+ var NUMERIC_OPT = [
15857
+ "GREATER",
15858
+ "LESS",
15859
+ "LESS_EQUAL",
15860
+ "GREATER_EQUAL",
15861
+ "UNEQUAL"
15862
+ ];
15863
+ var NO_VALUE_OPT = ["NULL", "HASVAL", "NOTNULL"];
15864
+ var MULTI_VALUE_OPT = ["IN", "NOT_IN"];
15865
+ var OPERATOR_LABELS2 = {
15866
+ GREATER: "\u5927\u4E8E",
15867
+ GREATER_EQUAL: "\u5927\u4E8E\u7B49\u4E8E",
15868
+ LESS_EQUAL: "\u5C0F\u4E8E\u7B49\u4E8E",
15869
+ LESS: "\u5C0F\u4E8E",
15870
+ EQUAL: "\u7B49\u4E8E",
15871
+ IN: "\u5305\u542B",
15872
+ NOT_IN: "\u4E0D\u5305\u542B",
15873
+ UNEQUAL: "\u4E0D\u7B49\u4E8E",
15874
+ LIKE: "\u7C7B\u4F3C",
15875
+ NULL: "\u4E3A\u7A7A",
15876
+ HASVAL: "\u6709\u503C",
15877
+ NOTNULL: "\u4E0D\u4E3A\u7A7A",
15878
+ BETWEEN: "\u8303\u56F4"
15879
+ };
15880
+ function operatorLabel2(operator) {
15881
+ return OPERATOR_LABELS2[operator] ?? operator;
15882
+ }
15883
+ var _key = 0;
15884
+ var nextKey = () => ++_key;
15885
+ var defaultCondition = () => ({ key: nextKey(), opt: "EQUAL" });
15886
+ function normalizeBetweenValue(value) {
15887
+ if (Array.isArray(value)) return [value[0], value[1]];
15888
+ if (typeof value === "string" && value.includes(",")) {
15889
+ const [a, b] = value.split(",");
15890
+ return [a?.trim(), b?.trim()];
15891
+ }
15892
+ if (value == null || value === "") return [void 0, void 0];
15893
+ return [value, void 0];
15894
+ }
15895
+ function formatConditionValue2(condition) {
15896
+ const { opt, value } = condition;
15897
+ if (value == null) return "-";
15898
+ if (opt === "BETWEEN") {
15899
+ const [a, b] = normalizeBetweenValue(value);
15900
+ return `${a ?? "-"} ~ ${b ?? "-"}`;
15901
+ }
15902
+ if (Array.isArray(value)) return value.join(", ");
15903
+ return String(value);
15904
+ }
15905
+ function RuleConfig({ value, onChange, disabled, size = "middle" }) {
15906
+ const rawConditions = value?.ruleConditions;
15907
+ const conditions = useMemo11(() => {
15908
+ if (!rawConditions?.length) return [defaultCondition()];
15909
+ const seen = /* @__PURE__ */ new Set();
15910
+ return rawConditions.map((c) => {
15911
+ if (c.key != null && !seen.has(c.key)) {
15912
+ seen.add(c.key);
15913
+ return c;
15914
+ }
15915
+ const key = nextKey();
15916
+ seen.add(key);
15917
+ return { ...c, key };
15918
+ });
15919
+ }, [rawConditions]);
15920
+ const initScore = value?.score ?? 1;
15921
+ const [scoreText, setScoreText] = useState57(String(initScore));
15922
+ const lastScoreRef = useRef17(value?.score);
15923
+ useEffect44(() => {
15924
+ if (value?.score === lastScoreRef.current) return;
15925
+ lastScoreRef.current = value?.score;
15926
+ setScoreText(value?.score == null ? "" : String(value.score));
15927
+ }, [value?.score]);
15928
+ const commitScore = useCallback5(
15929
+ (score) => {
15930
+ lastScoreRef.current = score;
15931
+ onChange?.({ score, ruleConditions: conditions });
15932
+ },
15933
+ [onChange, conditions]
15934
+ );
15935
+ const normalizeScore = (n) => Math.min(1e3, Math.max(1, Math.round(n)));
15936
+ const handleScoreTextChange = (text) => {
15937
+ setScoreText(text);
15938
+ if (text === "") return;
15939
+ const n = Number(text);
15940
+ if (Number.isFinite(n) && n >= 1 && n <= 1e3 && Number.isInteger(n)) {
15941
+ commitScore(n);
15942
+ }
15943
+ };
15944
+ const handleScoreBlur = () => {
15945
+ const n = scoreText.trim() === "" ? NaN : Number(scoreText);
15946
+ const next = Number.isFinite(n) ? normalizeScore(n) : 1;
15947
+ setScoreText(String(next));
15948
+ if (next !== lastScoreRef.current) commitScore(next);
15949
+ };
15950
+ const update = useCallback5(
15951
+ (next, nextScore) => onChange?.({
15952
+ score: nextScore ?? initScore,
15953
+ ruleConditions: next
15954
+ }),
15955
+ [onChange, initScore]
15956
+ );
15957
+ const handleOptChange = (key, opt) => {
15958
+ update(
15959
+ conditions.map(
15960
+ (c) => c.key === key ? { ...c, opt, value: opt === "BETWEEN" ? [] : void 0 } : c
15961
+ )
15962
+ );
15963
+ };
15964
+ const handleValueChange = (key, val) => {
15965
+ update(conditions.map((c) => c.key === key ? { ...c, value: val } : c));
15966
+ };
15967
+ const handleScoreChange = (key, score) => {
15968
+ update(
15969
+ conditions.map((c) => c.key === key ? { ...c, score } : c)
15970
+ );
15971
+ };
15972
+ const handleAdd = () => update([...conditions, defaultCondition()]);
15973
+ const handleDelete = (key) => update(conditions.filter((c) => c.key !== key));
15974
+ if (disabled) {
15975
+ return /* @__PURE__ */ jsxs114("div", { className: "space-y-2 text-sm", children: [
15976
+ /* @__PURE__ */ jsxs114("div", { className: "flex items-center gap-2 pb-2 border-b", children: [
15977
+ /* @__PURE__ */ jsx172("span", { className: "text-muted-foreground", children: "\u6743\u91CD" }),
15978
+ /* @__PURE__ */ jsx172("span", { className: "font-medium", children: initScore })
15979
+ ] }),
15980
+ conditions.map((condition) => /* @__PURE__ */ jsxs114("div", { className: "flex items-center gap-2", children: [
15981
+ /* @__PURE__ */ jsx172("span", { children: operatorLabel2(condition.opt) }),
15982
+ !NO_VALUE_OPT.includes(condition.opt) && /* @__PURE__ */ jsx172("span", { className: "font-medium", children: formatConditionValue2(condition) }),
15983
+ /* @__PURE__ */ jsxs114("span", { className: "text-muted-foreground", children: [
15984
+ "\u8BC4\u5206: ",
15985
+ condition.score ?? "-"
15986
+ ] })
15987
+ ] }, condition.key))
15988
+ ] });
15989
+ }
15990
+ return /* @__PURE__ */ jsxs114("div", { className: "space-y-2", children: [
15991
+ /* @__PURE__ */ jsxs114("div", { className: "flex items-center gap-1 pb-2 border-b gap-2", children: [
15992
+ /* @__PURE__ */ jsx172("span", { className: "text-sm shrink-0", children: "\u6743\u91CD" }),
15993
+ /* @__PURE__ */ jsx172(
15994
+ Input,
15995
+ {
15996
+ type: "number",
15997
+ className: cn("w-48", CONTROL_SIZE_BOX[size]),
15998
+ min: 1,
15999
+ max: 1e3,
16000
+ step: 1,
16001
+ value: scoreText,
16002
+ disabled,
16003
+ placeholder: "\u8BF7\u8F93\u5165\u6743\u91CD",
16004
+ onChange: (e) => handleScoreTextChange(e.target.value),
16005
+ onBlur: handleScoreBlur
14345
16006
  }
14346
16007
  )
14347
16008
  ] }),
14348
- conditions.map((condition) => /* @__PURE__ */ jsx161(
16009
+ conditions.map((condition) => /* @__PURE__ */ jsx172(
14349
16010
  ConditionRow2,
14350
16011
  {
14351
16012
  condition,
@@ -14360,7 +16021,7 @@ function RuleConfig({ value, onChange, disabled, size = "middle" }) {
14360
16021
  },
14361
16022
  condition.key
14362
16023
  )),
14363
- !disabled && /* @__PURE__ */ jsxs103(
16024
+ !disabled && /* @__PURE__ */ jsxs114(
14364
16025
  Button,
14365
16026
  {
14366
16027
  type: "button",
@@ -14369,7 +16030,7 @@ function RuleConfig({ value, onChange, disabled, size = "middle" }) {
14369
16030
  className: "h-auto p-0 text-sm mt-1",
14370
16031
  onClick: handleAdd,
14371
16032
  children: [
14372
- /* @__PURE__ */ jsx161(Plus2, { className: "h-3.5 w-3.5" }),
16033
+ /* @__PURE__ */ jsx172(Plus2, { className: "h-3.5 w-3.5" }),
14373
16034
  "\u6DFB\u52A0\u6761\u4EF6"
14374
16035
  ]
14375
16036
  }
@@ -14390,9 +16051,9 @@ function ConditionRow2({
14390
16051
  const { opt, value, score } = condition;
14391
16052
  const missingValue = !disabled && !!issue?.missingValue;
14392
16053
  const missingScore = !disabled && !!issue?.missingScore;
14393
- return /* @__PURE__ */ jsxs103("div", { className: "space-y-1", children: [
14394
- /* @__PURE__ */ jsxs103("div", { className: "flex items-center gap-2", children: [
14395
- /* @__PURE__ */ jsxs103(
16054
+ return /* @__PURE__ */ jsxs114("div", { className: "space-y-1", children: [
16055
+ /* @__PURE__ */ jsxs114("div", { className: "flex items-center gap-2", children: [
16056
+ /* @__PURE__ */ jsxs114(
14396
16057
  Select,
14397
16058
  {
14398
16059
  items: OPERATOR_VALUES.map((op) => ({
@@ -14403,23 +16064,23 @@ function ConditionRow2({
14403
16064
  onValueChange: (v) => onOptChange(v),
14404
16065
  disabled,
14405
16066
  children: [
14406
- /* @__PURE__ */ jsx161(
16067
+ /* @__PURE__ */ jsx172(
14407
16068
  SelectTrigger,
14408
16069
  {
14409
16070
  size: CONTROL_SIZE_SELECT_ATTR[size],
14410
16071
  className: cn("w-36 shrink-0", CONTROL_SIZE_TRIGGER_TEXT[size]),
14411
- children: /* @__PURE__ */ jsx161(SelectValue, {})
16072
+ children: /* @__PURE__ */ jsx172(SelectValue, {})
14412
16073
  }
14413
16074
  ),
14414
- /* @__PURE__ */ jsx161(SelectContent, { children: OPERATOR_VALUES.map((op) => /* @__PURE__ */ jsx161(SelectItem, { value: op, children: operatorLabel2(op) }, op)) })
16075
+ /* @__PURE__ */ jsx172(SelectContent, { children: OPERATOR_VALUES.map((op) => /* @__PURE__ */ jsx172(SelectItem, { value: op, children: operatorLabel2(op) }, op)) })
14415
16076
  ]
14416
16077
  }
14417
16078
  ),
14418
- !NO_VALUE_OPT.includes(opt) && /* @__PURE__ */ jsx161(
16079
+ !NO_VALUE_OPT.includes(opt) && /* @__PURE__ */ jsx172(
14419
16080
  "div",
14420
16081
  {
14421
16082
  className: "w-[30%]" + (missingValue ? " [&_input]:border-destructive" : ""),
14422
- children: /* @__PURE__ */ jsx161(
16083
+ children: /* @__PURE__ */ jsx172(
14423
16084
  ValueInput,
14424
16085
  {
14425
16086
  opt,
@@ -14431,7 +16092,7 @@ function ConditionRow2({
14431
16092
  )
14432
16093
  }
14433
16094
  ),
14434
- /* @__PURE__ */ jsx161(
16095
+ /* @__PURE__ */ jsx172(
14435
16096
  Input,
14436
16097
  {
14437
16098
  type: "number",
@@ -14449,7 +16110,7 @@ function ConditionRow2({
14449
16110
  )
14450
16111
  }
14451
16112
  ),
14452
- showDelete && !disabled && /* @__PURE__ */ jsx161(
16113
+ showDelete && !disabled && /* @__PURE__ */ jsx172(
14453
16114
  Button,
14454
16115
  {
14455
16116
  type: "button",
@@ -14457,11 +16118,11 @@ function ConditionRow2({
14457
16118
  size: "icon",
14458
16119
  className: "h-8 w-8 shrink-0 text-muted-foreground hover:text-destructive",
14459
16120
  onClick: onDelete,
14460
- children: /* @__PURE__ */ jsx161(Trash2, { className: "h-4 w-4" })
16121
+ children: /* @__PURE__ */ jsx172(Trash2, { className: "h-4 w-4" })
14461
16122
  }
14462
16123
  )
14463
16124
  ] }),
14464
- !disabled && issue && /* @__PURE__ */ jsx161("p", { className: "text-xs text-destructive", children: [
16125
+ !disabled && issue && /* @__PURE__ */ jsx172("p", { className: "text-xs text-destructive", children: [
14465
16126
  missingValue ? "\u8BF7\u586B\u5199\u53D6\u503C" : null,
14466
16127
  missingScore ? "\u8BF7\u586B\u5199\u8BC4\u5206" : null
14467
16128
  ].filter(Boolean).join("\uFF1B") })
@@ -14473,8 +16134,8 @@ function ValueInput({ opt, value, disabled, size, onChange }) {
14473
16134
  }
14474
16135
  if (opt === "BETWEEN") {
14475
16136
  const [v1, v2] = normalizeBetweenValue(value);
14476
- return /* @__PURE__ */ jsxs103("div", { className: "flex items-center gap-2", children: [
14477
- /* @__PURE__ */ jsx161(
16137
+ return /* @__PURE__ */ jsxs114("div", { className: "flex items-center gap-2", children: [
16138
+ /* @__PURE__ */ jsx172(
14478
16139
  Input,
14479
16140
  {
14480
16141
  type: "number",
@@ -14484,8 +16145,8 @@ function ValueInput({ opt, value, disabled, size, onChange }) {
14484
16145
  onChange: (e) => onChange([e.target.valueAsNumber, v2])
14485
16146
  }
14486
16147
  ),
14487
- /* @__PURE__ */ jsx161("span", { className: "text-muted-foreground text-sm shrink-0", children: "~" }),
14488
- /* @__PURE__ */ jsx161(
16148
+ /* @__PURE__ */ jsx172("span", { className: "text-muted-foreground text-sm shrink-0", children: "~" }),
16149
+ /* @__PURE__ */ jsx172(
14489
16150
  Input,
14490
16151
  {
14491
16152
  type: "number",
@@ -14498,7 +16159,7 @@ function ValueInput({ opt, value, disabled, size, onChange }) {
14498
16159
  ] });
14499
16160
  }
14500
16161
  if (MULTI_VALUE_OPT.includes(opt)) {
14501
- return /* @__PURE__ */ jsx161(
16162
+ return /* @__PURE__ */ jsx172(
14502
16163
  TagInput,
14503
16164
  {
14504
16165
  value: value ?? [],
@@ -14509,7 +16170,7 @@ function ValueInput({ opt, value, disabled, size, onChange }) {
14509
16170
  );
14510
16171
  }
14511
16172
  if (NUMERIC_OPT.includes(opt)) {
14512
- return /* @__PURE__ */ jsx161(
16173
+ return /* @__PURE__ */ jsx172(
14513
16174
  Input,
14514
16175
  {
14515
16176
  type: "number",
@@ -14520,7 +16181,7 @@ function ValueInput({ opt, value, disabled, size, onChange }) {
14520
16181
  }
14521
16182
  );
14522
16183
  }
14523
- return /* @__PURE__ */ jsx161(
16184
+ return /* @__PURE__ */ jsx172(
14524
16185
  Input,
14525
16186
  {
14526
16187
  type: "text",
@@ -14537,7 +16198,7 @@ function TagInput({
14537
16198
  size,
14538
16199
  onChange
14539
16200
  }) {
14540
- const [input, setInput] = useState51("");
16201
+ const [input, setInput] = useState57("");
14541
16202
  const addTag = () => {
14542
16203
  const tag = input.trim();
14543
16204
  if (tag && !value.includes(tag)) {
@@ -14546,7 +16207,7 @@ function TagInput({
14546
16207
  setInput("");
14547
16208
  };
14548
16209
  const removeTag = (tag) => onChange(value.filter((t) => t !== tag));
14549
- return /* @__PURE__ */ jsxs103(
16210
+ return /* @__PURE__ */ jsxs114(
14550
16211
  "div",
14551
16212
  {
14552
16213
  className: cn(
@@ -14555,9 +16216,9 @@ function TagInput({
14555
16216
  ),
14556
16217
  children: [
14557
16218
  " ",
14558
- value.map((tag) => /* @__PURE__ */ jsxs103(Badge, { variant: "secondary", className: "gap-1 pr-1", children: [
16219
+ value.map((tag) => /* @__PURE__ */ jsxs114(Badge, { variant: "secondary", className: "gap-1 pr-1", children: [
14559
16220
  tag,
14560
- !disabled && /* @__PURE__ */ jsx161(
16221
+ !disabled && /* @__PURE__ */ jsx172(
14561
16222
  "button",
14562
16223
  {
14563
16224
  type: "button",
@@ -14567,7 +16228,7 @@ function TagInput({
14567
16228
  }
14568
16229
  )
14569
16230
  ] }, tag)),
14570
- !disabled && /* @__PURE__ */ jsx161(
16231
+ !disabled && /* @__PURE__ */ jsx172(
14571
16232
  "input",
14572
16233
  {
14573
16234
  className: "flex-1 min-w-16 bg-transparent outline-none placeholder:text-muted-foreground",
@@ -14588,8 +16249,8 @@ function TagInput({
14588
16249
  }
14589
16250
 
14590
16251
  // src/components/business/RuleExpression/index.tsx
14591
- import { useLayoutEffect as useLayoutEffect3, useRef as useRef17, useState as useState52 } from "react";
14592
- import { jsx as jsx162, jsxs as jsxs104 } from "react/jsx-runtime";
16252
+ import { useLayoutEffect as useLayoutEffect3, useRef as useRef18, useState as useState58 } from "react";
16253
+ import { jsx as jsx173, jsxs as jsxs115 } from "react/jsx-runtime";
14593
16254
  function trailingWord(text) {
14594
16255
  const m = text.match(/[\w一-龥]+$/u);
14595
16256
  return m ? m[0] : "";
@@ -14727,11 +16388,11 @@ function RuleExpression({
14727
16388
  id,
14728
16389
  className
14729
16390
  }) {
14730
- const editorRef = useRef17(null);
14731
- const [focused, setFocused] = useState52(false);
14732
- const [activeIndex, setActiveIndex] = useState52(0);
14733
- const [matchText, setMatchText] = useState52("");
14734
- const lastEmittedRef = useRef17(null);
16391
+ const editorRef = useRef18(null);
16392
+ const [focused, setFocused] = useState58(false);
16393
+ const [activeIndex, setActiveIndex] = useState58(0);
16394
+ const [matchText, setMatchText] = useState58("");
16395
+ const lastEmittedRef = useRef18(null);
14735
16396
  const matched = matchText ? options.filter((o) => o.label.toLowerCase().includes(matchText.toLowerCase())) : [];
14736
16397
  const showSuggestions = focused && !disabled && matched.length > 0;
14737
16398
  const emitTokens = (tokens) => {
@@ -14879,7 +16540,7 @@ function RuleExpression({
14879
16540
  e.preventDefault();
14880
16541
  }
14881
16542
  };
14882
- return /* @__PURE__ */ jsxs104(
16543
+ return /* @__PURE__ */ jsxs115(
14883
16544
  "div",
14884
16545
  {
14885
16546
  className: cn("relative", className),
@@ -14889,7 +16550,7 @@ function RuleExpression({
14889
16550
  }
14890
16551
  },
14891
16552
  children: [
14892
- /* @__PURE__ */ jsx162(
16553
+ /* @__PURE__ */ jsx173(
14893
16554
  "div",
14894
16555
  {
14895
16556
  ref: editorRef,
@@ -14925,13 +16586,13 @@ function RuleExpression({
14925
16586
  }
14926
16587
  }
14927
16588
  ),
14928
- showSuggestions && /* @__PURE__ */ jsx162(
16589
+ showSuggestions && /* @__PURE__ */ jsx173(
14929
16590
  "ul",
14930
16591
  {
14931
16592
  role: "list",
14932
16593
  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",
14933
16594
  onMouseDown: (e) => e.preventDefault(),
14934
- children: matched.map((opt, index) => /* @__PURE__ */ jsx162("li", { children: /* @__PURE__ */ jsx162(
16595
+ children: matched.map((opt, index) => /* @__PURE__ */ jsx173("li", { children: /* @__PURE__ */ jsx173(
14935
16596
  "button",
14936
16597
  {
14937
16598
  type: "button",
@@ -14952,8 +16613,8 @@ function RuleExpression({
14952
16613
  }
14953
16614
 
14954
16615
  // src/components/business/ScriptEditor/index.tsx
14955
- import { useEffect as useEffect44, useRef as useRef18, useState as useState53 } from "react";
14956
- import { jsx as jsx163, jsxs as jsxs105 } from "react/jsx-runtime";
16616
+ import { useEffect as useEffect45, useRef as useRef19, useState as useState59 } from "react";
16617
+ import { jsx as jsx174, jsxs as jsxs116 } from "react/jsx-runtime";
14957
16618
  function escapeHtml(text) {
14958
16619
  return text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
14959
16620
  }
@@ -15020,12 +16681,12 @@ function ScriptEditor({
15020
16681
  height = 160,
15021
16682
  className
15022
16683
  }) {
15023
- const containerRef = useRef18(null);
15024
- const editorRef = useRef18(null);
15025
- const onChangeRef = useRef18(onChange);
16684
+ const containerRef = useRef19(null);
16685
+ const editorRef = useRef19(null);
16686
+ const onChangeRef = useRef19(onChange);
15026
16687
  onChangeRef.current = onChange;
15027
- const [isEmpty2, setIsEmpty] = useState53(!value);
15028
- useEffect44(() => {
16688
+ const [isEmpty2, setIsEmpty] = useState59(!value);
16689
+ useEffect45(() => {
15029
16690
  let disposed = false;
15030
16691
  (async () => {
15031
16692
  const ace = await import("ace-builds");
@@ -15063,7 +16724,7 @@ function ScriptEditor({
15063
16724
  editorRef.current = null;
15064
16725
  };
15065
16726
  }, []);
15066
- useEffect44(() => {
16727
+ useEffect45(() => {
15067
16728
  const editor = editorRef.current;
15068
16729
  if (!editor) return;
15069
16730
  const next = value ?? "";
@@ -15072,15 +16733,15 @@ function ScriptEditor({
15072
16733
  setIsEmpty(next === "");
15073
16734
  }
15074
16735
  }, [value]);
15075
- useEffect44(() => {
16736
+ useEffect45(() => {
15076
16737
  editorRef.current?.setOptions({
15077
16738
  enableBasicAutocompletion: [buildScriptCompletions(functions, variables)]
15078
16739
  });
15079
16740
  }, [functions, variables]);
15080
- useEffect44(() => {
16741
+ useEffect45(() => {
15081
16742
  editorRef.current?.setReadOnly(readonly ?? false);
15082
16743
  }, [readonly]);
15083
- return /* @__PURE__ */ jsxs105(
16744
+ return /* @__PURE__ */ jsxs116(
15084
16745
  "div",
15085
16746
  {
15086
16747
  className: cn(
@@ -15089,15 +16750,15 @@ function ScriptEditor({
15089
16750
  className
15090
16751
  ),
15091
16752
  children: [
15092
- /* @__PURE__ */ jsx163("div", { ref: containerRef, id, style: { height }, className: "w-full" }),
15093
- isEmpty2 && placeholder && /* @__PURE__ */ jsx163("div", { className: "absolute top-0 left-0 px-3 py-2 text-sm text-muted-foreground pointer-events-none z-10", children: placeholder })
16753
+ /* @__PURE__ */ jsx174("div", { ref: containerRef, id, style: { height }, className: "w-full" }),
16754
+ isEmpty2 && placeholder && /* @__PURE__ */ jsx174("div", { className: "absolute top-0 left-0 px-3 py-2 text-sm text-muted-foreground pointer-events-none z-10", children: placeholder })
15094
16755
  ]
15095
16756
  }
15096
16757
  );
15097
16758
  }
15098
16759
 
15099
16760
  // src/components/business/SiteFooter/index.tsx
15100
- import { jsx as jsx164, jsxs as jsxs106 } from "react/jsx-runtime";
16761
+ import { jsx as jsx175, jsxs as jsxs117 } from "react/jsx-runtime";
15101
16762
  function SiteFooter({
15102
16763
  brand,
15103
16764
  groups,
@@ -15109,7 +16770,7 @@ function SiteFooter({
15109
16770
  }) {
15110
16771
  const renderLink = (link) => {
15111
16772
  if (link.href) {
15112
- return /* @__PURE__ */ jsx164(
16773
+ return /* @__PURE__ */ jsx175(
15113
16774
  Link,
15114
16775
  {
15115
16776
  href: link.href,
@@ -15118,7 +16779,7 @@ function SiteFooter({
15118
16779
  }
15119
16780
  );
15120
16781
  }
15121
- return /* @__PURE__ */ jsx164(
16782
+ return /* @__PURE__ */ jsx175(
15122
16783
  "button",
15123
16784
  {
15124
16785
  type: "button",
@@ -15135,22 +16796,22 @@ function SiteFooter({
15135
16796
  if (!hasBrand && !hasGroups && !hasBottom) {
15136
16797
  return null;
15137
16798
  }
15138
- return /* @__PURE__ */ jsxs106(
16799
+ return /* @__PURE__ */ jsxs117(
15139
16800
  "footer",
15140
16801
  {
15141
16802
  "data-slot": "site-footer",
15142
16803
  className: cn("border-t bg-muted/40", className),
15143
16804
  style,
15144
16805
  children: [
15145
- hasBrand || hasGroups ? /* @__PURE__ */ jsxs106(
16806
+ hasBrand || hasGroups ? /* @__PURE__ */ jsxs117(
15146
16807
  "div",
15147
16808
  {
15148
16809
  "data-slot": "site-footer-main",
15149
16810
  className: "mx-auto flex w-full max-w-6xl flex-col gap-8 px-6 py-10 md:flex-row md:justify-between",
15150
16811
  children: [
15151
- hasBrand ? /* @__PURE__ */ jsxs106("div", { "data-slot": "site-footer-brand", className: "flex max-w-xs flex-col gap-3", children: [
15152
- brand.logo || brand.name ? /* @__PURE__ */ jsxs106("div", { className: "flex items-center gap-2", children: [
15153
- brand.logo ? /* @__PURE__ */ jsx164(
16812
+ hasBrand ? /* @__PURE__ */ jsxs117("div", { "data-slot": "site-footer-brand", className: "flex max-w-xs flex-col gap-3", children: [
16813
+ brand.logo || brand.name ? /* @__PURE__ */ jsxs117("div", { className: "flex items-center gap-2", children: [
16814
+ brand.logo ? /* @__PURE__ */ jsx175(
15154
16815
  "img",
15155
16816
  {
15156
16817
  src: brand.logo,
@@ -15158,23 +16819,23 @@ function SiteFooter({
15158
16819
  className: "size-8 rounded-md object-contain"
15159
16820
  }
15160
16821
  ) : null,
15161
- brand.name ? /* @__PURE__ */ jsx164("span", { className: "text-base font-semibold", children: brand.name }) : null
16822
+ brand.name ? /* @__PURE__ */ jsx175("span", { className: "text-base font-semibold", children: brand.name }) : null
15162
16823
  ] }) : null,
15163
- brand.description ? /* @__PURE__ */ jsx164("p", { className: "text-sm leading-relaxed text-muted-foreground", children: brand.description }) : null
16824
+ brand.description ? /* @__PURE__ */ jsx175("p", { className: "text-sm leading-relaxed text-muted-foreground", children: brand.description }) : null
15164
16825
  ] }) : null,
15165
- hasGroups ? /* @__PURE__ */ jsx164(
16826
+ hasGroups ? /* @__PURE__ */ jsx175(
15166
16827
  "div",
15167
16828
  {
15168
16829
  "data-slot": "site-footer-groups",
15169
16830
  className: "grid flex-1 grid-cols-2 gap-8 sm:grid-cols-3 md:justify-items-end",
15170
- children: groups.map((group) => /* @__PURE__ */ jsxs106(
16831
+ children: groups.map((group) => /* @__PURE__ */ jsxs117(
15171
16832
  "div",
15172
16833
  {
15173
16834
  "data-slot": "site-footer-group",
15174
16835
  className: "flex min-w-24 flex-col gap-3",
15175
16836
  children: [
15176
- /* @__PURE__ */ jsx164("span", { className: "text-sm font-medium", children: group.title }),
15177
- /* @__PURE__ */ jsx164("div", { className: "flex flex-col gap-2", children: group.links.map((link) => /* @__PURE__ */ jsx164("div", { children: renderLink(link) }, link.text)) })
16837
+ /* @__PURE__ */ jsx175("span", { className: "text-sm font-medium", children: group.title }),
16838
+ /* @__PURE__ */ jsx175("div", { className: "flex flex-col gap-2", children: group.links.map((link) => /* @__PURE__ */ jsx175("div", { children: renderLink(link) }, link.text)) })
15178
16839
  ]
15179
16840
  },
15180
16841
  group.title
@@ -15184,9 +16845,9 @@ function SiteFooter({
15184
16845
  ]
15185
16846
  }
15186
16847
  ) : null,
15187
- hasBottom ? /* @__PURE__ */ jsx164("div", { "data-slot": "site-footer-bottom", className: "border-t", children: /* @__PURE__ */ jsxs106("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: [
15188
- copyright ? /* @__PURE__ */ jsx164("span", { children: copyright }) : /* @__PURE__ */ jsx164("span", {}),
15189
- bottomLinks && bottomLinks.length > 0 ? /* @__PURE__ */ jsx164("div", { "data-slot": "site-footer-bottom-links", className: "flex items-center gap-4", children: bottomLinks.map((link) => /* @__PURE__ */ jsx164("div", { children: renderLink(link) }, link.text)) }) : null
16848
+ hasBottom ? /* @__PURE__ */ jsx175("div", { "data-slot": "site-footer-bottom", className: "border-t", children: /* @__PURE__ */ jsxs117("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: [
16849
+ copyright ? /* @__PURE__ */ jsx175("span", { children: copyright }) : /* @__PURE__ */ jsx175("span", {}),
16850
+ bottomLinks && bottomLinks.length > 0 ? /* @__PURE__ */ jsx175("div", { "data-slot": "site-footer-bottom-links", className: "flex items-center gap-4", children: bottomLinks.map((link) => /* @__PURE__ */ jsx175("div", { children: renderLink(link) }, link.text)) }) : null
15190
16851
  ] }) }) : null
15191
16852
  ]
15192
16853
  }
@@ -15366,6 +17027,7 @@ var builtinComponents = {
15366
17027
  Login,
15367
17028
  EntityCard,
15368
17029
  CardList,
17030
+ RecordingPage,
15369
17031
  SiteFooter,
15370
17032
  // 业务表单类组件(value/onChange 受控;DSL 用 props.value + events.onChange 读写 ${event})
15371
17033
  SearchableSelect,
@@ -15553,6 +17215,7 @@ export {
15553
17215
  FieldCondition,
15554
17216
  ExpressionEditor,
15555
17217
  Login,
17218
+ RecordingPage,
15556
17219
  RuleConfig,
15557
17220
  RuleExpression,
15558
17221
  ScriptEditor,