@zerodep-dev/vue-tsx-pro-ui 0.1.0 → 0.2.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.
Files changed (80) hide show
  1. package/dist/code-editor/CodeEditor.d.ts +18 -0
  2. package/dist/code-editor/CodeEditor.js +57 -0
  3. package/dist/code-editor/CodeEditor.js.map +1 -0
  4. package/dist/code-editor/editor.d.ts +52 -0
  5. package/dist/code-editor/editor.js +225 -0
  6. package/dist/code-editor/editor.js.map +1 -0
  7. package/dist/code-editor/index.d.ts +9 -0
  8. package/dist/code-editor/index.js +3 -0
  9. package/dist/config/lang/en-US.js +21 -3
  10. package/dist/config/lang/en-US.js.map +1 -1
  11. package/dist/config/lang/format.d.ts +2 -1
  12. package/dist/config/lang/format.js +9 -2
  13. package/dist/config/lang/format.js.map +1 -1
  14. package/dist/config/lang/lang.d.ts +19 -6
  15. package/dist/config/lang/lang.js +11 -2
  16. package/dist/config/lang/lang.js.map +1 -1
  17. package/dist/config/lang/zh-CN.js +21 -3
  18. package/dist/config/lang/zh-CN.js.map +1 -1
  19. package/dist/diagram/index.d.ts +2 -1
  20. package/dist/diagram/index.js +2 -1
  21. package/dist/diagram/layout.d.ts +57 -0
  22. package/dist/diagram/layout.js +50 -0
  23. package/dist/diagram/layout.js.map +1 -0
  24. package/dist/form/Field.d.ts +7 -0
  25. package/dist/form/Field.js +14 -3
  26. package/dist/form/Field.js.map +1 -1
  27. package/dist/form/useForm.d.ts +4 -1
  28. package/dist/form/useForm.js +35 -13
  29. package/dist/form/useForm.js.map +1 -1
  30. package/dist/index.d.ts +8 -5
  31. package/dist/index.js +8 -5
  32. package/dist/input/Combobox.js +1 -1
  33. package/dist/input/Combobox.js.map +1 -1
  34. package/dist/input/Mentions.js +1 -1
  35. package/dist/input/Mentions.js.map +1 -1
  36. package/dist/input/PeoplePickerPanel.js +11 -11
  37. package/dist/input/PeoplePickerPanel.js.map +1 -1
  38. package/dist/input/Select.js +1 -1
  39. package/dist/input/Select.js.map +1 -1
  40. package/dist/input/TreeSelect.js +1 -1
  41. package/dist/input/TreeSelect.js.map +1 -1
  42. package/dist/input/Upload.js +2 -1
  43. package/dist/input/Upload.js.map +1 -1
  44. package/dist/input/condition.d.ts +1 -1
  45. package/dist/input/condition.js +32 -14
  46. package/dist/input/condition.js.map +1 -1
  47. package/dist/input/people.d.ts +15 -14
  48. package/dist/input/people.js +5 -5
  49. package/dist/input/people.js.map +1 -1
  50. package/dist/input/remote-items.d.ts +4 -2
  51. package/dist/input/remote-items.js +7 -2
  52. package/dist/input/remote-items.js.map +1 -1
  53. package/dist/patterns/QueryTable.d.ts +3 -0
  54. package/dist/patterns/QueryTable.js +39 -14
  55. package/dist/patterns/QueryTable.js.map +1 -1
  56. package/dist/patterns/messages.d.ts +2 -0
  57. package/dist/patterns/messages.js +2 -0
  58. package/dist/patterns/messages.js.map +1 -1
  59. package/dist/utils/data/clone.d.ts +8 -0
  60. package/dist/utils/data/clone.js +21 -0
  61. package/dist/utils/data/clone.js.map +1 -0
  62. package/dist/utils/data/date.d.ts +10 -0
  63. package/dist/utils/data/date.js +13 -1
  64. package/dist/utils/data/date.js.map +1 -1
  65. package/dist/utils/data/numeric.d.ts +7 -0
  66. package/dist/utils/data/numeric.js +46 -1
  67. package/dist/utils/data/numeric.js.map +1 -1
  68. package/dist/utils/dom/download.d.ts +8 -1
  69. package/dist/utils/dom/download.js +19 -2
  70. package/dist/utils/dom/download.js.map +1 -1
  71. package/dist/utils/request/error-message.d.ts +17 -0
  72. package/dist/utils/request/error-message.js +50 -0
  73. package/dist/utils/request/error-message.js.map +1 -0
  74. package/dist/utils/request/http.d.ts +68 -4
  75. package/dist/utils/request/http.js +116 -23
  76. package/dist/utils/request/http.js.map +1 -1
  77. package/dist/utils/request/use-autosave.d.ts +35 -0
  78. package/dist/utils/request/use-autosave.js +69 -0
  79. package/dist/utils/request/use-autosave.js.map +1 -0
  80. package/package.json +57 -4
@@ -1,8 +1,13 @@
1
+ import { useLang } from "../config/context.js";
1
2
  import { mergeAttrs, mergePartProps } from "../utils/props.js";
3
+ import { Button } from "../base/Button.js";
2
4
  import { IconButton } from "../base/IconButton.js";
5
+ import { Alert } from "../feedback/Alert.js";
3
6
  import { Menu as Menu$1, MenuRadioGroup, MenuRadioItem } from "../overlay/Menu.js";
7
+ import { errorMessage } from "../utils/request/error-message.js";
4
8
  import { PaginationBar } from "../navigation/PaginationBar.js";
5
9
  import { usePersistentState } from "../utils/dom/storage.js";
10
+ import { cloneValue } from "../utils/data/clone.js";
6
11
  import { ColumnSettings } from "../table/ColumnSettings.js";
7
12
  import { DataTable } from "../table/DataTable.js";
8
13
  import { SelectionBar } from "../table/SelectionBar.js";
@@ -10,7 +15,7 @@ import { useMessages } from "../config/lang/messages.js";
10
15
  import { useFullscreen } from "../utils/dom/fullscreen.js";
11
16
  import { patternsMessages } from "./messages.js";
12
17
  import { FilterBar } from "./FilterBar.js";
13
- import { createVNode, mergeProps, reactive, shallowRef, toRaw } from "vue";
18
+ import { createVNode, mergeProps, reactive, shallowRef } from "vue";
14
19
  import { _component, bindable, readonlyProp, restProps, untrack } from "@zerodep-dev/vue-tsx-pro-tsx";
15
20
  import * as css from "@zerodep-dev/vue-tsx-pro-tsx/styles";
16
21
  import { Maximize, Minimize, RefreshCw, Rows3 } from "@lucide/icons";
@@ -100,10 +105,12 @@ var QueryTable = /*#__PURE__*/ _component((_props, _ctx) => {
100
105
  const propsTable = readonlyProp(_props, "propsTable");
101
106
  const propsSelectionBar = readonlyProp(_props, "propsSelectionBar");
102
107
  const propsPagination = readonlyProp(_props, "propsPagination");
108
+ const propsError = readonlyProp(_props, "propsError");
103
109
  const propsToolbarButton = readonlyProp(_props, "propsToolbarButton");
104
110
  const rest = restProps(_props, _ctx, true);
105
111
  const messages = useMessages("patterns", patternsMessages);
106
- const initial = structuredClone(toRaw(untrack(() => query.value.filters)));
112
+ const lang = useLang();
113
+ const initial = cloneValue(untrack(() => query.value.filters));
107
114
  const draft = reactive({ ...initial });
108
115
  const key = untrack(() => persistKey.value);
109
116
  let hidden = settingRef(key, "hidden", []);
@@ -114,10 +121,10 @@ var QueryTable = /*#__PURE__*/ _component((_props, _ctx) => {
114
121
  let panel = shallowRef(null);
115
122
  const fullscreen = useFullscreen(() => panel.value);
116
123
  function search() {
117
- query.value.search(structuredClone(toRaw(draft)));
124
+ query.value.search(cloneValue(draft));
118
125
  }
119
126
  function reset() {
120
- Object.assign(draft, structuredClone(toRaw(blankFilters.value ?? initial)));
127
+ Object.assign(draft, cloneValue(blankFilters.value ?? initial));
121
128
  search();
122
129
  }
123
130
  const toolButton = (props) => mergePartProps({
@@ -204,6 +211,23 @@ var QueryTable = /*#__PURE__*/ _component((_props, _ctx) => {
204
211
  default: () => [batchActions.value?.(selected.value)],
205
212
  $stable: true
206
213
  }),
214
+ query.value.error !== void 0 && createVNode(Alert, mergeProps(mergePartProps({
215
+ tone: "danger",
216
+ live: "assertive",
217
+ action: createVNode(Button, {
218
+ "size": "sm",
219
+ "variant": "outline",
220
+ "tone": "danger",
221
+ "onClick": _cache[5] || (_cache[5] = () => void query.value.refresh()),
222
+ "key": "__site2"
223
+ }, {
224
+ default: () => [messages.queryTableRetry],
225
+ $stable: true
226
+ })
227
+ }, propsError.value), { "key": "__site3" }), {
228
+ default: () => [errorMessage(query.value.error, lang)],
229
+ $stable: true
230
+ }),
207
231
  createVNode(DataTable, mergeProps(mergePartProps({
208
232
  "aria-label": title.value,
209
233
  flexible: fullscreen.active
@@ -214,33 +238,33 @@ var QueryTable = /*#__PURE__*/ _component((_props, _ctx) => {
214
238
  "manualSort": true,
215
239
  "multiSort": multiSort.value,
216
240
  "_sort": query.value.sort,
217
- "onUpdate:_sort": _cache[5] || (_cache[5] = ($event) => query.value.sort = $event),
241
+ "onUpdate:_sort": _cache[6] || (_cache[6] = ($event) => query.value.sort = $event),
218
242
  "_sorts": query.value.sorts,
219
- "onUpdate:_sorts": _cache[6] || (_cache[6] = ($event) => query.value.sorts = $event),
243
+ "onUpdate:_sorts": _cache[7] || (_cache[7] = ($event) => query.value.sorts = $event),
220
244
  "manualFilter": true,
221
245
  "_filters": query.value.columnFilters,
222
- "onUpdate:_filters": _cache[7] || (_cache[7] = ($event) => query.value.columnFilters = $event),
246
+ "onUpdate:_filters": _cache[8] || (_cache[8] = ($event) => query.value.columnFilters = $event),
223
247
  "loading": query.value.loading,
224
248
  "density": density.value,
225
249
  "selectionMode": selectionMode.value,
226
250
  "_selected": selected.value,
227
- "onUpdate:_selected": _cache[8] || (_cache[8] = ($event) => selected.value = $event),
251
+ "onUpdate:_selected": _cache[9] || (_cache[9] = ($event) => selected.value = $event),
228
252
  "_hiddenColumns": hidden.value,
229
- "onUpdate:_hiddenColumns": _cache[9] || (_cache[9] = ($event) => hidden.value = $event),
253
+ "onUpdate:_hiddenColumns": _cache[10] || (_cache[10] = ($event) => hidden.value = $event),
230
254
  "_columnOrder": order.value,
231
- "onUpdate:_columnOrder": _cache[10] || (_cache[10] = ($event) => order.value = $event),
255
+ "onUpdate:_columnOrder": _cache[11] || (_cache[11] = ($event) => order.value = $event),
232
256
  "_columnPins": pins.value,
233
- "onUpdate:_columnPins": _cache[11] || (_cache[11] = ($event) => pins.value = $event),
257
+ "onUpdate:_columnPins": _cache[12] || (_cache[12] = ($event) => pins.value = $event),
234
258
  "_columnWidths": widths.value,
235
- "onUpdate:_columnWidths": _cache[12] || (_cache[12] = ($event) => widths.value = $event),
259
+ "onUpdate:_columnWidths": _cache[13] || (_cache[13] = ($event) => widths.value = $event),
236
260
  "resizable": true,
237
261
  "columnMenu": true
238
262
  }), null),
239
263
  createVNode(PaginationBar, mergeProps(mergePartProps({ propsPagination: { "aria-label": messages.queryTablePagination(title.value) } }, propsPagination.value), {
240
264
  "_page": query.value.page,
241
- "onUpdate:_page": _cache[13] || (_cache[13] = ($event) => query.value.page = $event),
265
+ "onUpdate:_page": _cache[14] || (_cache[14] = ($event) => query.value.page = $event),
242
266
  "_pageSize": query.value.pageSize,
243
- "onUpdate:_pageSize": _cache[14] || (_cache[14] = ($event) => query.value.pageSize = $event),
267
+ "onUpdate:_pageSize": _cache[15] || (_cache[15] = ($event) => query.value.pageSize = $event),
244
268
  "total": query.value.total
245
269
  }), null)
246
270
  ])]);
@@ -267,6 +291,7 @@ var QueryTable = /*#__PURE__*/ _component((_props, _ctx) => {
267
291
  "propsTable",
268
292
  "propsSelectionBar",
269
293
  "propsPagination",
294
+ "propsError",
270
295
  "propsToolbarButton"
271
296
  ]
272
297
  });
@@ -1 +1 @@
1
- {"version":3,"file":"QueryTable.js","names":["_vtp_readonlyProp","_vtp_bindable","_vtp_restProps","_vtp_untrack","_vue_shallowRef","_createVNode","Menu","_mergeProps"],"sources":["../../src/patterns/QueryTable.tsx"],"sourcesContent":["/**\n * 查询表格(列表页的整块):查询栏(FilterBar)+ 工具栏(标题、自己的按钮、刷新、行高、列设置、全屏)+ 批量操作栏 + 数据表格 + 分页栏,\n * 状态都在 useTableQuery 里(服务端分页、排序、条件)。同 Ant Design ProComponents 的 ProTable。\n *\n * const tasks = useTableQuery(fetchTasks, { filters: { keyword: '', status: '' }, pageSize: 20 });\n * <QueryTable\n * query={tasks} columns={columns} getKey={(task) => task.id} title=\"任务台账\" persistKey=\"tasks\"\n * filters={(draft) => <Field label=\"关键字\"><TextField _value={draft.keyword} /></Field>}\n * toolbar={<Button icon={Plus}>新建</Button>}\n * />\n *\n * - 查询栏的条件改的是草稿(draft),点“查询”(或回车)才交给 query.search;“重置”回到 blankFilters(不写时是一开始的条件)并查询。\n * - 表头排序交给服务端(manualSort,写回 query.sort;multiSort 时按住 Shift 追加一列,写回 query.sorts),\n * 表头筛选也交给服务端(manualFilter,写回 query.columnFilters;列的 filter 要写 options,否则只列出当前这页出现过的值),\n * 分页栏绑定 query.page / pageSize / total。fetcher 用 tableParams(query, columns) 把这些写成接口的参数。\n * - persistKey:列设置(显示、顺序、固定、列宽)与行高记在浏览器里,下次打开还是这样。\n * - selectionMode 时勾选行,表格上方出现批量操作栏,batchActions 拿到已选的 key 给出按钮。\n *\n * 部件:Root(div)、FilterBar、Panel(工具栏与表格所在的区域,全屏的就是它)、Toolbar(div)、Title(div)、\n * Table(DataTable)、SelectionBar、Pagination(PaginationBar)。\n */\nimport { Maximize, Minimize, RefreshCw, Rows3 } from '@lucide/icons';\nimport { _component } from '@zerodep-dev/vue-tsx-pro-tsx';\nimport * as css from '@zerodep-dev/vue-tsx-pro-tsx/styles';\nimport { reactive, shallowRef, toRaw, type Ref, type VNodeChild } from 'vue';\nimport { IconButton, type IconButtonProps } from '../base/IconButton';\nimport { useMessages } from '../config/lang/messages';\nimport { PaginationBar, type PaginationBarProps } from '../navigation/PaginationBar';\nimport { Menu, MenuRadioGroup, MenuRadioItem } from '../overlay/Menu';\nimport { ColumnSettings } from '../table/ColumnSettings';\nimport type { ColumnStickies, DataTableColumn } from '../table/columns';\nimport { DataTable, type DataTableProps } from '../table/DataTable';\nimport { SelectionBar, type SelectionBarProps } from '../table/SelectionBar';\nimport type { DataTableDensities } from '../table/table-styles';\nimport type { TablePage, TableQueryState } from '../table/use-table-query';\nimport { useFullscreen } from '../utils/dom/fullscreen';\nimport { usePersistentState } from '../utils/dom/storage';\nimport { mergeAttrs, mergePartProps, type PartProps } from '../utils/props';\nimport { FilterBar, type FilterBarProps } from './FilterBar';\nimport { patternsMessages } from './messages';\n\n/** 未声明的属性落到外层 div 上 */\nexport interface QueryTableProps<T, Filters extends object> extends PartProps<'div'> {\n /** 列表状态:useTableQuery 的返回值 */\n query: TableQueryState<TablePage<T>, Filters>;\n /** 列定义 */\n columns: readonly DataTableColumn<T>[];\n /** 行的 key */\n getKey: (row: T, index: number) => string;\n /** 表格的名称(工具栏起始边的标题,也是表格的 aria-label) */\n title: string;\n /** 查询栏的条件:拿到草稿,控件绑定它的字段(`_value={draft.keyword}`);不写时没有查询栏 */\n filters?: (draft: Filters) => VNodeChild;\n /** 收起的条件(不常用的),点“展开”才显示 */\n moreFilters?: (draft: Filters) => VNodeChild;\n /** “重置”回到的条件;不写时是 query 一开始的条件 */\n blankFilters?: Filters;\n /** 工具栏上自己的按钮(新建、导出),在标题之后、内置按钮之前 */\n toolbar?: VNodeChild;\n /** 列设置与行高记在浏览器里的键(localStorage,自动加前缀);不写时只在这次打开里有效 */\n persistKey?: string;\n /** 多列排序:按住 Shift 点列标题追加一列(同 DataTable 的 multiSort),排序写在 query.sorts */\n multiSort?: boolean;\n /** 勾选行:多选时表格上方出现批量操作栏 */\n selectionMode?: DataTableProps<T>['selectionMode'];\n /** 已选行的 key:父级写 _selected={keys} */\n _selected?: string[];\n /** 批量操作栏里的按钮:拿到已选的 key */\n batchActions?: (keys: readonly string[]) => VNodeChild;\n /** 查询栏(FilterBar)的部件属性 */\n propsFilterBar?: Partial<FilterBarProps>;\n /** 工具栏与表格所在区域的部件属性(全屏的就是它) */\n propsPanel?: PartProps<'div'>;\n /** 工具栏的部件属性 */\n propsToolbar?: PartProps<'div'>;\n /** 表格(DataTable)的部件属性:列宽、详情行、行的色调等直接写在这里 */\n propsTable?: Partial<DataTableProps<T>>;\n /** 批量操作栏的部件属性 */\n propsSelectionBar?: Partial<SelectionBarProps>;\n /** 分页栏的部件属性 */\n propsPagination?: Partial<PaginationBarProps>;\n /** 工具栏内置按钮(刷新、行高、全屏)的部件属性 */\n propsToolbarButton?: Partial<IconButtonProps>;\n}\n\n/** QueryTable 的样式:root、panel、panelFullscreen、toolbar、title、tools */\nexport const queryTableStyles = css.create({\n root: { display: 'flex', flexDirection: 'column', gap: '_md', minWidth: 0 },\n panel: {\n display: 'flex',\n flexDirection: 'column',\n gap: '_sm',\n minWidth: 0,\n backgroundColor: '_surface',\n },\n // 全屏时铺满屏幕、四周留白,表格占满剩下的高度\n panelFullscreen: { padding: '_lg', overflow: 'auto' },\n toolbar: { display: 'flex', alignItems: 'center', flexWrap: 'wrap', gap: '_sm' },\n title: { flexGrow: 1, minWidth: 0, fontWeight: '_semibold', fontSize: '_lg' },\n tools: { display: 'flex', alignItems: 'center', gap: '_xs' },\n});\n\n/** 存在浏览器里(给了 persistKey)或只在这次打开里有效的状态 */\nfunction settingRef<V>(key: string | undefined, name: string, initial: V): Ref<V> {\n return key ? usePersistentState(`${key}:${name}`, initial) : shallowRef(initial);\n}\n\n/** 查询表格:查询栏 + 工具栏 + 表格 + 分页,状态来自 useTableQuery */\nexport const QueryTable = _component(\n <T, Filters extends object>({\n query,\n columns,\n getKey,\n title,\n filters,\n moreFilters,\n blankFilters,\n toolbar,\n persistKey,\n multiSort = false,\n selectionMode,\n _selected: selected = _bindable<string[]>([]),\n batchActions,\n propsFilterBar,\n propsPanel,\n propsToolbar,\n propsTable,\n propsSelectionBar,\n propsPagination,\n propsToolbarButton,\n ...rest\n }: QueryTableProps<T, Filters>) => {\n const messages = useMessages('patterns', patternsMessages);\n // 查询栏改的是草稿:点“查询”才交给 query\n const initial = structuredClone(toRaw(_untrack(query.filters)));\n const draft = reactive({ ...initial }) as Filters;\n const key = _untrack(persistKey);\n let hidden = _fromRef(settingRef<string[]>(key, 'hidden', []));\n let order = _fromRef(settingRef<string[]>(key, 'order', []));\n let pins = _fromRef(settingRef<Record<string, keyof ColumnStickies | null>>(key, 'pins', {}));\n let widths = _fromRef(settingRef<Record<string, number>>(key, 'widths', {}));\n let density = _fromRef(settingRef<keyof DataTableDensities>(key, 'density', 'standard'));\n let panel = _state.raw<HTMLElement | null>(null);\n const fullscreen = useFullscreen(() => panel);\n\n function search() {\n query.search(structuredClone(toRaw(draft)) as Filters);\n }\n\n function reset() {\n Object.assign(draft, structuredClone(toRaw(blankFilters ?? initial)));\n search();\n }\n\n const toolButton = (props: Partial<IconButtonProps>) =>\n mergePartProps<IconButtonProps>(\n { icon: RefreshCw, variant: 'ghost', tone: 'neutral', 'aria-label': '' },\n propsToolbarButton,\n props,\n );\n\n function renderTools() {\n return (\n <div {...css.attrs(queryTableStyles.tools)}>\n <IconButton\n {...toolButton({\n icon: RefreshCw,\n 'aria-label': messages.queryTableRefresh,\n loading: query.loading,\n onClick: () => void query.refresh(),\n })}\n />\n <Menu\n placement=\"bottom-end\"\n trigger={(props) => (\n <IconButton\n {...toolButton({ icon: Rows3, 'aria-label': messages.queryTableDensity })}\n {...props}\n />\n )}\n >\n <MenuRadioGroup\n _value={density}\n onUpdate:_value={(value: string) => (density = value as keyof DataTableDensities)}\n >\n <MenuRadioItem value=\"compact\">{messages.queryTableDensityCompact}</MenuRadioItem>\n <MenuRadioItem value=\"standard\">{messages.queryTableDensityStandard}</MenuRadioItem>\n <MenuRadioItem value=\"comfortable\">\n {messages.queryTableDensityComfortable}\n </MenuRadioItem>\n </MenuRadioGroup>\n </Menu>\n <ColumnSettings\n columns={columns}\n _hidden={hidden}\n _order={order}\n onReset={() => {\n pins = {};\n widths = {};\n }}\n propsTrigger={propsToolbarButton}\n />\n {fullscreen.supported && (\n <IconButton\n {...toolButton({\n icon: fullscreen.active ? Minimize : Maximize,\n 'aria-label': fullscreen.active\n ? messages.queryTableExitFullscreen\n : messages.queryTableFullscreen,\n 'aria-pressed': fullscreen.active,\n onClick: () => void fullscreen.toggle(),\n })}\n />\n )}\n </div>\n );\n }\n\n return () => (\n <div {...mergeAttrs<'div'>({ sx: queryTableStyles.root }, rest)}>\n {filters && (\n <FilterBar\n {...mergePartProps<Partial<FilterBarProps>>(\n // 一页上可能有几个查询栏:各有名称,search 地标才分得清\n { 'aria-label': messages.queryTableSearch(title) },\n propsFilterBar,\n {\n onSearch: search,\n onReset: reset,\n loading: query.loading,\n more: moreFilters?.(draft),\n },\n )}\n >\n {filters(draft)}\n </FilterBar>\n )}\n <div\n {...mergeAttrs<'div'>(\n {\n sx: [queryTableStyles.panel, fullscreen.active && queryTableStyles.panelFullscreen],\n },\n propsPanel,\n { ref: _toRef(panel) },\n )}\n >\n <div {...mergeAttrs<'div'>({ sx: queryTableStyles.toolbar }, propsToolbar)}>\n <div {...css.attrs(queryTableStyles.title)}>{title}</div>\n {toolbar}\n {renderTools()}\n </div>\n {selectionMode === 'multiple' && (\n <SelectionBar\n {...mergePartProps<SelectionBarProps>({ count: selected.length }, propsSelectionBar, {\n count: selected.length,\n onClear: () => (selected = []),\n })}\n >\n {batchActions?.(selected)}\n </SelectionBar>\n )}\n <DataTable\n {...mergePartProps<Partial<DataTableProps<T>>>(\n { 'aria-label': title, flexible: fullscreen.active },\n propsTable,\n )}\n rows={query.rows as T[]}\n columns={columns}\n getKey={getKey}\n manualSort\n multiSort={multiSort}\n _sort={query.sort}\n _sorts={query.sorts}\n manualFilter\n _filters={query.columnFilters}\n loading={query.loading}\n density={density}\n selectionMode={selectionMode}\n _selected={selected}\n _hiddenColumns={hidden}\n _columnOrder={order}\n _columnPins={pins}\n _columnWidths={widths}\n resizable\n columnMenu\n />\n <PaginationBar\n {...mergePartProps<Partial<PaginationBarProps>>(\n { propsPagination: { 'aria-label': messages.queryTablePagination(title) } },\n propsPagination,\n )}\n _page={query.page}\n _pageSize={query.pageSize}\n total={query.total}\n />\n </div>\n </div>\n );\n },\n);\n"],"mappings":"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"}
1
+ {"version":3,"file":"QueryTable.js","names":["_vtp_readonlyProp","_vtp_bindable","_vtp_restProps","_vtp_untrack","_vue_shallowRef","_createVNode","Menu","_mergeProps"],"sources":["../../src/patterns/QueryTable.tsx"],"sourcesContent":["/**\n * 查询表格(列表页的整块):查询栏(FilterBar)+ 工具栏(标题、自己的按钮、刷新、行高、列设置、全屏)+ 批量操作栏 + 数据表格 + 分页栏,\n * 状态都在 useTableQuery 里(服务端分页、排序、条件)。同 Ant Design ProComponents 的 ProTable。\n *\n * const tasks = useTableQuery(fetchTasks, { filters: { keyword: '', status: '' }, pageSize: 20 });\n * <QueryTable\n * query={tasks} columns={columns} getKey={(task) => task.id} title=\"任务台账\" persistKey=\"tasks\"\n * filters={(draft) => <Field label=\"关键字\"><TextField _value={draft.keyword} /></Field>}\n * toolbar={<Button icon={Plus}>新建</Button>}\n * />\n *\n * - 查询栏的条件改的是草稿(draft),点“查询”(或回车)才交给 query.search;“重置”回到 blankFilters(不写时是一开始的条件)并查询。\n * - 表头排序交给服务端(manualSort,写回 query.sort;multiSort 时按住 Shift 追加一列,写回 query.sorts),\n * 表头筛选也交给服务端(manualFilter,写回 query.columnFilters;列的 filter 要写 options,否则只列出当前这页出现过的值),\n * 分页栏绑定 query.page / pageSize / total。fetcher 用 tableParams(query, columns) 把这些写成接口的参数。\n * - persistKey:列设置(显示、顺序、固定、列宽)与行高记在浏览器里,下次打开还是这样。\n * - selectionMode 时勾选行,表格上方出现批量操作栏,batchActions 拿到已选的 key 给出按钮。\n *\n * 部件:Root(div)、FilterBar、Panel(工具栏与表格所在的区域,全屏的就是它)、Toolbar(div)、Title(div)、\n * Table(DataTable)、SelectionBar、Pagination(PaginationBar)。\n */\nimport { Maximize, Minimize, RefreshCw, Rows3 } from '@lucide/icons';\nimport { _component } from '@zerodep-dev/vue-tsx-pro-tsx';\nimport * as css from '@zerodep-dev/vue-tsx-pro-tsx/styles';\nimport { reactive, shallowRef, type Ref, type VNodeChild } from 'vue';\nimport { Button } from '../base/Button';\nimport { IconButton, type IconButtonProps } from '../base/IconButton';\nimport { useLang } from '../config/context';\nimport { useMessages } from '../config/lang/messages';\nimport { Alert, type AlertProps } from '../feedback/Alert';\nimport { PaginationBar, type PaginationBarProps } from '../navigation/PaginationBar';\nimport { Menu, MenuRadioGroup, MenuRadioItem } from '../overlay/Menu';\nimport { ColumnSettings } from '../table/ColumnSettings';\nimport type { ColumnStickies, DataTableColumn } from '../table/columns';\nimport { DataTable, type DataTableProps } from '../table/DataTable';\nimport { SelectionBar, type SelectionBarProps } from '../table/SelectionBar';\nimport type { DataTableDensities } from '../table/table-styles';\nimport type { TablePage, TableQueryState } from '../table/use-table-query';\nimport { cloneValue } from '../utils/data/clone';\nimport { useFullscreen } from '../utils/dom/fullscreen';\nimport { usePersistentState } from '../utils/dom/storage';\nimport { mergeAttrs, mergePartProps, type PartProps } from '../utils/props';\nimport { errorMessage } from '../utils/request/error-message';\nimport { FilterBar, type FilterBarProps } from './FilterBar';\nimport { patternsMessages } from './messages';\n\n/** 未声明的属性落到外层 div 上 */\nexport interface QueryTableProps<T, Filters extends object> extends PartProps<'div'> {\n /** 列表状态:useTableQuery 的返回值 */\n query: TableQueryState<TablePage<T>, Filters>;\n /** 列定义 */\n columns: readonly DataTableColumn<T>[];\n /** 行的 key */\n getKey: (row: T, index: number) => string;\n /** 表格的名称(工具栏起始边的标题,也是表格的 aria-label) */\n title: string;\n /** 查询栏的条件:拿到草稿,控件绑定它的字段(`_value={draft.keyword}`);不写时没有查询栏 */\n filters?: (draft: Filters) => VNodeChild;\n /** 收起的条件(不常用的),点“展开”才显示 */\n moreFilters?: (draft: Filters) => VNodeChild;\n /** “重置”回到的条件;不写时是 query 一开始的条件 */\n blankFilters?: Filters;\n /** 工具栏上自己的按钮(新建、导出),在标题之后、内置按钮之前 */\n toolbar?: VNodeChild;\n /** 列设置与行高记在浏览器里的键(localStorage,自动加前缀);不写时只在这次打开里有效 */\n persistKey?: string;\n /** 多列排序:按住 Shift 点列标题追加一列(同 DataTable 的 multiSort),排序写在 query.sorts */\n multiSort?: boolean;\n /** 勾选行:多选时表格上方出现批量操作栏 */\n selectionMode?: DataTableProps<T>['selectionMode'];\n /** 已选行的 key:父级写 _selected={keys} */\n _selected?: string[];\n /** 批量操作栏里的按钮:拿到已选的 key */\n batchActions?: (keys: readonly string[]) => VNodeChild;\n /** 查询栏(FilterBar)的部件属性 */\n propsFilterBar?: Partial<FilterBarProps>;\n /** 工具栏与表格所在区域的部件属性(全屏的就是它) */\n propsPanel?: PartProps<'div'>;\n /** 工具栏的部件属性 */\n propsToolbar?: PartProps<'div'>;\n /** 表格(DataTable)的部件属性:列宽、详情行、行的色调等直接写在这里 */\n propsTable?: Partial<DataTableProps<T>>;\n /** 批量操作栏的部件属性 */\n propsSelectionBar?: Partial<SelectionBarProps>;\n /** 分页栏的部件属性 */\n propsPagination?: Partial<PaginationBarProps>;\n /** 加载失败时表格上方的提示条(Alert)的部件属性 */\n propsError?: Partial<AlertProps>;\n /** 工具栏内置按钮(刷新、行高、全屏)的部件属性 */\n propsToolbarButton?: Partial<IconButtonProps>;\n}\n\n/** QueryTable 的样式:root、panel、panelFullscreen、toolbar、title、tools */\nexport const queryTableStyles = css.create({\n root: { display: 'flex', flexDirection: 'column', gap: '_md', minWidth: 0 },\n panel: {\n display: 'flex',\n flexDirection: 'column',\n gap: '_sm',\n minWidth: 0,\n backgroundColor: '_surface',\n },\n // 全屏时铺满屏幕、四周留白,表格占满剩下的高度\n panelFullscreen: { padding: '_lg', overflow: 'auto' },\n toolbar: { display: 'flex', alignItems: 'center', flexWrap: 'wrap', gap: '_sm' },\n title: { flexGrow: 1, minWidth: 0, fontWeight: '_semibold', fontSize: '_lg' },\n tools: { display: 'flex', alignItems: 'center', gap: '_xs' },\n});\n\n/** 存在浏览器里(给了 persistKey)或只在这次打开里有效的状态 */\nfunction settingRef<V>(key: string | undefined, name: string, initial: V): Ref<V> {\n return key ? usePersistentState(`${key}:${name}`, initial) : shallowRef(initial);\n}\n\n/** 查询表格:查询栏 + 工具栏 + 表格 + 分页,状态来自 useTableQuery */\nexport const QueryTable = _component(\n <T, Filters extends object>({\n query,\n columns,\n getKey,\n title,\n filters,\n moreFilters,\n blankFilters,\n toolbar,\n persistKey,\n multiSort = false,\n selectionMode,\n _selected: selected = _bindable<string[]>([]),\n batchActions,\n propsFilterBar,\n propsPanel,\n propsToolbar,\n propsTable,\n propsSelectionBar,\n propsPagination,\n propsError,\n propsToolbarButton,\n ...rest\n }: QueryTableProps<T, Filters>) => {\n const messages = useMessages('patterns', patternsMessages);\n const lang = useLang();\n // 查询栏改的是草稿:点“查询”才交给 query\n // 用 cloneValue 不用 structuredClone:条件里的日期(CalendarDate)、Decimal 要保持原样\n const initial = cloneValue(_untrack(query.filters));\n const draft = reactive({ ...initial }) as Filters;\n const key = _untrack(persistKey);\n let hidden = _fromRef(settingRef<string[]>(key, 'hidden', []));\n let order = _fromRef(settingRef<string[]>(key, 'order', []));\n let pins = _fromRef(settingRef<Record<string, keyof ColumnStickies | null>>(key, 'pins', {}));\n let widths = _fromRef(settingRef<Record<string, number>>(key, 'widths', {}));\n let density = _fromRef(settingRef<keyof DataTableDensities>(key, 'density', 'standard'));\n let panel = _state.raw<HTMLElement | null>(null);\n const fullscreen = useFullscreen(() => panel);\n\n function search() {\n query.search(cloneValue(draft) as Filters);\n }\n\n function reset() {\n Object.assign(draft, cloneValue(blankFilters ?? initial));\n search();\n }\n\n const toolButton = (props: Partial<IconButtonProps>) =>\n mergePartProps<IconButtonProps>(\n { icon: RefreshCw, variant: 'ghost', tone: 'neutral', 'aria-label': '' },\n propsToolbarButton,\n props,\n );\n\n function renderTools() {\n return (\n <div {...css.attrs(queryTableStyles.tools)}>\n <IconButton\n {...toolButton({\n icon: RefreshCw,\n 'aria-label': messages.queryTableRefresh,\n loading: query.loading,\n onClick: () => void query.refresh(),\n })}\n />\n <Menu\n placement=\"bottom-end\"\n trigger={(props) => (\n <IconButton\n {...toolButton({ icon: Rows3, 'aria-label': messages.queryTableDensity })}\n {...props}\n />\n )}\n >\n <MenuRadioGroup\n _value={density}\n onUpdate:_value={(value: string) => (density = value as keyof DataTableDensities)}\n >\n <MenuRadioItem value=\"compact\">{messages.queryTableDensityCompact}</MenuRadioItem>\n <MenuRadioItem value=\"standard\">{messages.queryTableDensityStandard}</MenuRadioItem>\n <MenuRadioItem value=\"comfortable\">\n {messages.queryTableDensityComfortable}\n </MenuRadioItem>\n </MenuRadioGroup>\n </Menu>\n <ColumnSettings\n columns={columns}\n _hidden={hidden}\n _order={order}\n onReset={() => {\n pins = {};\n widths = {};\n }}\n propsTrigger={propsToolbarButton}\n />\n {fullscreen.supported && (\n <IconButton\n {...toolButton({\n icon: fullscreen.active ? Minimize : Maximize,\n 'aria-label': fullscreen.active\n ? messages.queryTableExitFullscreen\n : messages.queryTableFullscreen,\n 'aria-pressed': fullscreen.active,\n onClick: () => void fullscreen.toggle(),\n })}\n />\n )}\n </div>\n );\n }\n\n return () => (\n <div {...mergeAttrs<'div'>({ sx: queryTableStyles.root }, rest)}>\n {filters && (\n <FilterBar\n {...mergePartProps<Partial<FilterBarProps>>(\n // 一页上可能有几个查询栏:各有名称,search 地标才分得清\n { 'aria-label': messages.queryTableSearch(title) },\n propsFilterBar,\n {\n onSearch: search,\n onReset: reset,\n loading: query.loading,\n more: moreFilters?.(draft),\n },\n )}\n >\n {filters(draft)}\n </FilterBar>\n )}\n <div\n {...mergeAttrs<'div'>(\n {\n sx: [queryTableStyles.panel, fullscreen.active && queryTableStyles.panelFullscreen],\n },\n propsPanel,\n { ref: _toRef(panel) },\n )}\n >\n <div {...mergeAttrs<'div'>({ sx: queryTableStyles.toolbar }, propsToolbar)}>\n <div {...css.attrs(queryTableStyles.title)}>{title}</div>\n {toolbar}\n {renderTools()}\n </div>\n {selectionMode === 'multiple' && (\n <SelectionBar\n {...mergePartProps<SelectionBarProps>({ count: selected.length }, propsSelectionBar, {\n count: selected.length,\n onClear: () => (selected = []),\n })}\n >\n {batchActions?.(selected)}\n </SelectionBar>\n )}\n {/* 加载失败:按错误码说明原因(网络、权限、条件写错),保留上一次的行,给一个重试 */}\n {query.error !== undefined && (\n <Alert\n {...mergePartProps<Partial<AlertProps>>(\n {\n tone: 'danger',\n live: 'assertive',\n action: (\n <Button\n size=\"sm\"\n variant=\"outline\"\n tone=\"danger\"\n onClick={() => void query.refresh()}\n >\n {messages.queryTableRetry}\n </Button>\n ),\n },\n propsError,\n )}\n >\n {errorMessage(query.error, lang)}\n </Alert>\n )}\n <DataTable\n {...mergePartProps<Partial<DataTableProps<T>>>(\n { 'aria-label': title, flexible: fullscreen.active },\n propsTable,\n )}\n rows={query.rows as T[]}\n columns={columns}\n getKey={getKey}\n manualSort\n multiSort={multiSort}\n _sort={query.sort}\n _sorts={query.sorts}\n manualFilter\n _filters={query.columnFilters}\n loading={query.loading}\n density={density}\n selectionMode={selectionMode}\n _selected={selected}\n _hiddenColumns={hidden}\n _columnOrder={order}\n _columnPins={pins}\n _columnWidths={widths}\n resizable\n columnMenu\n />\n <PaginationBar\n {...mergePartProps<Partial<PaginationBarProps>>(\n { propsPagination: { 'aria-label': messages.queryTablePagination(title) } },\n propsPagination,\n )}\n _page={query.page}\n _pageSize={query.pageSize}\n total={query.total}\n />\n </div>\n </div>\n );\n },\n);\n"],"mappings":"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"}
@@ -71,6 +71,8 @@ export interface PatternsMessages {
71
71
  readonly pageTabsCloseRight: string;
72
72
  /** 查询表格:刷新,默认“刷新” */
73
73
  readonly queryTableRefresh: string;
74
+ /** 查询表格:加载失败的提示条上的重试按钮,默认“重试” */
75
+ readonly queryTableRetry: string;
74
76
  /** 查询表格:行高菜单,默认“行高” */
75
77
  readonly queryTableDensity: string;
76
78
  /** 行高:紧凑,默认“紧凑” */
@@ -35,6 +35,7 @@ var patternsMessages = {
35
35
  pageTabsCloseOthers: "关闭其他",
36
36
  pageTabsCloseRight: "关闭右侧",
37
37
  queryTableRefresh: "刷新",
38
+ queryTableRetry: "重试",
38
39
  queryTableDensity: "行高",
39
40
  queryTableDensityCompact: "紧凑",
40
41
  queryTableDensityStandard: "标准",
@@ -123,6 +124,7 @@ var patternsMessages = {
123
124
  pageTabsCloseOthers: "Close others",
124
125
  pageTabsCloseRight: "Close tabs to the right",
125
126
  queryTableRefresh: "Refresh",
127
+ queryTableRetry: "Retry",
126
128
  queryTableDensity: "Row height",
127
129
  queryTableDensityCompact: "Compact",
128
130
  queryTableDensityStandard: "Standard",
@@ -1 +1 @@
1
- {"version":3,"file":"messages.js","names":[],"sources":["../../src/patterns/messages.ts"],"sourcesContent":["/**\n * 页面组合(AppShell、FilterBar、NotificationCenter、KanbanBoard、DeadlineBadge、ThemeSwitcher)自带的文案:\n * 中文与英文各一份,可以在 createUi 的 lang.messages.patterns 里按字段改写(见 config/lang/messages.ts)\n */\nimport type { MessageTable } from '../config/lang/messages';\n\n/** 页面组合的文案 */\nexport interface PatternsMessages {\n /** 查询栏的查询按钮,默认“查询” */\n readonly filterSearch: string;\n /** 查询栏的重置按钮,默认“重置” */\n readonly filterReset: string;\n /** 查询栏展开更多条件,默认“展开” */\n readonly filterExpand: string;\n /** 查询栏收起更多条件,默认“收起” */\n readonly filterCollapse: string;\n /** 收起的条件里已经填了几项:`(2)` → “已设 2 项” */\n readonly filterActive: (count: number) => string;\n /** 查询栏的高级筛选(按钮、条件构造器的名称、摘要的开头),默认“高级筛选” */\n readonly filterAdvanced: string;\n /** 时限标记:还剩几个工作日,默认“剩 n 个工作日” */\n readonly deadlineRemaining: (workdays: number) => string;\n /** 时限标记:今天到期,默认“今天到期” */\n readonly deadlineDue: string;\n /** 时限标记:超时几个工作日(0 时是周末、假日里刚过期),默认“超时 n 个工作日”“已超时” */\n readonly deadlineOverdue: (workdays: number) => string;\n /** 时限标记:按时完成,默认“按时完成” */\n readonly deadlineDone: string;\n /** 时限标记:超时完成,默认“超时 n 个工作日完成” */\n readonly deadlineDoneLate: (workdays: number) => string;\n /** 时限标记的完整说明(title 与读屏):截止日,默认“截止 2026-10-23” */\n readonly deadlineOn: (date: string) => string;\n /** 通知中心的标题与按钮名称,默认“通知” */\n readonly notifications: string;\n /** 通知中心按钮的名称(带未读数),默认“通知,未读 n 条” */\n readonly notificationsUnread: (count: number) => string;\n /** 通知中心:全部标为已读,默认“全部标为已读” */\n readonly notificationsMarkAllRead: string;\n /** 通知中心:不按类型筛选,默认“全部” */\n readonly notificationsAll: string;\n /** 通知中心:只看未读,默认“只看未读” */\n readonly notificationsUnreadOnly: string;\n /** 通知中心:没有通知,默认“没有通知” */\n readonly notificationsEmpty: string;\n /** 通知中心:一条未读的标记(读屏),默认“未读” */\n readonly notificationUnreadMark: string;\n /** 看板卡片把手的操作说明,默认“按空格拿起,左右方向键换列、上下方向键调整位置,再按空格放下,Esc 取消” */\n readonly kanbanInstructions: string;\n /** 看板:一列没有卡片时,默认“没有” */\n readonly kanbanEmpty: string;\n /** 窄屏时收着侧边导航的抽屉的标题,默认“导航” */\n readonly navigation: string;\n /** 窄屏时打开侧边导航的按钮,默认“打开导航” */\n readonly navigationOpen: string;\n /** 抽屉式侧边导航的开关按钮上的文字,默认“菜单” */\n readonly navigationMenu: string;\n /** 抽屉式侧边导航的宽度调整手柄,默认“调整导航宽度” */\n readonly navigationResize: string;\n /** AppShell 侧栏底部收起成图标栏的按钮,默认“收起侧栏” */\n readonly sidebarCollapse: string;\n /** AppShell 侧栏收起后展开的按钮,默认“展开侧栏” */\n readonly sidebarExpand: string;\n /** 页签区的名称,默认“打开的页面” */\n readonly pageTabsLabel: string;\n /** 页签的右键菜单的名称,默认“页签操作” */\n readonly pageTabsMenu: string;\n /** 页签的右键菜单:关闭这一个,默认“关闭” */\n readonly pageTabsClose: string;\n /** 页签的右键菜单:关闭其他的,默认“关闭其他” */\n readonly pageTabsCloseOthers: string;\n /** 页签的右键菜单:关闭右边的,默认“关闭右侧” */\n readonly pageTabsCloseRight: string;\n /** 查询表格:刷新,默认“刷新” */\n readonly queryTableRefresh: string;\n /** 查询表格:行高菜单,默认“行高” */\n readonly queryTableDensity: string;\n /** 行高:紧凑,默认“紧凑” */\n readonly queryTableDensityCompact: string;\n /** 行高:标准,默认“标准” */\n readonly queryTableDensityStandard: string;\n /** 行高:宽松,默认“宽松” */\n readonly queryTableDensityComfortable: string;\n /** 查询表格:全屏,默认“全屏” */\n readonly queryTableFullscreen: string;\n /** 查询表格:退出全屏,默认“退出全屏” */\n readonly queryTableExitFullscreen: string;\n /** 查询表格分页导航的名称:`('任务台账')` → “任务台账分页” */\n readonly queryTablePagination: (title: string) => string;\n /** 查询表格的查询栏(search 地标)的名称:`('任务台账')` → “任务台账查询” */\n readonly queryTableSearch: (title: string) => string;\n /** 分步表单:上一步,默认“上一步” */\n readonly stepsFormPrevious: string;\n /** 分步表单:下一步,默认“下一步” */\n readonly stepsFormNext: string;\n /** 分步表单:最后一步的提交,默认“提交” */\n readonly stepsFormSubmit: string;\n /** 分步表单这一步内容的名称:`(2, 3)` → “第 2 步,共 3 步” */\n readonly stepsFormStep: (step: number, total: number) => string;\n /** 导入的四步:上传文件、对应列、校验与预览、完成 */\n readonly dataImportSteps: readonly [string, string, string, string];\n /** 导入:支持的格式说明:`('.xlsx, .csv')` → “支持 .xlsx, .csv” */\n readonly dataImportAccept: (accept: string) => string;\n /** 导入:下载模板按钮,默认“下载模板” */\n readonly dataImportTemplate: string;\n /** 导入:选工作表,默认“工作表” */\n readonly dataImportSheet: string;\n /** 导入:读文件失败:`('…')` → “读不了这个文件:…” */\n readonly dataImportParseFailed: (reason: string) => string;\n /** 导入:文件里没有数据行,默认“文件里没有数据行” */\n readonly dataImportEmpty: string;\n /** 导入:对应列表格的列标题“字段” */\n readonly dataImportField: string;\n /** 导入:对应列表格的列标题“文件中的列” */\n readonly dataImportColumn: string;\n /** 导入:对应列表格的列标题“示例” */\n readonly dataImportSample: string;\n /** 导入:不导入这个字段,默认“不导入” */\n readonly dataImportSkip: string;\n /** 导入:必填字段还没对应:`(['零件号'])` → “必填的字段还没对应:零件号” */\n readonly dataImportUnmapped: (labels: readonly string[]) => string;\n /** 导入:校验结果:`(120, 118, 2)` → “共 120 行,可以导入 118 行,2 行有错” */\n readonly dataImportSummary: (total: number, valid: number, invalid: number) => string;\n /** 导入:只看有错的行,默认“只看有错的行” */\n readonly dataImportOnlyErrors: string;\n /** 导入:预览表的“序号”列(第几行数据) */\n readonly dataImportRow: string;\n /** 导入:预览表的“校验”列 */\n readonly dataImportStatus: string;\n /** 导入:没有错的行,默认“可以导入” */\n readonly dataImportValid: string;\n /** 导入:改了格子之后的提示,默认“格子可以直接改,改完重新校验” */\n readonly dataImportEditHint: string;\n /** 导入:确认按钮:`(118)` → “导入 118 行” */\n readonly dataImportSubmit: (count: number) => string;\n /** 导入:完成:`(118)` → “已导入 118 行” */\n readonly dataImportDone: (count: number) => string;\n /** 导入:再导入一份,默认“再导入一份” */\n readonly dataImportAgain: string;\n /** 导入:数字列里不是数字,默认“不是数字” */\n readonly dataImportNotNumber: string;\n /** 导入:所在的预览表的名称,默认“导入预览” */\n readonly dataImportPreview: string;\n /** 主题切换的名称,默认“主题” */\n readonly themeLabel: string;\n /** 留言:留言列表的名称,默认“留言” */\n readonly comments: string;\n /** 留言:没有留言时,默认“还没有留言” */\n readonly commentsEmpty: string;\n /** 留言:输入框的提示,默认“写下留言,输入 @ 提及相关的人” */\n readonly commentPlaceholder: string;\n /** 留言:回复按钮,默认“回复” */\n readonly commentReply: string;\n /** 留言:回复某人时输入框的名称:`('林小满')` → “回复 林小满” */\n readonly commentReplyTo: (name: string) => string;\n /** 留言:发送按钮,默认“发送” */\n readonly commentSend: string;\n /** 留言:取消回复,默认“取消” */\n readonly commentCancel: string;\n /** 留言:添加附件的按钮,默认“附件” */\n readonly commentAttach: string;\n /** 留言:发送的快捷键说明,默认“Ctrl + Enter 发送” */\n readonly commentSendHint: string;\n /** 留言:发送失败,默认“发送失败,内容已保留,请重试” */\n readonly commentSendFailed: string;\n /** 留言:改过的留言的标记,默认“已编辑” */\n readonly commentEdited: string;\n /** 留言:一条留言下面回复列表的名称:`(3)` → “3 条回复” */\n readonly commentReplies: (count: number) => string;\n /** 留言:附件列表的名称,默认“附件” */\n readonly commentAttachments: string;\n}\n\n/** 页面组合的文案表:中文与英文,别的语言先找同语种、再用英文 */\nexport const patternsMessages: MessageTable<PatternsMessages> = {\n 'zh-CN': {\n filterSearch: '查询',\n filterReset: '重置',\n filterExpand: '展开',\n filterCollapse: '收起',\n filterActive: (count) => `已设 ${count} 项`,\n filterAdvanced: '高级筛选',\n deadlineRemaining: (workdays) => `剩 ${workdays} 个工作日`,\n deadlineDue: '今天到期',\n deadlineOverdue: (workdays) => (workdays > 0 ? `超时 ${workdays} 个工作日` : '已超时'),\n deadlineDone: '按时完成',\n deadlineDoneLate: (workdays) => `超时 ${workdays} 个工作日完成`,\n deadlineOn: (date) => `截止 ${date}`,\n notifications: '通知',\n notificationsUnread: (count) => (count > 0 ? `通知,未读 ${count} 条` : '通知'),\n notificationsMarkAllRead: '全部标为已读',\n notificationsAll: '全部',\n notificationsUnreadOnly: '只看未读',\n notificationsEmpty: '没有通知',\n notificationUnreadMark: '未读',\n kanbanInstructions: '按空格拿起,左右方向键换列、上下方向键调整位置,再按空格放下,Esc 取消',\n kanbanEmpty: '没有',\n navigation: '导航',\n navigationOpen: '打开导航',\n navigationMenu: '菜单',\n navigationResize: '调整导航宽度',\n sidebarCollapse: '收起侧栏',\n sidebarExpand: '展开侧栏',\n pageTabsLabel: '打开的页面',\n pageTabsMenu: '页签操作',\n pageTabsClose: '关闭',\n pageTabsCloseOthers: '关闭其他',\n pageTabsCloseRight: '关闭右侧',\n queryTableRefresh: '刷新',\n queryTableDensity: '行高',\n queryTableDensityCompact: '紧凑',\n queryTableDensityStandard: '标准',\n queryTableDensityComfortable: '宽松',\n queryTableFullscreen: '全屏',\n queryTableExitFullscreen: '退出全屏',\n queryTablePagination: (title) => `${title}分页`,\n queryTableSearch: (title) => `${title}查询`,\n stepsFormPrevious: '上一步',\n stepsFormNext: '下一步',\n stepsFormSubmit: '提交',\n stepsFormStep: (step, total) => `第 ${step} 步,共 ${total} 步`,\n dataImportSteps: ['上传文件', '对应列', '校验与预览', '完成'],\n dataImportAccept: (accept) => `支持 ${accept}`,\n dataImportTemplate: '下载模板',\n dataImportSheet: '工作表',\n dataImportParseFailed: (reason) => `读不了这个文件:${reason}`,\n dataImportEmpty: '文件里没有数据行',\n dataImportField: '字段',\n dataImportColumn: '文件中的列',\n dataImportSample: '示例',\n dataImportSkip: '不导入',\n dataImportUnmapped: (labels) => `必填的字段还没对应:${labels.join('、')}`,\n dataImportSummary: (total, valid, invalid) =>\n `共 ${total} 行,可以导入 ${valid} 行${invalid ? `,${invalid} 行有错` : ''}`,\n dataImportOnlyErrors: '只看有错的行',\n dataImportRow: '序号',\n dataImportStatus: '校验',\n dataImportValid: '可以导入',\n dataImportEditHint: '有错的格子可以直接改,改完重新校验',\n dataImportSubmit: (count) => `导入 ${count} 行`,\n dataImportDone: (count) => `已导入 ${count} 行`,\n dataImportAgain: '再导入一份',\n dataImportNotNumber: '不是数字',\n dataImportPreview: '导入预览',\n themeLabel: '主题',\n comments: '留言',\n commentsEmpty: '还没有留言',\n commentPlaceholder: '写下留言,输入 @ 提及相关的人',\n commentReply: '回复',\n commentReplyTo: (name) => `回复 ${name}`,\n commentSend: '发送',\n commentCancel: '取消',\n commentAttach: '附件',\n commentSendHint: 'Ctrl + Enter 发送',\n commentSendFailed: '发送失败,内容已保留,请重试',\n commentEdited: '已编辑',\n commentReplies: (count) => `${count} 条回复`,\n commentAttachments: '附件',\n },\n 'en-US': {\n filterSearch: 'Search',\n filterReset: 'Reset',\n filterExpand: 'More filters',\n filterCollapse: 'Fewer filters',\n filterActive: (count) => `${count} set`,\n filterAdvanced: 'Advanced filter',\n deadlineRemaining: (workdays) => `${workdays} ${workdays === 1 ? 'workday' : 'workdays'} left`,\n deadlineDue: 'Due today',\n deadlineOverdue: (workdays) =>\n workdays > 0 ? `${workdays} ${workdays === 1 ? 'workday' : 'workdays'} overdue` : 'Overdue',\n deadlineDone: 'Done on time',\n deadlineDoneLate: (workdays) =>\n `Done ${workdays} ${workdays === 1 ? 'workday' : 'workdays'} late`,\n deadlineOn: (date) => `Due ${date}`,\n notifications: 'Notifications',\n notificationsUnread: (count) =>\n count > 0 ? `Notifications, ${count} unread` : 'Notifications',\n notificationsMarkAllRead: 'Mark all as read',\n notificationsAll: 'All',\n notificationsUnreadOnly: 'Unread only',\n notificationsEmpty: 'No notifications',\n notificationUnreadMark: 'Unread',\n kanbanInstructions:\n 'Press space to pick up, use the left and right arrow keys to change column and the up and down arrow keys to change position, press space again to drop, Escape to cancel',\n kanbanEmpty: 'None',\n navigation: 'Navigation',\n navigationOpen: 'Open navigation',\n navigationMenu: 'Menu',\n navigationResize: 'Resize navigation',\n sidebarCollapse: 'Collapse sidebar',\n sidebarExpand: 'Expand sidebar',\n pageTabsLabel: 'Open pages',\n pageTabsMenu: 'Tab actions',\n pageTabsClose: 'Close',\n pageTabsCloseOthers: 'Close others',\n pageTabsCloseRight: 'Close tabs to the right',\n queryTableRefresh: 'Refresh',\n queryTableDensity: 'Row height',\n queryTableDensityCompact: 'Compact',\n queryTableDensityStandard: 'Standard',\n queryTableDensityComfortable: 'Comfortable',\n queryTableFullscreen: 'Full screen',\n queryTableExitFullscreen: 'Exit full screen',\n queryTablePagination: (title) => `${title} pagination`,\n queryTableSearch: (title) => `Search ${title}`,\n stepsFormPrevious: 'Previous',\n stepsFormNext: 'Next',\n stepsFormSubmit: 'Submit',\n stepsFormStep: (step, total) => `Step ${step} of ${total}`,\n dataImportSteps: ['Upload', 'Map columns', 'Review', 'Done'],\n dataImportAccept: (accept) => `Supports ${accept}`,\n dataImportTemplate: 'Download template',\n dataImportSheet: 'Sheet',\n dataImportParseFailed: (reason) => `Can't read this file: ${reason}`,\n dataImportEmpty: 'The file has no data rows',\n dataImportField: 'Field',\n dataImportColumn: 'Column in file',\n dataImportSample: 'Sample',\n dataImportSkip: \"Don't import\",\n dataImportUnmapped: (labels) => `Required fields not mapped: ${labels.join(', ')}`,\n dataImportSummary: (total, valid, invalid) =>\n `${total} rows, ${valid} ready to import${invalid ? `, ${invalid} with problems` : ''}`,\n dataImportOnlyErrors: 'Only rows with problems',\n dataImportRow: '#',\n dataImportStatus: 'Check',\n dataImportValid: 'Ready',\n dataImportEditHint: 'Fix cells in place; they are checked again',\n dataImportSubmit: (count) => `Import ${count} rows`,\n dataImportDone: (count) => `Imported ${count} rows`,\n dataImportAgain: 'Import another file',\n dataImportNotNumber: 'Not a number',\n dataImportPreview: 'Import preview',\n themeLabel: 'Theme',\n comments: 'Comments',\n commentsEmpty: 'No comments yet',\n commentPlaceholder: 'Write a comment, type @ to mention someone',\n commentReply: 'Reply',\n commentReplyTo: (name) => `Reply to ${name}`,\n commentSend: 'Send',\n commentCancel: 'Cancel',\n commentAttach: 'Attach',\n commentSendHint: 'Ctrl + Enter to send',\n commentSendFailed: 'Could not send. Your text is kept, please try again',\n commentEdited: 'Edited',\n commentReplies: (count) => (count === 1 ? '1 reply' : `${count} replies`),\n commentAttachments: 'Attachments',\n },\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"messages.js","names":[],"sources":["../../src/patterns/messages.ts"],"sourcesContent":["/**\n * 页面组合(AppShell、FilterBar、NotificationCenter、KanbanBoard、DeadlineBadge、ThemeSwitcher)自带的文案:\n * 中文与英文各一份,可以在 createUi 的 lang.messages.patterns 里按字段改写(见 config/lang/messages.ts)\n */\nimport type { MessageTable } from '../config/lang/messages';\n\n/** 页面组合的文案 */\nexport interface PatternsMessages {\n /** 查询栏的查询按钮,默认“查询” */\n readonly filterSearch: string;\n /** 查询栏的重置按钮,默认“重置” */\n readonly filterReset: string;\n /** 查询栏展开更多条件,默认“展开” */\n readonly filterExpand: string;\n /** 查询栏收起更多条件,默认“收起” */\n readonly filterCollapse: string;\n /** 收起的条件里已经填了几项:`(2)` → “已设 2 项” */\n readonly filterActive: (count: number) => string;\n /** 查询栏的高级筛选(按钮、条件构造器的名称、摘要的开头),默认“高级筛选” */\n readonly filterAdvanced: string;\n /** 时限标记:还剩几个工作日,默认“剩 n 个工作日” */\n readonly deadlineRemaining: (workdays: number) => string;\n /** 时限标记:今天到期,默认“今天到期” */\n readonly deadlineDue: string;\n /** 时限标记:超时几个工作日(0 时是周末、假日里刚过期),默认“超时 n 个工作日”“已超时” */\n readonly deadlineOverdue: (workdays: number) => string;\n /** 时限标记:按时完成,默认“按时完成” */\n readonly deadlineDone: string;\n /** 时限标记:超时完成,默认“超时 n 个工作日完成” */\n readonly deadlineDoneLate: (workdays: number) => string;\n /** 时限标记的完整说明(title 与读屏):截止日,默认“截止 2026-10-23” */\n readonly deadlineOn: (date: string) => string;\n /** 通知中心的标题与按钮名称,默认“通知” */\n readonly notifications: string;\n /** 通知中心按钮的名称(带未读数),默认“通知,未读 n 条” */\n readonly notificationsUnread: (count: number) => string;\n /** 通知中心:全部标为已读,默认“全部标为已读” */\n readonly notificationsMarkAllRead: string;\n /** 通知中心:不按类型筛选,默认“全部” */\n readonly notificationsAll: string;\n /** 通知中心:只看未读,默认“只看未读” */\n readonly notificationsUnreadOnly: string;\n /** 通知中心:没有通知,默认“没有通知” */\n readonly notificationsEmpty: string;\n /** 通知中心:一条未读的标记(读屏),默认“未读” */\n readonly notificationUnreadMark: string;\n /** 看板卡片把手的操作说明,默认“按空格拿起,左右方向键换列、上下方向键调整位置,再按空格放下,Esc 取消” */\n readonly kanbanInstructions: string;\n /** 看板:一列没有卡片时,默认“没有” */\n readonly kanbanEmpty: string;\n /** 窄屏时收着侧边导航的抽屉的标题,默认“导航” */\n readonly navigation: string;\n /** 窄屏时打开侧边导航的按钮,默认“打开导航” */\n readonly navigationOpen: string;\n /** 抽屉式侧边导航的开关按钮上的文字,默认“菜单” */\n readonly navigationMenu: string;\n /** 抽屉式侧边导航的宽度调整手柄,默认“调整导航宽度” */\n readonly navigationResize: string;\n /** AppShell 侧栏底部收起成图标栏的按钮,默认“收起侧栏” */\n readonly sidebarCollapse: string;\n /** AppShell 侧栏收起后展开的按钮,默认“展开侧栏” */\n readonly sidebarExpand: string;\n /** 页签区的名称,默认“打开的页面” */\n readonly pageTabsLabel: string;\n /** 页签的右键菜单的名称,默认“页签操作” */\n readonly pageTabsMenu: string;\n /** 页签的右键菜单:关闭这一个,默认“关闭” */\n readonly pageTabsClose: string;\n /** 页签的右键菜单:关闭其他的,默认“关闭其他” */\n readonly pageTabsCloseOthers: string;\n /** 页签的右键菜单:关闭右边的,默认“关闭右侧” */\n readonly pageTabsCloseRight: string;\n /** 查询表格:刷新,默认“刷新” */\n readonly queryTableRefresh: string;\n /** 查询表格:加载失败的提示条上的重试按钮,默认“重试” */\n readonly queryTableRetry: string;\n /** 查询表格:行高菜单,默认“行高” */\n readonly queryTableDensity: string;\n /** 行高:紧凑,默认“紧凑” */\n readonly queryTableDensityCompact: string;\n /** 行高:标准,默认“标准” */\n readonly queryTableDensityStandard: string;\n /** 行高:宽松,默认“宽松” */\n readonly queryTableDensityComfortable: string;\n /** 查询表格:全屏,默认“全屏” */\n readonly queryTableFullscreen: string;\n /** 查询表格:退出全屏,默认“退出全屏” */\n readonly queryTableExitFullscreen: string;\n /** 查询表格分页导航的名称:`('任务台账')` → “任务台账分页” */\n readonly queryTablePagination: (title: string) => string;\n /** 查询表格的查询栏(search 地标)的名称:`('任务台账')` → “任务台账查询” */\n readonly queryTableSearch: (title: string) => string;\n /** 分步表单:上一步,默认“上一步” */\n readonly stepsFormPrevious: string;\n /** 分步表单:下一步,默认“下一步” */\n readonly stepsFormNext: string;\n /** 分步表单:最后一步的提交,默认“提交” */\n readonly stepsFormSubmit: string;\n /** 分步表单这一步内容的名称:`(2, 3)` → “第 2 步,共 3 步” */\n readonly stepsFormStep: (step: number, total: number) => string;\n /** 导入的四步:上传文件、对应列、校验与预览、完成 */\n readonly dataImportSteps: readonly [string, string, string, string];\n /** 导入:支持的格式说明:`('.xlsx, .csv')` → “支持 .xlsx, .csv” */\n readonly dataImportAccept: (accept: string) => string;\n /** 导入:下载模板按钮,默认“下载模板” */\n readonly dataImportTemplate: string;\n /** 导入:选工作表,默认“工作表” */\n readonly dataImportSheet: string;\n /** 导入:读文件失败:`('…')` → “读不了这个文件:…” */\n readonly dataImportParseFailed: (reason: string) => string;\n /** 导入:文件里没有数据行,默认“文件里没有数据行” */\n readonly dataImportEmpty: string;\n /** 导入:对应列表格的列标题“字段” */\n readonly dataImportField: string;\n /** 导入:对应列表格的列标题“文件中的列” */\n readonly dataImportColumn: string;\n /** 导入:对应列表格的列标题“示例” */\n readonly dataImportSample: string;\n /** 导入:不导入这个字段,默认“不导入” */\n readonly dataImportSkip: string;\n /** 导入:必填字段还没对应:`(['零件号'])` → “必填的字段还没对应:零件号” */\n readonly dataImportUnmapped: (labels: readonly string[]) => string;\n /** 导入:校验结果:`(120, 118, 2)` → “共 120 行,可以导入 118 行,2 行有错” */\n readonly dataImportSummary: (total: number, valid: number, invalid: number) => string;\n /** 导入:只看有错的行,默认“只看有错的行” */\n readonly dataImportOnlyErrors: string;\n /** 导入:预览表的“序号”列(第几行数据) */\n readonly dataImportRow: string;\n /** 导入:预览表的“校验”列 */\n readonly dataImportStatus: string;\n /** 导入:没有错的行,默认“可以导入” */\n readonly dataImportValid: string;\n /** 导入:改了格子之后的提示,默认“格子可以直接改,改完重新校验” */\n readonly dataImportEditHint: string;\n /** 导入:确认按钮:`(118)` → “导入 118 行” */\n readonly dataImportSubmit: (count: number) => string;\n /** 导入:完成:`(118)` → “已导入 118 行” */\n readonly dataImportDone: (count: number) => string;\n /** 导入:再导入一份,默认“再导入一份” */\n readonly dataImportAgain: string;\n /** 导入:数字列里不是数字,默认“不是数字” */\n readonly dataImportNotNumber: string;\n /** 导入:所在的预览表的名称,默认“导入预览” */\n readonly dataImportPreview: string;\n /** 主题切换的名称,默认“主题” */\n readonly themeLabel: string;\n /** 留言:留言列表的名称,默认“留言” */\n readonly comments: string;\n /** 留言:没有留言时,默认“还没有留言” */\n readonly commentsEmpty: string;\n /** 留言:输入框的提示,默认“写下留言,输入 @ 提及相关的人” */\n readonly commentPlaceholder: string;\n /** 留言:回复按钮,默认“回复” */\n readonly commentReply: string;\n /** 留言:回复某人时输入框的名称:`('林小满')` → “回复 林小满” */\n readonly commentReplyTo: (name: string) => string;\n /** 留言:发送按钮,默认“发送” */\n readonly commentSend: string;\n /** 留言:取消回复,默认“取消” */\n readonly commentCancel: string;\n /** 留言:添加附件的按钮,默认“附件” */\n readonly commentAttach: string;\n /** 留言:发送的快捷键说明,默认“Ctrl + Enter 发送” */\n readonly commentSendHint: string;\n /** 留言:发送失败,默认“发送失败,内容已保留,请重试” */\n readonly commentSendFailed: string;\n /** 留言:改过的留言的标记,默认“已编辑” */\n readonly commentEdited: string;\n /** 留言:一条留言下面回复列表的名称:`(3)` → “3 条回复” */\n readonly commentReplies: (count: number) => string;\n /** 留言:附件列表的名称,默认“附件” */\n readonly commentAttachments: string;\n}\n\n/** 页面组合的文案表:中文与英文,别的语言先找同语种、再用英文 */\nexport const patternsMessages: MessageTable<PatternsMessages> = {\n 'zh-CN': {\n filterSearch: '查询',\n filterReset: '重置',\n filterExpand: '展开',\n filterCollapse: '收起',\n filterActive: (count) => `已设 ${count} 项`,\n filterAdvanced: '高级筛选',\n deadlineRemaining: (workdays) => `剩 ${workdays} 个工作日`,\n deadlineDue: '今天到期',\n deadlineOverdue: (workdays) => (workdays > 0 ? `超时 ${workdays} 个工作日` : '已超时'),\n deadlineDone: '按时完成',\n deadlineDoneLate: (workdays) => `超时 ${workdays} 个工作日完成`,\n deadlineOn: (date) => `截止 ${date}`,\n notifications: '通知',\n notificationsUnread: (count) => (count > 0 ? `通知,未读 ${count} 条` : '通知'),\n notificationsMarkAllRead: '全部标为已读',\n notificationsAll: '全部',\n notificationsUnreadOnly: '只看未读',\n notificationsEmpty: '没有通知',\n notificationUnreadMark: '未读',\n kanbanInstructions: '按空格拿起,左右方向键换列、上下方向键调整位置,再按空格放下,Esc 取消',\n kanbanEmpty: '没有',\n navigation: '导航',\n navigationOpen: '打开导航',\n navigationMenu: '菜单',\n navigationResize: '调整导航宽度',\n sidebarCollapse: '收起侧栏',\n sidebarExpand: '展开侧栏',\n pageTabsLabel: '打开的页面',\n pageTabsMenu: '页签操作',\n pageTabsClose: '关闭',\n pageTabsCloseOthers: '关闭其他',\n pageTabsCloseRight: '关闭右侧',\n queryTableRefresh: '刷新',\n queryTableRetry: '重试',\n queryTableDensity: '行高',\n queryTableDensityCompact: '紧凑',\n queryTableDensityStandard: '标准',\n queryTableDensityComfortable: '宽松',\n queryTableFullscreen: '全屏',\n queryTableExitFullscreen: '退出全屏',\n queryTablePagination: (title) => `${title}分页`,\n queryTableSearch: (title) => `${title}查询`,\n stepsFormPrevious: '上一步',\n stepsFormNext: '下一步',\n stepsFormSubmit: '提交',\n stepsFormStep: (step, total) => `第 ${step} 步,共 ${total} 步`,\n dataImportSteps: ['上传文件', '对应列', '校验与预览', '完成'],\n dataImportAccept: (accept) => `支持 ${accept}`,\n dataImportTemplate: '下载模板',\n dataImportSheet: '工作表',\n dataImportParseFailed: (reason) => `读不了这个文件:${reason}`,\n dataImportEmpty: '文件里没有数据行',\n dataImportField: '字段',\n dataImportColumn: '文件中的列',\n dataImportSample: '示例',\n dataImportSkip: '不导入',\n dataImportUnmapped: (labels) => `必填的字段还没对应:${labels.join('、')}`,\n dataImportSummary: (total, valid, invalid) =>\n `共 ${total} 行,可以导入 ${valid} 行${invalid ? `,${invalid} 行有错` : ''}`,\n dataImportOnlyErrors: '只看有错的行',\n dataImportRow: '序号',\n dataImportStatus: '校验',\n dataImportValid: '可以导入',\n dataImportEditHint: '有错的格子可以直接改,改完重新校验',\n dataImportSubmit: (count) => `导入 ${count} 行`,\n dataImportDone: (count) => `已导入 ${count} 行`,\n dataImportAgain: '再导入一份',\n dataImportNotNumber: '不是数字',\n dataImportPreview: '导入预览',\n themeLabel: '主题',\n comments: '留言',\n commentsEmpty: '还没有留言',\n commentPlaceholder: '写下留言,输入 @ 提及相关的人',\n commentReply: '回复',\n commentReplyTo: (name) => `回复 ${name}`,\n commentSend: '发送',\n commentCancel: '取消',\n commentAttach: '附件',\n commentSendHint: 'Ctrl + Enter 发送',\n commentSendFailed: '发送失败,内容已保留,请重试',\n commentEdited: '已编辑',\n commentReplies: (count) => `${count} 条回复`,\n commentAttachments: '附件',\n },\n 'en-US': {\n filterSearch: 'Search',\n filterReset: 'Reset',\n filterExpand: 'More filters',\n filterCollapse: 'Fewer filters',\n filterActive: (count) => `${count} set`,\n filterAdvanced: 'Advanced filter',\n deadlineRemaining: (workdays) => `${workdays} ${workdays === 1 ? 'workday' : 'workdays'} left`,\n deadlineDue: 'Due today',\n deadlineOverdue: (workdays) =>\n workdays > 0 ? `${workdays} ${workdays === 1 ? 'workday' : 'workdays'} overdue` : 'Overdue',\n deadlineDone: 'Done on time',\n deadlineDoneLate: (workdays) =>\n `Done ${workdays} ${workdays === 1 ? 'workday' : 'workdays'} late`,\n deadlineOn: (date) => `Due ${date}`,\n notifications: 'Notifications',\n notificationsUnread: (count) =>\n count > 0 ? `Notifications, ${count} unread` : 'Notifications',\n notificationsMarkAllRead: 'Mark all as read',\n notificationsAll: 'All',\n notificationsUnreadOnly: 'Unread only',\n notificationsEmpty: 'No notifications',\n notificationUnreadMark: 'Unread',\n kanbanInstructions:\n 'Press space to pick up, use the left and right arrow keys to change column and the up and down arrow keys to change position, press space again to drop, Escape to cancel',\n kanbanEmpty: 'None',\n navigation: 'Navigation',\n navigationOpen: 'Open navigation',\n navigationMenu: 'Menu',\n navigationResize: 'Resize navigation',\n sidebarCollapse: 'Collapse sidebar',\n sidebarExpand: 'Expand sidebar',\n pageTabsLabel: 'Open pages',\n pageTabsMenu: 'Tab actions',\n pageTabsClose: 'Close',\n pageTabsCloseOthers: 'Close others',\n pageTabsCloseRight: 'Close tabs to the right',\n queryTableRefresh: 'Refresh',\n queryTableRetry: 'Retry',\n queryTableDensity: 'Row height',\n queryTableDensityCompact: 'Compact',\n queryTableDensityStandard: 'Standard',\n queryTableDensityComfortable: 'Comfortable',\n queryTableFullscreen: 'Full screen',\n queryTableExitFullscreen: 'Exit full screen',\n queryTablePagination: (title) => `${title} pagination`,\n queryTableSearch: (title) => `Search ${title}`,\n stepsFormPrevious: 'Previous',\n stepsFormNext: 'Next',\n stepsFormSubmit: 'Submit',\n stepsFormStep: (step, total) => `Step ${step} of ${total}`,\n dataImportSteps: ['Upload', 'Map columns', 'Review', 'Done'],\n dataImportAccept: (accept) => `Supports ${accept}`,\n dataImportTemplate: 'Download template',\n dataImportSheet: 'Sheet',\n dataImportParseFailed: (reason) => `Can't read this file: ${reason}`,\n dataImportEmpty: 'The file has no data rows',\n dataImportField: 'Field',\n dataImportColumn: 'Column in file',\n dataImportSample: 'Sample',\n dataImportSkip: \"Don't import\",\n dataImportUnmapped: (labels) => `Required fields not mapped: ${labels.join(', ')}`,\n dataImportSummary: (total, valid, invalid) =>\n `${total} rows, ${valid} ready to import${invalid ? `, ${invalid} with problems` : ''}`,\n dataImportOnlyErrors: 'Only rows with problems',\n dataImportRow: '#',\n dataImportStatus: 'Check',\n dataImportValid: 'Ready',\n dataImportEditHint: 'Fix cells in place; they are checked again',\n dataImportSubmit: (count) => `Import ${count} rows`,\n dataImportDone: (count) => `Imported ${count} rows`,\n dataImportAgain: 'Import another file',\n dataImportNotNumber: 'Not a number',\n dataImportPreview: 'Import preview',\n themeLabel: 'Theme',\n comments: 'Comments',\n commentsEmpty: 'No comments yet',\n commentPlaceholder: 'Write a comment, type @ to mention someone',\n commentReply: 'Reply',\n commentReplyTo: (name) => `Reply to ${name}`,\n commentSend: 'Send',\n commentCancel: 'Cancel',\n commentAttach: 'Attach',\n commentSendHint: 'Ctrl + Enter to send',\n commentSendFailed: 'Could not send. Your text is kept, please try again',\n commentEdited: 'Edited',\n commentReplies: (count) => (count === 1 ? '1 reply' : `${count} replies`),\n commentAttachments: 'Attachments',\n },\n};\n"],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * 复制表单、查询条件这类值:普通对象与数组逐层复制(各份互不影响),其余值原样保留;响应式代理先取原始对象。
3
+ * 不用 structuredClone:Decimal、@internationalized/date 的日期这些带方法的值克隆不了(会抛错,或变成丢了方法的普通对象),
4
+ * 它们本身不可变,共用同一个实例没有问题
5
+ *
6
+ * query.search(cloneValue(draft)); // draft 里的 CalendarDate 仍是 CalendarDate
7
+ */
8
+ export declare function cloneValue<T>(value: T): T;
@@ -0,0 +1,21 @@
1
+ import { toRaw } from "vue";
2
+ //#region src/utils/data/clone.ts
3
+ /**
4
+ * 复制表单、查询条件这类值:普通对象与数组逐层复制(各份互不影响),其余值原样保留;响应式代理先取原始对象。
5
+ * 不用 structuredClone:Decimal、@internationalized/date 的日期这些带方法的值克隆不了(会抛错,或变成丢了方法的普通对象),
6
+ * 它们本身不可变,共用同一个实例没有问题
7
+ *
8
+ * query.search(cloneValue(draft)); // draft 里的 CalendarDate 仍是 CalendarDate
9
+ */
10
+ function cloneValue(value) {
11
+ const raw = toRaw(value);
12
+ if (Array.isArray(raw)) return raw.map(cloneValue);
13
+ if (raw === null || typeof raw !== "object") return raw;
14
+ const prototype = Object.getPrototypeOf(raw);
15
+ if (prototype !== Object.prototype && prototype !== null) return raw;
16
+ return Object.fromEntries(Object.entries(raw).map(([key, item]) => [key, cloneValue(item)]));
17
+ }
18
+ //#endregion
19
+ export { cloneValue };
20
+
21
+ //# sourceMappingURL=clone.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"clone.js","names":[],"sources":["../../../src/utils/data/clone.ts"],"sourcesContent":["import { toRaw } from 'vue';\n\n/**\n * 复制表单、查询条件这类值:普通对象与数组逐层复制(各份互不影响),其余值原样保留;响应式代理先取原始对象。\n * 不用 structuredClone:Decimal、@internationalized/date 的日期这些带方法的值克隆不了(会抛错,或变成丢了方法的普通对象),\n * 它们本身不可变,共用同一个实例没有问题\n *\n * query.search(cloneValue(draft)); // draft 里的 CalendarDate 仍是 CalendarDate\n */\nexport function cloneValue<T>(value: T): T {\n const raw = toRaw(value);\n if (Array.isArray(raw)) return raw.map(cloneValue) as T;\n if (raw === null || typeof raw !== 'object') return raw;\n const prototype = Object.getPrototypeOf(raw);\n if (prototype !== Object.prototype && prototype !== null) return raw;\n return Object.fromEntries(Object.entries(raw).map(([key, item]) => [key, cloneValue(item)])) as T;\n}\n"],"mappings":";;;;;;;;;AASA,SAAgB,WAAc,OAAa;CACzC,MAAM,MAAM,MAAM,KAAK;CACvB,IAAI,MAAM,QAAQ,GAAG,GAAG,OAAO,IAAI,IAAI,UAAU;CACjD,IAAI,QAAQ,QAAQ,OAAO,QAAQ,UAAU,OAAO;CACpD,MAAM,YAAY,OAAO,eAAe,GAAG;CAC3C,IAAI,cAAc,OAAO,aAAa,cAAc,MAAM,OAAO;CACjE,OAAO,OAAO,YAAY,OAAO,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,KAAK,UAAU,CAAC,KAAK,WAAW,IAAI,CAAC,CAAC,CAAC;AAC7F"}
@@ -137,6 +137,16 @@ export interface DateRange<T = CalendarDate> {
137
137
  /** 结束(含) */
138
138
  end: T;
139
139
  }
140
+ /**
141
+ * 日期区间换成一对时刻,交给按时刻查的接口:从开始那天的零点起(含),到结束那天的第二天零点前(不含)。
142
+ * 一天按 timeZone 算(默认浏览器的时区),所以"10 月 27 日"在东八区是 26 日 16:00Z 到 27 日 16:00Z。
143
+ *
144
+ * const { from, to } = dayRangeBounds(range); // 发成 ISO:from.toISOString()
145
+ */
146
+ export declare function dayRangeBounds(range: DateRange, timeZone?: string): {
147
+ from: Date;
148
+ to: Date;
149
+ };
140
150
  /** 两个日期排成区间:先的在前 */
141
151
  export declare function orderedRange(a: CalendarDate, b: CalendarDate): DateRange;
142
152
  /** 日期是否在区间里(含两端;按粒度) */
@@ -240,6 +240,18 @@ function clampDate(date, { min, max }) {
240
240
  if (max != null && date.compare(toCalendar(max, date.calendar)) > 0) return toCalendar(max, date.calendar);
241
241
  return date;
242
242
  }
243
+ /**
244
+ * 日期区间换成一对时刻,交给按时刻查的接口:从开始那天的零点起(含),到结束那天的第二天零点前(不含)。
245
+ * 一天按 timeZone 算(默认浏览器的时区),所以"10 月 27 日"在东八区是 26 日 16:00Z 到 27 日 16:00Z。
246
+ *
247
+ * const { from, to } = dayRangeBounds(range); // 发成 ISO:from.toISOString()
248
+ */
249
+ function dayRangeBounds(range, timeZone = getLocalTimeZone()) {
250
+ return {
251
+ from: range.start.toDate(timeZone),
252
+ to: range.end.add({ days: 1 }).toDate(timeZone)
253
+ };
254
+ }
243
255
  /** 两个日期排成区间:先的在前 */
244
256
  function orderedRange(a, b) {
245
257
  return a.compare(b) <= 0 ? {
@@ -404,6 +416,6 @@ function cachedFormatter(locale, options) {
404
416
  return formatter;
405
417
  }
406
418
  //#endregion
407
- export { calendarOf, clampDate, compareDates, daysBetween, fullIsoDay, isDateDisabled, isInRange, isOutOfRange, isOutsideDecade, isSameDate, isoDayOfWeek, isoWeekOf, isoWeeksInYear, lastIsoDay, monthGrid, monthsOfYear, orderedRange, parseIsoDate, parseIsoDateTime, parseIsoRange, parseIsoTime, presetIsoRange, presetRange, rangeDays, rangeHasUnavailable, relativeUnit, shiftIsoDate, toDayOfWeek, toInstant, toIsoDate, toIsoDateTime, toIsoQuarter, toIsoRange, toIsoTime, toIsoWeek, todayIso, truncateDate, weekOfYear, weekdayNames, yearsOfDecade };
419
+ export { calendarOf, clampDate, compareDates, dayRangeBounds, daysBetween, fullIsoDay, isDateDisabled, isInRange, isOutOfRange, isOutsideDecade, isSameDate, isoDayOfWeek, isoWeekOf, isoWeeksInYear, lastIsoDay, monthGrid, monthsOfYear, orderedRange, parseIsoDate, parseIsoDateTime, parseIsoRange, parseIsoTime, presetIsoRange, presetRange, rangeDays, rangeHasUnavailable, relativeUnit, shiftIsoDate, toDayOfWeek, toInstant, toIsoDate, toIsoDateTime, toIsoQuarter, toIsoRange, toIsoTime, toIsoWeek, todayIso, truncateDate, weekOfYear, weekdayNames, yearsOfDecade };
408
420
 
409
421
  //# sourceMappingURL=date.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"date.js","names":[],"sources":["../../../src/utils/data/date.ts"],"sourcesContent":["/**\n * 日期运算(不含界面):ISO 字符串互转、月份网格、星期名与月份名、可选范围、区间、周数、快捷区间。\n * Calendar、DateField、各种日期选择器共用;运算交给 @internationalized/date(时区、地区的周起始日、非公历)。\n *\n * 组件对外的值是 ISO 8601 字符串('2026-10-20'、'14:30'、'2026-10-20T14:30'),与原生 input、URL 参数、\n * zod 的 z.iso.date() 一致;组件内部换成 CalendarDate 等对象运算。月份名、星期名一律取自 Intl。\n * 出错的约定:parseXxx 解析不了时返回 null(输入框里的半截内容是常态);shiftIsoDate、daysBetween 这类运算\n * 要求合法的 ISO 字符串,不合法时抛 RangeError 并带上原值(多半是调用方的数据错了,不该悄悄算出别的日子)。\n *\n * monthGrid(new CalendarDate(2026, 10, 1), { locale: 'zh-CN' }) → 6 行 × 7 天,补齐上下月\n * weekdayNames('en-US', { format: 'short' }) → ['Sun', 'Mon', …]\n */\nimport {\n CalendarDate,\n CalendarDateTime,\n createCalendar,\n DateFormatter,\n endOfMonth,\n getDayOfWeek,\n getLocalTimeZone,\n GregorianCalendar,\n parseDate,\n parseDateTime,\n parseTime,\n startOfMonth,\n startOfWeek,\n Time,\n toCalendar,\n today,\n type Calendar,\n type CalendarIdentifier,\n type DateDuration,\n type DateValue,\n type DayOfWeek,\n} from '@internationalized/date';\n\n// ───────── ISO 字符串 ─────────\n\n/** 'YYYY-MM-DD' → CalendarDate(公历);空值或格式不对时为 null */\nexport function parseIsoDate(value: string | null | undefined): CalendarDate | null {\n return tryParse(value, parseDate);\n}\n\n/** 'HH:mm' 或 'HH:mm:ss' → Time;空值或格式不对时为 null */\nexport function parseIsoTime(value: string | null | undefined): Time | null {\n return tryParse(value, parseTime);\n}\n\n/**\n * 补成完整的 ISO 日期(这一段的第一天):'2026' 与 '2026-10' 补成 1 日,'2026-Q4' 是 10 月 1 日,\n * '2026-W43' 是那一周的周一,日期时间取日期部分(DateField、各种日期选择器的粒度)\n */\nexport function fullIsoDay(iso: string): string {\n const period = parsePeriod(iso);\n if (period) return period.start.toString();\n return iso.length === 4 ? `${iso}-01-01` : iso.length === 7 ? `${iso}-01` : iso.slice(0, 10);\n}\n\n/** 这一段的最后一天:'2026' 是 12 月 31 日,'2026-10' 是 31 日,'2026-Q4' 是 12 月 31 日,'2026-W43' 是那周的周日 */\nexport function lastIsoDay(iso: string): string {\n const period = parsePeriod(iso);\n if (period) return period.end.toString();\n if (iso.length === 4) return `${iso}-12-31`;\n if (iso.length === 7) return endOfMonth(parseDate(`${iso}-01`)).toString();\n return iso.slice(0, 10);\n}\n\n// ───────── 季度与 ISO 周 ─────────\n\nconst QUARTER_PATTERN = /^(\\d{4})-Q([1-4])$/;\nconst WEEK_PATTERN = /^(\\d{4})-W(\\d{2})$/;\n\n/** 日期所在的季度:'2026-Q4' */\nexport function toIsoQuarter(date: DateValue): string {\n const gregorian = toCalendar(date, GREGORIAN);\n return `${String(gregorian.year).padStart(4, '0')}-Q${Math.ceil(gregorian.month / 3)}`;\n}\n\n/** ISO 8601 的周(周一开始,含 1 月 4 日的那周是第 1 周,跨年的周归周四所在的年):所属的年与第几周 */\nexport function isoWeekOf(date: DateValue): { year: number; week: number } {\n const gregorian = toCalendar(date, GREGORIAN);\n const day = new CalendarDate(gregorian.year, gregorian.month, gregorian.day);\n const thursday = day.add({ days: 4 - isoWeekday(day) });\n return {\n year: thursday.year,\n week: Math.floor(thursday.compare(new CalendarDate(thursday.year, 1, 1)) / 7) + 1,\n };\n}\n\n/** 日期所在的 ISO 周:'2026-W43'(同原生 input type=\"week\") */\nexport function toIsoWeek(date: DateValue): string {\n const { year, week } = isoWeekOf(date);\n return `${String(year).padStart(4, '0')}-W${String(week).padStart(2, '0')}`;\n}\n\n/** 一年有几个 ISO 周(52 或 53):12 月 28 日总在最后一周里 */\nexport const isoWeeksInYear = (year: number): number =>\n isoWeekOf(new CalendarDate(year, 12, 28)).week;\n\n/** 周一是 1、周日是 7(与地区无关) */\nfunction isoWeekday(date: CalendarDate): number {\n return date.toDate('UTC').getUTCDay() || 7;\n}\n\n/** '2026-Q4'、'2026-W43' → 这一段的第一天与最后一天;不是季度、周的形式时 null */\nfunction parsePeriod(iso: string): { start: CalendarDate; end: CalendarDate } | null {\n const quarter = QUARTER_PATTERN.exec(iso);\n if (quarter) {\n const start = new CalendarDate(Number(quarter[1]), Number(quarter[2]) * 3 - 2, 1);\n return { start, end: endOfMonth(start.add({ months: 2 })) };\n }\n const week = WEEK_PATTERN.exec(iso);\n if (week) {\n const january4 = new CalendarDate(Number(week[1]), 1, 4);\n const start = january4.add({ days: 1 - isoWeekday(january4) + (Number(week[2]) - 1) * 7 });\n return { start, end: start.add({ days: 6 }) };\n }\n return null;\n}\n\n/** 'YYYY-MM-DDTHH:mm[:ss]' → CalendarDateTime(公历);空值或格式不对时为 null */\nexport function parseIsoDateTime(value: string | null | undefined): CalendarDateTime | null {\n return tryParse(value, parseDateTime);\n}\n\n/** 日期 → 'YYYY-MM-DD';不是公历的日期先换回公历 */\nexport function toIsoDate(date: DateValue): string {\n const gregorian = toCalendar(date, GREGORIAN);\n return new CalendarDate(gregorian.year, gregorian.month, gregorian.day).toString();\n}\n\n/** 时间 → 'HH:mm';withSeconds 时 'HH:mm:ss'(同原生 input type=\"time\") */\nexport function toIsoTime(time: Time, withSeconds = false): string {\n const text = new Time(time.hour, time.minute, withSeconds ? time.second : 0).toString();\n return withSeconds ? text : text.slice(0, 5);\n}\n\n/** 日期时间 → 'YYYY-MM-DDTHH:mm';withSeconds 时带秒(同原生 input type=\"datetime-local\") */\nexport function toIsoDateTime(value: CalendarDateTime, withSeconds = false): string {\n const gregorian = toCalendar(value, GREGORIAN);\n return `${toIsoDate(gregorian)}T${toIsoTime(new Time(gregorian.hour, gregorian.minute, gregorian.second), withSeconds)}`;\n}\n\n/** 今天的 ISO 日期,按时区(不写时取浏览器的):`todayIso()` → '2026-10-20' */\nexport function todayIso(timeZone = getLocalTimeZone()): string {\n return today(timeZone).toString();\n}\n\n/** ISO 日期加减(月末自动夹到下个月的最后一天):`shiftIsoDate('2026-01-31', { months: 1 })` → '2026-02-28' */\nexport function shiftIsoDate(value: string, duration: DateDuration): string {\n const date = parseIsoDate(value);\n if (!date) throw new RangeError(`不是 ISO 日期:${value}`);\n return date.add(duration).toString();\n}\n\n/** 从 a 到 b 相隔几天(b 在后为正):`daysBetween('2026-10-20', '2026-10-23')` → 3 */\nexport function daysBetween(a: string, b: string): number {\n const start = parseIsoDate(a);\n const end = parseIsoDate(b);\n if (!start || !end) throw new RangeError(`不是 ISO 日期:${start ? b : a}`);\n return end.compare(start);\n}\n\n/**\n * ISO 日期是星期几:0 周日 … 6 周六(同 Date#getDay)。直接按日期算,不受时区影响;\n * `new Date('2026-10-20').getDay()` 在 UTC 以西的时区会算成前一天\n */\nexport function isoDayOfWeek(value: string): number {\n const date = parseIsoDate(value);\n if (!date) throw new RangeError(`不是 ISO 日期:${value}`);\n return getDayOfWeek(date, 'en-US');\n}\n\n// ───────── 日历系统与周 ─────────\n\nconst GREGORIAN = new GregorianCalendar();\n\n/**\n * 语言里的日历标识 → 运算用的日历;@internationalized/date 不支持的(如农历 'chinese')退回公历,\n * 月份网格仍按公历排,显示的文字照常由 Intl 按该日历格式化\n */\nexport function calendarOf(identifier: string): Calendar {\n if (identifier === 'gregory') return GREGORIAN;\n try {\n return createCalendar(identifier as CalendarIdentifier);\n } catch {\n return GREGORIAN;\n }\n}\n\nconst DAYS_OF_WEEK: readonly DayOfWeek[] = ['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'];\n\n/** 语言配置的一周第一天(0 表示周日)→ @internationalized/date 的写法;不写时按地区惯例 */\nexport function toDayOfWeek(firstDayOfWeek: number | undefined): DayOfWeek | undefined {\n return firstDayOfWeek == null ? undefined : DAYS_OF_WEEK[((firstDayOfWeek % 7) + 7) % 7];\n}\n\n/** 一周的排法:语言与一周第一天(0 表示周日,不写时按地区惯例) */\nexport interface WeekOptions {\n /** BCP 47 语言标签 */\n locale: string;\n /** 一周的第一天,0 表示周日;不写时按地区惯例(zh-CN 周一,en-US 周日) */\n firstDayOfWeek?: number;\n}\n\n/** monthGrid 的选项 */\nexport interface MonthGridOptions extends WeekOptions {\n /** 总是 6 行:几个月并排、或翻页时高度不跳,默认 true */\n fixedWeeks?: boolean;\n}\n\n/** 一个月的日期网格:按周分行,首尾用上个月、下个月的日期补齐(同 React Aria 的 getDatesInWeek) */\nexport function monthGrid(\n month: CalendarDate,\n { locale, firstDayOfWeek, fixedWeeks = true }: MonthGridOptions,\n): CalendarDate[][] {\n const first = startOfWeek(startOfMonth(month), locale, toDayOfWeek(firstDayOfWeek));\n const last = endOfMonth(month);\n const weeks: CalendarDate[][] = [];\n for (let start = first; weeks.length < 6; start = start.add({ weeks: 1 })) {\n if (!fixedWeeks && start.compare(last) > 0) break;\n weeks.push(Array.from({ length: 7 }, (_, index) => start.add({ days: index })));\n }\n return weeks;\n}\n\n/** 星期名的长短 */\nexport interface WeekdayFormats {\n /** 最短:一、二 / S、M */\n narrow: unknown;\n /** 简写:周一 / Mon */\n short: unknown;\n /** 全称:星期一 / Monday */\n long: unknown;\n}\n\n/** 按一周的排法列出七天的星期名(取自 Intl),从一周第一天开始 */\nexport function weekdayNames(\n locale: string,\n {\n firstDayOfWeek,\n format = 'short',\n }: { firstDayOfWeek?: number; format?: keyof WeekdayFormats } = {},\n): string[] {\n const formatter = cachedFormatter(locale, { weekday: format, timeZone: 'UTC' });\n // 任取一周:从这周的第一天起连续七天\n const start = startOfWeek(new CalendarDate(2024, 1, 10), locale, toDayOfWeek(firstDayOfWeek));\n return Array.from({ length: 7 }, (_, index) =>\n formatter.format(start.add({ days: index }).toDate('UTC')),\n );\n}\n\n/** 一年的各月(每月 1 日),按日期所在的日历系统(个别日历一年有 13 个月) */\nexport function monthsOfYear(date: CalendarDate): CalendarDate[] {\n const first = date.set({ month: 1, day: 1 });\n return Array.from({ length: date.calendar.getMonthsInYear(first) }, (_, index) =>\n first.add({ months: index }),\n );\n}\n\n/** 年份视图的一页:所在的十年,前后各补一年(共 12 年,排成 4 × 3;同 Ant Design 的年份面板) */\nexport function yearsOfDecade(date: CalendarDate): CalendarDate[] {\n const start = date.set({ year: Math.floor(date.year / 10) * 10, month: 1, day: 1 });\n return Array.from({ length: 12 }, (_, index) => start.add({ years: index - 1 }));\n}\n\n/** 是不是十年之外、补上的那两年 */\nexport const isOutsideDecade = (year: CalendarDate, page: CalendarDate) =>\n Math.floor(year.year / 10) !== Math.floor(page.year / 10);\n\n/**\n * 一年里的第几周:一周从周一开始时按 ISO 8601(含 1 月 4 日的那周是第 1 周),\n * 其他(周日、周六开始)按含 1 月 1 日的那周是第 1 周(美国、日本的惯例)\n */\nexport function weekOfYear(date: CalendarDate, options: WeekOptions): number {\n const gregorian = toCalendar(date, GREGORIAN);\n const monday =\n getDayOfWeek(\n new CalendarDate(2024, 1, 1),\n options.locale,\n toDayOfWeek(options.firstDayOfWeek),\n ) === 0;\n const weekStart = startOfWeek(gregorian, options.locale, toDayOfWeek(options.firstDayOfWeek));\n // 一周归属的年份:ISO 按这周的周四,其他按这周的最后一天(含 1 月 1 日的周就算新年的第 1 周)\n const anchor = weekStart.add({ days: monday ? 3 : 6 });\n const firstAnchor = new CalendarDate(anchor.year, 1, monday ? 4 : 1);\n const firstWeek = startOfWeek(firstAnchor, options.locale, toDayOfWeek(options.firstDayOfWeek));\n return Math.round(weekStart.compare(firstWeek) / 7) + 1;\n}\n\n// ───────── 比较、范围与不可选 ─────────\n\n/** 比较的粒度:日历的三种视图 */\nexport interface DateUnits {\n /** 天 */\n day: unknown;\n /** 月 */\n month: unknown;\n /** 年 */\n year: unknown;\n}\n\n/** 日期的粒度 */\nexport type DateUnit = keyof DateUnits;\n\n/** 截到粒度:月取 1 日,年取 1 月 1 日 */\nexport function truncateDate(date: CalendarDate, unit: DateUnit): CalendarDate {\n if (unit === 'day') return date;\n return unit === 'month' ? date.set({ day: 1 }) : date.set({ month: 1, day: 1 });\n}\n\n/** 按粒度比较:小于 0 表示 a 在前;跨日历系统时按同一天比较 */\nexport function compareDates(a: CalendarDate, b: CalendarDate, unit: DateUnit = 'day'): number {\n const other = toCalendar(b, a.calendar);\n return truncateDate(a, unit).compare(truncateDate(other, unit));\n}\n\n/** 是不是同一天 / 同一月 / 同一年;任一方为空时为 false */\nexport function isSameDate(\n a: CalendarDate | null | undefined,\n b: CalendarDate | null | undefined,\n unit: DateUnit = 'day',\n): boolean {\n return a != null && b != null && compareDates(a, b, unit) === 0;\n}\n\n/** 可选范围与不可选的日期:Calendar、DatePicker、DateField 共用 */\nexport interface DateLimits {\n /** 最早可选的日期 */\n min?: CalendarDate | null;\n /** 最晚可选的日期 */\n max?: CalendarDate | null;\n /** 不可选的日期(已订满、节假日):仍能用方向键经过,读屏能听到,不能选 */\n isUnavailable?: (date: CalendarDate) => boolean;\n}\n\n/** 在 min–max 之外(按粒度:月份视图里只要这个月有一天可选就不算在外面) */\nexport function isOutOfRange(\n date: CalendarDate,\n { min, max }: DateLimits,\n unit: DateUnit = 'day',\n): boolean {\n return (\n (min != null && compareDates(date, min, unit) < 0) ||\n (max != null && compareDates(date, max, unit) > 0)\n );\n}\n\n/** 不能选:在范围外,或是不可选的日期(只在天的粒度上判断 isUnavailable) */\nexport function isDateDisabled(\n date: CalendarDate,\n limits: DateLimits,\n unit: DateUnit = 'day',\n): boolean {\n return (\n isOutOfRange(date, limits, unit) || (unit === 'day' && (limits.isUnavailable?.(date) ?? false))\n );\n}\n\n/** 把日期夹到 min–max 之间 */\nexport function clampDate(date: CalendarDate, { min, max }: DateLimits): CalendarDate {\n if (min != null && date.compare(toCalendar(min, date.calendar)) < 0)\n return toCalendar(min, date.calendar);\n if (max != null && date.compare(toCalendar(max, date.calendar)) > 0)\n return toCalendar(max, date.calendar);\n return date;\n}\n\n/** 日期区间:两端都包含 */\nexport interface DateRange<T = CalendarDate> {\n /** 开始(含) */\n start: T;\n /** 结束(含) */\n end: T;\n}\n\n/** 两个日期排成区间:先的在前 */\nexport function orderedRange(a: CalendarDate, b: CalendarDate): DateRange {\n return a.compare(b) <= 0 ? { start: a, end: b } : { start: b, end: a };\n}\n\n/** 日期是否在区间里(含两端;按粒度) */\nexport function isInRange(\n date: CalendarDate,\n range: DateRange | null | undefined,\n unit: DateUnit = 'day',\n): boolean {\n return (\n range != null &&\n compareDates(date, range.start, unit) >= 0 &&\n compareDates(date, range.end, unit) <= 0\n );\n}\n\n/** 区间一共几天(含两端) */\nexport function rangeDays({ start, end }: DateRange): number {\n return end.compare(start) + 1;\n}\n\n/** 区间里有没有不可选的日期:酒店连住时中间不能有订满的一天(React Aria 的 allowsNonContiguousRanges 为 false 时) */\nexport function rangeHasUnavailable(\n { start, end }: DateRange,\n isUnavailable: ((date: CalendarDate) => boolean) | undefined,\n): boolean {\n if (!isUnavailable) return false;\n for (let date = start; date.compare(end) <= 0; date = date.add({ days: 1 })) {\n if (isUnavailable(date)) return true;\n }\n return false;\n}\n\n/** ISO 字符串的区间 → CalendarDate 的区间;任一端解析不了时为 null */\nexport function parseIsoRange(range: DateRange<string> | null | undefined): DateRange | null {\n const start = parseIsoDate(range?.start);\n const end = parseIsoDate(range?.end);\n return start && end ? orderedRange(start, end) : null;\n}\n\n/** CalendarDate 的区间 → ISO 字符串的区间 */\nexport function toIsoRange(range: DateRange): DateRange<string> {\n return { start: toIsoDate(range.start), end: toIsoDate(range.end) };\n}\n\n// ───────── 快捷区间 ─────────\n\n/** 常用的快捷区间:报表、筛选里的“最近 7 天”“本月” */\nexport interface DateRangePresets {\n /** 今天 */\n today: unknown;\n /** 昨天 */\n yesterday: unknown;\n /** 最近 7 天(含今天) */\n last7Days: unknown;\n /** 最近 30 天(含今天) */\n last30Days: unknown;\n /** 本周(按语言的一周第一天) */\n thisWeek: unknown;\n /** 本月 */\n thisMonth: unknown;\n /** 上月 */\n lastMonth: unknown;\n /** 今年 */\n thisYear: unknown;\n}\n\n/** 快捷区间的名字 */\nexport type DateRangePreset = keyof DateRangePresets;\n\n/** 按今天算出快捷区间 */\nexport function presetRange(\n preset: DateRangePreset,\n today: CalendarDate,\n week: WeekOptions,\n): DateRange {\n switch (preset) {\n case 'today':\n return { start: today, end: today };\n case 'yesterday': {\n const day = today.subtract({ days: 1 });\n return { start: day, end: day };\n }\n case 'last7Days':\n return { start: today.subtract({ days: 6 }), end: today };\n case 'last30Days':\n return { start: today.subtract({ days: 29 }), end: today };\n case 'thisWeek': {\n const start = startOfWeek(today, week.locale, toDayOfWeek(week.firstDayOfWeek));\n return { start, end: start.add({ days: 6 }) };\n }\n case 'thisMonth':\n return { start: startOfMonth(today), end: endOfMonth(today) };\n case 'lastMonth': {\n const month = startOfMonth(today).subtract({ months: 1 });\n return { start: month, end: endOfMonth(month) };\n }\n case 'thisYear':\n return { start: today.set({ month: 1, day: 1 }), end: today.set({ month: 12, day: 31 }) };\n }\n}\n\n/** 快捷区间的 ISO 值,按今天(时区,不写时取浏览器的)与一周的排法:`presetIsoRange('last7Days', { locale: 'zh-CN' })` */\nexport function presetIsoRange(\n preset: DateRangePreset,\n week: WeekOptions,\n timeZone = getLocalTimeZone(),\n): DateRange<string> {\n return toIsoRange(presetRange(preset, today(timeZone), week));\n}\n\n// ───────── 时刻与相对时间 ─────────\n\n/** 带时区或 UTC 标记的 ISO 字符串('2026-10-20T14:30:00Z'、'…+08:00'):本身就是一个时刻 */\nconst ABSOLUTE_ISO = /(?:[zZ]|[+-]\\d\\d:?\\d\\d)$/;\n\n/**\n * 日期值 → 时刻(毫秒时间戳):Date 与带时区的值照原样;不带时区的('2026-10-20T14:30'、CalendarDateTime)\n * 按 timeZone 的墙上时间算。格式不对时 NaN\n */\nexport function toInstant(value: Date | DateValue | string, timeZone = getLocalTimeZone()): number {\n if (value instanceof Date) return value.getTime();\n if (typeof value !== 'string') {\n return ('timeZone' in value ? value.toDate() : value.toDate(timeZone)).getTime();\n }\n if (ABSOLUTE_ISO.test(value)) return Date.parse(value);\n const parsed = parseIsoDateTime(value) ?? parseIsoDate(value);\n return parsed ? parsed.toDate(timeZone).getTime() : Number.NaN;\n}\n\n/** 相对时间用的单位:多久以内用这个单位(秒),参考 moment.js 的取整阈值 */\nconst RELATIVE_UNITS: readonly [Intl.RelativeTimeFormatUnit, number, number][] = [\n // [单位, 一个单位多少秒, 小于多少秒时用它]\n ['second', 1, 45],\n ['minute', 60, 45 * 60],\n ['hour', 3600, 22 * 3600],\n ['day', 86_400, 26 * 86_400],\n ['month', 30 * 86_400, 320 * 86_400],\n ['year', 365 * 86_400, Infinity],\n];\n\n/** 相差的毫秒数 → 相对时间的数值与单位:`relativeUnit(-180_000)` → `{ value: -3, unit: 'minute' }` */\nexport function relativeUnit(diff: number): { value: number; unit: Intl.RelativeTimeFormatUnit } {\n const seconds = diff / 1000;\n const [unit, size] = RELATIVE_UNITS.find(([, , below]) => Math.abs(seconds) < below)!;\n // -0 换成 0:Intl 的 numeric: auto 才念“现在”\n return { value: Math.round(seconds / size) || 0, unit };\n}\n\n// ───────── 内部实现 ─────────\n\nfunction tryParse<T>(value: string | null | undefined, parse: (text: string) => T): T | null {\n if (!value) return null;\n try {\n return parse(value);\n } catch {\n return null;\n }\n}\n\nconst formatters = new Map<string, DateFormatter>();\n\nfunction cachedFormatter(locale: string, options: Intl.DateTimeFormatOptions): DateFormatter {\n const key = `${locale}|${JSON.stringify(options)}`;\n let formatter = formatters.get(key);\n if (!formatter) formatters.set(key, (formatter = new DateFormatter(locale, options)));\n return formatter;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"date.js","names":[],"sources":["../../../src/utils/data/date.ts"],"sourcesContent":["/**\n * 日期运算(不含界面):ISO 字符串互转、月份网格、星期名与月份名、可选范围、区间、周数、快捷区间。\n * Calendar、DateField、各种日期选择器共用;运算交给 @internationalized/date(时区、地区的周起始日、非公历)。\n *\n * 组件对外的值是 ISO 8601 字符串('2026-10-20'、'14:30'、'2026-10-20T14:30'),与原生 input、URL 参数、\n * zod 的 z.iso.date() 一致;组件内部换成 CalendarDate 等对象运算。月份名、星期名一律取自 Intl。\n * 出错的约定:parseXxx 解析不了时返回 null(输入框里的半截内容是常态);shiftIsoDate、daysBetween 这类运算\n * 要求合法的 ISO 字符串,不合法时抛 RangeError 并带上原值(多半是调用方的数据错了,不该悄悄算出别的日子)。\n *\n * monthGrid(new CalendarDate(2026, 10, 1), { locale: 'zh-CN' }) → 6 行 × 7 天,补齐上下月\n * weekdayNames('en-US', { format: 'short' }) → ['Sun', 'Mon', …]\n */\nimport {\n CalendarDate,\n CalendarDateTime,\n createCalendar,\n DateFormatter,\n endOfMonth,\n getDayOfWeek,\n getLocalTimeZone,\n GregorianCalendar,\n parseDate,\n parseDateTime,\n parseTime,\n startOfMonth,\n startOfWeek,\n Time,\n toCalendar,\n today,\n type Calendar,\n type CalendarIdentifier,\n type DateDuration,\n type DateValue,\n type DayOfWeek,\n} from '@internationalized/date';\n\n// ───────── ISO 字符串 ─────────\n\n/** 'YYYY-MM-DD' → CalendarDate(公历);空值或格式不对时为 null */\nexport function parseIsoDate(value: string | null | undefined): CalendarDate | null {\n return tryParse(value, parseDate);\n}\n\n/** 'HH:mm' 或 'HH:mm:ss' → Time;空值或格式不对时为 null */\nexport function parseIsoTime(value: string | null | undefined): Time | null {\n return tryParse(value, parseTime);\n}\n\n/**\n * 补成完整的 ISO 日期(这一段的第一天):'2026' 与 '2026-10' 补成 1 日,'2026-Q4' 是 10 月 1 日,\n * '2026-W43' 是那一周的周一,日期时间取日期部分(DateField、各种日期选择器的粒度)\n */\nexport function fullIsoDay(iso: string): string {\n const period = parsePeriod(iso);\n if (period) return period.start.toString();\n return iso.length === 4 ? `${iso}-01-01` : iso.length === 7 ? `${iso}-01` : iso.slice(0, 10);\n}\n\n/** 这一段的最后一天:'2026' 是 12 月 31 日,'2026-10' 是 31 日,'2026-Q4' 是 12 月 31 日,'2026-W43' 是那周的周日 */\nexport function lastIsoDay(iso: string): string {\n const period = parsePeriod(iso);\n if (period) return period.end.toString();\n if (iso.length === 4) return `${iso}-12-31`;\n if (iso.length === 7) return endOfMonth(parseDate(`${iso}-01`)).toString();\n return iso.slice(0, 10);\n}\n\n// ───────── 季度与 ISO 周 ─────────\n\nconst QUARTER_PATTERN = /^(\\d{4})-Q([1-4])$/;\nconst WEEK_PATTERN = /^(\\d{4})-W(\\d{2})$/;\n\n/** 日期所在的季度:'2026-Q4' */\nexport function toIsoQuarter(date: DateValue): string {\n const gregorian = toCalendar(date, GREGORIAN);\n return `${String(gregorian.year).padStart(4, '0')}-Q${Math.ceil(gregorian.month / 3)}`;\n}\n\n/** ISO 8601 的周(周一开始,含 1 月 4 日的那周是第 1 周,跨年的周归周四所在的年):所属的年与第几周 */\nexport function isoWeekOf(date: DateValue): { year: number; week: number } {\n const gregorian = toCalendar(date, GREGORIAN);\n const day = new CalendarDate(gregorian.year, gregorian.month, gregorian.day);\n const thursday = day.add({ days: 4 - isoWeekday(day) });\n return {\n year: thursday.year,\n week: Math.floor(thursday.compare(new CalendarDate(thursday.year, 1, 1)) / 7) + 1,\n };\n}\n\n/** 日期所在的 ISO 周:'2026-W43'(同原生 input type=\"week\") */\nexport function toIsoWeek(date: DateValue): string {\n const { year, week } = isoWeekOf(date);\n return `${String(year).padStart(4, '0')}-W${String(week).padStart(2, '0')}`;\n}\n\n/** 一年有几个 ISO 周(52 或 53):12 月 28 日总在最后一周里 */\nexport const isoWeeksInYear = (year: number): number =>\n isoWeekOf(new CalendarDate(year, 12, 28)).week;\n\n/** 周一是 1、周日是 7(与地区无关) */\nfunction isoWeekday(date: CalendarDate): number {\n return date.toDate('UTC').getUTCDay() || 7;\n}\n\n/** '2026-Q4'、'2026-W43' → 这一段的第一天与最后一天;不是季度、周的形式时 null */\nfunction parsePeriod(iso: string): { start: CalendarDate; end: CalendarDate } | null {\n const quarter = QUARTER_PATTERN.exec(iso);\n if (quarter) {\n const start = new CalendarDate(Number(quarter[1]), Number(quarter[2]) * 3 - 2, 1);\n return { start, end: endOfMonth(start.add({ months: 2 })) };\n }\n const week = WEEK_PATTERN.exec(iso);\n if (week) {\n const january4 = new CalendarDate(Number(week[1]), 1, 4);\n const start = january4.add({ days: 1 - isoWeekday(january4) + (Number(week[2]) - 1) * 7 });\n return { start, end: start.add({ days: 6 }) };\n }\n return null;\n}\n\n/** 'YYYY-MM-DDTHH:mm[:ss]' → CalendarDateTime(公历);空值或格式不对时为 null */\nexport function parseIsoDateTime(value: string | null | undefined): CalendarDateTime | null {\n return tryParse(value, parseDateTime);\n}\n\n/** 日期 → 'YYYY-MM-DD';不是公历的日期先换回公历 */\nexport function toIsoDate(date: DateValue): string {\n const gregorian = toCalendar(date, GREGORIAN);\n return new CalendarDate(gregorian.year, gregorian.month, gregorian.day).toString();\n}\n\n/** 时间 → 'HH:mm';withSeconds 时 'HH:mm:ss'(同原生 input type=\"time\") */\nexport function toIsoTime(time: Time, withSeconds = false): string {\n const text = new Time(time.hour, time.minute, withSeconds ? time.second : 0).toString();\n return withSeconds ? text : text.slice(0, 5);\n}\n\n/** 日期时间 → 'YYYY-MM-DDTHH:mm';withSeconds 时带秒(同原生 input type=\"datetime-local\") */\nexport function toIsoDateTime(value: CalendarDateTime, withSeconds = false): string {\n const gregorian = toCalendar(value, GREGORIAN);\n return `${toIsoDate(gregorian)}T${toIsoTime(new Time(gregorian.hour, gregorian.minute, gregorian.second), withSeconds)}`;\n}\n\n/** 今天的 ISO 日期,按时区(不写时取浏览器的):`todayIso()` → '2026-10-20' */\nexport function todayIso(timeZone = getLocalTimeZone()): string {\n return today(timeZone).toString();\n}\n\n/** ISO 日期加减(月末自动夹到下个月的最后一天):`shiftIsoDate('2026-01-31', { months: 1 })` → '2026-02-28' */\nexport function shiftIsoDate(value: string, duration: DateDuration): string {\n const date = parseIsoDate(value);\n if (!date) throw new RangeError(`不是 ISO 日期:${value}`);\n return date.add(duration).toString();\n}\n\n/** 从 a 到 b 相隔几天(b 在后为正):`daysBetween('2026-10-20', '2026-10-23')` → 3 */\nexport function daysBetween(a: string, b: string): number {\n const start = parseIsoDate(a);\n const end = parseIsoDate(b);\n if (!start || !end) throw new RangeError(`不是 ISO 日期:${start ? b : a}`);\n return end.compare(start);\n}\n\n/**\n * ISO 日期是星期几:0 周日 … 6 周六(同 Date#getDay)。直接按日期算,不受时区影响;\n * `new Date('2026-10-20').getDay()` 在 UTC 以西的时区会算成前一天\n */\nexport function isoDayOfWeek(value: string): number {\n const date = parseIsoDate(value);\n if (!date) throw new RangeError(`不是 ISO 日期:${value}`);\n return getDayOfWeek(date, 'en-US');\n}\n\n// ───────── 日历系统与周 ─────────\n\nconst GREGORIAN = new GregorianCalendar();\n\n/**\n * 语言里的日历标识 → 运算用的日历;@internationalized/date 不支持的(如农历 'chinese')退回公历,\n * 月份网格仍按公历排,显示的文字照常由 Intl 按该日历格式化\n */\nexport function calendarOf(identifier: string): Calendar {\n if (identifier === 'gregory') return GREGORIAN;\n try {\n return createCalendar(identifier as CalendarIdentifier);\n } catch {\n return GREGORIAN;\n }\n}\n\nconst DAYS_OF_WEEK: readonly DayOfWeek[] = ['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'];\n\n/** 语言配置的一周第一天(0 表示周日)→ @internationalized/date 的写法;不写时按地区惯例 */\nexport function toDayOfWeek(firstDayOfWeek: number | undefined): DayOfWeek | undefined {\n return firstDayOfWeek == null ? undefined : DAYS_OF_WEEK[((firstDayOfWeek % 7) + 7) % 7];\n}\n\n/** 一周的排法:语言与一周第一天(0 表示周日,不写时按地区惯例) */\nexport interface WeekOptions {\n /** BCP 47 语言标签 */\n locale: string;\n /** 一周的第一天,0 表示周日;不写时按地区惯例(zh-CN 周一,en-US 周日) */\n firstDayOfWeek?: number;\n}\n\n/** monthGrid 的选项 */\nexport interface MonthGridOptions extends WeekOptions {\n /** 总是 6 行:几个月并排、或翻页时高度不跳,默认 true */\n fixedWeeks?: boolean;\n}\n\n/** 一个月的日期网格:按周分行,首尾用上个月、下个月的日期补齐(同 React Aria 的 getDatesInWeek) */\nexport function monthGrid(\n month: CalendarDate,\n { locale, firstDayOfWeek, fixedWeeks = true }: MonthGridOptions,\n): CalendarDate[][] {\n const first = startOfWeek(startOfMonth(month), locale, toDayOfWeek(firstDayOfWeek));\n const last = endOfMonth(month);\n const weeks: CalendarDate[][] = [];\n for (let start = first; weeks.length < 6; start = start.add({ weeks: 1 })) {\n if (!fixedWeeks && start.compare(last) > 0) break;\n weeks.push(Array.from({ length: 7 }, (_, index) => start.add({ days: index })));\n }\n return weeks;\n}\n\n/** 星期名的长短 */\nexport interface WeekdayFormats {\n /** 最短:一、二 / S、M */\n narrow: unknown;\n /** 简写:周一 / Mon */\n short: unknown;\n /** 全称:星期一 / Monday */\n long: unknown;\n}\n\n/** 按一周的排法列出七天的星期名(取自 Intl),从一周第一天开始 */\nexport function weekdayNames(\n locale: string,\n {\n firstDayOfWeek,\n format = 'short',\n }: { firstDayOfWeek?: number; format?: keyof WeekdayFormats } = {},\n): string[] {\n const formatter = cachedFormatter(locale, { weekday: format, timeZone: 'UTC' });\n // 任取一周:从这周的第一天起连续七天\n const start = startOfWeek(new CalendarDate(2024, 1, 10), locale, toDayOfWeek(firstDayOfWeek));\n return Array.from({ length: 7 }, (_, index) =>\n formatter.format(start.add({ days: index }).toDate('UTC')),\n );\n}\n\n/** 一年的各月(每月 1 日),按日期所在的日历系统(个别日历一年有 13 个月) */\nexport function monthsOfYear(date: CalendarDate): CalendarDate[] {\n const first = date.set({ month: 1, day: 1 });\n return Array.from({ length: date.calendar.getMonthsInYear(first) }, (_, index) =>\n first.add({ months: index }),\n );\n}\n\n/** 年份视图的一页:所在的十年,前后各补一年(共 12 年,排成 4 × 3;同 Ant Design 的年份面板) */\nexport function yearsOfDecade(date: CalendarDate): CalendarDate[] {\n const start = date.set({ year: Math.floor(date.year / 10) * 10, month: 1, day: 1 });\n return Array.from({ length: 12 }, (_, index) => start.add({ years: index - 1 }));\n}\n\n/** 是不是十年之外、补上的那两年 */\nexport const isOutsideDecade = (year: CalendarDate, page: CalendarDate) =>\n Math.floor(year.year / 10) !== Math.floor(page.year / 10);\n\n/**\n * 一年里的第几周:一周从周一开始时按 ISO 8601(含 1 月 4 日的那周是第 1 周),\n * 其他(周日、周六开始)按含 1 月 1 日的那周是第 1 周(美国、日本的惯例)\n */\nexport function weekOfYear(date: CalendarDate, options: WeekOptions): number {\n const gregorian = toCalendar(date, GREGORIAN);\n const monday =\n getDayOfWeek(\n new CalendarDate(2024, 1, 1),\n options.locale,\n toDayOfWeek(options.firstDayOfWeek),\n ) === 0;\n const weekStart = startOfWeek(gregorian, options.locale, toDayOfWeek(options.firstDayOfWeek));\n // 一周归属的年份:ISO 按这周的周四,其他按这周的最后一天(含 1 月 1 日的周就算新年的第 1 周)\n const anchor = weekStart.add({ days: monday ? 3 : 6 });\n const firstAnchor = new CalendarDate(anchor.year, 1, monday ? 4 : 1);\n const firstWeek = startOfWeek(firstAnchor, options.locale, toDayOfWeek(options.firstDayOfWeek));\n return Math.round(weekStart.compare(firstWeek) / 7) + 1;\n}\n\n// ───────── 比较、范围与不可选 ─────────\n\n/** 比较的粒度:日历的三种视图 */\nexport interface DateUnits {\n /** 天 */\n day: unknown;\n /** 月 */\n month: unknown;\n /** 年 */\n year: unknown;\n}\n\n/** 日期的粒度 */\nexport type DateUnit = keyof DateUnits;\n\n/** 截到粒度:月取 1 日,年取 1 月 1 日 */\nexport function truncateDate(date: CalendarDate, unit: DateUnit): CalendarDate {\n if (unit === 'day') return date;\n return unit === 'month' ? date.set({ day: 1 }) : date.set({ month: 1, day: 1 });\n}\n\n/** 按粒度比较:小于 0 表示 a 在前;跨日历系统时按同一天比较 */\nexport function compareDates(a: CalendarDate, b: CalendarDate, unit: DateUnit = 'day'): number {\n const other = toCalendar(b, a.calendar);\n return truncateDate(a, unit).compare(truncateDate(other, unit));\n}\n\n/** 是不是同一天 / 同一月 / 同一年;任一方为空时为 false */\nexport function isSameDate(\n a: CalendarDate | null | undefined,\n b: CalendarDate | null | undefined,\n unit: DateUnit = 'day',\n): boolean {\n return a != null && b != null && compareDates(a, b, unit) === 0;\n}\n\n/** 可选范围与不可选的日期:Calendar、DatePicker、DateField 共用 */\nexport interface DateLimits {\n /** 最早可选的日期 */\n min?: CalendarDate | null;\n /** 最晚可选的日期 */\n max?: CalendarDate | null;\n /** 不可选的日期(已订满、节假日):仍能用方向键经过,读屏能听到,不能选 */\n isUnavailable?: (date: CalendarDate) => boolean;\n}\n\n/** 在 min–max 之外(按粒度:月份视图里只要这个月有一天可选就不算在外面) */\nexport function isOutOfRange(\n date: CalendarDate,\n { min, max }: DateLimits,\n unit: DateUnit = 'day',\n): boolean {\n return (\n (min != null && compareDates(date, min, unit) < 0) ||\n (max != null && compareDates(date, max, unit) > 0)\n );\n}\n\n/** 不能选:在范围外,或是不可选的日期(只在天的粒度上判断 isUnavailable) */\nexport function isDateDisabled(\n date: CalendarDate,\n limits: DateLimits,\n unit: DateUnit = 'day',\n): boolean {\n return (\n isOutOfRange(date, limits, unit) || (unit === 'day' && (limits.isUnavailable?.(date) ?? false))\n );\n}\n\n/** 把日期夹到 min–max 之间 */\nexport function clampDate(date: CalendarDate, { min, max }: DateLimits): CalendarDate {\n if (min != null && date.compare(toCalendar(min, date.calendar)) < 0)\n return toCalendar(min, date.calendar);\n if (max != null && date.compare(toCalendar(max, date.calendar)) > 0)\n return toCalendar(max, date.calendar);\n return date;\n}\n\n/** 日期区间:两端都包含 */\nexport interface DateRange<T = CalendarDate> {\n /** 开始(含) */\n start: T;\n /** 结束(含) */\n end: T;\n}\n\n/**\n * 日期区间换成一对时刻,交给按时刻查的接口:从开始那天的零点起(含),到结束那天的第二天零点前(不含)。\n * 一天按 timeZone 算(默认浏览器的时区),所以\"10 月 27 日\"在东八区是 26 日 16:00Z 到 27 日 16:00Z。\n *\n * const { from, to } = dayRangeBounds(range); // 发成 ISO:from.toISOString()\n */\nexport function dayRangeBounds(\n range: DateRange,\n timeZone: string = getLocalTimeZone(),\n): { from: Date; to: Date } {\n return { from: range.start.toDate(timeZone), to: range.end.add({ days: 1 }).toDate(timeZone) };\n}\n\n/** 两个日期排成区间:先的在前 */\nexport function orderedRange(a: CalendarDate, b: CalendarDate): DateRange {\n return a.compare(b) <= 0 ? { start: a, end: b } : { start: b, end: a };\n}\n\n/** 日期是否在区间里(含两端;按粒度) */\nexport function isInRange(\n date: CalendarDate,\n range: DateRange | null | undefined,\n unit: DateUnit = 'day',\n): boolean {\n return (\n range != null &&\n compareDates(date, range.start, unit) >= 0 &&\n compareDates(date, range.end, unit) <= 0\n );\n}\n\n/** 区间一共几天(含两端) */\nexport function rangeDays({ start, end }: DateRange): number {\n return end.compare(start) + 1;\n}\n\n/** 区间里有没有不可选的日期:酒店连住时中间不能有订满的一天(React Aria 的 allowsNonContiguousRanges 为 false 时) */\nexport function rangeHasUnavailable(\n { start, end }: DateRange,\n isUnavailable: ((date: CalendarDate) => boolean) | undefined,\n): boolean {\n if (!isUnavailable) return false;\n for (let date = start; date.compare(end) <= 0; date = date.add({ days: 1 })) {\n if (isUnavailable(date)) return true;\n }\n return false;\n}\n\n/** ISO 字符串的区间 → CalendarDate 的区间;任一端解析不了时为 null */\nexport function parseIsoRange(range: DateRange<string> | null | undefined): DateRange | null {\n const start = parseIsoDate(range?.start);\n const end = parseIsoDate(range?.end);\n return start && end ? orderedRange(start, end) : null;\n}\n\n/** CalendarDate 的区间 → ISO 字符串的区间 */\nexport function toIsoRange(range: DateRange): DateRange<string> {\n return { start: toIsoDate(range.start), end: toIsoDate(range.end) };\n}\n\n// ───────── 快捷区间 ─────────\n\n/** 常用的快捷区间:报表、筛选里的“最近 7 天”“本月” */\nexport interface DateRangePresets {\n /** 今天 */\n today: unknown;\n /** 昨天 */\n yesterday: unknown;\n /** 最近 7 天(含今天) */\n last7Days: unknown;\n /** 最近 30 天(含今天) */\n last30Days: unknown;\n /** 本周(按语言的一周第一天) */\n thisWeek: unknown;\n /** 本月 */\n thisMonth: unknown;\n /** 上月 */\n lastMonth: unknown;\n /** 今年 */\n thisYear: unknown;\n}\n\n/** 快捷区间的名字 */\nexport type DateRangePreset = keyof DateRangePresets;\n\n/** 按今天算出快捷区间 */\nexport function presetRange(\n preset: DateRangePreset,\n today: CalendarDate,\n week: WeekOptions,\n): DateRange {\n switch (preset) {\n case 'today':\n return { start: today, end: today };\n case 'yesterday': {\n const day = today.subtract({ days: 1 });\n return { start: day, end: day };\n }\n case 'last7Days':\n return { start: today.subtract({ days: 6 }), end: today };\n case 'last30Days':\n return { start: today.subtract({ days: 29 }), end: today };\n case 'thisWeek': {\n const start = startOfWeek(today, week.locale, toDayOfWeek(week.firstDayOfWeek));\n return { start, end: start.add({ days: 6 }) };\n }\n case 'thisMonth':\n return { start: startOfMonth(today), end: endOfMonth(today) };\n case 'lastMonth': {\n const month = startOfMonth(today).subtract({ months: 1 });\n return { start: month, end: endOfMonth(month) };\n }\n case 'thisYear':\n return { start: today.set({ month: 1, day: 1 }), end: today.set({ month: 12, day: 31 }) };\n }\n}\n\n/** 快捷区间的 ISO 值,按今天(时区,不写时取浏览器的)与一周的排法:`presetIsoRange('last7Days', { locale: 'zh-CN' })` */\nexport function presetIsoRange(\n preset: DateRangePreset,\n week: WeekOptions,\n timeZone = getLocalTimeZone(),\n): DateRange<string> {\n return toIsoRange(presetRange(preset, today(timeZone), week));\n}\n\n// ───────── 时刻与相对时间 ─────────\n\n/** 带时区或 UTC 标记的 ISO 字符串('2026-10-20T14:30:00Z'、'…+08:00'):本身就是一个时刻 */\nconst ABSOLUTE_ISO = /(?:[zZ]|[+-]\\d\\d:?\\d\\d)$/;\n\n/**\n * 日期值 → 时刻(毫秒时间戳):Date 与带时区的值照原样;不带时区的('2026-10-20T14:30'、CalendarDateTime)\n * 按 timeZone 的墙上时间算。格式不对时 NaN\n */\nexport function toInstant(value: Date | DateValue | string, timeZone = getLocalTimeZone()): number {\n if (value instanceof Date) return value.getTime();\n if (typeof value !== 'string') {\n return ('timeZone' in value ? value.toDate() : value.toDate(timeZone)).getTime();\n }\n if (ABSOLUTE_ISO.test(value)) return Date.parse(value);\n const parsed = parseIsoDateTime(value) ?? parseIsoDate(value);\n return parsed ? parsed.toDate(timeZone).getTime() : Number.NaN;\n}\n\n/** 相对时间用的单位:多久以内用这个单位(秒),参考 moment.js 的取整阈值 */\nconst RELATIVE_UNITS: readonly [Intl.RelativeTimeFormatUnit, number, number][] = [\n // [单位, 一个单位多少秒, 小于多少秒时用它]\n ['second', 1, 45],\n ['minute', 60, 45 * 60],\n ['hour', 3600, 22 * 3600],\n ['day', 86_400, 26 * 86_400],\n ['month', 30 * 86_400, 320 * 86_400],\n ['year', 365 * 86_400, Infinity],\n];\n\n/** 相差的毫秒数 → 相对时间的数值与单位:`relativeUnit(-180_000)` → `{ value: -3, unit: 'minute' }` */\nexport function relativeUnit(diff: number): { value: number; unit: Intl.RelativeTimeFormatUnit } {\n const seconds = diff / 1000;\n const [unit, size] = RELATIVE_UNITS.find(([, , below]) => Math.abs(seconds) < below)!;\n // -0 换成 0:Intl 的 numeric: auto 才念“现在”\n return { value: Math.round(seconds / size) || 0, unit };\n}\n\n// ───────── 内部实现 ─────────\n\nfunction tryParse<T>(value: string | null | undefined, parse: (text: string) => T): T | null {\n if (!value) return null;\n try {\n return parse(value);\n } catch {\n return null;\n }\n}\n\nconst formatters = new Map<string, DateFormatter>();\n\nfunction cachedFormatter(locale: string, options: Intl.DateTimeFormatOptions): DateFormatter {\n const key = `${locale}|${JSON.stringify(options)}`;\n let formatter = formatters.get(key);\n if (!formatter) formatters.set(key, (formatter = new DateFormatter(locale, options)));\n return formatter;\n}\n"],"mappings":"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"}