@hostlink/nuxt-light 1.30.0 → 1.31.1
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/module.json +1 -1
- package/dist/runtime/components/l-customizer.vue +1 -0
- package/dist/runtime/components/l-input.vue +10 -10
- package/dist/runtime/components/l-input.vue.d.ts +15 -3
- package/dist/runtime/components/l-table.vue +120 -121
- package/dist/runtime/components/l-table.vue.d.ts +12 -35
- package/dist/runtime/pages/MailLog/index.vue +16 -5
- package/dist/runtime/pages/Permission/all.vue +49 -43
- package/dist/runtime/pages/System/database/backup.vue +21 -19
- package/dist/runtime/pages/System/database/process.vue +11 -13
- package/dist/runtime/pages/System/database/table.vue +12 -12
- package/dist/runtime/pages/User/setting/style.vue +1 -0
- package/package.json +1 -1
package/dist/module.json
CHANGED
|
@@ -60,8 +60,8 @@ const props = defineProps({
|
|
|
60
60
|
onBlur: { type: Function, required: false },
|
|
61
61
|
onClear: { type: Function, required: false }
|
|
62
62
|
});
|
|
63
|
-
const modelValue =
|
|
64
|
-
const new_rules = props.rules
|
|
63
|
+
const modelValue = defineModel();
|
|
64
|
+
const new_rules = Array.isArray(props.rules) ? [...props.rules] : [];
|
|
65
65
|
if (props.required) {
|
|
66
66
|
new_rules.push((val) => !!val || t("input_required", [t(props.label ?? "")]));
|
|
67
67
|
}
|
|
@@ -72,28 +72,29 @@ if (props.type == "email") {
|
|
|
72
72
|
}
|
|
73
73
|
});
|
|
74
74
|
}
|
|
75
|
-
|
|
75
|
+
const stringRules = new_rules.filter((r) => typeof r === "string");
|
|
76
|
+
if (stringRules.includes("containUpper")) {
|
|
76
77
|
new_rules.push((val) => {
|
|
77
78
|
if (val && !val.match(/[A-Z]/)) {
|
|
78
79
|
return t("Must contain at least one uppercase letter");
|
|
79
80
|
}
|
|
80
81
|
});
|
|
81
82
|
}
|
|
82
|
-
if (
|
|
83
|
+
if (stringRules.includes("containLower")) {
|
|
83
84
|
new_rules.push((val) => {
|
|
84
85
|
if (val && !val.match(/[a-z]/)) {
|
|
85
86
|
return t("Must contain at least one lowercase letter");
|
|
86
87
|
}
|
|
87
88
|
});
|
|
88
89
|
}
|
|
89
|
-
if (
|
|
90
|
+
if (stringRules.includes("containNumber")) {
|
|
90
91
|
new_rules.push((val) => {
|
|
91
92
|
if (val && !val.match(/[0-9]/)) {
|
|
92
93
|
return t("Must contain at least one number");
|
|
93
94
|
}
|
|
94
95
|
});
|
|
95
96
|
}
|
|
96
|
-
if (
|
|
97
|
+
if (stringRules.includes("containSpecial")) {
|
|
97
98
|
new_rules.push((val) => {
|
|
98
99
|
if (val && !val.match(/[!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?]/)) {
|
|
99
100
|
return t("Must contain at least one symbol");
|
|
@@ -154,10 +155,9 @@ const onClickTc2Sc = () => {
|
|
|
154
155
|
</template>
|
|
155
156
|
|
|
156
157
|
<template v-if="localShowPassword" v-slot:append>
|
|
157
|
-
<q-icon name="sym_o_visibility" class="cursor-pointer"
|
|
158
|
-
|
|
159
|
-
<q-icon name="sym_o_visibility_off" class="cursor-pointer"
|
|
160
|
-
@click="isShowPassword = true" v-else />
|
|
158
|
+
<q-icon name="sym_o_visibility" class="cursor-pointer" @click="isShowPassword = false"
|
|
159
|
+
v-if="isShowPassword" />
|
|
160
|
+
<q-icon name="sym_o_visibility_off" class="cursor-pointer" @click="isShowPassword = true" v-else />
|
|
161
161
|
</template>
|
|
162
162
|
|
|
163
163
|
</q-input>
|
|
@@ -4,23 +4,31 @@ export interface LInputProps extends QInputProps {
|
|
|
4
4
|
translate?: boolean;
|
|
5
5
|
required?: boolean;
|
|
6
6
|
}
|
|
7
|
+
type __VLS_Props = LInputProps;
|
|
7
8
|
declare const new_rules: import("quasar").ValidationRule[];
|
|
8
9
|
declare const isShowPassword: import("vue").Ref<boolean, boolean>;
|
|
9
10
|
declare const localType: import("vue").ComputedRef<"number" | "textarea" | "time" | "text" | "search" | "date" | "url" | "email" | "file" | "datetime-local" | "password" | "tel" | undefined>;
|
|
10
11
|
declare const localShowPassword: import("vue").ComputedRef<boolean>;
|
|
11
12
|
declare const onClickTc2Sc: () => void;
|
|
13
|
+
type __VLS_PublicProps = __VLS_Props & {
|
|
14
|
+
modelValue?: any;
|
|
15
|
+
};
|
|
12
16
|
declare const __VLS_ctx: InstanceType<__VLS_PickNotAny<typeof __VLS_self, new () => {}>>;
|
|
13
17
|
declare var __VLS_31: string | number, __VLS_32: any;
|
|
14
18
|
type __VLS_Slots = __VLS_PrettifyGlobal<__VLS_OmitStringIndex<typeof __VLS_ctx.$slots> & {
|
|
15
19
|
[K in NonNullable<typeof __VLS_31>]?: (props: typeof __VLS_32) => any;
|
|
16
20
|
}>;
|
|
17
|
-
declare const __VLS_self: import("vue").DefineComponent<
|
|
21
|
+
declare const __VLS_self: import("vue").DefineComponent<__VLS_PublicProps, {
|
|
18
22
|
new_rules: typeof new_rules;
|
|
19
23
|
isShowPassword: typeof isShowPassword;
|
|
20
24
|
localType: typeof localType;
|
|
21
25
|
localShowPassword: typeof localShowPassword;
|
|
22
26
|
onClickTc2Sc: typeof onClickTc2Sc;
|
|
23
|
-
}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
27
|
+
}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
28
|
+
"update:modelValue": (value: any) => any;
|
|
29
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
30
|
+
"onUpdate:modelValue"?: ((value: any) => any) | undefined;
|
|
31
|
+
}>, {
|
|
24
32
|
dense: boolean;
|
|
25
33
|
dark: boolean | null;
|
|
26
34
|
rounded: boolean;
|
|
@@ -31,7 +39,11 @@ declare const __VLS_self: import("vue").DefineComponent<LInputProps, {
|
|
|
31
39
|
standout: string | boolean;
|
|
32
40
|
stackLabel: boolean;
|
|
33
41
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
34
|
-
declare const __VLS_component: import("vue").DefineComponent<
|
|
42
|
+
declare const __VLS_component: import("vue").DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
43
|
+
"update:modelValue": (value: any) => any;
|
|
44
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
45
|
+
"onUpdate:modelValue"?: ((value: any) => any) | undefined;
|
|
46
|
+
}>, {
|
|
35
47
|
dense: boolean;
|
|
36
48
|
dark: boolean | null;
|
|
37
49
|
rounded: boolean;
|
|
@@ -9,8 +9,6 @@ import { collect } from "#imports";
|
|
|
9
9
|
import { useI18n } from "vue-i18n";
|
|
10
10
|
const $q = useQuasar();
|
|
11
11
|
const { t } = useI18n();
|
|
12
|
-
const minimized = defineModel("minimized", { type: Boolean, ...{ default: false } });
|
|
13
|
-
const maximized = defineModel("maximized", { type: Boolean, ...{ default: false } });
|
|
14
12
|
const errors = ref([]);
|
|
15
13
|
const props = defineProps({
|
|
16
14
|
fullscreen: { type: Boolean, required: false, skipCheck: true, default: false },
|
|
@@ -95,9 +93,7 @@ const props = defineProps({
|
|
|
95
93
|
actions: { type: Array, required: false, default: () => [] },
|
|
96
94
|
sortBy: { type: null, required: false },
|
|
97
95
|
modelName: { type: null, required: false },
|
|
98
|
-
searchable: { type:
|
|
99
|
-
maximizable: { type: Boolean, required: false, default: false },
|
|
100
|
-
minimizable: { type: Boolean, required: false, default: false },
|
|
96
|
+
searchable: { type: Boolean, required: false, default: false },
|
|
101
97
|
onRequestData: { type: Function, required: false },
|
|
102
98
|
addComponent: { type: Object, required: false },
|
|
103
99
|
addComponentProps: { type: null, required: false }
|
|
@@ -240,12 +236,22 @@ const onLocalRequest = async (p) => {
|
|
|
240
236
|
pagination.value.descending = p.pagination.descending;
|
|
241
237
|
pagination.value.rowsPerPage = p.pagination.rowsPerPage;
|
|
242
238
|
loading.value = false;
|
|
239
|
+
if (modelName.value) {
|
|
240
|
+
localStorage.setItem(`l-table-rowsPerPage-${modelName.value}`, String(pagination.value.rowsPerPage));
|
|
241
|
+
}
|
|
243
242
|
validateData();
|
|
244
243
|
},
|
|
245
244
|
loadObjects(model2, filters2 = null, fields = []) {
|
|
246
245
|
return this.loadData(model2, filters2, fields);
|
|
247
246
|
},
|
|
248
247
|
async loadData(model2, filters2 = null, fields = []) {
|
|
248
|
+
const saved = Number(localStorage.getItem(`l-table-rowsPerPage-${model2}`));
|
|
249
|
+
if (saved && props.rowsPerPageOptions.includes(saved) && saved !== pagination.value.rowsPerPage) {
|
|
250
|
+
pagination.value.rowsPerPage = saved;
|
|
251
|
+
if (typeof p !== "undefined" && p.pagination) {
|
|
252
|
+
p.pagination.rowsPerPage = saved;
|
|
253
|
+
}
|
|
254
|
+
}
|
|
249
255
|
fields.forEach((f) => {
|
|
250
256
|
builder.add(f);
|
|
251
257
|
});
|
|
@@ -443,16 +449,21 @@ const onAdd = () => {
|
|
|
443
449
|
</script>
|
|
444
450
|
|
|
445
451
|
<template>
|
|
446
|
-
<
|
|
447
|
-
v-model:
|
|
448
|
-
|
|
449
|
-
<
|
|
450
|
-
<q-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
452
|
+
<q-table v-bind="attrs" :loading="loading" :rows="rows" ref="table" @request="onLocalRequest" :columns="columns"
|
|
453
|
+
v-model:pagination="pagination" :filter="filter" v-model:selected="localSelected" :color="$light.color">
|
|
454
|
+
|
|
455
|
+
<template #header="props">
|
|
456
|
+
<q-tr :props="props">
|
|
457
|
+
<q-td v-if="selection != 'none'" auto-width>
|
|
458
|
+
<q-checkbox v-model="props.selected" />
|
|
459
|
+
</q-td>
|
|
460
|
+
<q-th v-if="hasRowExpand" auto-width></q-th>
|
|
461
|
+
<q-th v-if="hasActions" auto-width></q-th>
|
|
462
|
+
<q-th v-for="col in props.cols" :key="col.name" :props="props">{{ col.label }}</q-th>
|
|
463
|
+
</q-tr>
|
|
464
|
+
</template>
|
|
454
465
|
|
|
455
|
-
<template v-if="errors.length > 0">
|
|
466
|
+
<template #top v-if="errors.length > 0">
|
|
456
467
|
<div class="q-mb-sm">
|
|
457
468
|
<div class="q-gutter-sm">
|
|
458
469
|
<l-alert type="negative" v-for="e in errors">{{ e }}</l-alert>
|
|
@@ -460,96 +471,86 @@ const onAdd = () => {
|
|
|
460
471
|
</div>
|
|
461
472
|
</template>
|
|
462
473
|
|
|
463
|
-
<q-table v-bind="attrs" :loading="loading" :rows="rows" ref="table" @request="onLocalRequest" :columns="columns"
|
|
464
|
-
v-model:pagination="pagination" :filter="filter" v-model:selected="localSelected" :color="$light.color">
|
|
465
|
-
|
|
466
|
-
<template #header="props">
|
|
467
|
-
<q-tr :props="props">
|
|
468
|
-
<q-td v-if="selection != 'none'" auto-width>
|
|
469
|
-
<q-checkbox v-model="props.selected" />
|
|
470
|
-
</q-td>
|
|
471
|
-
<q-th v-if="hasRowExpand" auto-width></q-th>
|
|
472
|
-
<q-th v-if="hasActions" auto-width></q-th>
|
|
473
|
-
<q-th v-for="col in props.cols" :key="col.name" :props="props">{{ col.label }}</q-th>
|
|
474
|
-
</q-tr>
|
|
475
|
-
</template>
|
|
476
474
|
|
|
475
|
+
<template #top-left v-if="addComponent">
|
|
476
|
+
<q-btn icon="sym_o_add" :label="$t('Add')" :color="$light.color" @click="onAdd" outline />
|
|
477
|
+
</template>
|
|
477
478
|
|
|
478
479
|
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
480
|
+
<template #body="props">
|
|
481
|
+
<q-tr :props="props">
|
|
482
|
+
<q-td v-if="selection != 'none'" auto-width>
|
|
483
|
+
<q-checkbox v-model="props.selected" />
|
|
484
|
+
</q-td>
|
|
485
|
+
<q-td v-if="hasRowExpand" auto-width>
|
|
486
|
+
<q-btn :class="{ 'text-grey-8': !isDark }" flat round size="sm"
|
|
487
|
+
:icon="props.expand ? 'sym_o_expand_more' : 'sym_o_expand_less'"
|
|
488
|
+
@click="props.expand = !props.expand"></q-btn>
|
|
489
|
+
</q-td>
|
|
489
490
|
|
|
490
|
-
|
|
491
|
-
|
|
491
|
+
<q-td v-if="hasActions" auto-width>
|
|
492
|
+
<div :class="{ 'text-grey-8': !isDark }" v-if="primaryKey">
|
|
492
493
|
|
|
493
|
-
|
|
494
|
-
|
|
494
|
+
<l-view-btn v-if="actionView && props.row.canView"
|
|
495
|
+
:to="`/${modelName}/${props.row[primaryKey]}/view`" size="sm" />
|
|
495
496
|
|
|
496
|
-
|
|
497
|
-
|
|
497
|
+
<l-edit-btn v-if="activeEdit && props.row.canUpdate"
|
|
498
|
+
:to="`/${modelName}/${props.row[primaryKey]}/edit`" size="sm" />
|
|
498
499
|
|
|
499
|
-
|
|
500
|
-
|
|
500
|
+
<l-delete-btn v-if="actionDelete && props.row.canDelete"
|
|
501
|
+
@submit="onDelete(props.row[primaryKey])" size="sm"></l-delete-btn>
|
|
501
502
|
|
|
502
|
-
|
|
503
|
-
|
|
503
|
+
<slot name="actions" v-bind="props"></slot>
|
|
504
|
+
</div>
|
|
504
505
|
|
|
505
|
-
|
|
506
|
+
</q-td>
|
|
506
507
|
|
|
507
508
|
|
|
508
509
|
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
</template>
|
|
513
|
-
<template v-else>
|
|
514
|
-
<q-td :key="col.name" :props="props" :auto-width="col.autoWidth ?? false"
|
|
515
|
-
:style="getCellStyle(col, props.row)" :class="getCellClass(col, props.row)"><template
|
|
516
|
-
v-if="col.to" class="bg-primary">
|
|
517
|
-
<l-link :to="col.to(props.row)">{{ col.value }}</l-link>
|
|
518
|
-
</template>
|
|
519
|
-
<template v-else-if="col.component">
|
|
520
|
-
<component :is="col.component" v-model="props.row"
|
|
521
|
-
v-bind="col.componentProps ? col.componentProps(props.row) : null" />
|
|
522
|
-
</template>
|
|
523
|
-
<template v-else>
|
|
524
|
-
{{ col.value }}
|
|
525
|
-
</template>
|
|
526
|
-
</q-td>
|
|
527
|
-
</template>
|
|
510
|
+
<template v-for="col in props.cols">
|
|
511
|
+
<template v-if="ss.indexOf('body-cell-' + col.name) >= 0">
|
|
512
|
+
<slot :name="'body-cell-' + col.name" v-bind="props"></slot>
|
|
528
513
|
</template>
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
514
|
+
<template v-else>
|
|
515
|
+
<q-td :key="col.name" :props="props" :auto-width="col.autoWidth ?? false"
|
|
516
|
+
:style="getCellStyle(col, props.row)" :class="getCellClass(col, props.row)"><template
|
|
517
|
+
v-if="col.to" class="bg-primary">
|
|
518
|
+
<l-link :to="col.to(props.row)">{{ col.value }}</l-link>
|
|
519
|
+
</template>
|
|
520
|
+
<template v-else-if="col.component">
|
|
521
|
+
<component :is="col.component" v-model="props.row"
|
|
522
|
+
v-bind="col.componentProps ? col.componentProps(props.row) : null" />
|
|
523
|
+
</template>
|
|
524
|
+
<template v-else>
|
|
525
|
+
{{ col.value }}
|
|
526
|
+
</template>
|
|
527
|
+
</q-td>
|
|
543
528
|
</template>
|
|
544
|
-
</
|
|
529
|
+
</template>
|
|
530
|
+
</q-tr>
|
|
531
|
+
<q-tr v-show="props.expand" :props="props">
|
|
532
|
+
<q-td colspan="100%">
|
|
533
|
+
<slot name="row-expand" v-bind="props"></slot>
|
|
534
|
+
</q-td>
|
|
535
|
+
</q-tr>
|
|
536
|
+
</template>
|
|
537
|
+
|
|
545
538
|
|
|
539
|
+
<template #top-right="props" v-if="searchable">
|
|
540
|
+
<q-input v-if="searchable" outlined dense debounce="300" v-model="filter" :placeholder="$t('Search')"
|
|
541
|
+
:color="$light.color">
|
|
542
|
+
<template v-slot:append>
|
|
543
|
+
<q-icon name="search" />
|
|
544
|
+
</template>
|
|
545
|
+
</q-input>
|
|
546
546
|
|
|
547
547
|
|
|
548
548
|
|
|
549
|
-
|
|
549
|
+
|
|
550
|
+
</template>
|
|
550
551
|
|
|
551
552
|
|
|
552
|
-
|
|
553
|
+
<!-- template v-for="col in toColumns" v-slot:[col.slot_name]="props">
|
|
553
554
|
<q-td :props="props">
|
|
554
555
|
<l-link :to="col.to(props.row)">
|
|
555
556
|
{{ col.field(props.row) }}
|
|
@@ -558,49 +559,47 @@ const onAdd = () => {
|
|
|
558
559
|
</template -->
|
|
559
560
|
|
|
560
561
|
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
<template v-if="col.searchType == 'number'">
|
|
570
|
-
<q-input style="min-width: 80px;" dense clearable filled square
|
|
571
|
-
v-model.number="filters[col.name]" @keydown.enter.prevent="onFilters"
|
|
572
|
-
@clear="onFilters" mask="##########" :enterkeyhint="$t('search')"></q-input>
|
|
573
|
-
</template>
|
|
562
|
+
<template #top-row="props" v-if="hasSearch && isServerSide">
|
|
563
|
+
<q-tr>
|
|
564
|
+
<q-td v-if="selection != 'none'" auto-width />
|
|
565
|
+
<q-td v-if="hasRowExpand" auto-width />
|
|
566
|
+
<q-td v-if="hasActions" auto-width />
|
|
567
|
+
<q-td v-for="col in props.cols">
|
|
568
|
+
<template v-if="col.searchable">
|
|
574
569
|
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
570
|
+
<template v-if="col.searchType == 'number'">
|
|
571
|
+
<q-input style="min-width: 80px;" dense clearable filled square
|
|
572
|
+
v-model.number="filters[col.name]" @keydown.enter.prevent="onFilters" @clear="onFilters"
|
|
573
|
+
mask="##########" :enterkeyhint="$t('search')"></q-input>
|
|
574
|
+
</template>
|
|
579
575
|
|
|
580
|
-
|
|
576
|
+
<template v-if="col.searchType == 'select'">
|
|
577
|
+
<q-select dense clearable filled square v-model="filters[col.name]"
|
|
578
|
+
@update:model-value="onFilters" options-dense :options="col.searchOptions" emit-value
|
|
579
|
+
map-options :multiple="col.searchMultiple" :color="$light.color" />
|
|
581
580
|
|
|
581
|
+
</template>
|
|
582
582
|
|
|
583
|
-
<template v-if="col.searchType == 'date'">
|
|
584
|
-
<l-date-picker dense clearable filled square :outlined="false" hide-bottom-space
|
|
585
|
-
v-model="filters[col.name]" @update:model-value="onFilters" range
|
|
586
|
-
@clear="onFilters" />
|
|
587
|
-
</template>
|
|
588
583
|
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
584
|
+
<template v-if="col.searchType == 'date'">
|
|
585
|
+
<l-date-picker dense clearable filled square :outlined="false" hide-bottom-space
|
|
586
|
+
v-model="filters[col.name]" @update:model-value="onFilters" range @clear="onFilters" />
|
|
587
|
+
</template>
|
|
593
588
|
|
|
594
|
-
|
|
589
|
+
<template v-if="!col.searchType || col.searchType == 'text'">
|
|
590
|
+
<q-input style="min-width: 80px;" dense clearable filled square v-model="filters[col.name]"
|
|
591
|
+
@keydown.enter.prevent="onFilters" @clear="onFilters" :enterkeyhint="$t('search')"
|
|
592
|
+
:color="$light.color"></q-input>
|
|
595
593
|
|
|
596
594
|
</template>
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
595
|
+
|
|
596
|
+
</template>
|
|
597
|
+
</q-td>
|
|
598
|
+
</q-tr>
|
|
599
|
+
</template>
|
|
600
|
+
|
|
601
|
+
<template v-for="slot of ss" v-slot:[slot]="props">
|
|
602
|
+
<slot :name="slot" v-bind="props"></slot>
|
|
603
|
+
</template>
|
|
604
|
+
</q-table>
|
|
606
605
|
</template>
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import { QTable, Dialog } from 'quasar';
|
|
2
2
|
import type { QTableColumn, QTableProps } from 'quasar';
|
|
3
|
-
declare const minimized: import("vue").ModelRef<boolean, string, boolean, boolean>;
|
|
4
|
-
declare const maximized: import("vue").ModelRef<boolean, string, boolean, boolean>;
|
|
5
3
|
export interface LTableColumn extends QTableColumn {
|
|
6
4
|
searchable?: boolean;
|
|
7
5
|
searchType?: string;
|
|
@@ -18,16 +16,13 @@ export type LTableProps = QTableProps & {
|
|
|
18
16
|
sortBy?: any;
|
|
19
17
|
rowKey?: string;
|
|
20
18
|
modelName?: any;
|
|
21
|
-
searchable?:
|
|
19
|
+
searchable?: boolean;
|
|
22
20
|
selected?: Array<any>;
|
|
23
|
-
maximizable?: boolean;
|
|
24
|
-
minimizable?: boolean;
|
|
25
21
|
onRequestData?: (request: LTableRequest) => void;
|
|
26
22
|
addComponent?: Dialog;
|
|
27
23
|
addComponentProps?: any;
|
|
28
24
|
rows?: Array<any>;
|
|
29
25
|
};
|
|
30
|
-
type __VLS_Props = LTableProps;
|
|
31
26
|
declare const isServerSide: boolean;
|
|
32
27
|
declare const pagination: import("vue").Ref<{
|
|
33
28
|
sortBy?: string | null | undefined;
|
|
@@ -107,25 +102,19 @@ declare const getCellClass: (col: any, row: any) => any;
|
|
|
107
102
|
declare const localSelected: import("vue").WritableComputedRef<any[], any[]>;
|
|
108
103
|
declare function requestServerInteraction(): void;
|
|
109
104
|
declare const onAdd: () => void;
|
|
110
|
-
type __VLS_PublicProps = __VLS_Props & {
|
|
111
|
-
"minimized"?: boolean;
|
|
112
|
-
"maximized"?: boolean;
|
|
113
|
-
};
|
|
114
105
|
declare const __VLS_ctx: InstanceType<__VLS_PickNotAny<typeof __VLS_self, new () => {}>>;
|
|
115
|
-
declare var
|
|
106
|
+
declare var __VLS_91: any, __VLS_94: string, __VLS_95: any, __VLS_117: any, __VLS_183: string, __VLS_184: any;
|
|
116
107
|
type __VLS_Slots = __VLS_PrettifyGlobal<__VLS_OmitStringIndex<typeof __VLS_ctx.$slots> & {
|
|
117
|
-
[K in NonNullable<typeof
|
|
108
|
+
[K in NonNullable<typeof __VLS_94>]?: (props: typeof __VLS_95) => any;
|
|
118
109
|
} & {
|
|
119
|
-
[K in NonNullable<typeof
|
|
110
|
+
[K in NonNullable<typeof __VLS_183>]?: (props: typeof __VLS_184) => any;
|
|
120
111
|
} & {
|
|
121
|
-
actions?: (props: typeof
|
|
112
|
+
actions?: (props: typeof __VLS_91) => any;
|
|
122
113
|
} & {
|
|
123
|
-
'row-expand'?: (props: typeof
|
|
114
|
+
'row-expand'?: (props: typeof __VLS_117) => any;
|
|
124
115
|
}>;
|
|
125
|
-
declare const __VLS_self: import("vue").DefineComponent<
|
|
116
|
+
declare const __VLS_self: import("vue").DefineComponent<LTableProps, {
|
|
126
117
|
QTable: typeof QTable;
|
|
127
|
-
minimized: typeof minimized;
|
|
128
|
-
maximized: typeof maximized;
|
|
129
118
|
errors: typeof errors;
|
|
130
119
|
isServerSide: typeof isServerSide;
|
|
131
120
|
pagination: typeof pagination;
|
|
@@ -154,14 +143,10 @@ declare const __VLS_self: import("vue").DefineComponent<__VLS_PublicProps, {
|
|
|
154
143
|
onAdd: typeof onAdd;
|
|
155
144
|
}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
156
145
|
delete: (p: any) => any;
|
|
157
|
-
"update:minimized": (value: boolean) => any;
|
|
158
|
-
"update:maximized": (value: boolean) => any;
|
|
159
146
|
"request-data": (p: LTableRequest) => any;
|
|
160
147
|
"update:selected": (p: any[]) => any;
|
|
161
|
-
}, string, import("vue").PublicProps, Readonly<
|
|
148
|
+
}, string, import("vue").PublicProps, Readonly<LTableProps> & Readonly<{
|
|
162
149
|
onDelete?: ((p: any) => any) | undefined;
|
|
163
|
-
"onUpdate:minimized"?: ((value: boolean) => any) | undefined;
|
|
164
|
-
"onUpdate:maximized"?: ((value: boolean) => any) | undefined;
|
|
165
150
|
"onRequest-data"?: ((p: LTableRequest) => any) | undefined;
|
|
166
151
|
"onUpdate:selected"?: ((p: any[]) => any) | undefined;
|
|
167
152
|
}>, {
|
|
@@ -170,8 +155,6 @@ declare const __VLS_self: import("vue").DefineComponent<__VLS_PublicProps, {
|
|
|
170
155
|
dark: boolean | null;
|
|
171
156
|
bordered: boolean;
|
|
172
157
|
fullscreen: boolean;
|
|
173
|
-
minimizable: boolean;
|
|
174
|
-
maximizable: boolean;
|
|
175
158
|
selected: any[];
|
|
176
159
|
actions: Array<string>;
|
|
177
160
|
pagination: {
|
|
@@ -186,20 +169,16 @@ declare const __VLS_self: import("vue").DefineComponent<__VLS_PublicProps, {
|
|
|
186
169
|
noDataLabel: string;
|
|
187
170
|
rowsPerPageOptions: readonly any[];
|
|
188
171
|
rowsPerPageLabel: string;
|
|
189
|
-
searchable:
|
|
172
|
+
searchable: boolean;
|
|
190
173
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
191
|
-
declare const __VLS_component: import("vue").DefineComponent<
|
|
174
|
+
declare const __VLS_component: import("vue").DefineComponent<LTableProps, {
|
|
192
175
|
requestServerInteraction: typeof requestServerInteraction;
|
|
193
176
|
}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
194
177
|
delete: (p: any) => any;
|
|
195
|
-
"update:minimized": (value: boolean) => any;
|
|
196
|
-
"update:maximized": (value: boolean) => any;
|
|
197
178
|
"request-data": (p: LTableRequest) => any;
|
|
198
179
|
"update:selected": (p: any[]) => any;
|
|
199
|
-
}, string, import("vue").PublicProps, Readonly<
|
|
180
|
+
}, string, import("vue").PublicProps, Readonly<LTableProps> & Readonly<{
|
|
200
181
|
onDelete?: ((p: any) => any) | undefined;
|
|
201
|
-
"onUpdate:minimized"?: ((value: boolean) => any) | undefined;
|
|
202
|
-
"onUpdate:maximized"?: ((value: boolean) => any) | undefined;
|
|
203
182
|
"onRequest-data"?: ((p: LTableRequest) => any) | undefined;
|
|
204
183
|
"onUpdate:selected"?: ((p: any[]) => any) | undefined;
|
|
205
184
|
}>, {
|
|
@@ -208,8 +187,6 @@ declare const __VLS_component: import("vue").DefineComponent<__VLS_PublicProps,
|
|
|
208
187
|
dark: boolean | null;
|
|
209
188
|
bordered: boolean;
|
|
210
189
|
fullscreen: boolean;
|
|
211
|
-
minimizable: boolean;
|
|
212
|
-
maximizable: boolean;
|
|
213
190
|
selected: any[];
|
|
214
191
|
actions: Array<string>;
|
|
215
192
|
pagination: {
|
|
@@ -224,7 +201,7 @@ declare const __VLS_component: import("vue").DefineComponent<__VLS_PublicProps,
|
|
|
224
201
|
noDataLabel: string;
|
|
225
202
|
rowsPerPageOptions: readonly any[];
|
|
226
203
|
rowsPerPageLabel: string;
|
|
227
|
-
searchable:
|
|
204
|
+
searchable: boolean;
|
|
228
205
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
229
206
|
declare const _default: __VLS_WithSlots<typeof __VLS_component, __VLS_Slots>;
|
|
230
207
|
export default _default;
|
|
@@ -8,17 +8,28 @@ const columns = model("MailLog").columns({
|
|
|
8
8
|
created_time: true,
|
|
9
9
|
body: true
|
|
10
10
|
});
|
|
11
|
+
function requestMailLog(event) {
|
|
12
|
+
event.loadObjects("MailLog", {}, ["body"]);
|
|
13
|
+
}
|
|
11
14
|
</script>
|
|
12
15
|
|
|
13
16
|
<template>
|
|
14
17
|
<l-page>
|
|
15
|
-
<l-table
|
|
16
|
-
|
|
17
|
-
|
|
18
|
+
<l-table
|
|
19
|
+
row-key="maillog_id"
|
|
20
|
+
@request-data="requestMailLog"
|
|
21
|
+
:columns="columns"
|
|
22
|
+
sort-by="maillog_id:desc"
|
|
23
|
+
>
|
|
18
24
|
<template #row-expand="props">
|
|
19
|
-
<iframe
|
|
25
|
+
<iframe
|
|
26
|
+
width="100%"
|
|
27
|
+
height="300px"
|
|
28
|
+
:srcdoc="props.row.body"
|
|
29
|
+
frameborder="0"
|
|
30
|
+
sandbox
|
|
31
|
+
></iframe>
|
|
20
32
|
</template>
|
|
21
|
-
|
|
22
33
|
</l-table>
|
|
23
34
|
</l-page>
|
|
24
35
|
</template>
|
|
@@ -1,67 +1,73 @@
|
|
|
1
1
|
<script setup>
|
|
2
|
-
import {
|
|
2
|
+
import { computed, ref } from "vue";
|
|
3
3
|
import { m, api } from "#imports";
|
|
4
4
|
import { useI18n } from "vue-i18n";
|
|
5
5
|
const { t } = useI18n();
|
|
6
|
-
const
|
|
7
|
-
app: {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
6
|
+
const fetchApp = async () => {
|
|
7
|
+
const { app: app2 } = await api.query({
|
|
8
|
+
app: {
|
|
9
|
+
permissions: true,
|
|
10
|
+
roles: {
|
|
11
|
+
name: true,
|
|
12
|
+
permissions: true
|
|
13
|
+
}
|
|
12
14
|
}
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
align: "left"
|
|
20
|
-
|
|
21
|
-
roles.forEach((role) => {
|
|
22
|
-
columns.push({
|
|
15
|
+
});
|
|
16
|
+
return app2;
|
|
17
|
+
};
|
|
18
|
+
const app = ref(await fetchApp());
|
|
19
|
+
const roles = computed(() => app.value.roles);
|
|
20
|
+
const columns = computed(() => [
|
|
21
|
+
{ label: t("Permission"), field: "permission", align: "left" },
|
|
22
|
+
...roles.value.map((role) => ({
|
|
23
23
|
label: role.name,
|
|
24
24
|
field: role.name,
|
|
25
25
|
align: "left"
|
|
26
|
-
})
|
|
27
|
-
|
|
28
|
-
const rows =
|
|
29
|
-
app.permissions.
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
}
|
|
39
|
-
});
|
|
40
|
-
rows.push(row);
|
|
41
|
-
});
|
|
42
|
-
const onUpdate = (value, role, permission) => {
|
|
26
|
+
}))
|
|
27
|
+
]);
|
|
28
|
+
const rows = computed(
|
|
29
|
+
() => app.value.permissions.map((permission) => {
|
|
30
|
+
const row = { permission };
|
|
31
|
+
roles.value.forEach((role) => {
|
|
32
|
+
row[role.name] = role.permissions.includes(permission);
|
|
33
|
+
});
|
|
34
|
+
return row;
|
|
35
|
+
})
|
|
36
|
+
);
|
|
37
|
+
const onUpdate = async (value, role, permission) => {
|
|
43
38
|
if (value) {
|
|
44
|
-
m("addPermission", { value: permission, role });
|
|
39
|
+
await m("addPermission", { value: permission, role });
|
|
45
40
|
} else {
|
|
46
|
-
m("removePermission", { value: permission, role });
|
|
41
|
+
await m("removePermission", { value: permission, role });
|
|
47
42
|
}
|
|
48
|
-
|
|
49
|
-
if (row.permission == permission) {
|
|
50
|
-
row[role] = value;
|
|
51
|
-
}
|
|
52
|
-
});
|
|
43
|
+
app.value = await fetchApp();
|
|
53
44
|
};
|
|
45
|
+
const filter = ref("");
|
|
46
|
+
const filteredRows = computed(() => {
|
|
47
|
+
if (!filter.value) return rows.value;
|
|
48
|
+
return rows.value.filter(
|
|
49
|
+
(row) => row.permission.toLowerCase().includes(filter.value.toLowerCase())
|
|
50
|
+
);
|
|
51
|
+
});
|
|
54
52
|
</script>
|
|
55
53
|
|
|
56
54
|
<template>
|
|
57
55
|
<l-page>
|
|
58
|
-
<q-table :columns="columns" flat bordered :rows="
|
|
56
|
+
<q-table :columns="columns" flat bordered :rows="filteredRows" :pagination="{ rowsPerPage: 0 }" dense>
|
|
57
|
+
<template #top-left>
|
|
58
|
+
<q-input :color="$light.color" v-model="filter" :placeholder="t('Filter permissions')" dense clearable
|
|
59
|
+
outlined>
|
|
60
|
+
<template v-slot:append>
|
|
61
|
+
<q-icon name="sym_o_search" />
|
|
62
|
+
</template>
|
|
63
|
+
</q-input>
|
|
64
|
+
</template>
|
|
59
65
|
<template #body="props">
|
|
60
66
|
<q-tr :props="props">
|
|
61
67
|
<q-td>
|
|
62
68
|
{{ props.row.permission }}
|
|
63
69
|
</q-td>
|
|
64
|
-
<q-td v-for="role in roles">
|
|
70
|
+
<q-td v-for="role in roles" :key="role.name">
|
|
65
71
|
<q-checkbox v-model="props.row[role.name]"
|
|
66
72
|
@update:model-value="onUpdate($event, role.name, props.row.permission)"
|
|
67
73
|
:color="$light.color" />
|
|
@@ -1,26 +1,28 @@
|
|
|
1
1
|
<script setup>
|
|
2
2
|
import { q } from "#imports";
|
|
3
|
-
import { Loading } from "quasar";
|
|
3
|
+
import { Loading, Notify } from "quasar";
|
|
4
4
|
const onClickDownload = async () => {
|
|
5
|
-
Loading.show({
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
5
|
+
Loading.show({ message: "Exporting database..." });
|
|
6
|
+
try {
|
|
7
|
+
const data = await q({
|
|
8
|
+
system: {
|
|
9
|
+
database: {
|
|
10
|
+
export: true
|
|
11
|
+
}
|
|
12
12
|
}
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
13
|
+
});
|
|
14
|
+
const blob = new Blob([data.system.database.export], { type: "text/plain;charset=utf-8" });
|
|
15
|
+
const url = URL.createObjectURL(blob);
|
|
16
|
+
const a = document.createElement("a");
|
|
17
|
+
a.download = "backup.sql";
|
|
18
|
+
a.href = url;
|
|
19
|
+
a.click();
|
|
20
|
+
setTimeout(() => URL.revokeObjectURL(url), 1e3);
|
|
21
|
+
} catch (e) {
|
|
22
|
+
Notify.create({ type: "negative", message: "\u4E0B\u8F09\u5931\u6557\uFF0C\u8ACB\u7A0D\u5F8C\u518D\u8A66\u3002" });
|
|
23
|
+
} finally {
|
|
24
|
+
Loading.hide();
|
|
25
|
+
}
|
|
24
26
|
};
|
|
25
27
|
</script>
|
|
26
28
|
|
|
@@ -15,28 +15,28 @@ const { data, refresh } = await useAsyncData(async () => {
|
|
|
15
15
|
return system;
|
|
16
16
|
});
|
|
17
17
|
const autoRefresh = ref(0);
|
|
18
|
-
|
|
18
|
+
const interval = ref(null);
|
|
19
19
|
watch(autoRefresh, (value) => {
|
|
20
|
-
if (interval)
|
|
21
|
-
clearInterval(interval);
|
|
20
|
+
if (interval.value)
|
|
21
|
+
clearInterval(interval.value);
|
|
22
22
|
if (value) {
|
|
23
|
-
interval = setInterval(
|
|
23
|
+
interval.value = setInterval(() => {
|
|
24
|
+
refresh();
|
|
25
|
+
}, value);
|
|
24
26
|
}
|
|
25
|
-
});
|
|
27
|
+
}, { immediate: true });
|
|
26
28
|
onUnmounted(() => {
|
|
27
|
-
if (interval)
|
|
28
|
-
clearInterval(interval);
|
|
29
|
+
if (interval.value)
|
|
30
|
+
clearInterval(interval.value);
|
|
29
31
|
});
|
|
30
32
|
</script>
|
|
31
33
|
|
|
32
34
|
<template>
|
|
33
35
|
<l-page title="System Database Process">
|
|
34
|
-
<q-table :rows="data
|
|
36
|
+
<q-table :rows="data?.database?.processList || []" hide-bottom v-bind="$light.styles.table" :loading="loading">
|
|
35
37
|
<template #top-left>
|
|
36
38
|
<q-btn label="Reload" outline :color="$light.color" icon="sym_o_refresh" @click="refresh"></q-btn>
|
|
37
|
-
|
|
38
39
|
</template>
|
|
39
|
-
|
|
40
40
|
<template #top-right>
|
|
41
41
|
<q-select label="Auto Refresh" v-model="autoRefresh" :options="[
|
|
42
42
|
{ label: 'Off', value: 0 },
|
|
@@ -48,11 +48,9 @@ onUnmounted(() => {
|
|
|
48
48
|
{ label: '10m', value: 600000 },
|
|
49
49
|
{ label: '30m', value: 1800000 },
|
|
50
50
|
{ label: '1h', value: 3600000 }
|
|
51
|
-
]" @
|
|
51
|
+
]" @update:model-value="autoRefresh && refresh()" outlined :color="$light.color" dense style="min-width: 200px"
|
|
52
52
|
map-options emit-value></q-select>
|
|
53
|
-
|
|
54
53
|
</template>
|
|
55
54
|
</q-table>
|
|
56
|
-
|
|
57
55
|
</l-page>
|
|
58
56
|
</template>
|
|
@@ -16,10 +16,10 @@ const { data, refresh } = await useAsyncData("database", async () => {
|
|
|
16
16
|
});
|
|
17
17
|
const SYSTEM_TABLES = ["Config", "EventLog", "MailLog", "Permission", "Role", "SystemValue", "Translate", "User", "UserLog", "UserRole", "MyFavorite", "CustomField"];
|
|
18
18
|
const custom_tables = computed(() => {
|
|
19
|
-
return data.value
|
|
19
|
+
return (data.value?.tableStatus ?? []).filter((table) => !SYSTEM_TABLES.includes(table.Name));
|
|
20
20
|
});
|
|
21
21
|
const systables = computed(() => {
|
|
22
|
-
return data.value
|
|
22
|
+
return (data.value?.tableStatus ?? []).filter((table) => SYSTEM_TABLES.includes(table.Name));
|
|
23
23
|
});
|
|
24
24
|
const field_add = resolveComponent("l-dialog-database-field-add");
|
|
25
25
|
const table_add = resolveComponent("l-database-create-table-dialog");
|
|
@@ -51,8 +51,10 @@ const add = async (table) => {
|
|
|
51
51
|
});
|
|
52
52
|
};
|
|
53
53
|
const selected = reactive({});
|
|
54
|
-
|
|
55
|
-
|
|
54
|
+
if (data.value?.table) {
|
|
55
|
+
for (let table of data.value.table) {
|
|
56
|
+
selected[table.name] = [];
|
|
57
|
+
}
|
|
56
58
|
}
|
|
57
59
|
const removeField = async (table) => {
|
|
58
60
|
light.dialog({
|
|
@@ -173,14 +175,14 @@ const truncatTable = async () => {
|
|
|
173
175
|
</l-list>
|
|
174
176
|
</l-card>
|
|
175
177
|
|
|
176
|
-
<q-card
|
|
178
|
+
<q-card>
|
|
177
179
|
<q-list separator bordered>
|
|
178
180
|
<q-expansion-item label="Table Status" dense>
|
|
179
|
-
<div
|
|
181
|
+
<div s>
|
|
180
182
|
|
|
181
183
|
<q-table :rows="custom_tables" hide-pagination flat bordered separator="cell" dense
|
|
182
184
|
:rows-per-page-options="[0]" v-model:selected="selectedTable" selection="multiple"
|
|
183
|
-
row-key="Name">
|
|
185
|
+
row-key="Name" :color="$light.color">
|
|
184
186
|
|
|
185
187
|
<template #top-left>
|
|
186
188
|
<q-btn icon="sym_o_add" @click="createTable()" round flat size="sm">
|
|
@@ -210,13 +212,12 @@ const truncatTable = async () => {
|
|
|
210
212
|
</q-list>
|
|
211
213
|
</q-card>
|
|
212
214
|
|
|
213
|
-
<q-card
|
|
215
|
+
<q-card>
|
|
214
216
|
<q-list separator bordered>
|
|
215
217
|
<q-expansion-item :label="table.name" v-for="table in data.table" dense>
|
|
216
218
|
<div class="q-ma-sm">
|
|
217
|
-
<q-table row-key="Field"
|
|
218
|
-
:
|
|
219
|
-
v-model:selected="selected[table.name]">
|
|
219
|
+
<q-table row-key="Field" :rows="table.columns" :rows-per-page-options="[0]" hide-pagination flat
|
|
220
|
+
bordered selection="multiple" v-model:selected="selected[table.name]" :color="$light.color">
|
|
220
221
|
<template #top-left>
|
|
221
222
|
<q-btn icon="sym_o_add" @click="add(table.name)" round flat size="sm">
|
|
222
223
|
<q-tooltip>Add field</q-tooltip>
|
|
@@ -233,6 +234,5 @@ const truncatTable = async () => {
|
|
|
233
234
|
</q-list>
|
|
234
235
|
</q-card>
|
|
235
236
|
|
|
236
|
-
|
|
237
237
|
</l-page>
|
|
238
238
|
</template>
|