v-nuxt-ui 0.2.24 → 0.2.26

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 (88) hide show
  1. package/README.md +6 -0
  2. package/dist/module.json +1 -1
  3. package/dist/runtime/components/AsyncSelect.vue +16 -1
  4. package/dist/runtime/components/AsyncTreeSelect.vue +15 -9
  5. package/dist/runtime/components/DeleteModal.d.vue.ts +25 -22
  6. package/dist/runtime/components/DeleteModal.vue +39 -4
  7. package/dist/runtime/components/DeleteModal.vue.d.ts +25 -22
  8. package/dist/runtime/components/ScrollArea.vue +20 -9
  9. package/dist/runtime/components/form/field/AsyncObjectSelect.vue +14 -3
  10. package/dist/runtime/components/form/save-model-template/ConfirmUpdateModal.d.vue.ts +19 -0
  11. package/dist/runtime/components/form/save-model-template/ConfirmUpdateModal.vue +111 -0
  12. package/dist/runtime/components/form/save-model-template/ConfirmUpdateModal.vue.d.ts +19 -0
  13. package/dist/runtime/components/form/{create-modal-template → save-model-template}/WithApi.d.vue.ts +2 -2
  14. package/dist/runtime/components/form/{create-modal-template → save-model-template}/WithApi.vue +4 -3
  15. package/dist/runtime/components/form/{create-modal-template → save-model-template}/WithApi.vue.d.ts +2 -2
  16. package/dist/runtime/components/form/{create-modal-template → save-model-template}/index.d.vue.ts +2 -2
  17. package/dist/runtime/components/form/{create-modal-template → save-model-template}/index.vue +54 -7
  18. package/dist/runtime/components/form/{create-modal-template → save-model-template}/index.vue.d.ts +2 -2
  19. package/dist/runtime/components/layout/button/UserMenu.vue +1 -2
  20. package/dist/runtime/components/sys/company/{CreateModal.vue → SaveModal.vue} +2 -2
  21. package/dist/runtime/components/sys/company/Table.vue +5 -4
  22. package/dist/runtime/components/sys/department/{CreateModal.vue → SaveModal.vue} +3 -2
  23. package/dist/runtime/components/sys/department/Table.vue +6 -5
  24. package/dist/runtime/components/sys/flow/EditNodeModal.vue +4 -3
  25. package/dist/runtime/components/sys/flow/{CreateModal.vue → SaveModal.vue} +3 -2
  26. package/dist/runtime/components/sys/flow/Table.vue +5 -4
  27. package/dist/runtime/components/sys/issue-record/{CreateModal.vue → SaveModal.vue} +2 -2
  28. package/dist/runtime/components/sys/issue-record/Table.vue +5 -4
  29. package/dist/runtime/components/sys/job-title/{CreateModal.vue → SaveModal.vue} +2 -2
  30. package/dist/runtime/components/sys/job-title/Table.vue +5 -4
  31. package/dist/runtime/components/sys/menu/{CreateModal.vue → SaveModal.vue} +3 -2
  32. package/dist/runtime/components/sys/menu/Table.vue +6 -5
  33. package/dist/runtime/components/sys/role/{CreateModal.vue → SaveModal.vue} +8 -5
  34. package/dist/runtime/components/sys/role/Table.vue +5 -4
  35. package/dist/runtime/components/sys/table/{CreateModal.vue → SaveModal.vue} +4 -3
  36. package/dist/runtime/components/sys/table/Table.vue +4 -4
  37. package/dist/runtime/components/sys/table/TableColumnModal.vue +4 -3
  38. package/dist/runtime/components/sys/user/{CreateModal.vue → SaveModal.vue} +4 -3
  39. package/dist/runtime/components/sys/user/Table.vue +7 -6
  40. package/dist/runtime/components/table/Page.vue +2 -1
  41. package/dist/runtime/components/table/UpdateDiffModal.d.vue.ts +14 -0
  42. package/dist/runtime/components/table/UpdateDiffModal.vue +156 -0
  43. package/dist/runtime/components/table/UpdateDiffModal.vue.d.ts +14 -0
  44. package/dist/runtime/components/table/header/index.vue +181 -183
  45. package/dist/runtime/components/table/index.vue +2 -1
  46. package/dist/runtime/composables/form/index.d.ts +2 -0
  47. package/dist/runtime/composables/form/index.js +2 -0
  48. package/dist/runtime/composables/form/useForm.d.ts +21 -0
  49. package/dist/runtime/composables/{useForm.js → form/useForm.js} +23 -1
  50. package/dist/runtime/composables/form/useFormUpdate.d.ts +6 -0
  51. package/dist/runtime/composables/form/useFormUpdate.js +101 -0
  52. package/dist/runtime/composables/index.d.ts +1 -1
  53. package/dist/runtime/composables/index.js +1 -1
  54. package/dist/runtime/composables/table/useTable.js +10 -1
  55. package/dist/runtime/composables/table/useTableRowActions.d.ts +3 -0
  56. package/dist/runtime/composables/table/useTableRowActions.js +24 -0
  57. package/dist/runtime/composables/useDate.js +2 -0
  58. package/dist/runtime/types/components/form/field.d.ts +2 -0
  59. package/dist/runtime/types/components/form/index.d.ts +4 -3
  60. package/dist/runtime/types/components/table/header.d.ts +2 -0
  61. package/dist/runtime/types/components/table/index.d.ts +1 -0
  62. package/dist/runtime/types/time.d.ts +1 -1
  63. package/dist/runtime/utils/cron.d.ts +1 -0
  64. package/dist/runtime/utils/cron.js +182 -0
  65. package/dist/runtime/utils/index.d.ts +1 -0
  66. package/dist/runtime/utils/index.js +1 -0
  67. package/dist/runtime/utils/vueuse.d.ts +1 -1
  68. package/dist/runtime/utils/vueuse.js +1 -0
  69. package/package.json +16 -15
  70. package/dist/runtime/composables/useForm.d.ts +0 -9
  71. /package/dist/runtime/components/sys/company/{CreateModal.d.vue.ts → SaveModal.d.vue.ts} +0 -0
  72. /package/dist/runtime/components/sys/company/{CreateModal.vue.d.ts → SaveModal.vue.d.ts} +0 -0
  73. /package/dist/runtime/components/sys/department/{CreateModal.d.vue.ts → SaveModal.d.vue.ts} +0 -0
  74. /package/dist/runtime/components/sys/department/{CreateModal.vue.d.ts → SaveModal.vue.d.ts} +0 -0
  75. /package/dist/runtime/components/sys/flow/{CreateModal.d.vue.ts → SaveModal.d.vue.ts} +0 -0
  76. /package/dist/runtime/components/sys/flow/{CreateModal.vue.d.ts → SaveModal.vue.d.ts} +0 -0
  77. /package/dist/runtime/components/sys/issue-record/{CreateModal.d.vue.ts → SaveModal.d.vue.ts} +0 -0
  78. /package/dist/runtime/components/sys/issue-record/{CreateModal.vue.d.ts → SaveModal.vue.d.ts} +0 -0
  79. /package/dist/runtime/components/sys/job-title/{CreateModal.d.vue.ts → SaveModal.d.vue.ts} +0 -0
  80. /package/dist/runtime/components/sys/job-title/{CreateModal.vue.d.ts → SaveModal.vue.d.ts} +0 -0
  81. /package/dist/runtime/components/sys/menu/{CreateModal.d.vue.ts → SaveModal.d.vue.ts} +0 -0
  82. /package/dist/runtime/components/sys/menu/{CreateModal.vue.d.ts → SaveModal.vue.d.ts} +0 -0
  83. /package/dist/runtime/components/sys/role/{CreateModal.d.vue.ts → SaveModal.d.vue.ts} +0 -0
  84. /package/dist/runtime/components/sys/role/{CreateModal.vue.d.ts → SaveModal.vue.d.ts} +0 -0
  85. /package/dist/runtime/components/sys/table/{CreateModal.d.vue.ts → SaveModal.d.vue.ts} +0 -0
  86. /package/dist/runtime/components/sys/table/{CreateModal.vue.d.ts → SaveModal.vue.d.ts} +0 -0
  87. /package/dist/runtime/components/sys/user/{CreateModal.d.vue.ts → SaveModal.d.vue.ts} +0 -0
  88. /package/dist/runtime/components/sys/user/{CreateModal.vue.d.ts → SaveModal.vue.d.ts} +0 -0
@@ -0,0 +1,21 @@
1
+ import { type Ref, type MaybeRefOrGetter } from 'vue';
2
+ import type { ApiGroup, BaseModel, VFormFieldProps } from '#v/types';
3
+ import type { ConfirmDiffItem } from '#v/components/form/save-model-template/ConfirmUpdateModal.vue';
4
+ export declare const useFormValues: <T>(raw: Ref<T>, defaultValues?: Partial<T>) => {
5
+ oldValues: Ref<T>;
6
+ newValues: Ref<T>;
7
+ };
8
+ export declare const useFormSubmission: <T extends BaseModel>(oldValues: Ref<T>, newValues: Ref<T>, close: (ok: boolean) => void, save: (model: T) => void, apiGroup: () => ApiGroup<T>, arrayTypeFieldKeys?: (keyof T)[], rowKey?: keyof T, versionKey?: keyof T, getExtraFields?: () => Record<string, any>) => {
9
+ onSubmit: () => Promise<void>;
10
+ };
11
+ export declare const useConfirmDiff: (fields: MaybeRefOrGetter<VFormFieldProps[]>, diffItems: MaybeRefOrGetter<ConfirmDiffItem[]>, oldModelValue: MaybeRefOrGetter<Record<string, unknown>>, newModelValue: MaybeRefOrGetter<Record<string, unknown>>) => {
12
+ diffedItems: import("vue").ComputedRef<{
13
+ oldDisplay: string;
14
+ newDisplay: string;
15
+ parts: import("diff").ChangeObject<string>[];
16
+ field: VFormFieldProps | undefined;
17
+ fieldName: string;
18
+ oldValue: unknown;
19
+ newValue: unknown;
20
+ }[]>;
21
+ };
@@ -1,6 +1,7 @@
1
- import { ref, watch } from "vue";
1
+ import { ref, watch, computed, toValue } from "vue";
2
2
  import { defu } from "defu";
3
3
  import { getObjWithModifiedFields } from "#v/utils";
4
+ import { resolveDisplayValue, smartDiff } from "#v/composables";
4
5
  import { useToast } from "@nuxt/ui/composables";
5
6
  export const useFormValues = (raw, defaultValues) => {
6
7
  const oldValues = ref({});
@@ -62,3 +63,24 @@ export const useFormSubmission = (oldValues, newValues, close, save, apiGroup, a
62
63
  }
63
64
  return { onSubmit };
64
65
  };
66
+ export const useConfirmDiff = (fields, diffItems, oldModelValue, newModelValue) => {
67
+ const resolvedItems = computed(
68
+ () => toValue(diffItems).map((item) => ({
69
+ ...item,
70
+ field: toValue(fields).find((f) => f.name === item.fieldName)
71
+ })).filter((item) => item.field != null)
72
+ );
73
+ const diffedItems = computed(
74
+ () => resolvedItems.value.map((item) => {
75
+ const oldDisplay = resolveDisplayValue(item.field, item.oldValue, toValue(oldModelValue));
76
+ const newDisplay = resolveDisplayValue(item.field, item.newValue, toValue(newModelValue));
77
+ return {
78
+ ...item,
79
+ oldDisplay,
80
+ newDisplay,
81
+ parts: smartDiff(oldDisplay, newDisplay)
82
+ };
83
+ })
84
+ );
85
+ return { diffedItems };
86
+ };
@@ -0,0 +1,6 @@
1
+ import type { VFormFieldProps } from '#v/types';
2
+ export declare function resolveSelectLabel(rawVal: unknown, items: readonly any[]): string;
3
+ export declare function resolveDisplayValue(field: VFormFieldProps, rawVal: unknown, modelSource: Record<string, unknown>): string;
4
+ export declare function smartDiff(oldStr: string, newStr: string): import("diff").ChangeObject<string>[];
5
+ export declare const diffEligibleTypes: Set<string>;
6
+ export declare function formatValue(val: unknown): string;
@@ -0,0 +1,101 @@
1
+ import dayjs from "dayjs";
2
+ import { diffWords, diffChars } from "diff";
3
+ import { dateFormat } from "#v/constants";
4
+ export function resolveSelectLabel(rawVal, items) {
5
+ if (Array.isArray(rawVal)) {
6
+ return rawVal.map((v) => items.find((i) => i?.value === v)?.label ?? String(v)).join(", ") || "";
7
+ }
8
+ return items.find((i) => i?.value === rawVal)?.label ?? String(rawVal);
9
+ }
10
+ export function resolveDisplayValue(field, rawVal, modelSource) {
11
+ if (rawVal === null || rawVal === void 0) return "";
12
+ switch (field.type) {
13
+ case "switch":
14
+ case "button-switch":
15
+ return rawVal ? "\u662F" : "\u5426";
16
+ case "date-picker": {
17
+ if (typeof rawVal === "string") {
18
+ const d = dayjs(rawVal);
19
+ if (d.isValid()) return d.format(dateFormat);
20
+ }
21
+ return String(rawVal);
22
+ }
23
+ case "select": {
24
+ const items = field.enableEmptyOption ? [{ label: "\u65E0", value: 0 }, ...field.items ?? []] : field.items ?? [];
25
+ return resolveSelectLabel(rawVal, items);
26
+ }
27
+ case "multiple-select-string":
28
+ case "radio-select":
29
+ return resolveSelectLabel(rawVal, field.items ?? []);
30
+ case "async-select":
31
+ case "async-tree-select":
32
+ case "async-object-select": {
33
+ if (!field.name) return String(rawVal);
34
+ if (rawVal === 0) return "";
35
+ const labelField = field.labelField;
36
+ if (!labelField) return String(rawVal);
37
+ let model;
38
+ for (const v of Object.values(modelSource)) {
39
+ if (v && typeof v === "object" && v[labelField] !== void 0) {
40
+ if (String(v.id) === String(rawVal)) {
41
+ model = v;
42
+ break;
43
+ }
44
+ }
45
+ }
46
+ if (!model) {
47
+ model = field.initModel;
48
+ }
49
+ if (!model) return String(rawVal);
50
+ if (Array.isArray(model)) {
51
+ return model.map((m) => m && typeof m === "object" ? String(m[labelField] ?? "") : String(m)).filter(Boolean).join(", ") || "";
52
+ }
53
+ if (typeof model === "object") {
54
+ const label = model[labelField];
55
+ if (label != null) return String(label);
56
+ }
57
+ return String(rawVal);
58
+ }
59
+ case "input-string-number": {
60
+ const v = rawVal === 0 ? "0" : String(rawVal);
61
+ const trailing = field.trailingString;
62
+ return trailing ? `${v} ${trailing}` : v;
63
+ }
64
+ case "tree-select-transfer": {
65
+ if (Array.isArray(rawVal)) {
66
+ return rawVal.map((item) => {
67
+ if (item && typeof item === "object") {
68
+ const obj = item;
69
+ return String(obj.label ?? obj.name ?? "");
70
+ }
71
+ return String(item);
72
+ }).filter(Boolean).join(", ") || "";
73
+ }
74
+ return formatValue(rawVal);
75
+ }
76
+ default:
77
+ return formatValue(rawVal);
78
+ }
79
+ }
80
+ export function smartDiff(oldStr, newStr) {
81
+ if (!oldStr.includes(" ") && !newStr.includes(" ")) {
82
+ return diffChars(oldStr, newStr);
83
+ }
84
+ return diffWords(oldStr, newStr);
85
+ }
86
+ export const diffEligibleTypes = /* @__PURE__ */ new Set([
87
+ "input",
88
+ "dynamic-input",
89
+ "input-string-number",
90
+ "input-number",
91
+ "textarea",
92
+ "input-pwd",
93
+ "sql-editor",
94
+ "date-picker"
95
+ ]);
96
+ export function formatValue(val) {
97
+ if (val === null || val === void 0) return "";
98
+ if (typeof val === "boolean") return val ? "\u662F" : "\u5426";
99
+ if (typeof val === "object") return JSON.stringify(val);
100
+ return String(val);
101
+ }
@@ -5,7 +5,7 @@ export * from './useApp.js';
5
5
  export * from './useBoolean.js';
6
6
  export * from './useDate.js';
7
7
  export * from './useEChart.js';
8
- export * from './useForm.js';
8
+ export * from './form/index.js';
9
9
  export * from './useTheme.js';
10
10
  export * from './useSidebarMenu.js';
11
11
  export * from './usePermission.js';
@@ -5,7 +5,7 @@ export * from "./useApp.js";
5
5
  export * from "./useBoolean.js";
6
6
  export * from "./useDate.js";
7
7
  export * from "./useEChart.js";
8
- export * from "./useForm.js";
8
+ export * from "./form/index.js";
9
9
  export * from "./useTheme.js";
10
10
  export * from "./useSidebarMenu.js";
11
11
  export * from "./usePermission.js";
@@ -44,7 +44,8 @@ export function useTable(props) {
44
44
  disableRowSelection,
45
45
  expandable,
46
46
  rowSpanColumns,
47
- customRowCopyFn
47
+ customRowCopyFn,
48
+ displayFnInDeleteModal
48
49
  } = props;
49
50
  const queryComposable = useTableQuery({
50
51
  name,
@@ -96,6 +97,9 @@ export function useTable(props) {
96
97
  } = dataComposable;
97
98
  const rowSelectionComposable = useTableRowSelection(data, rowKey);
98
99
  const { rowSelection, selectedIds, clearRowSelection: _clearRowSelection } = rowSelectionComposable;
100
+ const selectedModels = computed(
101
+ () => data.value.filter((row) => selectedIds.value.includes(row[rowKey]))
102
+ );
99
103
  const whereQueryRef = useTemplateRef("proTableQueryWhere");
100
104
  const onFilterClick = (field) => {
101
105
  whereQueryOpen.value = true;
@@ -149,6 +153,8 @@ export function useTable(props) {
149
153
  } = columnsComposable;
150
154
  const rowActionsComposable = useTableRowActions({
151
155
  rowKey,
156
+ tableName: name,
157
+ bizColumns,
152
158
  disableRowActions,
153
159
  disableRowUpdate,
154
160
  disableRowCopy,
@@ -157,6 +163,7 @@ export function useTable(props) {
157
163
  extraRowActions,
158
164
  useApiGroup,
159
165
  customRowCopyFn,
166
+ displayFnInDeleteModal,
160
167
  fetchList
161
168
  });
162
169
  const { getRowActions, generateActionColumn } = rowActionsComposable;
@@ -287,6 +294,8 @@ export function useTable(props) {
287
294
  fetchList,
288
295
  onEditRowFromModal,
289
296
  selectedIds: selectedIds.value,
297
+ selectedModels: selectedModels.value,
298
+ displayFnInDeleteModal,
290
299
  disableCreation,
291
300
  disableWhereQuery,
292
301
  whereQueryProps: tblWhereQueryProps.value,
@@ -2,6 +2,8 @@ import type { VColumn } from '#v/types';
2
2
  import type { DropdownMenuItem, TableRow } from '@nuxt/ui';
3
3
  export declare function useTableRowActions<T>(props: {
4
4
  rowKey: keyof T;
5
+ tableName?: string;
6
+ bizColumns?: VColumn<T>[];
5
7
  disableRowActions?: boolean;
6
8
  disableRowUpdate?: boolean;
7
9
  disableRowCopy?: boolean;
@@ -10,6 +12,7 @@ export declare function useTableRowActions<T>(props: {
10
12
  extraRowActions?: any[];
11
13
  useApiGroup?: (...args: any[]) => any;
12
14
  customRowCopyFn?: (...args: any[]) => any;
15
+ displayFnInDeleteModal?: (model: T) => string | undefined;
13
16
  fetchList: () => Promise<void>;
14
17
  }): {
15
18
  getRowActions: (row: TableRow<T>) => DropdownMenuItem[];
@@ -1,11 +1,14 @@
1
1
  import { ref, h } from "vue";
2
2
  import { useOverlay } from "@nuxt/ui/composables";
3
3
  import DeleteModal from "#v/components/DeleteModal.vue";
4
+ import UpdateDiffModal from "#v/components/table/UpdateDiffModal.vue";
4
5
  import UDropdownMenu from "@nuxt/ui/components/DropdownMenu.vue";
5
6
  import UButton from "@nuxt/ui/components/Button.vue";
6
7
  export function useTableRowActions(props) {
7
8
  const {
8
9
  rowKey,
10
+ tableName,
11
+ bizColumns,
9
12
  disableRowActions: _disableRowActions,
10
13
  disableRowUpdate,
11
14
  disableRowCopy,
@@ -14,10 +17,12 @@ export function useTableRowActions(props) {
14
17
  extraRowActions,
15
18
  useApiGroup,
16
19
  customRowCopyFn,
20
+ displayFnInDeleteModal,
17
21
  fetchList
18
22
  } = props;
19
23
  const overlay = useOverlay();
20
24
  const deleteModal = overlay.create(DeleteModal);
25
+ const updateDiffModal = overlay.create(UpdateDiffModal);
21
26
  const apiGroup = useApiGroup?.();
22
27
  const actionLoadingRowIdxSet = ref(/* @__PURE__ */ new Set());
23
28
  function getRowActions(row) {
@@ -89,6 +94,23 @@ export function useTableRowActions(props) {
89
94
  extraRowActions?.forEach((action) => {
90
95
  actionItems.push(buildActionItem(action));
91
96
  });
97
+ if (tableName) {
98
+ if (actionItems.length > 0 && !disableRowDeletion) {
99
+ actionItems.push({ type: "separator" });
100
+ }
101
+ actionItems.push({
102
+ label: "\u53D8\u66F4\u8BB0\u5F55",
103
+ icon: "i-lucide-history",
104
+ onClick: () => {
105
+ updateDiffModal.open({
106
+ tableName,
107
+ rowId: row.original[rowKey],
108
+ columns: bizColumns || [],
109
+ title: "\u53D8\u66F4\u8BB0\u5F55"
110
+ });
111
+ }
112
+ });
113
+ }
92
114
  if (!disableRowDeletion) {
93
115
  if (actionItems.length > 0) {
94
116
  actionItems.push({ type: "separator" });
@@ -100,6 +122,8 @@ export function useTableRowActions(props) {
100
122
  onSelect: async () => {
101
123
  const result = await deleteModal.open({
102
124
  ids: [row.original[rowKey]],
125
+ models: [row.original],
126
+ displayFn: displayFnInDeleteModal,
103
127
  onDelete: (ids) => apiGroup?.batchDelete({ ids })
104
128
  }).result;
105
129
  if (result) {
@@ -40,6 +40,8 @@ const _useDate = () => {
40
40
  }
41
41
  case "day":
42
42
  return date.format("YYYY-MM-DD");
43
+ case "time":
44
+ return date.format("YYYY-MM-DD HH:mm:ss");
43
45
  default:
44
46
  throw new Error(`Unsupported time unit: ${unit}`);
45
47
  }
@@ -33,6 +33,8 @@ export type VFormFieldProps = FormFieldProps & {
33
33
  placeholder?: string;
34
34
  annotation?: string;
35
35
  enterKeydownSubmit?: boolean;
36
+ /** 在确认修改弹窗中是否使用逐词 diff 高亮 */
37
+ diffable?: boolean;
36
38
  } & ({
37
39
  type: 'separator';
38
40
  separatorLabel?: string;
@@ -8,20 +8,21 @@ export type FormTemplateProps<T> = {
8
8
  onUpdateModelValue?: (newVal: Partial<T>) => void;
9
9
  onTriggerSubmit?: (e: Event) => void;
10
10
  };
11
- export type CreateModalFormTemplateProps<T> = {
11
+ export type SaveModalFormTemplateProps<T> = {
12
12
  title: string;
13
13
  description?: string;
14
14
  onClose: (ok: boolean) => void;
15
15
  onSubmit: () => Promise<void>;
16
16
  fields: VFormFieldProps[];
17
+ oldModelValue: Partial<T>;
17
18
  modelValue: Partial<T>;
18
19
  onUpdateModelValue?: (newVal: Partial<T>) => void;
19
20
  rowKey?: keyof T;
20
21
  fullscreen?: ModalProps['fullscreen'];
21
22
  };
22
- export type CreateModalFormTemplatePropsWithApi<T> = {
23
+ export type SaveModalFormTemplatePropsWithApi<T> = {
23
24
  apiGroup: () => ApiGroup<T>;
24
25
  valuePruneFn?: (value: T) => T;
25
26
  defaultModelValue?: Partial<T>;
26
27
  onSave: (model: T) => void;
27
- } & Pick<CreateModalFormTemplateProps<T>, 'title' | 'description' | 'fields' | 'onClose' | 'modelValue' | 'onUpdateModelValue'>;
28
+ } & Pick<SaveModalFormTemplateProps<T>, 'title' | 'description' | 'fields' | 'onClose' | 'modelValue' | 'onUpdateModelValue'>;
@@ -13,6 +13,8 @@ export type TableHeaderProps<T> = {
13
13
  fetchList: () => Promise<void>;
14
14
  onEditRowFromModal?: (row: T) => Promise<boolean>;
15
15
  selectedIds?: number[];
16
+ selectedModels?: T[];
17
+ displayFnInDeleteModal?: (model: T) => string | undefined;
16
18
  disableCreation?: boolean;
17
19
  disableWhereQuery?: boolean;
18
20
  whereQueryProps: WhereQueryProps<T>;
@@ -102,4 +102,5 @@ export type VTableProps<T> = {
102
102
  expandVNode?: (row: T) => VNode;
103
103
  rowSpanColumns?: (keyof T)[];
104
104
  customRowCopyFn?: (model: T) => T;
105
+ displayFnInDeleteModal?: (model: T) => string | undefined;
105
106
  };
@@ -1,4 +1,4 @@
1
- export type TimeUnit = 'day' | 'week' | 'month' | 'quarter' | 'year';
1
+ export type TimeUnit = 'day' | 'week' | 'month' | 'quarter' | 'year' | 'time';
2
2
  export declare enum CalendarEventType {
3
3
  NONE = 0,
4
4
  HOLIDAY = 1,
@@ -0,0 +1 @@
1
+ export declare const cronToCn: (val: string | undefined | null, tzOffset?: number) => string | null;
@@ -0,0 +1,182 @@
1
+ const WEEKDAY_CN = ["\u65E5", "\u4E00", "\u4E8C", "\u4E09", "\u56DB", "\u4E94", "\u516D"];
2
+ function pad(v) {
3
+ return String(v).padStart(2, "0");
4
+ }
5
+ function parseFields(cron) {
6
+ const parts = cron.trim().split(/\s+/);
7
+ if (parts.length !== 5) return null;
8
+ return {
9
+ minute: parts[0],
10
+ hour: parts[1],
11
+ dayOfMonth: parts[2],
12
+ month: parts[3],
13
+ dayOfWeek: parts[4]
14
+ };
15
+ }
16
+ function validateField(val, min, max) {
17
+ if (val === "*" || val === "?") return true;
18
+ const segments = val.split(",");
19
+ for (const seg of segments) {
20
+ const stepIdx = seg.indexOf("/");
21
+ const base = stepIdx >= 0 ? seg.slice(0, stepIdx) : seg;
22
+ const step = stepIdx >= 0 ? Number(seg.slice(stepIdx + 1)) : 1;
23
+ if (step < 1) return false;
24
+ if (base === "*") continue;
25
+ const dashIdx = base.indexOf("-");
26
+ if (dashIdx >= 0) {
27
+ const lo = Number(base.slice(0, dashIdx));
28
+ const hi = Number(base.slice(dashIdx + 1));
29
+ if (isNaN(lo) || isNaN(hi)) return false;
30
+ if (lo < min || lo > max || hi < min || hi > max || lo > hi) return false;
31
+ } else {
32
+ const n = Number(base);
33
+ if (isNaN(n) || n < min || n > max) return false;
34
+ }
35
+ }
36
+ return true;
37
+ }
38
+ function validateCron(fields) {
39
+ return validateField(fields.minute, 0, 59) && validateField(fields.hour, 0, 23) && validateField(fields.dayOfMonth, 1, 31) && validateField(fields.month, 1, 12) && validateField(fields.dayOfWeek, 0, 7);
40
+ }
41
+ function isSimpleNumber(val) {
42
+ return /^\d+$/.test(val);
43
+ }
44
+ function shiftDow(val, shift) {
45
+ return val.split(",").map((v) => {
46
+ const dashIdx = v.indexOf("-");
47
+ if (dashIdx >= 0) {
48
+ const lo = Number(v.slice(0, dashIdx));
49
+ const hi = Number(v.slice(dashIdx + 1));
50
+ const loNorm = lo === 7 ? 0 : lo;
51
+ const hiNorm = hi === 7 ? 0 : hi;
52
+ return `${(loNorm + shift) % 7}-${(hiNorm + shift) % 7}`;
53
+ }
54
+ const n = v === "7" ? 0 : Number(v);
55
+ return String((n + shift) % 7);
56
+ }).join(",");
57
+ }
58
+ function shiftDom(val, shift) {
59
+ return val.split(",").map((v) => {
60
+ const dashIdx = v.indexOf("-");
61
+ if (dashIdx >= 0) {
62
+ const lo = Number(v.slice(0, dashIdx));
63
+ const hi = Number(v.slice(dashIdx + 1));
64
+ return `${lo + shift}-${hi + shift}`;
65
+ }
66
+ return String(Number(v) + shift);
67
+ }).join(",");
68
+ }
69
+ function applyTzOffset(fields, offset) {
70
+ const result = { ...fields };
71
+ if (fields.hour === "*") return result;
72
+ if (!isSimpleNumber(fields.hour)) {
73
+ return result;
74
+ }
75
+ const hour = Number(fields.hour);
76
+ const newHour = (hour + offset) % 24;
77
+ const dayShift = hour + offset >= 24 ? 1 : hour + offset < 0 ? -1 : 0;
78
+ result.hour = String(newHour);
79
+ if (dayShift > 0) {
80
+ if (fields.dayOfWeek !== "*" && fields.dayOfWeek !== "?") {
81
+ result.dayOfWeek = shiftDow(fields.dayOfWeek, dayShift);
82
+ }
83
+ if (fields.dayOfMonth !== "*" && fields.dayOfMonth !== "?" && !fields.dayOfMonth.includes("L") && !fields.dayOfMonth.includes("W")) {
84
+ result.dayOfMonth = shiftDom(fields.dayOfMonth, dayShift);
85
+ }
86
+ }
87
+ return result;
88
+ }
89
+ function isWildcard(v) {
90
+ return v === "*" || v === "?";
91
+ }
92
+ function describeMinute(minute) {
93
+ if (isWildcard(minute)) return "\u6BCF\u5206\u949F";
94
+ if (minute.startsWith("*/")) {
95
+ return `\u6BCF${minute.slice(2)}\u5206\u949F`;
96
+ }
97
+ return "";
98
+ }
99
+ function describeHour(hour) {
100
+ if (isWildcard(hour)) return "";
101
+ if (hour.includes(",")) {
102
+ return hour.split(",").map((h) => `${h}\u70B9`).join("\u3001");
103
+ }
104
+ if (hour.includes("-")) {
105
+ const [lo, hi] = hour.split("-");
106
+ return `${lo}\u70B9\u81F3${hi}\u70B9`;
107
+ }
108
+ return `${hour}\u70B9`;
109
+ }
110
+ function describeDayOfWeek(dayOfWeek) {
111
+ if (isWildcard(dayOfWeek) || dayOfWeek === "?") return "";
112
+ if (dayOfWeek.includes(",")) {
113
+ const days = dayOfWeek.split(",").map((d) => {
114
+ const n = Number(d);
115
+ return `\u5468${WEEKDAY_CN[n]}`;
116
+ }).join("\u3001");
117
+ return `\u6BCF${days}`;
118
+ }
119
+ if (dayOfWeek.includes("-")) {
120
+ const [lo, hi] = dayOfWeek.split("-");
121
+ return `\u6BCF\u5468${WEEKDAY_CN[Number(lo)]}\u81F3\u5468${WEEKDAY_CN[Number(hi)]}`;
122
+ }
123
+ return `\u6BCF\u5468${WEEKDAY_CN[Number(dayOfWeek)]}`;
124
+ }
125
+ function describeDayOfMonth(dayOfMonth) {
126
+ if (isWildcard(dayOfMonth) || dayOfMonth === "?") return "";
127
+ if (dayOfMonth.includes(",")) {
128
+ return "\u6BCF\u6708" + dayOfMonth.split(",").map((d) => `${d}\u65E5`).join("\u3001");
129
+ }
130
+ if (dayOfMonth.includes("-")) {
131
+ const [lo, hi] = dayOfMonth.split("-");
132
+ return `\u6BCF\u6708${lo}\u65E5\u81F3${hi}\u65E5`;
133
+ }
134
+ if (dayOfMonth.startsWith("*/")) {
135
+ return `\u6BCF${dayOfMonth.slice(2)}\u65E5`;
136
+ }
137
+ return `\u6BCF\u6708${dayOfMonth}\u65E5`;
138
+ }
139
+ function describeMonth(month) {
140
+ if (isWildcard(month)) return "";
141
+ if (month.includes(",")) {
142
+ return month.split(",").map((m) => `${m}\u6708`).join("\u3001");
143
+ }
144
+ return `${month}\u6708`;
145
+ }
146
+ function toChinese(fields) {
147
+ const minDesc = describeMinute(fields.minute);
148
+ const hourDesc = describeHour(fields.hour);
149
+ const dowDesc = describeDayOfWeek(fields.dayOfWeek);
150
+ const domDesc = describeDayOfMonth(fields.dayOfMonth);
151
+ const monthDesc = describeMonth(fields.month);
152
+ if (minDesc && isWildcard(fields.hour) && isWildcard(fields.dayOfMonth) && isWildcard(fields.month) && isWildcard(fields.dayOfWeek)) {
153
+ return minDesc;
154
+ }
155
+ if (!hourDesc) return "\u65E0\u6548\u8868\u8FBE\u5F0F";
156
+ const scheduleParts = [];
157
+ if (monthDesc) scheduleParts.push(monthDesc);
158
+ if (domDesc) scheduleParts.push(domDesc);
159
+ if (dowDesc) {
160
+ scheduleParts.push(dowDesc);
161
+ }
162
+ let timeStr;
163
+ if (fields.minute === "0") {
164
+ timeStr = hourDesc;
165
+ } else if (isWildcard(fields.minute)) {
166
+ timeStr = `${hourDesc}\u6BCF\u5206\u949F`;
167
+ } else {
168
+ timeStr = `${hourDesc}:${pad(Number(fields.minute))}`;
169
+ }
170
+ if (scheduleParts.length === 0) {
171
+ return `\u6BCF\u5929 ${timeStr}`;
172
+ }
173
+ return `${scheduleParts.join(" ")} ${timeStr}`;
174
+ }
175
+ export const cronToCn = (val, tzOffset = 8) => {
176
+ if (!val?.trim()) return null;
177
+ const fields = parseFields(val);
178
+ if (!fields) return null;
179
+ if (!validateCron(fields)) return null;
180
+ const localFields = applyTzOffset(fields, tzOffset);
181
+ return toChinese(localFields);
182
+ };
@@ -9,3 +9,4 @@ export * from './string.js';
9
9
  export * from './tree.js';
10
10
  export * from './type.js';
11
11
  export * from './vueuse.js';
12
+ export * from './cron.js';
@@ -9,3 +9,4 @@ export * from "./string.js";
9
9
  export * from "./tree.js";
10
10
  export * from "./type.js";
11
11
  export * from "./vueuse.js";
12
+ export * from "./cron.js";
@@ -1 +1 @@
1
- export declare const useCnTimeAgo: (time: string | Date) => import("vue").ComputedRef<string>;
1
+ export declare const useCnTimeAgo: (time: string | Date | undefined) => "" | import("vue").ComputedRef<string>;
@@ -1,5 +1,6 @@
1
1
  import { useTimeAgo } from "@vueuse/core";
2
2
  export const useCnTimeAgo = (time) => {
3
+ if (!time) return "";
3
4
  return useTimeAgo(time, {
4
5
  messages: {
5
6
  justNow: "\u521A\u521A",