@simitgroup/simpleapp-generator 1.6.4-c-alpha → 1.6.4-d-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/dist/buildinschemas/documentevent.d.ts +3 -0
- package/dist/buildinschemas/documentevent.d.ts.map +1 -0
- package/dist/buildinschemas/documentevent.js +38 -0
- package/dist/buildinschemas/documentevent.js.map +1 -0
- package/dist/buildinschemas/index.d.ts +2 -0
- package/dist/buildinschemas/index.d.ts.map +1 -1
- package/dist/buildinschemas/index.js +5 -1
- package/dist/buildinschemas/index.js.map +1 -1
- package/dist/buildinschemas/tenant.d.ts.map +1 -1
- package/dist/buildinschemas/tenant.js +8 -0
- package/dist/buildinschemas/tenant.js.map +1 -1
- package/dist/buildinschemas/webhook.d.ts.map +1 -1
- package/dist/buildinschemas/webhook.js +21 -3
- package/dist/buildinschemas/webhook.js.map +1 -1
- package/dist/buildinschemas/webhookhistory.d.ts +3 -0
- package/dist/buildinschemas/webhookhistory.d.ts.map +1 -0
- package/dist/buildinschemas/webhookhistory.js +44 -0
- package/dist/buildinschemas/webhookhistory.js.map +1 -0
- package/dist/framework.js +1 -1
- package/dist/framework.js.map +1 -1
- package/dist/generate.js +1 -1
- package/dist/generate.js.map +1 -1
- package/package.json +1 -1
- package/src/buildinschemas/documentevent.ts +36 -0
- package/src/buildinschemas/index.ts +3 -1
- package/src/buildinschemas/tenant.ts +8 -0
- package/src/buildinschemas/webhook.ts +22 -3
- package/src/buildinschemas/webhookhistory.ts +42 -0
- package/src/framework.ts +1 -1
- package/src/generate.ts +1 -1
- package/templates/basic/nest/apischema.ts.eta +6 -2
- package/templates/basic/nest/controller.ts.eta +4 -3
- package/templates/basic/nest/default.ts.eta +6 -5
- package/templates/basic/nuxt/default.ts.eta +2 -0
- package/templates/basic/nuxt/simpleapp.generate.client.ts.eta +1 -6
- package/templates/nest/src/simpleapp/apischemas/index.ts._eta +17 -0
- package/templates/nest/src/simpleapp/generate/commons/audittrail.service.ts.eta +37 -7
- package/templates/nest/src/simpleapp/generate/commons/runwebhook.service.ts.eta +39 -20
- package/templates/nest/src/simpleapp/generate/commons/user.context.ts.eta +53 -39
- package/templates/nest/src/simpleapp/generate/controllers/simpleapp.controller.ts.eta +3 -3
- package/templates/nest/src/simpleapp/generate/processors/simpleapp.processor.ts.eta +100 -34
- package/templates/nest/src/simpleapp/profile/profile.service.ts.eta +5 -0
- package/templates/nest/src/simpleapp/simpleapp.module.ts.eta +3 -3
- package/templates/nest/src/simpleapp/types/index.ts._eta +14 -0
- package/templates/nuxt/app.vue.eta +9 -7
- package/templates/nuxt/components/image/ImageAvatar.vue.eta._vue +7 -14
- package/templates/nuxt/components/list/ListView.vue.eta +97 -111
- package/templates/nuxt/components/renderer/RendererDocHistories.vue.eta +102 -42
- package/templates/nuxt/components/search/SearchBox.vue._eta +371 -0
- package/templates/nuxt/components/search/SearchBoxBefore.vue._eta +11 -0
- package/templates/nuxt/components/search/SearchBoxProduct.vue._eta +26 -0
- package/templates/nuxt/components/simpleApp/SimpleAppAutocomplete.vue.eta +24 -3
- package/templates/nuxt/components/simpleApp/SimpleAppCalendarInput.vue.eta +1 -0
- package/templates/nuxt/components/simpleApp/SimpleAppChildrenList.vue.eta +10 -5
- package/templates/nuxt/components/simpleApp/SimpleAppFormToolBar.vue._eta +4 -3
- package/templates/nuxt/components/user/UserTenantPicker.vue.eta +18 -16
- package/templates/nuxt/composables/getOpenApi.generate.ts.eta +6 -49
- package/templates/nuxt/composables/stringHelper.generate.ts.eta +2 -2
- package/templates/nuxt/middleware/30.acl.global.ts.eta +6 -5
- package/templates/nuxt/pages/[xorg]/pickgroup.vue._eta +28 -27
- package/templates/nuxt/pages/picktenant.vue._eta +3 -3
- package/templates/nuxt/plugins/20.simpleapp-userstore.ts.eta +49 -29
- package/templates/nuxt/simpleapp/generate/clients/SimpleAppClient.ts.eta +7 -1
- package/templates/nuxt/types/others.ts.eta +7 -1
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -1,56 +1,116 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
2
|
+
<div
|
|
3
|
+
class="flex flex-row text-xs cursor-pointer justify-end "
|
|
4
|
+
v-if="data?.updated && data?.updated != ''"
|
|
5
|
+
@click="viewHistories"
|
|
6
|
+
>
|
|
7
|
+
<ImageAvatar
|
|
8
|
+
v-if="data?.updatedBy"
|
|
9
|
+
:id="data.updatedBy"
|
|
10
|
+
:size="8"
|
|
11
|
+
></ImageAvatar>
|
|
12
|
+
<div class="flex flex-col flex-1">
|
|
13
|
+
<TextDocStatus v-if="data?.documentStatus" :docStatus="data?.documentStatus" />
|
|
14
|
+
<!-- <TextSubsubtitle class="text-gray-400 italic"
|
|
15
|
+
>{{ t("updated") }}:</TextSubsubtitle
|
|
16
|
+
> -->
|
|
17
|
+
<RendererDateAge :value="data?.updated" class="text-gray-400 italic" />
|
|
9
18
|
</div>
|
|
10
|
-
|
|
11
19
|
|
|
12
|
-
<Dialog
|
|
13
|
-
:
|
|
20
|
+
<Dialog
|
|
21
|
+
v-model:visible="visibleHistories"
|
|
22
|
+
modal
|
|
23
|
+
:header="t(documentName) + ' ' + t('histories')"
|
|
24
|
+
:pt="{ root: { class: 'w-1/3' } }"
|
|
25
|
+
>
|
|
14
26
|
<Timeline :value="events" class="w-full md:w-20rem">
|
|
15
|
-
<template #opposite="
|
|
16
|
-
<
|
|
27
|
+
<template #opposite="{ item }">
|
|
28
|
+
<div class="flex flex-row">
|
|
29
|
+
<ImageAvatar :email="item.email" :id="item.uid" :size="12" />
|
|
30
|
+
<div class="flex flex-col">
|
|
31
|
+
<span>{{ item.fullName }}</span>
|
|
32
|
+
<RendererDateAge
|
|
33
|
+
class="italic text-gray-400 text-xs whitespace-nowrap"
|
|
34
|
+
:value="item.eventDate"
|
|
35
|
+
/>
|
|
36
|
+
</div>
|
|
37
|
+
</div>
|
|
17
38
|
</template>
|
|
18
|
-
<template #content="
|
|
39
|
+
<template #content="{ item }">
|
|
19
40
|
<div>
|
|
20
|
-
<div>{{
|
|
21
|
-
</div>
|
|
22
|
-
|
|
41
|
+
<div>{{ item.status }}</div>
|
|
42
|
+
</div>
|
|
23
43
|
</template>
|
|
24
|
-
|
|
44
|
+
</Timeline>
|
|
25
45
|
</Dialog>
|
|
26
46
|
</div>
|
|
27
|
-
|
|
28
47
|
</template>
|
|
29
48
|
<script lang="ts" setup>
|
|
30
|
-
import TextSubsubtitle from
|
|
31
|
-
import RendererDateTime from
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
49
|
+
import TextSubsubtitle from "../text/TextSubsubtitle.vue";
|
|
50
|
+
import RendererDateTime from "./RendererDateTime.vue";
|
|
51
|
+
import { Documentevent, User } from "~/simpleapp/generate/openapi";
|
|
52
|
+
const eventDoc = useNuxtApp().$DocumenteventDoc();
|
|
53
|
+
const visibleHistories = ref(false);
|
|
54
|
+
const props = defineProps<{ data: any; documentName: string }>();
|
|
55
|
+
type EventHistory = {
|
|
56
|
+
status: string;
|
|
57
|
+
eventDate: string;
|
|
58
|
+
uid?: string;
|
|
59
|
+
fullName?: string;
|
|
60
|
+
email?: string;
|
|
61
|
+
};
|
|
62
|
+
const events = ref<EventHistory[]>([]);
|
|
63
|
+
const getEvents = async () => {
|
|
64
|
+
const simplelog = [
|
|
65
|
+
{
|
|
66
|
+
status: t("created"),
|
|
67
|
+
eventDate: props.data.created,
|
|
68
|
+
uid: props.data.createdBy,
|
|
69
|
+
},
|
|
70
|
+
];
|
|
71
|
+
if (props.data.updated != props.data.created) {
|
|
72
|
+
simplelog.push({
|
|
73
|
+
status: t("lastUpdate"),
|
|
74
|
+
eventDate: props.data.updated,
|
|
75
|
+
uid: props.data.updatedBy,
|
|
76
|
+
});
|
|
77
|
+
}
|
|
51
78
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
79
|
+
// events.value=[];
|
|
80
|
+
// console.log("Renderer getEvents histories");
|
|
81
|
+
const list: (Documentevent & { _user: User })[] = await eventDoc.search({
|
|
82
|
+
filter: {
|
|
83
|
+
documentName: props.documentName,
|
|
84
|
+
documentId: props.data._id,
|
|
85
|
+
},
|
|
86
|
+
fields: ["created", "createdBy", "eventType"],
|
|
87
|
+
sorts: [["created", "asc"]],
|
|
88
|
+
lookup: { "user.uid": "createdBy" },
|
|
89
|
+
});
|
|
90
|
+
if (list.length > 0) {
|
|
91
|
+
events.value = list.map((item) => ({
|
|
92
|
+
_id: <string>item._id,
|
|
93
|
+
status: t(<string>item.eventType),
|
|
94
|
+
eventDate: <string>item.created,
|
|
95
|
+
uid: <string>item.createdBy,
|
|
96
|
+
fullName: <string>item._user.fullName,
|
|
97
|
+
email: <string>item._user.email,
|
|
98
|
+
}));
|
|
99
|
+
} else {
|
|
100
|
+
events.value = simplelog;
|
|
55
101
|
}
|
|
102
|
+
};
|
|
103
|
+
const severity = computed(() => {
|
|
104
|
+
const stat = props.data.docStatus;
|
|
105
|
+
if (props.data.docStatus == "confirm") return "success";
|
|
106
|
+
else if (props.data.docStatus == "void") return "danger";
|
|
107
|
+
else if (props.data.docStatus == "draft") return "secondary";
|
|
108
|
+
else return "warning";
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
const viewHistories = async () => {
|
|
112
|
+
visibleHistories.value = true;
|
|
113
|
+
await getEvents();
|
|
114
|
+
// console.log("histories");
|
|
115
|
+
};
|
|
56
116
|
</script>
|
|
@@ -0,0 +1,371 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div
|
|
3
|
+
v-if="getCurrentXorg() && canPerform('student', 'search')"
|
|
4
|
+
class="w-full border p-2 rounded-lg flex flex-row gap-1 cursor-pointer justify-between"
|
|
5
|
+
@click="showDialog"
|
|
6
|
+
>
|
|
7
|
+
<i class="pi pi-search p-1" />
|
|
8
|
+
|
|
9
|
+
<span>{{ t("search") }}</span>
|
|
10
|
+
<span
|
|
11
|
+
v-if="isMacOS"
|
|
12
|
+
class="bg-green-800 text-white pl-2 pr-2 text-sm rounded border"
|
|
13
|
+
>
|
|
14
|
+
⌘+k
|
|
15
|
+
</span>
|
|
16
|
+
<span
|
|
17
|
+
v-else
|
|
18
|
+
class="bg-green-800 text-white pl-2 pr-2 text-sm rounded border"
|
|
19
|
+
>
|
|
20
|
+
cmd+k
|
|
21
|
+
</span>
|
|
22
|
+
|
|
23
|
+
<Dialog
|
|
24
|
+
v-model:visible="visiblesearch"
|
|
25
|
+
:closable="false"
|
|
26
|
+
dismissable-mask
|
|
27
|
+
position="top"
|
|
28
|
+
modal
|
|
29
|
+
:pt="{ root: { class: 'mt-0 w-1/2 max-h-screen' } }"
|
|
30
|
+
>
|
|
31
|
+
<template #header>
|
|
32
|
+
<div class="flex flex-col w-full">
|
|
33
|
+
<SearchInput
|
|
34
|
+
ref="searchbox"
|
|
35
|
+
id="searchbox"
|
|
36
|
+
v-model="searchVal"
|
|
37
|
+
:searchIcon="false"
|
|
38
|
+
:shortcutIcon="true"
|
|
39
|
+
:clearIcon="false"
|
|
40
|
+
:hideShortcutIconOnBlur="false"
|
|
41
|
+
:selectOnFocus="true"
|
|
42
|
+
:placeholder="t('searchKeyword')"
|
|
43
|
+
@update:modelValue="onchange"
|
|
44
|
+
@keydown="onKeyDown"
|
|
45
|
+
></SearchInput>
|
|
46
|
+
</div>
|
|
47
|
+
</template>
|
|
48
|
+
<template #default :tabIndex="tabIndex">
|
|
49
|
+
<div v-if="searchVal == ''"><SearchBoxBefore /></div>
|
|
50
|
+
<div v-else-if="searchVal != keyword"><ProgressSpinner /></div>
|
|
51
|
+
<TabView v-else-if="list.length > 0 || menulist.length > 0" lazy>
|
|
52
|
+
<TabPanel :header="t('all')">
|
|
53
|
+
<Listbox
|
|
54
|
+
ref="alllist"
|
|
55
|
+
@update:model-value="selectItem"
|
|
56
|
+
v-model="selecteddata"
|
|
57
|
+
:options="groupedData"
|
|
58
|
+
optionGroupLabel="label"
|
|
59
|
+
optionGroupChildren="items"
|
|
60
|
+
>
|
|
61
|
+
<template #optiongroup="{ option, index }">
|
|
62
|
+
<div class="flex align-items-center font-semibold">
|
|
63
|
+
<div>{{ option.label }}</div>
|
|
64
|
+
</div>
|
|
65
|
+
</template>
|
|
66
|
+
<template #option="{ option, index }">
|
|
67
|
+
<div v-if="option.documentName == 'menu'">
|
|
68
|
+
<SearchBoxMenu :item="option.data" />
|
|
69
|
+
</div>
|
|
70
|
+
<div v-else>
|
|
71
|
+
<SearchBoxStudent
|
|
72
|
+
v-if="option.documentName == 'student'"
|
|
73
|
+
:item="option.data"
|
|
74
|
+
/>
|
|
75
|
+
<SearchBoxTeacher
|
|
76
|
+
v-else-if="option.documentName == 'teacher'"
|
|
77
|
+
:item="option.data"
|
|
78
|
+
/>
|
|
79
|
+
<SearchBoxAccTrans
|
|
80
|
+
v-else-if="option.documentName == 'accounttransaction'"
|
|
81
|
+
:item="option.data"
|
|
82
|
+
/>
|
|
83
|
+
<SearchBoxProduct
|
|
84
|
+
v-else-if="option.documentName == 'product'"
|
|
85
|
+
:item="option.data"
|
|
86
|
+
/>
|
|
87
|
+
<TextSubsubtitle class="italic"
|
|
88
|
+
>{{ option.documentName }}
|
|
89
|
+
{{ option.data.score }}</TextSubsubtitle
|
|
90
|
+
>
|
|
91
|
+
</div>
|
|
92
|
+
</template>
|
|
93
|
+
</Listbox>
|
|
94
|
+
|
|
95
|
+
<!-- <ListView ref="searchlistel" :list="list" idField="_id" @click="selectItem" #default="{item,index}">
|
|
96
|
+
<SearchBoxMenu v-if="item.documentName=='menu'" :item="item.data"/>
|
|
97
|
+
<SearchBoxStudent v-else-if="item.documentName=='student'" :item="item.data"/>
|
|
98
|
+
<SearchBoxTeacher v-else-if="item.documentName=='teacher'" :item="item.data"/>
|
|
99
|
+
<SearchBoxAccTrans v-else-if="item.documentName=='accounttransaction'" :item="item.data"/>
|
|
100
|
+
</ListView> -->
|
|
101
|
+
</TabPanel>
|
|
102
|
+
<TabPanel :header="t('students')" v-if="students.length > 0">
|
|
103
|
+
<ListView
|
|
104
|
+
ref="searchstudentlistel"
|
|
105
|
+
:list="students"
|
|
106
|
+
idField="_id"
|
|
107
|
+
#default="{ item, index }"
|
|
108
|
+
>
|
|
109
|
+
<SearchBoxStudent :item="item.data" />
|
|
110
|
+
</ListView>
|
|
111
|
+
</TabPanel>
|
|
112
|
+
<TabPanel :header="t('transactions')" v-if="acctrans.length > 0">
|
|
113
|
+
<ListView
|
|
114
|
+
ref="searchstudentlistel"
|
|
115
|
+
:list="acctrans"
|
|
116
|
+
idField="_id"
|
|
117
|
+
#default="{ item, index }"
|
|
118
|
+
>
|
|
119
|
+
<SearchBoxAccTrans :item="item.data" />
|
|
120
|
+
</ListView>
|
|
121
|
+
</TabPanel>
|
|
122
|
+
<TabPanel :header="t('teacher')" v-if="teachers.length > 0">
|
|
123
|
+
<ListView
|
|
124
|
+
ref="searchteacherlistel"
|
|
125
|
+
:list="teachers"
|
|
126
|
+
idField="_id"
|
|
127
|
+
#default="{ item, index }"
|
|
128
|
+
>
|
|
129
|
+
<SearchBoxTeacher :item="item.data" />
|
|
130
|
+
</ListView>
|
|
131
|
+
</TabPanel>
|
|
132
|
+
</TabView>
|
|
133
|
+
<div v-else><NodataLarge /></div>
|
|
134
|
+
</template>
|
|
135
|
+
</Dialog>
|
|
136
|
+
</div>
|
|
137
|
+
</template>
|
|
138
|
+
<script setup lang="ts">
|
|
139
|
+
/**
|
|
140
|
+
* This file was automatically generated by simpleapp generator during initialization. It is changable.
|
|
141
|
+
* last change 2024-02-22
|
|
142
|
+
* author: Ks Tan
|
|
143
|
+
*/
|
|
144
|
+
import SearchInput from "vue-search-input";
|
|
145
|
+
import { getAllDocuments } from "~/simpleapp/generate/commons/documents";
|
|
146
|
+
import "vue-search-input/dist/styles.css";
|
|
147
|
+
import { debounce } from "lodash"; // Assuming you have Lodash installed
|
|
148
|
+
import {
|
|
149
|
+
Accounttransaction,
|
|
150
|
+
Student,
|
|
151
|
+
Teacher,
|
|
152
|
+
} from "~/simpleapp/generate/openapi";
|
|
153
|
+
import { SimpleAppDocuments, MenuData, ForeignKey } from "~/types";
|
|
154
|
+
import TextSubsubtitle from "../text/TextSubsubtitle.vue";
|
|
155
|
+
const alllist = ref();
|
|
156
|
+
const selecteddata = ref();
|
|
157
|
+
const students = computed(() =>
|
|
158
|
+
list.value.filter((item) => item.documentName == "student"),
|
|
159
|
+
);
|
|
160
|
+
const parents = computed(() =>
|
|
161
|
+
list.value.filter((item) => item.documentName == "parent"),
|
|
162
|
+
);
|
|
163
|
+
const teachers = computed(() =>
|
|
164
|
+
list.value.filter((item) => item.documentName == "teacher"),
|
|
165
|
+
);
|
|
166
|
+
const acctrans = computed(() =>
|
|
167
|
+
list.value.filter((item) => item.documentName == "accounttransaction"),
|
|
168
|
+
);
|
|
169
|
+
|
|
170
|
+
type ResultDataType = { _id: string; documentName: string; data: any };
|
|
171
|
+
const list = ref<ResultDataType[]>([]);
|
|
172
|
+
const menulist = ref<ResultDataType[]>([]);
|
|
173
|
+
|
|
174
|
+
const groupedData = computed(() => [
|
|
175
|
+
{
|
|
176
|
+
label: t("menus"),
|
|
177
|
+
items: menulist.value,
|
|
178
|
+
},
|
|
179
|
+
{
|
|
180
|
+
label: t("results"),
|
|
181
|
+
items: list.value.sort((a, b) => {
|
|
182
|
+
const vA = a.data.score;
|
|
183
|
+
const vB = b.data.score;
|
|
184
|
+
if (vA < vB) {
|
|
185
|
+
return 1;
|
|
186
|
+
}
|
|
187
|
+
if (vA > vB) {
|
|
188
|
+
return -1;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
return 0;
|
|
192
|
+
}),
|
|
193
|
+
},
|
|
194
|
+
]);
|
|
195
|
+
|
|
196
|
+
const searchlistel = ref(null);
|
|
197
|
+
const deviceType: any = useNuxtApp().$device;
|
|
198
|
+
type SearchDoc = {
|
|
199
|
+
[key: string]: {
|
|
200
|
+
fields: string[];
|
|
201
|
+
// search:string[]
|
|
202
|
+
// sort:string
|
|
203
|
+
};
|
|
204
|
+
};
|
|
205
|
+
const documents: SearchDoc = {
|
|
206
|
+
student: {
|
|
207
|
+
fields: [
|
|
208
|
+
"studentName",
|
|
209
|
+
"studentCode",
|
|
210
|
+
"alternateName",
|
|
211
|
+
"level",
|
|
212
|
+
"studentGroup",
|
|
213
|
+
"status",
|
|
214
|
+
"updated",
|
|
215
|
+
],
|
|
216
|
+
},
|
|
217
|
+
parent: {
|
|
218
|
+
fields: ["parentName", "active", "updated"],
|
|
219
|
+
},
|
|
220
|
+
product: {
|
|
221
|
+
fields: [
|
|
222
|
+
"productCode",
|
|
223
|
+
"productName",
|
|
224
|
+
"defaultPrice",
|
|
225
|
+
"billingMethod",
|
|
226
|
+
"category",
|
|
227
|
+
"categoryType",
|
|
228
|
+
"active",
|
|
229
|
+
"updated",
|
|
230
|
+
],
|
|
231
|
+
},
|
|
232
|
+
teacher: {
|
|
233
|
+
fields: [
|
|
234
|
+
"teacherNo",
|
|
235
|
+
"teacherName",
|
|
236
|
+
"alternateName",
|
|
237
|
+
"teacherGroup",
|
|
238
|
+
"active",
|
|
239
|
+
"updated",
|
|
240
|
+
],
|
|
241
|
+
},
|
|
242
|
+
accounttransaction: {
|
|
243
|
+
fields: [
|
|
244
|
+
"date",
|
|
245
|
+
"document",
|
|
246
|
+
"documentNo",
|
|
247
|
+
"documentName",
|
|
248
|
+
"amount",
|
|
249
|
+
"updated",
|
|
250
|
+
"student",
|
|
251
|
+
],
|
|
252
|
+
},
|
|
253
|
+
};
|
|
254
|
+
|
|
255
|
+
const isMacOS = computed(() => deviceType.isMacOS);
|
|
256
|
+
const havedata = ref(false);
|
|
257
|
+
const searchbox = ref();
|
|
258
|
+
const visiblesearch = ref(false);
|
|
259
|
+
const searchVal = ref("");
|
|
260
|
+
const keyword = ref("");
|
|
261
|
+
const tabIndex = ref(0);
|
|
262
|
+
const selectedIndex = ref(0);
|
|
263
|
+
const isloading = ref(false);
|
|
264
|
+
|
|
265
|
+
const showDialog = () => {
|
|
266
|
+
searchVal.value = "";
|
|
267
|
+
keyword.value = "";
|
|
268
|
+
visiblesearch.value = true;
|
|
269
|
+
setTimeout(() => {
|
|
270
|
+
const el = document.querySelector("#searchbox") as HTMLInputElement;
|
|
271
|
+
if (el !== undefined) el.focus();
|
|
272
|
+
}, 500);
|
|
273
|
+
};
|
|
274
|
+
|
|
275
|
+
onMounted(() => {
|
|
276
|
+
document.onkeydown = function (e) {
|
|
277
|
+
if (e.key === "k" && (e.ctrlKey || e.metaKey)) {
|
|
278
|
+
e.preventDefault(); // present "Save Page" from getting triggered.
|
|
279
|
+
showDialog();
|
|
280
|
+
} else if (e.key == "Escape") {
|
|
281
|
+
visiblesearch.value = false;
|
|
282
|
+
}
|
|
283
|
+
};
|
|
284
|
+
});
|
|
285
|
+
const onchange = debounce((str: string) => {
|
|
286
|
+
havedata.value = false;
|
|
287
|
+
if (searchVal.value == "") return false;
|
|
288
|
+
keyword.value = searchVal.value;
|
|
289
|
+
search();
|
|
290
|
+
havedata.value = true;
|
|
291
|
+
}, 800);
|
|
292
|
+
|
|
293
|
+
const search = () => {
|
|
294
|
+
list.value = [];
|
|
295
|
+
isloading.value = true;
|
|
296
|
+
searchdocument();
|
|
297
|
+
for (const key in documents) {
|
|
298
|
+
const searchdoc = documents[key];
|
|
299
|
+
if (canPerform(key, "search")) {
|
|
300
|
+
let doc;
|
|
301
|
+
if (key == "student") doc = useNuxtApp().$StudentDoc();
|
|
302
|
+
else if (key == "teacher") doc = useNuxtApp().$TeacherDoc();
|
|
303
|
+
else if (key == "accounttransaction")
|
|
304
|
+
doc = useNuxtApp().$AccounttransactionDoc();
|
|
305
|
+
else if (key == "product") doc = useNuxtApp().$ProductDoc();
|
|
306
|
+
else if (key == "parent") doc = useNuxtApp().$ParentDoc();
|
|
307
|
+
else {
|
|
308
|
+
continue;
|
|
309
|
+
}
|
|
310
|
+
doc
|
|
311
|
+
.runFullTextSearh({
|
|
312
|
+
keyword: keyword.value,
|
|
313
|
+
})
|
|
314
|
+
.then((data: any[]) => {
|
|
315
|
+
if (data.length > 0) {
|
|
316
|
+
list.value = list.value.concat(
|
|
317
|
+
data.map((item) => {
|
|
318
|
+
const tmp: ResultDataType = {
|
|
319
|
+
_id: <string>item._id,
|
|
320
|
+
documentName: doc.getDocName(),
|
|
321
|
+
data: item,
|
|
322
|
+
};
|
|
323
|
+
return tmp;
|
|
324
|
+
}),
|
|
325
|
+
);
|
|
326
|
+
}
|
|
327
|
+
});
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
isloading.value = false;
|
|
331
|
+
// setTimeout(() => setFocus(), 200);
|
|
332
|
+
};
|
|
333
|
+
|
|
334
|
+
function onKeyDown(event:KeyboardEvent){
|
|
335
|
+
if(['ArrowDown','ArrowUp'].includes(event.code)){
|
|
336
|
+
setFocus()
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
const searchdocument = () => {
|
|
340
|
+
menulist.value = getAllDocuments()
|
|
341
|
+
.filter(
|
|
342
|
+
(item) =>
|
|
343
|
+
item.page != "" && item.docName.includes(keyword.value.toLowerCase()),
|
|
344
|
+
)
|
|
345
|
+
.map((item) => {
|
|
346
|
+
const tmp: ResultDataType = {
|
|
347
|
+
_id: item.docName,
|
|
348
|
+
documentName: "menu",
|
|
349
|
+
data: item,
|
|
350
|
+
};
|
|
351
|
+
return tmp;
|
|
352
|
+
})
|
|
353
|
+
.sort();
|
|
354
|
+
};
|
|
355
|
+
|
|
356
|
+
const selectItem = (item: ResultDataType) => {
|
|
357
|
+
if (item.documentName == "menu") {
|
|
358
|
+
goTo(item._id);
|
|
359
|
+
} else if (item.documentName == "student") {
|
|
360
|
+
goTo("managestudents", item._id);
|
|
361
|
+
} else {
|
|
362
|
+
goTo(item.documentName, item._id);
|
|
363
|
+
}
|
|
364
|
+
visiblesearch.value = false;
|
|
365
|
+
};
|
|
366
|
+
|
|
367
|
+
function setFocus() {
|
|
368
|
+
const listbodyid = alllist.value?.$el?.id;
|
|
369
|
+
document.querySelector(`#${listbodyid} .p-listbox-list`)?.focus();
|
|
370
|
+
}
|
|
371
|
+
</script>
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
|
|
3
|
+
</template>
|
|
4
|
+
<script setup lang="ts">
|
|
5
|
+
/**
|
|
6
|
+
* This file was automatically generated by simpleapp generator during initialization. It is changable.
|
|
7
|
+
* --remove-this-line-to-prevent-override--
|
|
8
|
+
* last change 2024-02-22
|
|
9
|
+
* author: Ks Tan
|
|
10
|
+
*/
|
|
11
|
+
</script>
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
|
|
3
|
+
<div class="flex flex-row justify-between cursor-pointer">
|
|
4
|
+
<div>
|
|
5
|
+
<div class="font-semibold">
|
|
6
|
+
{{ item.productCode }} - {{ item.productName }}
|
|
7
|
+
</div>
|
|
8
|
+
</div>
|
|
9
|
+
<div class="flex flex-col text-right">
|
|
10
|
+
<RendererMoney class="font-semibold" :value="item.defaultPrice" />
|
|
11
|
+
<div>{{ item.billingMethod }}</div>
|
|
12
|
+
</div>
|
|
13
|
+
</div>
|
|
14
|
+
</template>
|
|
15
|
+
<script setup lang="ts">
|
|
16
|
+
/**
|
|
17
|
+
* This file was automatically generated by simpleapp generator during initialization. It is changable.
|
|
18
|
+
* --remove-this-line-to-prevent-override--
|
|
19
|
+
* last change 2024-02-22
|
|
20
|
+
* author: Ks Tan
|
|
21
|
+
*/
|
|
22
|
+
import { Product } from "~/simpleapp/generate/openapi";
|
|
23
|
+
import {SimpleAppDocuments} from "~/types"
|
|
24
|
+
const props = defineProps<{item:Product}>()
|
|
25
|
+
|
|
26
|
+
</script>
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
class="p-2 border rounded-lg border-gray-300 dark:border-blue-900/40"
|
|
5
5
|
>
|
|
6
6
|
<button
|
|
7
|
+
type="button"
|
|
7
8
|
:readonly="readonly"
|
|
8
9
|
class="cursor-pointer text-primary-600 dark:text-primary-400"
|
|
9
10
|
tabindex="0"
|
|
@@ -16,9 +17,12 @@
|
|
|
16
17
|
v-else-if="modelValue !== undefined"
|
|
17
18
|
class="p-2 border rounded-lg border-gray-300 dark:border-blue-900/40 relative"
|
|
18
19
|
>
|
|
20
|
+
<!-- readonly -->
|
|
19
21
|
<button
|
|
20
22
|
ref="autocompleteinput"
|
|
21
|
-
|
|
23
|
+
type="button"
|
|
24
|
+
:id="inputId"
|
|
25
|
+
|
|
22
26
|
class="cursor-pointer text-primary-600 dark:text-primary-400"
|
|
23
27
|
@click="openViewer(true)"
|
|
24
28
|
>
|
|
@@ -29,6 +33,7 @@
|
|
|
29
33
|
class="absolute h-full top-0 right-0 text-right text-white z-10 align-middle p-3"
|
|
30
34
|
>
|
|
31
35
|
<button
|
|
36
|
+
type="button"
|
|
32
37
|
class="pi pi-times rounded-full bg-slate-500 p-1 cursor-pointer text-xs"
|
|
33
38
|
@click="clear"
|
|
34
39
|
tabindex="0"
|
|
@@ -189,7 +194,7 @@ import {
|
|
|
189
194
|
SchemaType,
|
|
190
195
|
} from "~/types";
|
|
191
196
|
const mobileVisible = ref(false);
|
|
192
|
-
const autocompleteinput = ref
|
|
197
|
+
const autocompleteinput = ref();
|
|
193
198
|
const { $event } = useNuxtApp();
|
|
194
199
|
const list = ref<any[]>([]);
|
|
195
200
|
const props = withDefaults(
|
|
@@ -237,6 +242,13 @@ if (modelValue.value && modelValue.value._id) {
|
|
|
237
242
|
const clear = () => {
|
|
238
243
|
autocompleteitem.value = undefined;
|
|
239
244
|
modelValue.value = undefined;
|
|
245
|
+
if(!isMobile()){
|
|
246
|
+
setTimeout(()=>{
|
|
247
|
+
const autoel = autocompleteinput.value.$el
|
|
248
|
+
autoel?.firstElementChild?.focus()
|
|
249
|
+
},100)
|
|
250
|
+
}
|
|
251
|
+
|
|
240
252
|
};
|
|
241
253
|
|
|
242
254
|
//if record picked, click button show record info instead
|
|
@@ -285,7 +297,10 @@ const getListFromAutocompleteApi = (event: any) => {
|
|
|
285
297
|
console.log("Run autocomplete?");
|
|
286
298
|
list.value = res.data;
|
|
287
299
|
|
|
288
|
-
if (
|
|
300
|
+
if (
|
|
301
|
+
props.allowAddNew &&
|
|
302
|
+
canPerform(upperFirst(targetDocument), "create")
|
|
303
|
+
) {
|
|
289
304
|
list.value = list.value.concat({
|
|
290
305
|
_id: "new",
|
|
291
306
|
label: "<" + t("new") + ">",
|
|
@@ -323,6 +338,12 @@ watch(modelValue, (newvalue: any) => {
|
|
|
323
338
|
});
|
|
324
339
|
const emitChanges = () => {
|
|
325
340
|
emits("change", modelValue.value);
|
|
341
|
+
if(!isMobile()){
|
|
342
|
+
setTimeout(()=>{
|
|
343
|
+
const autoel = autocompleteinput.value
|
|
344
|
+
autoel?.focus()
|
|
345
|
+
},100)}
|
|
346
|
+
|
|
326
347
|
};
|
|
327
348
|
|
|
328
349
|
const setFocus = (ev: any) => {
|
|
@@ -11,19 +11,23 @@
|
|
|
11
11
|
</ButtonDefault>
|
|
12
12
|
</div>
|
|
13
13
|
</div>
|
|
14
|
-
<
|
|
14
|
+
<ListContainer
|
|
15
15
|
class="p-2 dark:bg-slate-900 bg-slate-200 rounded-lg"
|
|
16
16
|
:list="list"
|
|
17
|
-
#default="{
|
|
17
|
+
#default="{item,index }"
|
|
18
18
|
@click="showRow"
|
|
19
19
|
>
|
|
20
20
|
<slot name="listbody" :item="item" :index="index">
|
|
21
21
|
<div class="flex flex-row">item {{ item._id }}</div>
|
|
22
22
|
</slot>
|
|
23
|
-
</
|
|
23
|
+
</ListContainer>
|
|
24
24
|
|
|
25
|
-
<Dialog
|
|
26
|
-
|
|
25
|
+
<Dialog
|
|
26
|
+
v-model:visible="showDialog"
|
|
27
|
+
modal
|
|
28
|
+
:header="t('editDetails')"
|
|
29
|
+
:pt="{ root: { class: 'w-1/2' } }"
|
|
30
|
+
>
|
|
27
31
|
<div class="flex flex-col p-2 gap-4">
|
|
28
32
|
<slot name="popupbody" :index="rowIndex" :item="list[rowIndex]">
|
|
29
33
|
row {{ rowIndex }} define SimpleAppInputs here
|
|
@@ -40,6 +44,7 @@
|
|
|
40
44
|
</template>
|
|
41
45
|
<script setup lang="ts" generic="T extends { [key: string]: any }">
|
|
42
46
|
import { SimpleAppClient } from "~/simpleapp/generate/clients/SimpleAppClient";
|
|
47
|
+
import ListContainer from "../list/ListContainer.vue";
|
|
43
48
|
/**
|
|
44
49
|
* This file was automatically generated by simpleapp generator. Every
|
|
45
50
|
* MODIFICATION OVERRIDE BY GENERATEOR
|