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.
- package/README.md +6 -0
- package/dist/module.json +1 -1
- package/dist/runtime/components/AsyncSelect.vue +16 -1
- package/dist/runtime/components/AsyncTreeSelect.vue +15 -9
- package/dist/runtime/components/DeleteModal.d.vue.ts +25 -22
- package/dist/runtime/components/DeleteModal.vue +39 -4
- package/dist/runtime/components/DeleteModal.vue.d.ts +25 -22
- package/dist/runtime/components/ScrollArea.vue +20 -9
- package/dist/runtime/components/form/field/AsyncObjectSelect.vue +14 -3
- package/dist/runtime/components/form/save-model-template/ConfirmUpdateModal.d.vue.ts +19 -0
- package/dist/runtime/components/form/save-model-template/ConfirmUpdateModal.vue +111 -0
- package/dist/runtime/components/form/save-model-template/ConfirmUpdateModal.vue.d.ts +19 -0
- package/dist/runtime/components/form/{create-modal-template → save-model-template}/WithApi.d.vue.ts +2 -2
- package/dist/runtime/components/form/{create-modal-template → save-model-template}/WithApi.vue +4 -3
- package/dist/runtime/components/form/{create-modal-template → save-model-template}/WithApi.vue.d.ts +2 -2
- package/dist/runtime/components/form/{create-modal-template → save-model-template}/index.d.vue.ts +2 -2
- package/dist/runtime/components/form/{create-modal-template → save-model-template}/index.vue +54 -7
- package/dist/runtime/components/form/{create-modal-template → save-model-template}/index.vue.d.ts +2 -2
- package/dist/runtime/components/layout/button/UserMenu.vue +1 -2
- package/dist/runtime/components/sys/company/{CreateModal.vue → SaveModal.vue} +2 -2
- package/dist/runtime/components/sys/company/Table.vue +5 -4
- package/dist/runtime/components/sys/department/{CreateModal.vue → SaveModal.vue} +3 -2
- package/dist/runtime/components/sys/department/Table.vue +6 -5
- package/dist/runtime/components/sys/flow/EditNodeModal.vue +4 -3
- package/dist/runtime/components/sys/flow/{CreateModal.vue → SaveModal.vue} +3 -2
- package/dist/runtime/components/sys/flow/Table.vue +5 -4
- package/dist/runtime/components/sys/issue-record/{CreateModal.vue → SaveModal.vue} +2 -2
- package/dist/runtime/components/sys/issue-record/Table.vue +5 -4
- package/dist/runtime/components/sys/job-title/{CreateModal.vue → SaveModal.vue} +2 -2
- package/dist/runtime/components/sys/job-title/Table.vue +5 -4
- package/dist/runtime/components/sys/menu/{CreateModal.vue → SaveModal.vue} +3 -2
- package/dist/runtime/components/sys/menu/Table.vue +6 -5
- package/dist/runtime/components/sys/role/{CreateModal.vue → SaveModal.vue} +8 -5
- package/dist/runtime/components/sys/role/Table.vue +5 -4
- package/dist/runtime/components/sys/table/{CreateModal.vue → SaveModal.vue} +4 -3
- package/dist/runtime/components/sys/table/Table.vue +4 -4
- package/dist/runtime/components/sys/table/TableColumnModal.vue +4 -3
- package/dist/runtime/components/sys/user/{CreateModal.vue → SaveModal.vue} +4 -3
- package/dist/runtime/components/sys/user/Table.vue +7 -6
- package/dist/runtime/components/table/Page.vue +2 -1
- package/dist/runtime/components/table/UpdateDiffModal.d.vue.ts +14 -0
- package/dist/runtime/components/table/UpdateDiffModal.vue +156 -0
- package/dist/runtime/components/table/UpdateDiffModal.vue.d.ts +14 -0
- package/dist/runtime/components/table/header/index.vue +181 -183
- package/dist/runtime/components/table/index.vue +2 -1
- package/dist/runtime/composables/form/index.d.ts +2 -0
- package/dist/runtime/composables/form/index.js +2 -0
- package/dist/runtime/composables/form/useForm.d.ts +21 -0
- package/dist/runtime/composables/{useForm.js → form/useForm.js} +23 -1
- package/dist/runtime/composables/form/useFormUpdate.d.ts +6 -0
- package/dist/runtime/composables/form/useFormUpdate.js +101 -0
- package/dist/runtime/composables/index.d.ts +1 -1
- package/dist/runtime/composables/index.js +1 -1
- package/dist/runtime/composables/table/useTable.js +10 -1
- package/dist/runtime/composables/table/useTableRowActions.d.ts +3 -0
- package/dist/runtime/composables/table/useTableRowActions.js +24 -0
- package/dist/runtime/composables/useDate.js +2 -0
- package/dist/runtime/types/components/form/field.d.ts +2 -0
- package/dist/runtime/types/components/form/index.d.ts +4 -3
- package/dist/runtime/types/components/table/header.d.ts +2 -0
- package/dist/runtime/types/components/table/index.d.ts +1 -0
- package/dist/runtime/types/time.d.ts +1 -1
- package/dist/runtime/utils/cron.d.ts +1 -0
- package/dist/runtime/utils/cron.js +182 -0
- package/dist/runtime/utils/index.d.ts +1 -0
- package/dist/runtime/utils/index.js +1 -0
- package/dist/runtime/utils/vueuse.d.ts +1 -1
- package/dist/runtime/utils/vueuse.js +1 -0
- package/package.json +16 -15
- package/dist/runtime/composables/useForm.d.ts +0 -9
- /package/dist/runtime/components/sys/company/{CreateModal.d.vue.ts → SaveModal.d.vue.ts} +0 -0
- /package/dist/runtime/components/sys/company/{CreateModal.vue.d.ts → SaveModal.vue.d.ts} +0 -0
- /package/dist/runtime/components/sys/department/{CreateModal.d.vue.ts → SaveModal.d.vue.ts} +0 -0
- /package/dist/runtime/components/sys/department/{CreateModal.vue.d.ts → SaveModal.vue.d.ts} +0 -0
- /package/dist/runtime/components/sys/flow/{CreateModal.d.vue.ts → SaveModal.d.vue.ts} +0 -0
- /package/dist/runtime/components/sys/flow/{CreateModal.vue.d.ts → SaveModal.vue.d.ts} +0 -0
- /package/dist/runtime/components/sys/issue-record/{CreateModal.d.vue.ts → SaveModal.d.vue.ts} +0 -0
- /package/dist/runtime/components/sys/issue-record/{CreateModal.vue.d.ts → SaveModal.vue.d.ts} +0 -0
- /package/dist/runtime/components/sys/job-title/{CreateModal.d.vue.ts → SaveModal.d.vue.ts} +0 -0
- /package/dist/runtime/components/sys/job-title/{CreateModal.vue.d.ts → SaveModal.vue.d.ts} +0 -0
- /package/dist/runtime/components/sys/menu/{CreateModal.d.vue.ts → SaveModal.d.vue.ts} +0 -0
- /package/dist/runtime/components/sys/menu/{CreateModal.vue.d.ts → SaveModal.vue.d.ts} +0 -0
- /package/dist/runtime/components/sys/role/{CreateModal.d.vue.ts → SaveModal.d.vue.ts} +0 -0
- /package/dist/runtime/components/sys/role/{CreateModal.vue.d.ts → SaveModal.vue.d.ts} +0 -0
- /package/dist/runtime/components/sys/table/{CreateModal.d.vue.ts → SaveModal.d.vue.ts} +0 -0
- /package/dist/runtime/components/sys/table/{CreateModal.vue.d.ts → SaveModal.vue.d.ts} +0 -0
- /package/dist/runtime/components/sys/user/{CreateModal.d.vue.ts → SaveModal.d.vue.ts} +0 -0
- /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 './
|
|
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 "./
|
|
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) {
|
|
@@ -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
|
|
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
|
|
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<
|
|
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>;
|
|
@@ -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
|
+
};
|
|
@@ -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>;
|