v-nuxt-ui 0.2.26 → 0.2.28

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 (33) hide show
  1. package/dist/module.json +1 -1
  2. package/dist/runtime/components/form/save-modal-template/ConfirmUpdateModal.d.vue.ts +19 -0
  3. package/dist/runtime/components/form/save-modal-template/ConfirmUpdateModal.vue +111 -0
  4. package/dist/runtime/components/form/save-modal-template/ConfirmUpdateModal.vue.d.ts +19 -0
  5. package/dist/runtime/components/form/save-modal-template/WithApi.d.vue.ts +19 -0
  6. package/dist/runtime/components/form/save-modal-template/WithApi.vue +37 -0
  7. package/dist/runtime/components/form/save-modal-template/WithApi.vue.d.ts +19 -0
  8. package/dist/runtime/components/form/save-modal-template/index.d.vue.ts +21 -0
  9. package/dist/runtime/components/form/save-modal-template/index.vue +123 -0
  10. package/dist/runtime/components/form/save-modal-template/index.vue.d.ts +21 -0
  11. package/dist/runtime/components/form/save-model-template/WithApi.vue +2 -2
  12. package/dist/runtime/components/sys/company/SaveModal.vue +2 -2
  13. package/dist/runtime/components/sys/department/SaveModal.vue +2 -2
  14. package/dist/runtime/components/sys/flow/EditNodeModal.vue +2 -2
  15. package/dist/runtime/components/sys/flow/SaveModal.vue +2 -2
  16. package/dist/runtime/components/sys/issue-record/SaveModal.vue +2 -2
  17. package/dist/runtime/components/sys/job-title/SaveModal.vue +2 -2
  18. package/dist/runtime/components/sys/menu/SaveModal.vue +2 -2
  19. package/dist/runtime/components/sys/role/SaveModal.vue +3 -3
  20. package/dist/runtime/components/sys/table/SaveModal.vue +3 -3
  21. package/dist/runtime/components/sys/table/TableColumnModal.vue +2 -2
  22. package/dist/runtime/components/sys/user/SaveModal.vue +3 -3
  23. package/dist/runtime/components/table/Page.vue +1 -0
  24. package/dist/runtime/components/table/index.vue +1 -0
  25. package/dist/runtime/composables/form/useForm.d.ts +1 -1
  26. package/dist/runtime/composables/table/useTable.d.ts +2 -0
  27. package/dist/runtime/composables/table/useTable.js +22 -2
  28. package/dist/runtime/composables/table/useTableRowActions.d.ts +3 -0
  29. package/dist/runtime/composables/table/useTableRowActions.js +28 -13
  30. package/dist/runtime/composables/table/useTableView.d.ts +2 -0
  31. package/dist/runtime/composables/table/useTableView.js +6 -2
  32. package/dist/runtime/types/components/table/index.d.ts +1 -0
  33. package/package.json +1 -1
package/dist/module.json CHANGED
@@ -7,7 +7,7 @@
7
7
  "dependencies": [
8
8
  "@nuxt/ui"
9
9
  ],
10
- "version": "0.2.26",
10
+ "version": "0.2.28",
11
11
  "builder": {
12
12
  "@nuxt/module-builder": "1.0.2",
13
13
  "unbuild": "3.6.1"
@@ -0,0 +1,19 @@
1
+ import type { VFormFieldProps } from '#v/types';
2
+ export interface ConfirmDiffItem {
3
+ fieldName: string;
4
+ oldValue: unknown;
5
+ newValue: unknown;
6
+ }
7
+ type __VLS_Props = {
8
+ fields: VFormFieldProps[];
9
+ diffItems: ConfirmDiffItem[];
10
+ oldModelValue: Record<string, unknown>;
11
+ newModelValue: Record<string, unknown>;
12
+ };
13
+ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
14
+ close: (args_0: boolean) => any;
15
+ }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
16
+ onClose?: ((args_0: boolean) => any) | undefined;
17
+ }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
18
+ declare const _default: typeof __VLS_export;
19
+ export default _default;
@@ -0,0 +1,111 @@
1
+ <script setup>
2
+ import { isEmptyString } from "#v/utils";
3
+ import { diffEligibleTypes, useConfirmDiff } from "#v/composables";
4
+ const props = defineProps({
5
+ fields: { type: Array, required: true },
6
+ diffItems: { type: Array, required: true },
7
+ oldModelValue: { type: Object, required: true },
8
+ newModelValue: { type: Object, required: true }
9
+ });
10
+ const emit = defineEmits(["close"]);
11
+ const { diffedItems } = useConfirmDiff(
12
+ () => props.fields,
13
+ () => props.diffItems,
14
+ () => props.oldModelValue,
15
+ () => props.newModelValue
16
+ );
17
+ </script>
18
+
19
+ <template>
20
+ <UModal
21
+ title="确认修改"
22
+ :close="{ onClick: () => emit('close', false) }"
23
+ :dismissible="false"
24
+ >
25
+ <template #description>
26
+ <div class="flex items-center gap-3 w-full">
27
+ <span>
28
+ 请确认以下 {{ diffedItems.length }} 处修改内容
29
+ </span>
30
+ </div>
31
+ </template>
32
+ <template #body>
33
+ <div class="overflow-y-auto max-h-96">
34
+ <div class="space-y-4">
35
+ <UFormField
36
+ v-for="item in diffedItems"
37
+ :key="item.fieldName"
38
+ :label="item.field.label || item.fieldName"
39
+ >
40
+ <!-- String types: word diff -->
41
+ <div v-if="item.field.diffable ?? diffEligibleTypes.has(item.field.type)" class="flex items-center flex-wrap gap-2">
42
+ <span
43
+ class="rounded-md bg-muted px-2 py-1 text-sm text-dimmed"
44
+ :title="item.oldDisplay"
45
+ >
46
+ <span v-if="!item.parts.filter((part2) => !part2.added).length">{{ "\xA0" }}</span>
47
+ <template v-for="(part, idx) in item.parts" :key="idx">
48
+ <span
49
+ v-if="!part.added"
50
+ :class="{ 'bg-red-200 text-red-800 dark:bg-red-800 dark:text-red-200 rounded-sm line-through px-0.5': part.removed }"
51
+ >{{ isEmptyString(part.value) ? "\xA0" : part.value }}</span>
52
+ </template>
53
+ </span>
54
+ <UIcon
55
+ name="i-lucide-arrow-right"
56
+ class="text-dimmed shrink-0 size-4"
57
+ />
58
+ <span
59
+ class="rounded-md bg-elevated px-2 py-1 text-sm text-highlighted font-bold"
60
+ :title="item.newDisplay"
61
+ >
62
+ <span v-if="!item.parts.filter((part2) => !part2.removed).length">{{ "\xA0" }}</span>
63
+ <template v-for="(part, idx) in item.parts" :key="idx">
64
+ <span
65
+ v-if="!part.removed"
66
+ :class="{ 'bg-green-200 text-green-800 dark:bg-green-800 dark:text-green-200 rounded-sm px-0.5': part.added }"
67
+ >{{ isEmptyString(part.value) ? "\xA0" : part.value }}</span>
68
+ </template>
69
+ </span>
70
+ </div>
71
+ <!-- Other types: simple old -> new -->
72
+ <div v-else class="flex items-center flex-wrap gap-2">
73
+ <span
74
+ class="rounded-md bg-muted px-2 py-1 text-sm text-dimmed"
75
+ :title="item.oldDisplay"
76
+ >
77
+ {{ isEmptyString(item.oldDisplay) ? "\xA0" : item.oldDisplay }}
78
+ </span>
79
+ <UIcon
80
+ name="i-lucide-arrow-right"
81
+ class="text-dimmed shrink-0 size-4"
82
+ />
83
+ <span
84
+ class="rounded-md bg-elevated px-2 py-1 text-sm text-highlighted font-medium"
85
+ :title="item.newDisplay"
86
+ >
87
+ {{ isEmptyString(item.newDisplay) ? "\xA0" : item.newDisplay }}
88
+ </span>
89
+ </div>
90
+ </UFormField>
91
+ </div>
92
+ </div>
93
+ </template>
94
+ <template #footer>
95
+ <UButton
96
+ label="取消"
97
+ color="neutral"
98
+ variant="subtle"
99
+ icon="i-lucide-x"
100
+ @click="emit('close', false)"
101
+ />
102
+ <UButton
103
+ :label="`\u786E\u8BA4 ${diffedItems.length} \u5904\u4FEE\u6539`"
104
+ color="primary"
105
+ variant="solid"
106
+ icon="i-lucide-check"
107
+ @click="emit('close', true)"
108
+ />
109
+ </template>
110
+ </UModal>
111
+ </template>
@@ -0,0 +1,19 @@
1
+ import type { VFormFieldProps } from '#v/types';
2
+ export interface ConfirmDiffItem {
3
+ fieldName: string;
4
+ oldValue: unknown;
5
+ newValue: unknown;
6
+ }
7
+ type __VLS_Props = {
8
+ fields: VFormFieldProps[];
9
+ diffItems: ConfirmDiffItem[];
10
+ oldModelValue: Record<string, unknown>;
11
+ newModelValue: Record<string, unknown>;
12
+ };
13
+ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
14
+ close: (args_0: boolean) => any;
15
+ }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
16
+ onClose?: ((args_0: boolean) => any) | undefined;
17
+ }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
18
+ declare const _default: typeof __VLS_export;
19
+ export default _default;
@@ -0,0 +1,19 @@
1
+ import type { BaseModel, SaveModalFormTemplatePropsWithApi } from '#v/types';
2
+ declare const __VLS_export: <T extends BaseModel>(__VLS_props: NonNullable<Awaited<typeof __VLS_setup>>["props"], __VLS_ctx?: __VLS_PrettifyLocal<Pick<NonNullable<Awaited<typeof __VLS_setup>>, "attrs" | "emit" | "slots">>, __VLS_exposed?: NonNullable<Awaited<typeof __VLS_setup>>["expose"], __VLS_setup?: Promise<{
3
+ props: import("vue").PublicProps & __VLS_PrettifyLocal<SaveModalFormTemplatePropsWithApi<T>> & (typeof globalThis extends {
4
+ __VLS_PROPS_FALLBACK: infer P;
5
+ } ? P : {});
6
+ expose: (exposed: {}) => void;
7
+ attrs: any;
8
+ slots: {};
9
+ emit: {};
10
+ }>) => import("vue").VNode & {
11
+ __ctx?: Awaited<typeof __VLS_setup>;
12
+ };
13
+ declare const _default: typeof __VLS_export;
14
+ export default _default;
15
+ type __VLS_PrettifyLocal<T> = (T extends any ? {
16
+ [K in keyof T]: T[K];
17
+ } : {
18
+ [K in keyof T as K]: T[K];
19
+ }) & {};
@@ -0,0 +1,37 @@
1
+ <script setup>
2
+ import { toRef } from "vue";
3
+ import { useFormSubmission, useFormValues } from "#v/composables/form/useForm";
4
+ import FormSaveModalTemplate from "./index.vue";
5
+ const props = defineProps({
6
+ apiGroup: { type: Function, required: true },
7
+ valuePruneFn: { type: Function, required: false },
8
+ defaultModelValue: { type: Object, required: false },
9
+ onSave: { type: Function, required: true },
10
+ title: { type: String, required: true },
11
+ description: { type: String, required: false },
12
+ fields: { type: Array, required: true },
13
+ onClose: { type: Function, required: true },
14
+ modelValue: { type: Object, required: true },
15
+ onUpdateModelValue: { type: Function, required: false }
16
+ });
17
+ const { oldValues, newValues } = useFormValues(toRef(props.modelValue), props.defaultModelValue);
18
+ const { onSubmit } = useFormSubmission(
19
+ toRef(oldValues),
20
+ toRef(newValues),
21
+ props.onClose,
22
+ props.onSave,
23
+ props.apiGroup
24
+ );
25
+ </script>
26
+
27
+ <template>
28
+ <FormSaveModalTemplate
29
+ v-model:model-value="newValues"
30
+ :old-model-value="oldValues"
31
+ :title="title"
32
+ :description="description"
33
+ :on-close="onClose"
34
+ :on-submit="onSubmit"
35
+ :fields="fields"
36
+ />
37
+ </template>
@@ -0,0 +1,19 @@
1
+ import type { BaseModel, SaveModalFormTemplatePropsWithApi } from '#v/types';
2
+ declare const __VLS_export: <T extends BaseModel>(__VLS_props: NonNullable<Awaited<typeof __VLS_setup>>["props"], __VLS_ctx?: __VLS_PrettifyLocal<Pick<NonNullable<Awaited<typeof __VLS_setup>>, "attrs" | "emit" | "slots">>, __VLS_exposed?: NonNullable<Awaited<typeof __VLS_setup>>["expose"], __VLS_setup?: Promise<{
3
+ props: import("vue").PublicProps & __VLS_PrettifyLocal<SaveModalFormTemplatePropsWithApi<T>> & (typeof globalThis extends {
4
+ __VLS_PROPS_FALLBACK: infer P;
5
+ } ? P : {});
6
+ expose: (exposed: {}) => void;
7
+ attrs: any;
8
+ slots: {};
9
+ emit: {};
10
+ }>) => import("vue").VNode & {
11
+ __ctx?: Awaited<typeof __VLS_setup>;
12
+ };
13
+ declare const _default: typeof __VLS_export;
14
+ export default _default;
15
+ type __VLS_PrettifyLocal<T> = (T extends any ? {
16
+ [K in keyof T]: T[K];
17
+ } : {
18
+ [K in keyof T as K]: T[K];
19
+ }) & {};
@@ -0,0 +1,21 @@
1
+ import type { BaseModel, SaveModalFormTemplateProps } from '#v/types';
2
+ declare const __VLS_export: <T extends BaseModel>(__VLS_props: NonNullable<Awaited<typeof __VLS_setup>>["props"], __VLS_ctx?: __VLS_PrettifyLocal<Pick<NonNullable<Awaited<typeof __VLS_setup>>, "attrs" | "emit" | "slots">>, __VLS_exposed?: NonNullable<Awaited<typeof __VLS_setup>>["expose"], __VLS_setup?: Promise<{
3
+ props: import("vue").PublicProps & __VLS_PrettifyLocal<SaveModalFormTemplateProps<T>> & (typeof globalThis extends {
4
+ __VLS_PROPS_FALLBACK: infer P;
5
+ } ? P : {});
6
+ expose: (exposed: {}) => void;
7
+ attrs: any;
8
+ slots: {
9
+ 'after-form'?: (props: {}) => any;
10
+ };
11
+ emit: {};
12
+ }>) => import("vue").VNode & {
13
+ __ctx?: Awaited<typeof __VLS_setup>;
14
+ };
15
+ declare const _default: typeof __VLS_export;
16
+ export default _default;
17
+ type __VLS_PrettifyLocal<T> = (T extends any ? {
18
+ [K in keyof T]: T[K];
19
+ } : {
20
+ [K in keyof T as K]: T[K];
21
+ }) & {};
@@ -0,0 +1,123 @@
1
+ <script setup>
2
+ import { computed, ref, useTemplateRef } from "vue";
3
+ import { useOverlay } from "@nuxt/ui/composables";
4
+ import { useSubmitting } from "#v/composables";
5
+ import Form from "../index.vue";
6
+ import ConfirmUpdateModal from "./ConfirmUpdateModal.vue";
7
+ const props = defineProps({
8
+ title: { type: String, required: true },
9
+ description: { type: String, required: false },
10
+ onClose: { type: Function, required: true },
11
+ onSubmit: { type: Function, required: true },
12
+ fields: { type: Array, required: true },
13
+ oldModelValue: { type: Object, required: true },
14
+ modelValue: { type: Object, required: true },
15
+ onUpdateModelValue: { type: Function, required: false },
16
+ rowKey: { type: null, required: false, default: "id" },
17
+ fullscreen: { type: Boolean, required: false }
18
+ });
19
+ const form = useTemplateRef("form");
20
+ const action = computed(() => props.modelValue[props.rowKey] === 0 ? "\u521B\u5EFA" : "\u66F4\u65B0");
21
+ const isUpdate = computed(() => props.modelValue[props.rowKey] !== 0);
22
+ const titleWithAction = computed(() => `${action.value}${props.title}`);
23
+ const descWithAction = computed(() => props.description ?? `\u8BF7${action.value}${props.title}`);
24
+ const submitIcon = computed(() => props.modelValue[props.rowKey] === 0 ? "i-lucide-clipboard-plus" : "i-lucide-clipboard-pen-line");
25
+ const initialModelValue = ref(JSON.parse(JSON.stringify(props.modelValue)));
26
+ const overlay = useOverlay();
27
+ const confirmModal = overlay.create(ConfirmUpdateModal);
28
+ function computeDiff() {
29
+ const items = [];
30
+ for (const field of props.fields) {
31
+ if (!field.name || field.hidden) continue;
32
+ const name = field.name;
33
+ const oldVal = initialModelValue.value[name];
34
+ const newVal = props.modelValue[name];
35
+ if ((oldVal === null || oldVal === void 0) && (newVal === null || newVal === void 0)) continue;
36
+ if (oldVal === newVal) continue;
37
+ if (typeof oldVal === "object" && typeof newVal === "object" && oldVal !== null && newVal !== null) {
38
+ if (JSON.stringify(oldVal) === JSON.stringify(newVal)) continue;
39
+ }
40
+ items.push({
41
+ fieldName: name,
42
+ oldValue: oldVal,
43
+ newValue: newVal
44
+ });
45
+ }
46
+ return items;
47
+ }
48
+ const { submitting, startSubmitting, endSubmitting } = useSubmitting();
49
+ async function doSubmit() {
50
+ try {
51
+ startSubmitting();
52
+ await props.onSubmit();
53
+ } finally {
54
+ endSubmitting();
55
+ }
56
+ }
57
+ async function onSubmitWithValidation(e) {
58
+ e.preventDefault();
59
+ e.stopPropagation();
60
+ try {
61
+ await form.value?.validate?.();
62
+ } catch {
63
+ return;
64
+ }
65
+ if (isUpdate.value) {
66
+ const items = computeDiff();
67
+ if (items.length === 0) {
68
+ await doSubmit();
69
+ return;
70
+ }
71
+ const confirmed = await confirmModal.open({
72
+ fields: props.fields,
73
+ diffItems: items,
74
+ oldModelValue: props.oldModelValue,
75
+ newModelValue: props.modelValue
76
+ }).result;
77
+ if (confirmed) {
78
+ await doSubmit();
79
+ }
80
+ return;
81
+ }
82
+ await doSubmit();
83
+ }
84
+ </script>
85
+
86
+ <template>
87
+ <UModal
88
+ :title="titleWithAction"
89
+ :description="descWithAction"
90
+ :close="{ onClick: () => props.onClose(false) }"
91
+ :dismissible="false"
92
+ :fullscreen="fullscreen"
93
+ >
94
+ <template #body>
95
+ <Form
96
+ ref="form"
97
+ :fields="fields"
98
+ :loading="submitting"
99
+ :model-value="modelValue"
100
+ @trigger-submit="onSubmitWithValidation"
101
+ @update-model-value="onUpdateModelValue"
102
+ />
103
+ <slot name="after-form" />
104
+ </template>
105
+ <template #footer>
106
+ <UButton
107
+ label="取消"
108
+ color="neutral"
109
+ variant="subtle"
110
+ icon="i-lucide-x"
111
+ @click="props.onClose(false)"
112
+ />
113
+ <UButton
114
+ :label="action"
115
+ color="primary"
116
+ variant="solid"
117
+ :icon="submitIcon"
118
+ :loading="submitting"
119
+ @click="onSubmitWithValidation"
120
+ />
121
+ </template>
122
+ </UModal>
123
+ </template>
@@ -0,0 +1,21 @@
1
+ import type { BaseModel, SaveModalFormTemplateProps } from '#v/types';
2
+ declare const __VLS_export: <T extends BaseModel>(__VLS_props: NonNullable<Awaited<typeof __VLS_setup>>["props"], __VLS_ctx?: __VLS_PrettifyLocal<Pick<NonNullable<Awaited<typeof __VLS_setup>>, "attrs" | "emit" | "slots">>, __VLS_exposed?: NonNullable<Awaited<typeof __VLS_setup>>["expose"], __VLS_setup?: Promise<{
3
+ props: import("vue").PublicProps & __VLS_PrettifyLocal<SaveModalFormTemplateProps<T>> & (typeof globalThis extends {
4
+ __VLS_PROPS_FALLBACK: infer P;
5
+ } ? P : {});
6
+ expose: (exposed: {}) => void;
7
+ attrs: any;
8
+ slots: {
9
+ 'after-form'?: (props: {}) => any;
10
+ };
11
+ emit: {};
12
+ }>) => import("vue").VNode & {
13
+ __ctx?: Awaited<typeof __VLS_setup>;
14
+ };
15
+ declare const _default: typeof __VLS_export;
16
+ export default _default;
17
+ type __VLS_PrettifyLocal<T> = (T extends any ? {
18
+ [K in keyof T]: T[K];
19
+ } : {
20
+ [K in keyof T as K]: T[K];
21
+ }) & {};
@@ -1,7 +1,7 @@
1
1
  <script setup>
2
2
  import { toRef } from "vue";
3
3
  import { useFormSubmission, useFormValues } from "#v/composables/form/useForm";
4
- import FormSaveModelTemplate from "./index.vue";
4
+ import FormSaveModalTemplate from "./index.vue";
5
5
  const props = defineProps({
6
6
  apiGroup: { type: Function, required: true },
7
7
  valuePruneFn: { type: Function, required: false },
@@ -25,7 +25,7 @@ const { onSubmit } = useFormSubmission(
25
25
  </script>
26
26
 
27
27
  <template>
28
- <FormSaveModelTemplate
28
+ <FormSaveModalTemplate
29
29
  v-model:model-value="newValues"
30
30
  :old-model-value="oldValues"
31
31
  :title="title"
@@ -1,6 +1,6 @@
1
1
  <script setup>
2
2
  import * as z from "zod";
3
- import FormSaveModelTemplateWithApi from "#v/components/form/save-model-template/WithApi.vue";
3
+ import FormSaveModalTemplateWithApi from "#v/components/form/save-modal-template/WithApi.vue";
4
4
  import { useCompanyApi } from "#v/composables";
5
5
  defineProps({
6
6
  model: { type: Object, required: true }
@@ -9,7 +9,7 @@ const emit = defineEmits(["close", "save"]);
9
9
  </script>
10
10
 
11
11
  <template>
12
- <FormSaveModelTemplateWithApi
12
+ <FormSaveModalTemplateWithApi
13
13
  title="公司信息"
14
14
  :on-close="(ok) => emit('close', ok)"
15
15
  :on-save="(model) => emit('save', model)"
@@ -1,6 +1,6 @@
1
1
  <script setup>
2
2
  import * as z from "zod";
3
- import FormSaveModelTemplate from "#v/components/form/save-model-template/index.vue";
3
+ import FormSaveModalTemplate from "#v/components/form/save-modal-template/index.vue";
4
4
  import { useCompanyApi, useDepartmentApi, useFormSubmission, useFormValues, useUserApi } from "#v/composables";
5
5
  import { toRef, watch } from "vue";
6
6
  const props = defineProps({
@@ -27,7 +27,7 @@ const { onSubmit } = useFormSubmission(
27
27
  </script>
28
28
 
29
29
  <template>
30
- <FormSaveModelTemplate
30
+ <FormSaveModalTemplate
31
31
  title="部门信息"
32
32
  :on-close="(ok) => emit('close', ok)"
33
33
  :fields="[
@@ -1,6 +1,6 @@
1
1
  <script setup>
2
2
  import * as z from "zod";
3
- import FormSaveModelTemplate from "#v/components/form/save-model-template/index.vue";
3
+ import FormSaveModalTemplate from "#v/components/form/save-modal-template/index.vue";
4
4
  import { useFormValues } from "#v/composables";
5
5
  import { toRef } from "vue";
6
6
  const props = defineProps({
@@ -14,7 +14,7 @@ const { oldValues, newValues } = useFormValues(toRef(props.model), {
14
14
  </script>
15
15
 
16
16
  <template>
17
- <FormSaveModelTemplate
17
+ <FormSaveModalTemplate
18
18
  title="编辑节点"
19
19
  :on-close="(ok) => emit('close', ok)"
20
20
  :fields="[
@@ -1,6 +1,6 @@
1
1
  <script setup>
2
2
  import * as z from "zod";
3
- import FormSaveModelTemplate from "#v/components/form/save-model-template/index.vue";
3
+ import FormSaveModalTemplate from "#v/components/form/save-modal-template/index.vue";
4
4
  import { useFlowApi, useFormSubmission, useFormValues } from "#v/composables";
5
5
  import { toRef } from "vue";
6
6
  const props = defineProps({
@@ -18,7 +18,7 @@ const { onSubmit } = useFormSubmission(
18
18
  </script>
19
19
 
20
20
  <template>
21
- <FormSaveModelTemplate
21
+ <FormSaveModalTemplate
22
22
  title="流程信息"
23
23
  :on-close="(ok) => emit('close', ok)"
24
24
  :fields="[
@@ -1,6 +1,6 @@
1
1
  <script setup>
2
2
  import * as z from "zod";
3
- import FormSaveModelTemplateWithApi from "#v/components/form/save-model-template/WithApi.vue";
3
+ import FormSaveModalTemplateWithApi from "#v/components/form/save-modal-template/WithApi.vue";
4
4
  import { useIssueRecordApi } from "#v/composables";
5
5
  defineProps({
6
6
  model: { type: Object, required: true }
@@ -9,7 +9,7 @@ const emit = defineEmits(["close", "save"]);
9
9
  </script>
10
10
 
11
11
  <template>
12
- <FormSaveModelTemplateWithApi
12
+ <FormSaveModalTemplateWithApi
13
13
  title="改进建议"
14
14
  description="您可以针对该网页提出任何改进建议或直接联系chenrn@mail.veken.com"
15
15
  :on-close="(ok) => emit('close', ok)"
@@ -1,6 +1,6 @@
1
1
  <script setup>
2
2
  import * as z from "zod";
3
- import FormSaveModelTemplateWithApi from "#v/components/form/save-model-template/WithApi.vue";
3
+ import FormSaveModalTemplateWithApi from "#v/components/form/save-modal-template/WithApi.vue";
4
4
  import { useJobTitleApi } from "#v/composables";
5
5
  defineProps({
6
6
  model: { type: Object, required: true }
@@ -9,7 +9,7 @@ const emit = defineEmits(["close", "save"]);
9
9
  </script>
10
10
 
11
11
  <template>
12
- <FormSaveModelTemplateWithApi
12
+ <FormSaveModalTemplateWithApi
13
13
  title="职位信息"
14
14
  :on-close="(ok) => emit('close', ok)"
15
15
  :on-save="(model) => emit('save', model)"
@@ -1,6 +1,6 @@
1
1
  <script setup>
2
2
  import * as z from "zod";
3
- import FormSaveModelTemplate from "#v/components/form/save-model-template/index.vue";
3
+ import FormSaveModalTemplate from "#v/components/form/save-modal-template/index.vue";
4
4
  import { useMenuApi, useFormSubmission, useFormValues } from "#v/composables";
5
5
  import { toRef } from "vue";
6
6
  import { menuTypeOptions } from "#v/constants";
@@ -20,7 +20,7 @@ const { onSubmit } = useFormSubmission(
20
20
  </script>
21
21
 
22
22
  <template>
23
- <FormSaveModelTemplate
23
+ <FormSaveModalTemplate
24
24
  title="菜单信息"
25
25
  :on-close="(ok) => emit('close', ok)"
26
26
  :fields="[
@@ -1,6 +1,6 @@
1
1
  <script setup>
2
2
  import * as z from "zod";
3
- import FormSaveModelTemplate from "#v/components/form/save-model-template/index.vue";
3
+ import FormSaveModalTemplate from "#v/components/form/save-modal-template/index.vue";
4
4
  import TablePermissionTab from "#v/components/table/permission/TablePermissionTab.vue";
5
5
  import { useFormSubmission, useFormValues, useMenuApi, useRoleApi } from "#v/composables";
6
6
  import { computed, onMounted, ref, toRef } from "vue";
@@ -86,7 +86,7 @@ onMounted(async () => {
86
86
  </script>
87
87
 
88
88
  <template>
89
- <FormSaveModelTemplate
89
+ <FormSaveModalTemplate
90
90
  title="角色信息"
91
91
  :on-close="(ok) => emit('close', ok)"
92
92
  :fields="fields"
@@ -103,5 +103,5 @@ onMounted(async () => {
103
103
  <TablePermissionTab v-model="tablePermissions" />
104
104
  </div>
105
105
  </template>
106
- </FormSaveModelTemplate>
106
+ </FormSaveModalTemplate>
107
107
  </template>
@@ -1,6 +1,6 @@
1
1
  <script setup>
2
2
  import * as z from "zod";
3
- import FormSaveModelTemplate from "#v/components/form/save-model-template/index.vue";
3
+ import FormSaveModalTemplate from "#v/components/form/save-modal-template/index.vue";
4
4
  import TableColumnList from "./TableColumnList.vue";
5
5
  import { useFormSubmission, useFormValues, useTableApi } from "#v/composables";
6
6
  import { computed, ref, toRef } from "vue";
@@ -40,7 +40,7 @@ function updateModelValue(newVal) {
40
40
  </script>
41
41
 
42
42
  <template>
43
- <FormSaveModelTemplate
43
+ <FormSaveModalTemplate
44
44
  title="Table"
45
45
  :on-close="(ok) => emit('close', ok)"
46
46
  :fields="fields"
@@ -52,5 +52,5 @@ function updateModelValue(newVal) {
52
52
  <template #after-form>
53
53
  <TableColumnList ref="columnListRef" :initial-columns="model.columns" />
54
54
  </template>
55
- </FormSaveModelTemplate>
55
+ </FormSaveModalTemplate>
56
56
  </template>
@@ -1,6 +1,6 @@
1
1
  <script setup>
2
2
  import * as z from "zod";
3
- import FormSaveModelTemplate from "#v/components/form/save-model-template/index.vue";
3
+ import FormSaveModalTemplate from "#v/components/form/save-modal-template/index.vue";
4
4
  import { useFormValues } from "#v/composables";
5
5
  import { computed, toRef } from "vue";
6
6
  const props = defineProps({
@@ -25,7 +25,7 @@ const fields = computed(() => [
25
25
  </script>
26
26
 
27
27
  <template>
28
- <FormSaveModelTemplate
28
+ <FormSaveModalTemplate
29
29
  title="列配置"
30
30
  :on-close="(ok) => emit('close', ok)"
31
31
  :fields="fields"
@@ -2,7 +2,7 @@
2
2
  import { useFormValues, useFormSubmission, useUserApi, useRoleApi, useMenuApi, useDepartmentApi } from "#v/composables";
3
3
  import { treeifyOptions } from "#v/utils";
4
4
  import { toRef, ref, computed, onMounted } from "vue";
5
- import FormSaveModelTemplate from "#v/components/form/save-model-template/index.vue";
5
+ import FormSaveModalTemplate from "#v/components/form/save-modal-template/index.vue";
6
6
  import TablePermissionTab from "#v/components/table/permission/TablePermissionTab.vue";
7
7
  import { loginTypeOptions, genderOptions, Gender } from "#v/constants";
8
8
  import * as z from "zod";
@@ -191,7 +191,7 @@ onMounted(async () => {
191
191
  </script>
192
192
 
193
193
  <template>
194
- <FormSaveModelTemplate
194
+ <FormSaveModalTemplate
195
195
  title="用户信息"
196
196
  :on-close="(ok) => emit('close', ok)"
197
197
  :fields="fields"
@@ -208,5 +208,5 @@ onMounted(async () => {
208
208
  <TablePermissionTab v-model="tablePermissions" />
209
209
  </div>
210
210
  </template>
211
- </FormSaveModelTemplate>
211
+ </FormSaveModalTemplate>
212
212
  </template>
@@ -41,6 +41,7 @@ const props = defineProps({
41
41
  disableRowCopy: { type: Boolean, required: false },
42
42
  disableRowDeletion: { type: Boolean, required: false },
43
43
  disableRowSelection: { type: Boolean, required: false },
44
+ disableRowDiff: { type: Boolean, required: false },
44
45
  expandable: { type: Boolean, required: false },
45
46
  expandVNode: { type: Function, required: false },
46
47
  rowSpanColumns: { type: Array, required: false },
@@ -40,6 +40,7 @@ const props = defineProps({
40
40
  disableRowCopy: { type: Boolean, required: false },
41
41
  disableRowDeletion: { type: Boolean, required: false },
42
42
  disableRowSelection: { type: Boolean, required: false },
43
+ disableRowDiff: { type: Boolean, required: false },
43
44
  expandable: { type: Boolean, required: false },
44
45
  expandVNode: { type: Function, required: false },
45
46
  rowSpanColumns: { type: Array, required: false },
@@ -1,6 +1,6 @@
1
1
  import { type Ref, type MaybeRefOrGetter } from 'vue';
2
2
  import type { ApiGroup, BaseModel, VFormFieldProps } from '#v/types';
3
- import type { ConfirmDiffItem } from '#v/components/form/save-model-template/ConfirmUpdateModal.vue';
3
+ import type { ConfirmDiffItem } from '#v/components/form/save-modal-template/ConfirmUpdateModal.vue';
4
4
  export declare const useFormValues: <T>(raw: Ref<T>, defaultValues?: Partial<T>) => {
5
5
  oldValues: Ref<T>;
6
6
  newValues: Ref<T>;
@@ -21,5 +21,7 @@ export interface UseTableReturn<T> {
21
21
  tblHeaderProps: ComputedRef<TableHeaderProps<T>>;
22
22
  tblPaginationProps: ComputedRef<TablePaginationProps<T>>;
23
23
  tblContextMenuItems: Ref<ContextMenuItem[]>;
24
+ deletingRowKey: Ref<number | null>;
25
+ editingRowKey: Ref<number | null>;
24
26
  }
25
27
  export declare function useTable<T>(props: VTableProps<T>): UseTableReturn<T>;
@@ -42,6 +42,7 @@ export function useTable(props) {
42
42
  disableRowCopy,
43
43
  disableRowDeletion,
44
44
  disableRowSelection,
45
+ disableRowDiff,
45
46
  expandable,
46
47
  rowSpanColumns,
47
48
  customRowCopyFn,
@@ -159,6 +160,7 @@ export function useTable(props) {
159
160
  disableRowUpdate,
160
161
  disableRowCopy,
161
162
  disableRowDeletion,
163
+ disableRowDiff,
162
164
  onEditRowFromModal,
163
165
  extraRowActions,
164
166
  useApiGroup,
@@ -166,7 +168,7 @@ export function useTable(props) {
166
168
  displayFnInDeleteModal,
167
169
  fetchList
168
170
  });
169
- const { getRowActions, generateActionColumn } = rowActionsComposable;
171
+ const { getRowActions, generateActionColumn, deletingRowKey, editingRowKey } = rowActionsComposable;
170
172
  const columns = computed(() => {
171
173
  const newCols = [];
172
174
  if (!disableRowSelection) {
@@ -243,6 +245,22 @@ export function useTable(props) {
243
245
  if (!disableRowActions) {
244
246
  newCols.push(generateActionColumn());
245
247
  }
248
+ newCols.forEach((col) => {
249
+ const existingTdClass = col.meta?.class?.td;
250
+ col.meta = col.meta || {};
251
+ col.meta.class = col.meta.class || {};
252
+ col.meta.class.td = (cell) => {
253
+ const rowKeyValue = cell.row.original[rowKey];
254
+ let highlightClass = "";
255
+ if (deletingRowKey.value !== null && deletingRowKey.value === rowKeyValue) {
256
+ highlightClass = "!bg-(--ui-color-error-50) dark:!bg-(--ui-color-error-900)";
257
+ } else if (editingRowKey.value !== null && editingRowKey.value === rowKeyValue) {
258
+ highlightClass = "!bg-(--ui-color-primary-50) dark:!bg-(--ui-color-primary-900)";
259
+ }
260
+ const existingClass = typeof existingTdClass === "function" ? existingTdClass(cell) : existingTdClass || "";
261
+ return [existingClass, highlightClass].filter(Boolean).join(" ");
262
+ };
263
+ });
246
264
  return newCols;
247
265
  });
248
266
  const tblContextMenuItems = ref([]);
@@ -345,6 +363,8 @@ export function useTable(props) {
345
363
  tblHeaderProps,
346
364
  tblPaginationProps,
347
365
  // others
348
- tblContextMenuItems
366
+ tblContextMenuItems,
367
+ deletingRowKey,
368
+ editingRowKey
349
369
  };
350
370
  }
@@ -8,6 +8,7 @@ export declare function useTableRowActions<T>(props: {
8
8
  disableRowUpdate?: boolean;
9
9
  disableRowCopy?: boolean;
10
10
  disableRowDeletion?: boolean;
11
+ disableRowDiff?: boolean;
11
12
  onEditRowFromModal?: (...args: any[]) => any;
12
13
  extraRowActions?: any[];
13
14
  useApiGroup?: (...args: any[]) => any;
@@ -18,4 +19,6 @@ export declare function useTableRowActions<T>(props: {
18
19
  getRowActions: (row: TableRow<T>) => DropdownMenuItem[];
19
20
  generateActionColumn: () => VColumn<T>;
20
21
  actionLoadingRowIdxSet: import("vue").Ref<Set<number> & Omit<Set<number>, keyof Set<any>>, Set<number> | (Set<number> & Omit<Set<number>, keyof Set<any>>)>;
22
+ deletingRowKey: import("vue").Ref<number | null, number | null>;
23
+ editingRowKey: import("vue").Ref<number | null, number | null>;
21
24
  };
@@ -13,6 +13,7 @@ export function useTableRowActions(props) {
13
13
  disableRowUpdate,
14
14
  disableRowCopy,
15
15
  disableRowDeletion,
16
+ disableRowDiff,
16
17
  onEditRowFromModal,
17
18
  extraRowActions,
18
19
  useApiGroup,
@@ -25,6 +26,8 @@ export function useTableRowActions(props) {
25
26
  const updateDiffModal = overlay.create(UpdateDiffModal);
26
27
  const apiGroup = useApiGroup?.();
27
28
  const actionLoadingRowIdxSet = ref(/* @__PURE__ */ new Set());
29
+ const deletingRowKey = ref(null);
30
+ const editingRowKey = ref(null);
28
31
  function getRowActions(row) {
29
32
  const actionItems = [];
30
33
  if (!disableRowUpdate && onEditRowFromModal) {
@@ -32,9 +35,14 @@ export function useTableRowActions(props) {
32
35
  label: "\u7F16\u8F91",
33
36
  icon: "i-lucide-clipboard-pen-line",
34
37
  onClick: async () => {
35
- const result = await onEditRowFromModal(row.original);
36
- if (result) {
37
- await fetchList();
38
+ editingRowKey.value = row.original[rowKey];
39
+ try {
40
+ const result = await onEditRowFromModal(row.original);
41
+ if (result) {
42
+ await fetchList();
43
+ }
44
+ } finally {
45
+ editingRowKey.value = null;
38
46
  }
39
47
  }
40
48
  });
@@ -94,7 +102,7 @@ export function useTableRowActions(props) {
94
102
  extraRowActions?.forEach((action) => {
95
103
  actionItems.push(buildActionItem(action));
96
104
  });
97
- if (tableName) {
105
+ if (tableName && !disableRowDiff) {
98
106
  if (actionItems.length > 0 && !disableRowDeletion) {
99
107
  actionItems.push({ type: "separator" });
100
108
  }
@@ -120,14 +128,19 @@ export function useTableRowActions(props) {
120
128
  icon: "i-lucide-trash-2",
121
129
  color: "error",
122
130
  onSelect: async () => {
123
- const result = await deleteModal.open({
124
- ids: [row.original[rowKey]],
125
- models: [row.original],
126
- displayFn: displayFnInDeleteModal,
127
- onDelete: (ids) => apiGroup?.batchDelete({ ids })
128
- }).result;
129
- if (result) {
130
- await fetchList();
131
+ deletingRowKey.value = row.original[rowKey];
132
+ try {
133
+ const result = await deleteModal.open({
134
+ ids: [row.original[rowKey]],
135
+ models: [row.original],
136
+ displayFn: displayFnInDeleteModal,
137
+ onDelete: (ids) => apiGroup?.batchDelete({ ids })
138
+ }).result;
139
+ if (result) {
140
+ await fetchList();
141
+ }
142
+ } finally {
143
+ deletingRowKey.value = null;
131
144
  }
132
145
  }
133
146
  });
@@ -185,6 +198,8 @@ export function useTableRowActions(props) {
185
198
  return {
186
199
  getRowActions,
187
200
  generateActionColumn,
188
- actionLoadingRowIdxSet
201
+ actionLoadingRowIdxSet,
202
+ deletingRowKey,
203
+ editingRowKey
189
204
  };
190
205
  }
@@ -23,5 +23,7 @@ export interface UseProTableViewReturn<T> {
23
23
  th: string;
24
24
  td: string;
25
25
  }>;
26
+ deletingRowKey: Ref<number | null>;
27
+ editingRowKey: Ref<number | null>;
26
28
  }
27
29
  export declare function useProTableView<T>(props: VTableProps<T>): UseProTableViewReturn<T>;
@@ -27,7 +27,9 @@ export function useProTableView(props) {
27
27
  tblWhereQueryProps,
28
28
  tblHeaderProps,
29
29
  tblPaginationProps,
30
- tblContextMenuItems
30
+ tblContextMenuItems,
31
+ deletingRowKey,
32
+ editingRowKey
31
33
  } = useTable(props);
32
34
  const thClass = computed(() => {
33
35
  const classList = [];
@@ -145,6 +147,8 @@ export function useProTableView(props) {
145
147
  tableWidth,
146
148
  updateTableWidth,
147
149
  tblClasses,
148
- tblUi
150
+ tblUi,
151
+ deletingRowKey,
152
+ editingRowKey
149
153
  };
150
154
  }
@@ -98,6 +98,7 @@ export type VTableProps<T> = {
98
98
  disableRowCopy?: boolean;
99
99
  disableRowDeletion?: boolean;
100
100
  disableRowSelection?: boolean;
101
+ disableRowDiff?: boolean;
101
102
  expandable?: boolean;
102
103
  expandVNode?: (row: T) => VNode;
103
104
  rowSpanColumns?: (keyof T)[];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "v-nuxt-ui",
3
- "version": "0.2.26",
3
+ "version": "0.2.28",
4
4
  "description": "Veken UI Component Library - Reusable Nuxt UI components, composables, and utilities for enterprise applications",
5
5
  "type": "module",
6
6
  "style": "./dist/runtime/index.css",