vome-core 0.0.67 → 0.0.69
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/dist/admin/config/plugin-dev.js +1 -1
- package/dist/admin/crud/components/vm-json-editor.vue +32 -3
- package/dist/admin/crud/config.js +1 -1
- package/dist/admin/crud/confirm.js +1 -1
- package/dist/admin/crud/dict.js +1 -1
- package/dist/admin/crud/index.d.ts +1 -1
- package/dist/admin/crud/index.js +1 -1
- package/dist/admin/crud/key.js +1 -1
- package/dist/admin/crud/mitt.js +1 -1
- package/dist/admin/crud/plugins.js +1 -1
- package/dist/admin/crud/span.js +1 -1
- package/dist/admin/crud/style.d.ts +37 -0
- package/dist/admin/crud/style.js +1 -1
- package/dist/admin/crud/validate.js +1 -1
- package/dist/admin/crud/vm-add-btn.vue +2 -1
- package/dist/admin/crud/vm-adv-search.vue +5 -4
- package/dist/admin/crud/vm-crud.vue +14 -9
- package/dist/admin/crud/vm-export-btn.vue +2 -1
- package/dist/admin/crud/vm-import-btn.vue +2 -1
- package/dist/admin/crud/vm-multi-delete-btn.vue +2 -1
- package/dist/admin/crud/vm-pagination.vue +16 -7
- package/dist/admin/crud/vm-refresh-btn.vue +2 -1
- package/dist/admin/crud/vm-search-key.vue +3 -2
- package/dist/admin/crud/vm-search.vue +29 -20
- package/dist/admin/crud/vm-table.vue +55 -17
- package/dist/admin/crud/vm-toolbar.vue +12 -13
- package/dist/admin/crud/vm-upsert.vue +12 -6
- package/dist/admin/directives/perm.js +1 -1
- package/dist/admin/hooks/useUpload.js +1 -1
- package/dist/admin/index.d.ts +1 -1
- package/dist/admin/index.js +6 -1
- package/dist/admin/lib/browser.js +1 -1
- package/dist/admin/lib/cn.js +1 -1
- package/dist/admin/lib/dialog-float.js +1 -1
- package/dist/admin/lib/export-excel.js +1 -1
- package/dist/admin/lib/file-preview.js +1 -1
- package/dist/admin/lib/import-excel.js +1 -1
- package/dist/admin/lib/json.js +1 -1
- package/dist/admin/lib/menu.js +1 -1
- package/dist/admin/lib/tree.js +1 -1
- package/dist/admin/lib/upload.js +1 -1
- package/dist/admin/lib/video-frame.js +1 -1
- package/dist/admin/styles/base.css +33 -0
- package/dist/ai/index.js +28761 -0
- package/dist/ai.d.ts +1 -0
- package/dist/client/base.js +3 -1
- package/dist/client/index.d.ts +1 -1
- package/dist/client/index.js +3 -5
- package/dist/client/locale-store.d.ts +59 -0
- package/dist/client/locale-store.js +159 -0
- package/dist/client/vite-plugin-eps.js +0 -21
- package/dist/index.js +1 -1
- package/dist/server/index.js +1 -1
- package/dist/shared/excel.js +1 -1
- package/dist/shared/index.js +1 -1
- package/dist/shared/locale-json.js +1 -0
- package/dist/shared/tree.js +1 -1
- package/dist/src/ai/adapters/anthropic-gemini.d.ts +5 -0
- package/dist/src/ai/adapters/auth-headers.d.ts +4 -0
- package/dist/src/ai/adapters/index.d.ts +3 -0
- package/dist/src/ai/adapters/openai-compatible.d.ts +4 -0
- package/dist/src/ai/call-log-helpers.d.ts +13 -0
- package/dist/src/ai/index.d.ts +10 -0
- package/dist/src/ai/normalize.d.ts +18 -0
- package/dist/src/ai/sse.d.ts +13 -0
- package/dist/src/ai/transport.d.ts +16 -0
- package/dist/src/ai/types.d.ts +194 -0
- package/dist/src/core/index.d.ts +1 -1
- package/dist/src/index.d.ts +1 -0
- package/dist/src/orm/index.d.ts +1 -1
- package/dist/src/server/index.d.ts +3 -1
- package/dist/src/shared/index.d.ts +1 -0
- package/dist/src/shared/locale-json.d.ts +7 -0
- package/dist/typings/routing/eps.d.ts +2 -0
- package/package.json +7 -2
- package/src/shared/index.ts +6 -0
- package/src/shared/locale-json.ts +79 -0
- package/typings/admin/comm/crud.d.ts +12 -0
- package/typings/admin/comm/crud.ts +12 -0
- package/typings/admin/comm/eps.d.ts +3 -0
- package/typings/admin/comm/eps.ts +3 -0
- package/typings/admin/comm/request.d.ts +1 -1
- package/typings/admin/comm/request.ts +1 -1
- package/dist/client/ai-model.d.ts +0 -38
- package/dist/client/ai-model.js +0 -39
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
<div class="vm-adv-search">
|
|
3
3
|
<Button size="sm" variant="outline" class="h-8" @click="open = true">
|
|
4
4
|
<i class="ri-filter-3-line" />
|
|
5
|
-
{{ crud.dict.label
|
|
5
|
+
{{ crudLabel('advSearch', crud.dict.label) }}
|
|
6
6
|
</Button>
|
|
7
7
|
<Dialog :open="open" @update:open="onOpenChange">
|
|
8
8
|
<DialogContent
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
>
|
|
15
15
|
<DialogHeader class="vm-crud-shell__head">
|
|
16
16
|
<DialogTitle class="vm-crud-shell__title">
|
|
17
|
-
{{ crud.dict.label
|
|
17
|
+
{{ crudLabel('advSearch', crud.dict.label) }}
|
|
18
18
|
</DialogTitle>
|
|
19
19
|
</DialogHeader>
|
|
20
20
|
<div class="vm-crud-shell__body">
|
|
@@ -26,14 +26,14 @@
|
|
|
26
26
|
class="vm-crud-shell__btn is-ghost"
|
|
27
27
|
@click="reset"
|
|
28
28
|
>
|
|
29
|
-
{{ crud.dict.label
|
|
29
|
+
{{ crudLabel('reset', crud.dict.label) }}
|
|
30
30
|
</button>
|
|
31
31
|
<button
|
|
32
32
|
type="button"
|
|
33
33
|
class="vm-crud-shell__btn is-primary"
|
|
34
34
|
@click="search"
|
|
35
35
|
>
|
|
36
|
-
{{ crud.dict.label
|
|
36
|
+
{{ crudLabel('search', crud.dict.label) }}
|
|
37
37
|
</button>
|
|
38
38
|
</DialogFooter>
|
|
39
39
|
</DialogContent>
|
|
@@ -45,6 +45,7 @@
|
|
|
45
45
|
import { ref } from 'vue'
|
|
46
46
|
import { preventDialogOutsideClose } from '../lib/dialog-float'
|
|
47
47
|
import { useCrud } from './useCrud'
|
|
48
|
+
import { crudLabel } from './style'
|
|
48
49
|
defineOptions({ name: 'vm-adv-search' })
|
|
49
50
|
|
|
50
51
|
const props = withDefaults(
|
|
@@ -12,6 +12,7 @@ import { mergeDict, mergePermission } from './config'
|
|
|
12
12
|
import { vmConfirm } from './confirm'
|
|
13
13
|
import { CRUD_KEY, CRUD_MITT_KEY, injectCrudOptions, injectTableOptions, injectUpsertOptions } from './key'
|
|
14
14
|
import { createMitt } from './mitt'
|
|
15
|
+
import { crudLabel } from './style'
|
|
15
16
|
defineOptions({ name: 'vm-crud' })
|
|
16
17
|
|
|
17
18
|
const props = withDefaults(
|
|
@@ -283,7 +284,9 @@ async function doDelete(targets: Record<string, unknown>[], force = false) {
|
|
|
283
284
|
.map((r) => r[dict.primaryId] as string | number)
|
|
284
285
|
.filter((id) => id != null)
|
|
285
286
|
await svc.delete({ ids, force })
|
|
286
|
-
toast.success(
|
|
287
|
+
toast.success(
|
|
288
|
+
force ? crudLabel('forceDeleted', dict.label) : crudLabel('deleteSuccess', dict.label),
|
|
289
|
+
)
|
|
287
290
|
await refresh()
|
|
288
291
|
}
|
|
289
292
|
|
|
@@ -305,7 +308,9 @@ async function rowDelete(rows?: Record<string, unknown>[], force = false) {
|
|
|
305
308
|
...(payload as { ids: Array<string | number> }),
|
|
306
309
|
force: hard,
|
|
307
310
|
})
|
|
308
|
-
toast.success(
|
|
311
|
+
toast.success(
|
|
312
|
+
hard ? crudLabel('forceDeleted', dict.label) : crudLabel('deleteSuccess', dict.label),
|
|
313
|
+
)
|
|
309
314
|
await refresh()
|
|
310
315
|
return
|
|
311
316
|
}
|
|
@@ -318,13 +323,13 @@ async function rowDelete(rows?: Record<string, unknown>[], force = false) {
|
|
|
318
323
|
}
|
|
319
324
|
|
|
320
325
|
const tip = hard
|
|
321
|
-
? dict.label
|
|
322
|
-
: dict.label
|
|
326
|
+
? crudLabel('forceDeleteConfirm', dict.label)
|
|
327
|
+
: crudLabel('deleteConfirm', dict.label)
|
|
323
328
|
const ok = await vmConfirm({
|
|
324
|
-
title: hard ? '
|
|
329
|
+
title: hard ? crudLabel('forceDelete', dict.label) : crudLabel('tips', dict.label),
|
|
325
330
|
message: tip,
|
|
326
|
-
confirmText: '
|
|
327
|
-
cancelText: '
|
|
331
|
+
confirmText: crudLabel('confirm', dict.label),
|
|
332
|
+
cancelText: crudLabel('close', dict.label),
|
|
328
333
|
})
|
|
329
334
|
if (!ok) return
|
|
330
335
|
await next()
|
|
@@ -362,11 +367,11 @@ async function upsertSubmit() {
|
|
|
362
367
|
if (upsertMode.value === 'add') {
|
|
363
368
|
if (!svc.add) throw new Error('未配置 add')
|
|
364
369
|
await svc.add(data)
|
|
365
|
-
toast.success(dict.label
|
|
370
|
+
toast.success(crudLabel('saveSuccess', dict.label))
|
|
366
371
|
} else {
|
|
367
372
|
if (!svc.update) throw new Error('未配置 update')
|
|
368
373
|
await svc.update(data)
|
|
369
|
-
toast.success(dict.label
|
|
374
|
+
toast.success(crudLabel('saveSuccess', dict.label))
|
|
370
375
|
}
|
|
371
376
|
const after = async () => {
|
|
372
377
|
upsertVisible.value = false
|
|
@@ -25,6 +25,7 @@ import {
|
|
|
25
25
|
type TableApi,
|
|
26
26
|
} from './key'
|
|
27
27
|
import { useCrud } from './useCrud'
|
|
28
|
+
import { crudLabel } from './style'
|
|
28
29
|
|
|
29
30
|
defineOptions({ name: 'vm-export-btn' })
|
|
30
31
|
|
|
@@ -59,7 +60,7 @@ const submitting = ref(false)
|
|
|
59
60
|
const visible = computed(() => Boolean(crud.getPermission(props.permission)))
|
|
60
61
|
|
|
61
62
|
const buttonText = computed(
|
|
62
|
-
() => props.text || crud.dict.label
|
|
63
|
+
() => props.text || crudLabel('export', crud.dict.label),
|
|
63
64
|
)
|
|
64
65
|
|
|
65
66
|
const exportColumns = computed(() => {
|
|
@@ -167,6 +167,7 @@ import {
|
|
|
167
167
|
uploadImportExcel,
|
|
168
168
|
} from '../lib/import-excel'
|
|
169
169
|
import { useCrud } from './useCrud'
|
|
170
|
+
import { crudLabel } from './style'
|
|
170
171
|
|
|
171
172
|
defineOptions({ name: 'vm-import-btn' })
|
|
172
173
|
|
|
@@ -215,7 +216,7 @@ const dragDepth = ref(0)
|
|
|
215
216
|
const visible = computed(() => Boolean(crud.getPermission(props.permission)))
|
|
216
217
|
|
|
217
218
|
const buttonText = computed(
|
|
218
|
-
() => props.text || crud.dict.label
|
|
219
|
+
() => props.text || crudLabel('import', crud.dict.label),
|
|
219
220
|
)
|
|
220
221
|
|
|
221
222
|
const totalPages = computed(() =>
|
|
@@ -7,12 +7,13 @@
|
|
|
7
7
|
@click="crud.rowDelete()"
|
|
8
8
|
>
|
|
9
9
|
<i class="ri-delete-bin-line" />
|
|
10
|
-
{{ crud.dict.label
|
|
10
|
+
{{ crudLabel('multiDelete', crud.dict.label) }}
|
|
11
11
|
</button>
|
|
12
12
|
</template>
|
|
13
13
|
|
|
14
14
|
<script setup lang="ts">
|
|
15
15
|
import { useCrud } from './useCrud'
|
|
16
|
+
import { crudLabel } from './style'
|
|
16
17
|
|
|
17
18
|
defineOptions({ name: 'vm-multi-delete-btn' })
|
|
18
19
|
const crud = useCrud()
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div class="vm-crud-pagination">
|
|
3
|
-
<span class="vm-crud-pagination__total"
|
|
3
|
+
<span class="vm-crud-pagination__total">{{ totalText }}</span>
|
|
4
4
|
<div class="vm-crud-pagination__actions">
|
|
5
5
|
<Select
|
|
6
6
|
:model-value="String(crud.pagination.value.size)"
|
|
@@ -10,10 +10,9 @@
|
|
|
10
10
|
<SelectValue />
|
|
11
11
|
</SelectTrigger>
|
|
12
12
|
<SelectContent>
|
|
13
|
-
<SelectItem
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
<SelectItem value="100">100 / 页</SelectItem>
|
|
13
|
+
<SelectItem v-for="n in pageSizes" :key="n" :value="String(n)">
|
|
14
|
+
{{ pageSizeText(n) }}
|
|
15
|
+
</SelectItem>
|
|
17
16
|
</SelectContent>
|
|
18
17
|
</Select>
|
|
19
18
|
<button
|
|
@@ -22,7 +21,7 @@
|
|
|
22
21
|
:disabled="crud.pagination.value.page <= 1"
|
|
23
22
|
@click="go(crud.pagination.value.page - 1)"
|
|
24
23
|
>
|
|
25
|
-
|
|
24
|
+
{{ crudLabel('prevPage', crud.dict.label) }}
|
|
26
25
|
</button>
|
|
27
26
|
<span class="vm-crud-pagination__page">
|
|
28
27
|
{{ crud.pagination.value.page }} / {{ totalPages }}
|
|
@@ -33,7 +32,7 @@
|
|
|
33
32
|
:disabled="crud.pagination.value.page >= totalPages"
|
|
34
33
|
@click="go(crud.pagination.value.page + 1)"
|
|
35
34
|
>
|
|
36
|
-
|
|
35
|
+
{{ crudLabel('nextPage', crud.dict.label) }}
|
|
37
36
|
</button>
|
|
38
37
|
</div>
|
|
39
38
|
</div>
|
|
@@ -42,15 +41,25 @@
|
|
|
42
41
|
<script setup lang="ts">
|
|
43
42
|
import { computed } from 'vue'
|
|
44
43
|
import { useCrud } from './useCrud'
|
|
44
|
+
import { crudFormat, crudLabel } from './style'
|
|
45
45
|
|
|
46
46
|
defineOptions({ name: 'vm-pagination' })
|
|
47
47
|
|
|
48
48
|
const crud = useCrud()
|
|
49
|
+
const pageSizes = [10, 20, 50, 100]
|
|
49
50
|
|
|
50
51
|
const totalPages = computed(() =>
|
|
51
52
|
Math.max(1, Math.ceil(crud.pagination.value.total / crud.pagination.value.size) || 1),
|
|
52
53
|
)
|
|
53
54
|
|
|
55
|
+
const totalText = computed(() =>
|
|
56
|
+
crudFormat(crudLabel('total', crud.dict.label), crud.pagination.value.total),
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
function pageSizeText(n: number) {
|
|
60
|
+
return crudFormat(crudLabel('pageSize', crud.dict.label), n)
|
|
61
|
+
}
|
|
62
|
+
|
|
54
63
|
function go(page: number) {
|
|
55
64
|
const next = Math.min(Math.max(1, page), totalPages.value)
|
|
56
65
|
crud.pagination.value = { ...crud.pagination.value, page: next }
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<button type="button" class="vm-crud-toolbar__btn is-ghost" @click="crud.refresh()">
|
|
3
3
|
<i class="ri-refresh-line" />
|
|
4
|
-
{{ crud.dict.label
|
|
4
|
+
{{ crudLabel('refresh', crud.dict.label) }}
|
|
5
5
|
</button>
|
|
6
6
|
</template>
|
|
7
7
|
|
|
8
8
|
<script setup lang="ts">
|
|
9
9
|
import { useCrud } from './useCrud'
|
|
10
|
+
import { crudLabel } from './style'
|
|
10
11
|
|
|
11
12
|
defineOptions({ name: 'vm-refresh-btn' })
|
|
12
13
|
const crud = useCrud()
|
|
@@ -3,12 +3,12 @@
|
|
|
3
3
|
<Input
|
|
4
4
|
class="vm-crud-search-key__input"
|
|
5
5
|
:model-value="keyword"
|
|
6
|
-
:placeholder="placeholder || crud.dict.label
|
|
6
|
+
:placeholder="placeholder || crudLabel('searchKey', crud.dict.label)"
|
|
7
7
|
@update:model-value="onInput"
|
|
8
8
|
@keydown.enter.prevent="search"
|
|
9
9
|
/>
|
|
10
10
|
<button type="button" class="vm-crud-search-key__btn" @click="search">
|
|
11
|
-
{{ crud.dict.label
|
|
11
|
+
{{ crudLabel('search', crud.dict.label) }}
|
|
12
12
|
</button>
|
|
13
13
|
</div>
|
|
14
14
|
</template>
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
<script setup lang="ts">
|
|
17
17
|
import { ref } from 'vue'
|
|
18
18
|
import { useCrud } from './useCrud'
|
|
19
|
+
import { crudLabel } from './style'
|
|
19
20
|
|
|
20
21
|
defineOptions({ name: 'vm-search-key' })
|
|
21
22
|
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
@update:model-value="(v) => (form[item.prop] = coerceSelect(item, v))"
|
|
18
18
|
>
|
|
19
19
|
<SelectTrigger class="vm-crud-search__control">
|
|
20
|
-
<SelectValue :placeholder="item
|
|
20
|
+
<SelectValue :placeholder="itemPlaceholder(item)" />
|
|
21
21
|
</SelectTrigger>
|
|
22
22
|
<SelectContent>
|
|
23
23
|
<SelectItem
|
|
@@ -33,15 +33,19 @@
|
|
|
33
33
|
v-else
|
|
34
34
|
class="vm-crud-search__control"
|
|
35
35
|
:model-value="String(form[item.prop] ?? '')"
|
|
36
|
-
:placeholder="item
|
|
36
|
+
:placeholder="itemPlaceholder(item)"
|
|
37
37
|
@update:model-value="(v) => (form[item.prop] = v)"
|
|
38
38
|
@keydown.enter.prevent="search"
|
|
39
39
|
/>
|
|
40
40
|
</template>
|
|
41
41
|
</div>
|
|
42
42
|
<div v-if="inlineActions" class="vm-crud-search__actions">
|
|
43
|
-
<button type="button" class="vm-crud-search__btn is-primary" @click="search"
|
|
44
|
-
|
|
43
|
+
<button type="button" class="vm-crud-search__btn is-primary" @click="search">
|
|
44
|
+
{{ crudLabel('search', crud.dict.label) }}
|
|
45
|
+
</button>
|
|
46
|
+
<button type="button" class="vm-crud-search__btn is-ghost" @click="reset">
|
|
47
|
+
{{ crudLabel('reset', crud.dict.label) }}
|
|
48
|
+
</button>
|
|
45
49
|
<slot />
|
|
46
50
|
</div>
|
|
47
51
|
</div>
|
|
@@ -53,7 +57,13 @@ import { onBeforeUnmount } from 'vue'
|
|
|
53
57
|
import { useCrud } from './useCrud'
|
|
54
58
|
import { injectSearchOptions } from './key'
|
|
55
59
|
import { buildAutoSearchItems } from './plugins'
|
|
56
|
-
import {
|
|
60
|
+
import {
|
|
61
|
+
getCrudStyle,
|
|
62
|
+
crudLocaleRev,
|
|
63
|
+
crudLabel,
|
|
64
|
+
resolveSearchPlaceholder,
|
|
65
|
+
resolveRangePlaceholders,
|
|
66
|
+
} from './style'
|
|
57
67
|
import { resolveCrudComponent } from './registry'
|
|
58
68
|
import { service } from '../service'
|
|
59
69
|
defineOptions({ name: 'vm-search' })
|
|
@@ -85,7 +95,14 @@ function mergeSearchItems(auto: CrudSearchItem[], manual: CrudSearchItem[]) {
|
|
|
85
95
|
return merged
|
|
86
96
|
}
|
|
87
97
|
|
|
88
|
-
const items = computed(() =>
|
|
98
|
+
const items = computed(() => {
|
|
99
|
+
void crudLocaleRev.value
|
|
100
|
+
return mergeSearchItems(autoItems.value, manualItems.value)
|
|
101
|
+
})
|
|
102
|
+
|
|
103
|
+
function itemPlaceholder(item: CrudSearchItem) {
|
|
104
|
+
return resolveSearchPlaceholder(item)
|
|
105
|
+
}
|
|
89
106
|
|
|
90
107
|
const form = reactive<Record<string, unknown>>({})
|
|
91
108
|
|
|
@@ -194,30 +211,22 @@ function resolveField(item: CrudSearchItem) {
|
|
|
194
211
|
}
|
|
195
212
|
|
|
196
213
|
function fieldProps(item: CrudSearchItem) {
|
|
197
|
-
const
|
|
214
|
+
const ph = itemPlaceholder(item)
|
|
198
215
|
const rangePlaceholders =
|
|
199
|
-
item.type === 'number-range'
|
|
200
|
-
?
|
|
201
|
-
|
|
202
|
-
endPlaceholder: `${name}最大值`,
|
|
203
|
-
}
|
|
204
|
-
: item.type === 'daterange' && name
|
|
205
|
-
? {
|
|
206
|
-
startPlaceholder: `${name}开始`,
|
|
207
|
-
endPlaceholder: `${name}结束`,
|
|
208
|
-
}
|
|
209
|
-
: {}
|
|
216
|
+
item.type === 'number-range' || item.type === 'daterange' || item.phMode === 'range'
|
|
217
|
+
? resolveRangePlaceholders(item)
|
|
218
|
+
: {}
|
|
210
219
|
return {
|
|
211
220
|
options: resolveOptions(item.options),
|
|
212
|
-
placeholder: item.placeholder || item.label,
|
|
213
221
|
refreshOnChange: false,
|
|
214
222
|
precision: item.range?.rangeType,
|
|
215
223
|
mode:
|
|
216
224
|
item.range?.rangeType === 'float' || item.range?.rangeType === 'int'
|
|
217
225
|
? item.range.rangeType
|
|
218
226
|
: undefined,
|
|
219
|
-
...rangePlaceholders,
|
|
220
227
|
...(item.component?.props || {}),
|
|
228
|
+
placeholder: ph,
|
|
229
|
+
...rangePlaceholders,
|
|
221
230
|
}
|
|
222
231
|
}
|
|
223
232
|
|
|
@@ -6,7 +6,9 @@
|
|
|
6
6
|
'is-auto-height': autoHeight,
|
|
7
7
|
}"
|
|
8
8
|
>
|
|
9
|
-
<div v-if="crud.loading.value" class="vm-crud-table__loading"
|
|
9
|
+
<div v-if="crud.loading.value" class="vm-crud-table__loading">
|
|
10
|
+
{{ crudLabel('loading', crud.dict.label) }}
|
|
11
|
+
</div>
|
|
10
12
|
<div ref="scrollRef" class="vm-crud-table__scroll vm-scroll">
|
|
11
13
|
<Table>
|
|
12
14
|
<TableHeader>
|
|
@@ -26,7 +28,7 @@
|
|
|
26
28
|
@click="onSortClick(col)"
|
|
27
29
|
>
|
|
28
30
|
<span class="vm-crud-table__th-inner">
|
|
29
|
-
{{ col
|
|
31
|
+
{{ columnLabel(col) }}
|
|
30
32
|
<i
|
|
31
33
|
v-if="isSortable(col) && col.prop"
|
|
32
34
|
class="vm-crud-table__sort"
|
|
@@ -39,7 +41,7 @@
|
|
|
39
41
|
class="vm-crud-table__th vm-crud-table__op"
|
|
40
42
|
:style="{ width: `${opWidth}px`, minWidth: `${opWidth}px` }"
|
|
41
43
|
>
|
|
42
|
-
{{ crud.dict.label
|
|
44
|
+
{{ crudLabel('op', crud.dict.label) }}
|
|
43
45
|
</TableHead>
|
|
44
46
|
</TableRow>
|
|
45
47
|
</TableHeader>
|
|
@@ -85,14 +87,14 @@
|
|
|
85
87
|
class="vm-crud-table__ops"
|
|
86
88
|
>
|
|
87
89
|
<Button size="xs" variant="softPrimary" @click="crud.rowRestore([row])">
|
|
88
|
-
|
|
90
|
+
{{ crudLabel('restore', crud.dict.label) }}
|
|
89
91
|
</Button>
|
|
90
92
|
<Button
|
|
91
93
|
size="xs"
|
|
92
94
|
variant="softDestructive"
|
|
93
95
|
@click="crud.rowDelete([row], true)"
|
|
94
96
|
>
|
|
95
|
-
|
|
97
|
+
{{ crudLabel('forceDelete', crud.dict.label) }}
|
|
96
98
|
</Button>
|
|
97
99
|
</div>
|
|
98
100
|
<div v-else class="vm-crud-table__ops">
|
|
@@ -104,7 +106,7 @@
|
|
|
104
106
|
variant="softPrimary"
|
|
105
107
|
@click.stop="crud.rowEdit(row)"
|
|
106
108
|
>
|
|
107
|
-
{{ crud.dict.label
|
|
109
|
+
{{ crudLabel('update', crud.dict.label) }}
|
|
108
110
|
</Button>
|
|
109
111
|
<Button
|
|
110
112
|
v-else-if="btn === 'delete' && crud.getPermission('delete')"
|
|
@@ -113,7 +115,7 @@
|
|
|
113
115
|
variant="softDestructive"
|
|
114
116
|
@click.stop="crud.rowDelete([row])"
|
|
115
117
|
>
|
|
116
|
-
{{ crud.dict.label
|
|
118
|
+
{{ crudLabel('delete', crud.dict.label) }}
|
|
117
119
|
</Button>
|
|
118
120
|
<Button
|
|
119
121
|
v-else-if="btn === 'info' && crud.getPermission('info')"
|
|
@@ -122,7 +124,7 @@
|
|
|
122
124
|
variant="ghost"
|
|
123
125
|
@click.stop="crud.rowInfo(row)"
|
|
124
126
|
>
|
|
125
|
-
{{ crud.dict.label
|
|
127
|
+
{{ crudLabel('info', crud.dict.label) }}
|
|
126
128
|
</Button>
|
|
127
129
|
<Button
|
|
128
130
|
v-else-if="typeof btn === 'object' && !btn.hidden"
|
|
@@ -208,14 +210,14 @@
|
|
|
208
210
|
class="vm-crud-table__ops"
|
|
209
211
|
>
|
|
210
212
|
<Button size="xs" variant="softPrimary" @click="crud.rowRestore([row])">
|
|
211
|
-
|
|
213
|
+
{{ crudLabel('restore', crud.dict.label) }}
|
|
212
214
|
</Button>
|
|
213
215
|
<Button
|
|
214
216
|
size="xs"
|
|
215
217
|
variant="softDestructive"
|
|
216
218
|
@click="crud.rowDelete([row], true)"
|
|
217
219
|
>
|
|
218
|
-
|
|
220
|
+
{{ crudLabel('forceDelete', crud.dict.label) }}
|
|
219
221
|
</Button>
|
|
220
222
|
</div>
|
|
221
223
|
<slot v-else name="op" :row="row" />
|
|
@@ -234,7 +236,8 @@ import { useCrud } from './useCrud'
|
|
|
234
236
|
import { injectTableOptions, TABLE_API_KEY } from './key'
|
|
235
237
|
import { flattenTree } from '../lib/tree'
|
|
236
238
|
import { resolveCrudComponent } from './registry'
|
|
237
|
-
import { getCrudStyle } from './style'
|
|
239
|
+
import { getCrudStyle, crudLabel, crudT, crudLocaleRev } from './style'
|
|
240
|
+
import { findEpsEntity } from '../lib/eps'
|
|
238
241
|
defineOptions({ name: 'vm-table' })
|
|
239
242
|
|
|
240
243
|
const props = withDefaults(
|
|
@@ -289,6 +292,41 @@ const dataColumns = computed(() =>
|
|
|
289
292
|
)
|
|
290
293
|
const showSlotOp = computed(() => Boolean(slots.op) && !hasOpCol.value)
|
|
291
294
|
|
|
295
|
+
/** EPS 列 → field.{table}.{prop} */
|
|
296
|
+
function epsFieldKey(prop: string): string | undefined {
|
|
297
|
+
const ns = (crud.service as { namespace?: string } | undefined)?.namespace
|
|
298
|
+
if (!ns || !prop) return undefined
|
|
299
|
+
const entity = findEpsEntity(`/${ns}`)
|
|
300
|
+
if (!entity) return undefined
|
|
301
|
+
const cols = [
|
|
302
|
+
...((entity as { columns?: Array<{ propertyName?: string; table?: string; source?: string }> }).columns || []),
|
|
303
|
+
...((entity as { pageColumns?: Array<{ propertyName?: string; table?: string; source?: string }> }).pageColumns || []),
|
|
304
|
+
]
|
|
305
|
+
const meta =
|
|
306
|
+
cols.find((c) => c.propertyName === prop) ||
|
|
307
|
+
cols.find((c) => c.source === `a.${prop}`) ||
|
|
308
|
+
cols.find((c) => c.source?.endsWith(`.${prop}`))
|
|
309
|
+
const table = meta?.table?.trim()
|
|
310
|
+
const name = (meta?.propertyName || prop).trim()
|
|
311
|
+
if (!table || !name) return undefined
|
|
312
|
+
return `${table}.${name}`
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
/** 表头文案:labelKey → field.* → label / op */
|
|
316
|
+
function columnLabel(col: CrudColumn): string {
|
|
317
|
+
void crudLocaleRev.value
|
|
318
|
+
if (col.type === 'op') {
|
|
319
|
+
return col.labelKey
|
|
320
|
+
? crudT(col.labelKey, col.label || crudLabel('op', crud.dict.label))
|
|
321
|
+
: col.label || crudLabel('op', crud.dict.label)
|
|
322
|
+
}
|
|
323
|
+
const fb = col.label || col.prop || ''
|
|
324
|
+
if (col.labelKey) return crudT(col.labelKey, fb)
|
|
325
|
+
const fk = col.fieldKey || (col.prop ? epsFieldKey(col.prop) : undefined)
|
|
326
|
+
if (fk) return crudT(`field.${fk}`, fb)
|
|
327
|
+
return fb
|
|
328
|
+
}
|
|
329
|
+
|
|
292
330
|
const colSpan = computed(
|
|
293
331
|
() =>
|
|
294
332
|
dataColumns.value.length +
|
|
@@ -408,12 +446,12 @@ const ctxItems = computed<CtxMenuItem[]>(() => {
|
|
|
408
446
|
? conf
|
|
409
447
|
: ['refresh', 'check', 'edit', 'delete', 'order-asc', 'order-desc']
|
|
410
448
|
const map: Record<string, string> = {
|
|
411
|
-
refresh: crud.dict.label
|
|
412
|
-
check: crud.dict.label
|
|
413
|
-
edit: crud.dict.label
|
|
414
|
-
delete: crud.dict.label
|
|
415
|
-
'order-asc': crud.dict.label
|
|
416
|
-
'order-desc': crud.dict.label
|
|
449
|
+
refresh: crudLabel('refresh', crud.dict.label),
|
|
450
|
+
check: crudLabel('select', crud.dict.label),
|
|
451
|
+
edit: crudLabel('update', crud.dict.label),
|
|
452
|
+
delete: crudLabel('delete', crud.dict.label),
|
|
453
|
+
'order-asc': crudLabel('asc', crud.dict.label),
|
|
454
|
+
'order-desc': crudLabel('desc', crud.dict.label),
|
|
417
455
|
}
|
|
418
456
|
return keys.map((k) => ({
|
|
419
457
|
key: k,
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
@click="onAdd"
|
|
9
9
|
>
|
|
10
10
|
<i class="ri-add-line" />
|
|
11
|
-
{{ addText
|
|
11
|
+
{{ addText ?? crudLabel('add', crud.dict.label) }}
|
|
12
12
|
</button>
|
|
13
13
|
<button
|
|
14
14
|
v-if="showDelete && crud.getPermission('delete')"
|
|
@@ -18,11 +18,11 @@
|
|
|
18
18
|
@click="crud.rowDelete()"
|
|
19
19
|
>
|
|
20
20
|
<i class="ri-delete-bin-line" />
|
|
21
|
-
{{ deleteText
|
|
21
|
+
{{ deleteText ?? crudLabel('multiDelete', crud.dict.label) }}
|
|
22
22
|
</button>
|
|
23
23
|
<vm-export-btn
|
|
24
24
|
v-if="showExport"
|
|
25
|
-
:text="exportText || crud.dict.label
|
|
25
|
+
:text="exportText || crudLabel('export', crud.dict.label)"
|
|
26
26
|
:filename="exportFilename"
|
|
27
27
|
:max-export-limit="maxExportLimit"
|
|
28
28
|
:columns="exportColumns"
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
/>
|
|
31
31
|
<vm-import-btn
|
|
32
32
|
v-if="showImport"
|
|
33
|
-
:text="importText || crud.dict.label
|
|
33
|
+
:text="importText || crudLabel('import', crud.dict.label)"
|
|
34
34
|
:tip="importTip"
|
|
35
35
|
:template-filename="importTemplateFilename"
|
|
36
36
|
:max-size-mb="importMaxSizeMb"
|
|
@@ -41,10 +41,10 @@
|
|
|
41
41
|
<slot name="right" />
|
|
42
42
|
<div v-if="showSearchActions" class="vm-crud-toolbar__search">
|
|
43
43
|
<button type="button" class="vm-crud-toolbar__btn is-primary" @click="onSearch">
|
|
44
|
-
|
|
44
|
+
{{ crudLabel('search', crud.dict.label) }}
|
|
45
45
|
</button>
|
|
46
46
|
<button type="button" class="vm-crud-toolbar__btn is-ghost" @click="onReset">
|
|
47
|
-
|
|
47
|
+
{{ crudLabel('reset', crud.dict.label) }}
|
|
48
48
|
</button>
|
|
49
49
|
</div>
|
|
50
50
|
<vm-tabs
|
|
@@ -63,13 +63,9 @@ import { useCrud } from './useCrud'
|
|
|
63
63
|
import VmExportBtn from './vm-export-btn.vue'
|
|
64
64
|
import VmImportBtn from './vm-import-btn.vue'
|
|
65
65
|
import VmTabs from './vm-tabs.vue'
|
|
66
|
+
import { crudLabel } from './style'
|
|
66
67
|
defineOptions({ name: 'vm-toolbar' })
|
|
67
68
|
|
|
68
|
-
const trashTabs = [
|
|
69
|
-
{ label: '列表', value: 'default' as const },
|
|
70
|
-
{ label: '回收站', value: 'onlyTrashed' as const },
|
|
71
|
-
]
|
|
72
|
-
|
|
73
69
|
const props = withDefaults(
|
|
74
70
|
defineProps<{
|
|
75
71
|
trash?: boolean
|
|
@@ -107,8 +103,6 @@ const props = withDefaults(
|
|
|
107
103
|
showExport: true,
|
|
108
104
|
showImport: true,
|
|
109
105
|
hideAddInTrash: true,
|
|
110
|
-
addText: '新增',
|
|
111
|
-
deleteText: '删除',
|
|
112
106
|
maxExportLimit: 5000,
|
|
113
107
|
importMaxSizeMb: 10,
|
|
114
108
|
},
|
|
@@ -116,6 +110,11 @@ const props = withDefaults(
|
|
|
116
110
|
|
|
117
111
|
const crud = useCrud()
|
|
118
112
|
|
|
113
|
+
const trashTabs = computed(() => [
|
|
114
|
+
{ label: crudLabel('list', crud.dict.label), value: 'default' as const },
|
|
115
|
+
{ label: crudLabel('trash', crud.dict.label), value: 'onlyTrashed' as const },
|
|
116
|
+
])
|
|
117
|
+
|
|
119
118
|
/** 是否显示新增:权限与回收站 */
|
|
120
119
|
const showAddBtn = computed(() => {
|
|
121
120
|
if (!props.showAdd) return false
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
>
|
|
6
6
|
<DialogContent
|
|
7
7
|
shell="crud"
|
|
8
|
+
:show-close-button="false"
|
|
8
9
|
class="vm-crud-upsert"
|
|
9
10
|
:class="{
|
|
10
11
|
'is-empty': isBodyEmpty,
|
|
@@ -17,6 +18,11 @@
|
|
|
17
18
|
>
|
|
18
19
|
<DialogHeader class="vm-crud-shell__head">
|
|
19
20
|
<DialogTitle class="vm-crud-shell__title">{{ titleText }}</DialogTitle>
|
|
21
|
+
<slot name="title-extra" />
|
|
22
|
+
<DialogClose class="vm-crud-shell__close">
|
|
23
|
+
<i class="ri-close-line" />
|
|
24
|
+
<span class="sr-only">Close</span>
|
|
25
|
+
</DialogClose>
|
|
20
26
|
</DialogHeader>
|
|
21
27
|
<div
|
|
22
28
|
class="vm-crud-upsert__body"
|
|
@@ -134,7 +140,7 @@ import { ref, computed, watch, useSlots } from 'vue'
|
|
|
134
140
|
import { toast } from 'vue-sonner'
|
|
135
141
|
import { useCrud } from './useCrud'
|
|
136
142
|
import { injectUpsertOptions } from './key'
|
|
137
|
-
import { getCrudStyle } from './style'
|
|
143
|
+
import { getCrudStyle, crudLabel } from './style'
|
|
138
144
|
import { resolveCrudComponent } from './registry'
|
|
139
145
|
import { applySetRules, validateFormFields } from './validate'
|
|
140
146
|
import { resolveFormSpan, useFormCols } from './span'
|
|
@@ -199,9 +205,9 @@ const mergedItems = computed(() => {
|
|
|
199
205
|
const titleText = computed(() => {
|
|
200
206
|
if (props.title != null && props.title !== '') return props.title
|
|
201
207
|
if (upsertOpts?.dialog?.title) return upsertOpts.dialog.title
|
|
202
|
-
if (crud.upsertMode.value === 'add') return crud.dict.label
|
|
203
|
-
if (crud.upsertMode.value === 'info') return crud.dict.label
|
|
204
|
-
return crud.dict.label
|
|
208
|
+
if (crud.upsertMode.value === 'add') return crudLabel('add', crud.dict.label)
|
|
209
|
+
if (crud.upsertMode.value === 'info') return crudLabel('info', crud.dict.label)
|
|
210
|
+
return crudLabel('update', crud.dict.label)
|
|
205
211
|
})
|
|
206
212
|
|
|
207
213
|
const visibleItems = computed(() =>
|
|
@@ -238,13 +244,13 @@ const confirmLabel = computed(
|
|
|
238
244
|
() =>
|
|
239
245
|
props.confirmText ||
|
|
240
246
|
upsertOpts?.dialog?.confirmText ||
|
|
241
|
-
crud.dict.label
|
|
247
|
+
crudLabel('confirm', crud.dict.label),
|
|
242
248
|
)
|
|
243
249
|
const closeLabel = computed(
|
|
244
250
|
() =>
|
|
245
251
|
props.closeText ||
|
|
246
252
|
upsertOpts?.dialog?.closeText ||
|
|
247
|
-
crud.dict.label
|
|
253
|
+
crudLabel('close', crud.dict.label),
|
|
248
254
|
)
|
|
249
255
|
const isBodyEmpty = computed(
|
|
250
256
|
() => !visibleItems.value.length && !slots.default,
|