@simitgroup/simpleapp-generator 1.6.1-alpha → 1.6.3-alpha
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -4
- package/dist/buildinschemas/branch.d.ts.map +1 -1
- package/dist/buildinschemas/branch.js +0 -2
- package/dist/buildinschemas/branch.js.map +1 -1
- package/dist/index.js +4 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/buildinschemas/branch.ts +0 -2
- package/src/index.ts +8 -3
- package/templates/basic/nuxt/pages.form.vue.eta +2 -2
- package/templates/basic/nuxt/pages.landing.vue.eta +1 -1
- package/templates/nest/src/simpleapp/generate/commons/docnogenerator.service.ts.eta +36 -30
- package/templates/nest/src/simpleapp/generate/processors/simpleapp.processor.ts.eta +16 -3
- package/templates/nest/src/simpleapp/services/userresolver.service.ts._eta +22 -25
- package/templates/nuxt/{app.vue._eta → app.vue.eta} +3 -1
- package/templates/nuxt/components/button/ButtonAction.vue._eta +49 -8
- package/templates/nuxt/components/calendar/CalendarInput.vue.eta +26 -0
- package/templates/nuxt/components/event/EventDocumentViewer.vue._eta +30 -13
- package/templates/nuxt/components/list/ListDocument.vue.eta +10 -5
- package/templates/nuxt/components/list/ListDocumentTable.vue.eta +2 -2
- package/templates/nuxt/components/list/ListMessages.vue.eta +1 -1
- package/templates/nuxt/components/list/ListView.vue.eta +80 -30
- package/templates/nuxt/components/overlay/OverlayPanelWithToolBar.vue.eta +10 -4
- package/templates/nuxt/components/overlay/OverlaySideBarCrud.vue.eta +17 -6
- package/templates/nuxt/components/overlay/OverlayViewer.vue.eta +16 -6
- package/templates/nuxt/components/page/PageDocList.vue.eta +81 -27
- package/templates/nuxt/components/select/SelectTemplate.vue.eta +43 -31
- package/templates/nuxt/components/simpleApp/SimpleAppAutocomplete.vue.eta +45 -17
- package/templates/nuxt/components/simpleApp/SimpleAppChildrenList.vue.eta +15 -11
- package/templates/nuxt/components/simpleApp/SimpleAppFormToolBar.vue._eta +71 -20
- package/templates/nuxt/composables/confirm.generate.ts.eta +19 -0
- package/templates/nuxt/composables/date.generate.ts.eta +2 -0
- package/templates/nuxt/composables/stringHelper.generate.ts.eta +2 -1
- package/templates/nuxt/pages/[xorg]/docnoformat.vue.eta +1 -1
- package/templates/nuxt/pages/[xorg]/mobile/docnoformat/index.vue.eta +1 -1
- package/templates/nuxt/pages/[xorg]/mobile/user/index.vue.eta +1 -1
- package/templates/nuxt/pages/[xorg]/organization.vue.eta +1 -1
- package/templates/nuxt/pages/[xorg]/profile.vue.eta +1 -1
- package/templates/nuxt/pages/[xorg]/user.vue.eta +1 -1
- package/templates/nuxt/plugins/10.simpleapp-event.ts.eta +4 -0
- package/templates/project/jsonschemas/invoice.json._eta +15 -7
- package/templates/project/lang/default._json +4 -1
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -1,21 +1,31 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div class="relative">
|
|
3
|
-
<div v-if="withFilter" class="flex flex-row">
|
|
4
|
-
<
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
3
|
+
<div v-if="withFilter" class="flex flex-row p-2">
|
|
4
|
+
<InputGroup>
|
|
5
|
+
<InputGroupAddon v-if="filter">
|
|
6
|
+
<ButtonText
|
|
7
|
+
@click="showMoreFilter"
|
|
8
|
+
v-if="Object.keys(filter) == 0"
|
|
9
|
+
>
|
|
10
|
+
<i class="pi pi-filter"></i>
|
|
11
|
+
</ButtonText>
|
|
12
|
+
<ButtonWarning @click="showMoreFilter" v-else>
|
|
13
|
+
<i class="pi pi-filter"></i>
|
|
14
|
+
</ButtonWarning>
|
|
15
|
+
</InputGroupAddon>
|
|
16
|
+
<InputText
|
|
17
|
+
:placeholder="t('searchKeyword')"
|
|
18
|
+
v-model="searchvalue"
|
|
19
|
+
class="w-full dark:text-white text-sm"
|
|
20
|
+
type="search"
|
|
21
|
+
ref="listviewfilter"
|
|
22
|
+
/>
|
|
23
|
+
<InputGroupAddon v-if="withAddNew">
|
|
24
|
+
<ButtonPrimary @click="emits('add')">
|
|
25
|
+
<i class="pi pi-plus"></i>
|
|
26
|
+
</ButtonPrimary>
|
|
27
|
+
</InputGroupAddon>
|
|
28
|
+
</InputGroup>
|
|
19
29
|
</div>
|
|
20
30
|
|
|
21
31
|
<div
|
|
@@ -46,12 +56,15 @@
|
|
|
46
56
|
<span>{{ item[titleField][0] }}</span>
|
|
47
57
|
</div>
|
|
48
58
|
<div
|
|
49
|
-
@click="onClick(index, item)"
|
|
59
|
+
@click="onClick(index, item, $event)"
|
|
50
60
|
:class="`border-l-none border-r-none listview-item dark:border-t-gray-700 ${
|
|
51
61
|
index > 0 ? 'border-t-2' : ''
|
|
52
62
|
}`"
|
|
53
63
|
>
|
|
54
|
-
<NuxtLink
|
|
64
|
+
<NuxtLink
|
|
65
|
+
:to="getUrl(item)"
|
|
66
|
+
:class="`p-2 ${showClickEffect ? 'listlink' : ''}`"
|
|
67
|
+
>
|
|
55
68
|
<slot name="default" :item="item" :index="index">
|
|
56
69
|
<div class="flex flex-row">
|
|
57
70
|
<div class="flex-1 mr-2 dark:text-white">
|
|
@@ -76,6 +89,22 @@
|
|
|
76
89
|
</slot>
|
|
77
90
|
</div>
|
|
78
91
|
</div>
|
|
92
|
+
|
|
93
|
+
<Dialog v-model:visible="visibleMoreFilter" :header="t('filter')">
|
|
94
|
+
<slot name="filter"> define filter in #filter </slot>
|
|
95
|
+
<template #footer>
|
|
96
|
+
<div class="flex flex-row">
|
|
97
|
+
<ButtonDefault @click="clearFilter" class="flex flex-row p-2">
|
|
98
|
+
<i class="pi pi-times mr-1" />
|
|
99
|
+
<span class="mr-1">{{ t("clear") }}</span>
|
|
100
|
+
</ButtonDefault>
|
|
101
|
+
<ButtonPrimary @click="runFilter" class="flex flex-row p-2">
|
|
102
|
+
<i class="pi pi-filter mr-1" />
|
|
103
|
+
<span class="mr-1">{{ t("ok") }}</span>
|
|
104
|
+
</ButtonPrimary>
|
|
105
|
+
</div>
|
|
106
|
+
</template>
|
|
107
|
+
</Dialog>
|
|
79
108
|
</div>
|
|
80
109
|
</template>
|
|
81
110
|
<script setup lang="ts" generic="T extends { [key: string]: any }">
|
|
@@ -88,6 +117,7 @@
|
|
|
88
117
|
import { ref } from "vue";
|
|
89
118
|
import { ListItem } from "~/types/listview";
|
|
90
119
|
import _ from "lodash";
|
|
120
|
+
const visibleMoreFilter = ref(false);
|
|
91
121
|
const listviewfilter = ref();
|
|
92
122
|
const props = withDefaults(
|
|
93
123
|
defineProps<{
|
|
@@ -97,9 +127,10 @@ const props = withDefaults(
|
|
|
97
127
|
idField?: string;
|
|
98
128
|
subTitleField?: string;
|
|
99
129
|
withFilter?: boolean;
|
|
130
|
+
filter?: Object;
|
|
100
131
|
withAddNew?: boolean;
|
|
101
132
|
showIndex?: boolean;
|
|
102
|
-
showClickEffect?:boolean
|
|
133
|
+
showClickEffect?: boolean;
|
|
103
134
|
}>(),
|
|
104
135
|
{
|
|
105
136
|
idField: "_id",
|
|
@@ -108,7 +139,7 @@ const props = withDefaults(
|
|
|
108
139
|
const letters = ref<string[]>([]);
|
|
109
140
|
let lastchar = "";
|
|
110
141
|
|
|
111
|
-
const emits = defineEmits(["add", "click"]);
|
|
142
|
+
const emits = defineEmits(["add", "runFilter", "clearFilter", "click"]);
|
|
112
143
|
const searchvalue = ref("");
|
|
113
144
|
const selecteditem = ref("");
|
|
114
145
|
const clickRow = (item: ListItem) => {
|
|
@@ -128,15 +159,23 @@ const filterlist = computed(() => {
|
|
|
128
159
|
return [];
|
|
129
160
|
}
|
|
130
161
|
if (props.list !== undefined) {
|
|
162
|
+
const searchstr = searchvalue.value.toLowerCase()
|
|
163
|
+
|
|
131
164
|
newlist = props.list.filter((item: T) => {
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
.
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
165
|
+
let res = false
|
|
166
|
+
if(searchstr.length==0) return true
|
|
167
|
+
if(props.titleField && item[props.titleField]){
|
|
168
|
+
res = item[props.titleField].toLowerCase()
|
|
169
|
+
.includes(searchstr)
|
|
170
|
+
}
|
|
171
|
+
if(res) return true
|
|
172
|
+
|
|
173
|
+
if(props.subTitleField && item[props.subTitleField])
|
|
174
|
+
res = item[props.subTitleField].toLowerCase()
|
|
175
|
+
.includes(searchstr)
|
|
176
|
+
if(res) return true
|
|
177
|
+
|
|
178
|
+
return false;
|
|
140
179
|
});
|
|
141
180
|
}
|
|
142
181
|
|
|
@@ -168,10 +207,21 @@ const showCategoryBar = (letter: string) => {
|
|
|
168
207
|
}
|
|
169
208
|
};
|
|
170
209
|
|
|
171
|
-
const onClick = (index: number, data: T) => {
|
|
172
|
-
emits("click", index, data);
|
|
210
|
+
const onClick = (index: number, data: T, event: Event | MouseEvent) => {
|
|
211
|
+
emits("click", index, data, event);
|
|
173
212
|
};
|
|
174
213
|
|
|
214
|
+
const showMoreFilter = () => {
|
|
215
|
+
visibleMoreFilter.value = true;
|
|
216
|
+
};
|
|
217
|
+
const clearFilter = () => {
|
|
218
|
+
visibleMoreFilter.value = false;
|
|
219
|
+
emits("clearFilter");
|
|
220
|
+
};
|
|
221
|
+
const runFilter = () => {
|
|
222
|
+
visibleMoreFilter.value = false;
|
|
223
|
+
emits("runFilter");
|
|
224
|
+
};
|
|
175
225
|
onMounted(() => {
|
|
176
226
|
// if(props.withFilter) listviewfilter.value.$el.focus()
|
|
177
227
|
});
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<Sidebar
|
|
3
|
-
position="right"
|
|
3
|
+
:position="position??'right'"
|
|
4
4
|
v-if="showDialog"
|
|
5
5
|
v-model:visible="showDialog"
|
|
6
6
|
modal
|
|
7
7
|
:show-close-icon="false"
|
|
8
|
+
:dismissable="dismissable"
|
|
8
9
|
#container
|
|
9
10
|
>
|
|
10
|
-
<div class="overflow-y-scroll">
|
|
11
|
+
<div class="overflow-y-scroll border-l-2">
|
|
11
12
|
<MobileToolbar class="bg-gray-800 text-white">
|
|
12
13
|
<template #start>
|
|
13
14
|
<slot name="headerLeft"></slot>
|
|
@@ -19,7 +20,7 @@
|
|
|
19
20
|
<slot name="headerRight"></slot>
|
|
20
21
|
</template>
|
|
21
22
|
</MobileToolbar>
|
|
22
|
-
<div >
|
|
23
|
+
<div class="p-2">
|
|
23
24
|
<slot name="default"></slot>
|
|
24
25
|
</div>
|
|
25
26
|
</div>
|
|
@@ -33,7 +34,12 @@
|
|
|
33
34
|
* Author: Ks Tan
|
|
34
35
|
*/
|
|
35
36
|
const showDialog = defineModel<boolean>({ required: true });
|
|
36
|
-
const props = defineProps<{
|
|
37
|
+
const props = defineProps<{
|
|
38
|
+
closeEventName: string;
|
|
39
|
+
dismissable?: boolean;
|
|
40
|
+
position?:string
|
|
41
|
+
}>();
|
|
42
|
+
// const position = ref(props?.position ?? 'right')
|
|
37
43
|
useNuxtApp().$listen("CloseDialog", (closeEventName: string) => {
|
|
38
44
|
if (props.closeEventName == closeEventName) {
|
|
39
45
|
showDialog.value = false;
|
|
@@ -3,12 +3,18 @@
|
|
|
3
3
|
position="right"
|
|
4
4
|
v-if="showDialog"
|
|
5
5
|
v-model:visible="showDialog"
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
:dismissable="dismissable"
|
|
7
|
+
modal
|
|
8
8
|
#container
|
|
9
|
-
>
|
|
10
|
-
<div class="
|
|
11
|
-
<
|
|
9
|
+
>
|
|
10
|
+
<div class="border-l-2 pl-2">
|
|
11
|
+
<div class="flex flex-row justify-end p-2" v-if="title">
|
|
12
|
+
<TextTitle class="dark:text-white line-clamp-2 flex-1">{{title}}</TextTitle>
|
|
13
|
+
<ButtonText @click="showDialog=false"><i class="pi pi-times" /></ButtonText>
|
|
14
|
+
</div>
|
|
15
|
+
<div class="overflow-y-scroll">
|
|
16
|
+
<slot name="default"></slot>
|
|
17
|
+
</div>
|
|
12
18
|
</div>
|
|
13
19
|
</Sidebar>
|
|
14
20
|
</template>
|
|
@@ -20,7 +26,12 @@
|
|
|
20
26
|
* Author: Ks Tan
|
|
21
27
|
*/
|
|
22
28
|
const showDialog = defineModel<boolean>({ required: true });
|
|
23
|
-
const props = defineProps<{
|
|
29
|
+
const props = defineProps<{
|
|
30
|
+
closeEventName: string
|
|
31
|
+
title?:string
|
|
32
|
+
dismissable?:boolean
|
|
33
|
+
|
|
34
|
+
}>();
|
|
24
35
|
useNuxtApp().$listen("CloseDialog", (closeEventName: string) => {
|
|
25
36
|
if (props.closeEventName == closeEventName) {
|
|
26
37
|
showDialog.value = false;
|
|
@@ -1,16 +1,25 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<
|
|
3
|
-
position="bottom"
|
|
2
|
+
<Dialog
|
|
4
3
|
v-if="showDialog"
|
|
5
4
|
v-model:visible="showDialog"
|
|
6
|
-
|
|
5
|
+
|
|
6
|
+
maximizable
|
|
7
|
+
:dismissable="false"
|
|
7
8
|
:show-close-icon="false"
|
|
8
|
-
|
|
9
|
+
:closeOnEscape="false"
|
|
10
|
+
:modal="true"
|
|
11
|
+
:pt="{root:{class:'w-11/12 border top-0'}, mask: {
|
|
12
|
+
style: 'backdrop-filter: blur(2px);background-color: red;'
|
|
13
|
+
}}"
|
|
14
|
+
|
|
9
15
|
>
|
|
10
|
-
<
|
|
16
|
+
<template #header>
|
|
17
|
+
<slot name="header">{{t(title)}}</slot>
|
|
18
|
+
</template>
|
|
19
|
+
<div class="overflow-y-scroll bg-white">
|
|
11
20
|
<slot name="default"></slot>
|
|
12
21
|
</div>
|
|
13
|
-
</
|
|
22
|
+
</Dialog>
|
|
14
23
|
</template>
|
|
15
24
|
<script lang="ts" setup>
|
|
16
25
|
/**
|
|
@@ -23,4 +32,5 @@ const showDialog = defineModel<boolean>({ required: true });
|
|
|
23
32
|
useNuxtApp().$listen("CloseDialog", (closeEventName: string) => {
|
|
24
33
|
if (closeEventName == "viewer") showDialog.value = false;
|
|
25
34
|
});
|
|
35
|
+
|
|
26
36
|
</script>
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<title v-if="!id">{{ t(doc.getDocName()) }}</title>
|
|
3
|
+
|
|
3
4
|
<div v-if="isMobile()" class="w-full">
|
|
4
5
|
<div class="p-2 flex flex-row justify-end place-items-center h-14">
|
|
5
6
|
<div class="flex-1">
|
|
6
|
-
<
|
|
7
|
+
<TextMain>{{ t(doc.getDocName()) }}</TextMain>
|
|
7
8
|
</div>
|
|
8
9
|
<div>
|
|
9
10
|
<ButtonText
|
|
@@ -45,37 +46,82 @@
|
|
|
45
46
|
</template>
|
|
46
47
|
<template #default>
|
|
47
48
|
<slot name="dataTableColumns">
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
class="min-w-[5rem]"
|
|
52
|
-
#body="{ index, data }"
|
|
49
|
+
<!-- :sortable="schemacols[col] && schemacols[col].type!='object'" -->
|
|
50
|
+
<template
|
|
51
|
+
v-for="col in columns.filter((item, index) => index < maxcolumns)"
|
|
53
52
|
>
|
|
54
|
-
<
|
|
55
|
-
v-if="
|
|
56
|
-
:
|
|
57
|
-
|
|
58
|
-
:
|
|
53
|
+
<Column
|
|
54
|
+
v-if="schemacols[col]"
|
|
55
|
+
:header="t(col)"
|
|
56
|
+
sortable
|
|
57
|
+
:field="schemacols[col]['x-foreignkey'] ? col + '.label' : col"
|
|
58
|
+
:class="`min-w-[5rem] ${getCssClass(col)}`"
|
|
59
|
+
#body="{ index, data }"
|
|
59
60
|
>
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
61
|
+
<RendererLink
|
|
62
|
+
v-if="uniqueKey === col || documentTitle === col"
|
|
63
|
+
:value="data"
|
|
64
|
+
:setting="{ path: resourcename.toLocaleLowerCase() }"
|
|
65
|
+
:fields="[col]"
|
|
66
|
+
>
|
|
67
|
+
</RendererLink>
|
|
68
|
+
<span v-else-if="typeof schemacols[col].enum != 'undefined'">
|
|
69
|
+
{{ t(data[col]) }}
|
|
70
|
+
</span>
|
|
71
|
+
<span v-else-if="schemacols[col].type == 'boolean'">
|
|
72
|
+
<RendererBoolean v-model="data[col]" />
|
|
73
|
+
</span>
|
|
74
|
+
<RendererForeignKey
|
|
75
|
+
v-else-if="schemacols[col]['x-foreignkey']"
|
|
76
|
+
v-model="data[col]"
|
|
77
|
+
:setting="{ collection: schemacols[col]['x-foreignkey'] }"
|
|
78
|
+
>
|
|
79
|
+
{{ data[col]?.label ?? data[col]?.code ?? data[col] }}
|
|
80
|
+
</RendererForeignKey>
|
|
81
|
+
<span v-else-if="data[col]?.label !== undefined">{{
|
|
82
|
+
data[col].label
|
|
83
|
+
}}</span>
|
|
84
|
+
<span v-else>{{ data[col] }}</span>
|
|
85
|
+
</Column>
|
|
86
|
+
</template>
|
|
67
87
|
</slot>
|
|
68
88
|
</template>
|
|
69
89
|
</ListDocumentTable>
|
|
70
90
|
</div>
|
|
71
|
-
<
|
|
91
|
+
<OverlayPanelWithToolBar
|
|
72
92
|
v-model="showDialog"
|
|
73
93
|
:closeEventName="doc.getDocName()"
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
94
|
+
:dismissable="false"
|
|
95
|
+
:position="sidebarposition"
|
|
96
|
+
>
|
|
97
|
+
<template #headerLeft>
|
|
98
|
+
<ButtonText @click="showDialog = false">
|
|
99
|
+
<i class="pi pi-times"></i>
|
|
100
|
+
</ButtonText>
|
|
101
|
+
</template>
|
|
102
|
+
<template #headerCenter>
|
|
103
|
+
<TextTitle class="text-center text-white">{{
|
|
104
|
+
t(doc.getDocName())
|
|
105
|
+
}}</TextTitle>
|
|
106
|
+
</template>
|
|
107
|
+
<template #headerRight>
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
<ButtonText @click="sidebarposition = sidebarposition == 'right' ? sidebarposition='full': 'right'">
|
|
113
|
+
<i v-if="sidebarposition=='right'" class="pi pi-window-maximize"/>
|
|
114
|
+
<i v-if="sidebarposition=='full'" class="pi pi-window-minimize"/>
|
|
115
|
+
</ButtonText>
|
|
116
|
+
|
|
117
|
+
</template>
|
|
118
|
+
|
|
119
|
+
<div class="p-2">
|
|
120
|
+
<slot name="default">
|
|
121
|
+
<NuxtPage :_id="id"></NuxtPage>
|
|
122
|
+
</slot>
|
|
123
|
+
</div>
|
|
124
|
+
</OverlayPanelWithToolBar>
|
|
79
125
|
</template>
|
|
80
126
|
|
|
81
127
|
<script setup lang="ts" generic="T extends { [key: string]: any }">
|
|
@@ -89,14 +135,16 @@ import { ref } from "vue";
|
|
|
89
135
|
import _ from "lodash";
|
|
90
136
|
import { SearchBody } from "~/types";
|
|
91
137
|
import { SimpleAppClient } from "~/simpleapp/generate/clients/SimpleAppClient";
|
|
138
|
+
const sidebarposition = ref('right')
|
|
92
139
|
const props = defineProps<{
|
|
93
140
|
document: SimpleAppClient<any, any>;
|
|
94
141
|
data: T;
|
|
142
|
+
dismissable?: boolean;
|
|
95
143
|
columns: string[];
|
|
96
144
|
mobileColumns?: string[];
|
|
97
145
|
sorts?: string[][];
|
|
98
146
|
}>();
|
|
99
|
-
|
|
147
|
+
const maxcolumns = 16;
|
|
100
148
|
const emits = defineEmits(["selectRow"]);
|
|
101
149
|
const id = computed(() => getPathPara("id"));
|
|
102
150
|
const resourcename = ref(_.upperFirst(props.document.getDocName()));
|
|
@@ -115,7 +163,13 @@ const { $event, $listen } = useNuxtApp();
|
|
|
115
163
|
const recordlist = ref<T[]>();
|
|
116
164
|
const uniqueKey = doc.getSchema()["x-simpleapp-config"].uniqueKey;
|
|
117
165
|
const documentTitle = doc.getSchema()["x-simpleapp-config"].documentTitle;
|
|
118
|
-
|
|
166
|
+
const schemacols = doc.getSchema().properties;
|
|
167
|
+
const getCssClass = (col: string) => {
|
|
168
|
+
if (schemacols[col]?.type == "number") return "text-right";
|
|
169
|
+
else if (schemacols[col]?.type == "boolean")
|
|
170
|
+
return "text-center place-items-center";
|
|
171
|
+
else return "text-left";
|
|
172
|
+
};
|
|
119
173
|
const refresh = () => {
|
|
120
174
|
const searchbody: SearchBody = {
|
|
121
175
|
fields: props.columns,
|
|
@@ -154,7 +208,7 @@ watch(showDialog, () => {
|
|
|
154
208
|
watch(
|
|
155
209
|
() => useRoute().path,
|
|
156
210
|
async () => {
|
|
157
|
-
if(!isMobile()){
|
|
211
|
+
if (!isMobile()) {
|
|
158
212
|
if (getPathPara("id")) {
|
|
159
213
|
showDialog.value = true;
|
|
160
214
|
} else {
|
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div>
|
|
3
|
-
<div class="flex flex-row
|
|
3
|
+
<div class="flex flex-row">
|
|
4
4
|
<label v-if="!hideLabel" :for="fieldid" class="pt-2">
|
|
5
|
-
|
|
5
|
+
{{ t(documentName) }}
|
|
6
6
|
</label>
|
|
7
|
-
<ButtonText
|
|
8
|
-
|
|
7
|
+
<ButtonText
|
|
8
|
+
v-if="allowAddNew"
|
|
9
|
+
@click="addnew"
|
|
10
|
+
class="text-xs text-blue-600"
|
|
11
|
+
>
|
|
12
|
+
<span>{{ t("new") }}</span>
|
|
9
13
|
</ButtonText>
|
|
10
14
|
</div>
|
|
11
15
|
<MultiSelect
|
|
@@ -20,7 +24,6 @@
|
|
|
20
24
|
:placeholder="placeholder"
|
|
21
25
|
/>
|
|
22
26
|
<Dropdown
|
|
23
|
-
|
|
24
27
|
:input-id="fieldid"
|
|
25
28
|
v-else
|
|
26
29
|
@update:modelValue="change"
|
|
@@ -40,20 +43,25 @@
|
|
|
40
43
|
* Author: Ks Tan
|
|
41
44
|
*/
|
|
42
45
|
import Dropdown from "primevue/dropdown";
|
|
43
|
-
|
|
46
|
+
|
|
47
|
+
import { ForeignKey,SimpleAppDocuments, FormCrudEvent } from "~/types";
|
|
44
48
|
const emits = defineEmits(["change"]);
|
|
45
|
-
|
|
46
|
-
const list = ref<ForeignKey[]>([]);
|
|
47
|
-
const fieldid = randomUUID()
|
|
49
|
+
|
|
48
50
|
const props = defineProps<{
|
|
49
|
-
documentName:
|
|
51
|
+
documentName: SimpleAppDocuments;
|
|
50
52
|
placeholder?: string;
|
|
51
53
|
showNull?: boolean;
|
|
52
54
|
allowAddNew?: boolean;
|
|
53
55
|
filter?: any;
|
|
54
56
|
multiple?: boolean;
|
|
55
|
-
hideLabel?:boolean
|
|
57
|
+
hideLabel?: boolean;
|
|
56
58
|
}>();
|
|
59
|
+
// const initvalue = props.multiple==true ? [] : ''
|
|
60
|
+
const modelValue = defineModel<string | string[]>();
|
|
61
|
+
|
|
62
|
+
const list = ref<ForeignKey[]>([]);
|
|
63
|
+
const fieldid = randomUUID();
|
|
64
|
+
|
|
57
65
|
const options = ref<
|
|
58
66
|
{
|
|
59
67
|
value: string;
|
|
@@ -79,30 +87,34 @@ onMounted(async () => {
|
|
|
79
87
|
});
|
|
80
88
|
const getItem = (id: string) => list.value?.find((item) => item._id == id);
|
|
81
89
|
|
|
82
|
-
const change = (id: string) => {
|
|
90
|
+
const change = (id: string|string[]) => {
|
|
83
91
|
const selectedItem = getItem(id);
|
|
84
92
|
emits("change", id, selectedItem);
|
|
85
|
-
|
|
86
93
|
};
|
|
87
94
|
|
|
88
|
-
const addnew=()=>{
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
modelValue.value =
|
|
101
|
-
|
|
95
|
+
const addnew = () => {
|
|
96
|
+
const doc = getDocument(props.documentName )?.docClass;
|
|
97
|
+
if (doc) {
|
|
98
|
+
const tmpdata = doc?.getReactiveData();
|
|
99
|
+
type DataType = typeof tmpdata.value;
|
|
100
|
+
onScreenAddDocument<DataType>(
|
|
101
|
+
props.documentName ,
|
|
102
|
+
undefined,
|
|
103
|
+
async (eventType: FormCrudEvent, data: DataType) => {
|
|
104
|
+
if (eventType == FormCrudEvent.create) {
|
|
105
|
+
await getListOptions();
|
|
106
|
+
if(props.multiple) {
|
|
107
|
+
if(modelValue.value===undefined) modelValue.value=[data._id]
|
|
108
|
+
else if(Array.isArray(modelValue.value))
|
|
109
|
+
modelValue.value.push(data._id);
|
|
110
|
+
|
|
111
|
+
|
|
102
112
|
}
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
113
|
+
else modelValue.value = data._id;
|
|
114
|
+
emits("change", data._id, getItem(data._id));
|
|
115
|
+
}
|
|
116
|
+
},
|
|
117
|
+
);
|
|
106
118
|
}
|
|
107
|
-
}
|
|
119
|
+
};
|
|
108
120
|
</script>
|
|
@@ -1,7 +1,41 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div
|
|
2
|
+
<div
|
|
3
|
+
v-if="readonly"
|
|
4
|
+
class="p-3 border rounded-lg border-gray-300 dark:border-blue-900/40"
|
|
5
|
+
>
|
|
6
|
+
<button
|
|
7
|
+
:readonly="readonly"
|
|
8
|
+
class="cursor-pointer text-primary-600 dark:text-primary-400"
|
|
9
|
+
tabindex="0"
|
|
10
|
+
@click="openViewer(true)"
|
|
11
|
+
>{{ modelValue && modelValue.label ? modelValue.label : "-" }}</button
|
|
12
|
+
>
|
|
13
|
+
</div>
|
|
14
|
+
<div
|
|
15
|
+
v-else-if="modelValue !== undefined"
|
|
16
|
+
class="p-3 border rounded-lg border-gray-300 dark:border-blue-900/40 relative"
|
|
17
|
+
>
|
|
18
|
+
<button
|
|
19
|
+
ref="autocompleteinput"
|
|
20
|
+
readonly
|
|
21
|
+
class="cursor-pointer text-primary-600 dark:text-primary-400"
|
|
22
|
+
|
|
23
|
+
@click="openViewer(true)"
|
|
24
|
+
>{{ modelValue && modelValue.label ? modelValue.label : "-" }}</button>
|
|
25
|
+
|
|
26
|
+
<div
|
|
27
|
+
class="absolute h-full top-0 right-0 text-right text-white z-10 align-middle p-3"
|
|
28
|
+
>
|
|
29
|
+
<button
|
|
30
|
+
class="pi pi-times rounded-full bg-slate-500 p-1 cursor-pointer text-xs"
|
|
31
|
+
@click="clear" tabindex="0"
|
|
32
|
+
|
|
33
|
+
></button>
|
|
34
|
+
</div>
|
|
35
|
+
</div>
|
|
36
|
+
<div v-else class="relative">
|
|
3
37
|
<div
|
|
4
|
-
class="absolute h-full top-0 right-10 text-right
|
|
38
|
+
class="absolute h-full top-0 right-10 text-right text-white z-10 align-middle p-3"
|
|
5
39
|
v-if="modelValue?._id"
|
|
6
40
|
>
|
|
7
41
|
<span
|
|
@@ -24,14 +58,15 @@
|
|
|
24
58
|
:dropdown="true"
|
|
25
59
|
@clear="clear"
|
|
26
60
|
:dropdown-mode="'current'"
|
|
61
|
+
:readonly="readonly"
|
|
27
62
|
:pt="pt"
|
|
28
63
|
:delay="500"
|
|
29
64
|
:disabled="readonly"
|
|
65
|
+
@click="clickAutocomplete"
|
|
30
66
|
:suggestions="list"
|
|
31
67
|
@blur="onBlurAutocomplete"
|
|
32
68
|
:inputId="inputId"
|
|
33
69
|
:path="setting.instancepath"
|
|
34
|
-
:readonly="readonly"
|
|
35
70
|
>
|
|
36
71
|
<template #header>
|
|
37
72
|
<slot name="header">
|
|
@@ -46,7 +81,7 @@
|
|
|
46
81
|
</template>
|
|
47
82
|
<template #option="{ index, option }">
|
|
48
83
|
<slot name="option" :index="index" :option="option">
|
|
49
|
-
<div class="flex flex-row text-white">
|
|
84
|
+
<div class="flex flex-row dark:text-white">
|
|
50
85
|
<div class="w w-1/3">{{ option.code }}</div>
|
|
51
86
|
<div class="w w-2/3">{{ option.label }}</div>
|
|
52
87
|
</div>
|
|
@@ -91,7 +126,7 @@
|
|
|
91
126
|
<i class="pi pi-plus"></i>
|
|
92
127
|
</ButtonText> -->
|
|
93
128
|
</template>
|
|
94
|
-
</mobile-toolbar>
|
|
129
|
+
</mobile-toolbar>
|
|
95
130
|
<ListView
|
|
96
131
|
:list="list"
|
|
97
132
|
:withFilter="true"
|
|
@@ -124,18 +159,6 @@
|
|
|
124
159
|
</OverlaySideBarCrud>
|
|
125
160
|
</div>
|
|
126
161
|
</div>
|
|
127
|
-
<div
|
|
128
|
-
v-else
|
|
129
|
-
class="p-3 border rounded-lg border-gray-300 dark:border-blue-900/40"
|
|
130
|
-
>
|
|
131
|
-
<span
|
|
132
|
-
:readonly="readonly"
|
|
133
|
-
class="cursor-pointer text-primary-600 dark:text-primary-400"
|
|
134
|
-
tabindex="0"
|
|
135
|
-
@click="openViewer(true)"
|
|
136
|
-
>{{ modelValue && modelValue.label ? modelValue.label : "-" }}</span
|
|
137
|
-
>
|
|
138
|
-
</div>
|
|
139
162
|
</template>
|
|
140
163
|
<script setup lang="ts">
|
|
141
164
|
/**
|
|
@@ -368,4 +391,9 @@ const afterRenderMobileForm = async (
|
|
|
368
391
|
mobileVisible.value = false;
|
|
369
392
|
}
|
|
370
393
|
};
|
|
394
|
+
|
|
395
|
+
const clickAutocomplete = (a, b) => {
|
|
396
|
+
console.log("clickAutocomplete", a, b);
|
|
397
|
+
return false;
|
|
398
|
+
};
|
|
371
399
|
</script>
|