@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.
Files changed (65) hide show
  1. package/dist/buildinschemas/documentevent.d.ts +3 -0
  2. package/dist/buildinschemas/documentevent.d.ts.map +1 -0
  3. package/dist/buildinschemas/documentevent.js +38 -0
  4. package/dist/buildinschemas/documentevent.js.map +1 -0
  5. package/dist/buildinschemas/index.d.ts +2 -0
  6. package/dist/buildinschemas/index.d.ts.map +1 -1
  7. package/dist/buildinschemas/index.js +5 -1
  8. package/dist/buildinschemas/index.js.map +1 -1
  9. package/dist/buildinschemas/tenant.d.ts.map +1 -1
  10. package/dist/buildinschemas/tenant.js +8 -0
  11. package/dist/buildinschemas/tenant.js.map +1 -1
  12. package/dist/buildinschemas/webhook.d.ts.map +1 -1
  13. package/dist/buildinschemas/webhook.js +21 -3
  14. package/dist/buildinschemas/webhook.js.map +1 -1
  15. package/dist/buildinschemas/webhookhistory.d.ts +3 -0
  16. package/dist/buildinschemas/webhookhistory.d.ts.map +1 -0
  17. package/dist/buildinschemas/webhookhistory.js +44 -0
  18. package/dist/buildinschemas/webhookhistory.js.map +1 -0
  19. package/dist/framework.js +1 -1
  20. package/dist/framework.js.map +1 -1
  21. package/dist/generate.js +1 -1
  22. package/dist/generate.js.map +1 -1
  23. package/package.json +1 -1
  24. package/src/buildinschemas/documentevent.ts +36 -0
  25. package/src/buildinschemas/index.ts +3 -1
  26. package/src/buildinschemas/tenant.ts +8 -0
  27. package/src/buildinschemas/webhook.ts +22 -3
  28. package/src/buildinschemas/webhookhistory.ts +42 -0
  29. package/src/framework.ts +1 -1
  30. package/src/generate.ts +1 -1
  31. package/templates/basic/nest/apischema.ts.eta +6 -2
  32. package/templates/basic/nest/controller.ts.eta +4 -3
  33. package/templates/basic/nest/default.ts.eta +6 -5
  34. package/templates/basic/nuxt/default.ts.eta +2 -0
  35. package/templates/basic/nuxt/simpleapp.generate.client.ts.eta +1 -6
  36. package/templates/nest/src/simpleapp/apischemas/index.ts._eta +17 -0
  37. package/templates/nest/src/simpleapp/generate/commons/audittrail.service.ts.eta +37 -7
  38. package/templates/nest/src/simpleapp/generate/commons/runwebhook.service.ts.eta +39 -20
  39. package/templates/nest/src/simpleapp/generate/commons/user.context.ts.eta +53 -39
  40. package/templates/nest/src/simpleapp/generate/controllers/simpleapp.controller.ts.eta +3 -3
  41. package/templates/nest/src/simpleapp/generate/processors/simpleapp.processor.ts.eta +100 -34
  42. package/templates/nest/src/simpleapp/profile/profile.service.ts.eta +5 -0
  43. package/templates/nest/src/simpleapp/simpleapp.module.ts.eta +3 -3
  44. package/templates/nest/src/simpleapp/types/index.ts._eta +14 -0
  45. package/templates/nuxt/app.vue.eta +9 -7
  46. package/templates/nuxt/components/image/ImageAvatar.vue.eta._vue +7 -14
  47. package/templates/nuxt/components/list/ListView.vue.eta +97 -111
  48. package/templates/nuxt/components/renderer/RendererDocHistories.vue.eta +102 -42
  49. package/templates/nuxt/components/search/SearchBox.vue._eta +371 -0
  50. package/templates/nuxt/components/search/SearchBoxBefore.vue._eta +11 -0
  51. package/templates/nuxt/components/search/SearchBoxProduct.vue._eta +26 -0
  52. package/templates/nuxt/components/simpleApp/SimpleAppAutocomplete.vue.eta +24 -3
  53. package/templates/nuxt/components/simpleApp/SimpleAppCalendarInput.vue.eta +1 -0
  54. package/templates/nuxt/components/simpleApp/SimpleAppChildrenList.vue.eta +10 -5
  55. package/templates/nuxt/components/simpleApp/SimpleAppFormToolBar.vue._eta +4 -3
  56. package/templates/nuxt/components/user/UserTenantPicker.vue.eta +18 -16
  57. package/templates/nuxt/composables/getOpenApi.generate.ts.eta +6 -49
  58. package/templates/nuxt/composables/stringHelper.generate.ts.eta +2 -2
  59. package/templates/nuxt/middleware/30.acl.global.ts.eta +6 -5
  60. package/templates/nuxt/pages/[xorg]/pickgroup.vue._eta +28 -27
  61. package/templates/nuxt/pages/picktenant.vue._eta +3 -3
  62. package/templates/nuxt/plugins/20.simpleapp-userstore.ts.eta +49 -29
  63. package/templates/nuxt/simpleapp/generate/clients/SimpleAppClient.ts.eta +7 -1
  64. package/templates/nuxt/types/others.ts.eta +7 -1
  65. package/tsconfig.tsbuildinfo +1 -1
@@ -1,56 +1,116 @@
1
1
  <template>
2
- <div class="flex flex-row text-xs cursor-pointer"
3
- v-if="data?.updated && data?.updated !=''" @click="viewHistories">
4
- <ImageAvatar v-if="data?.updatedBy" :id="data.updatedBy" :size="12"></ImageAvatar>
5
- <div class="flex flex-col p-2">
6
- <TextDocStatus v-if="data?.docStatus" :docStatus="data?.docStatus" />
7
- <TextSubsubtitle class=" text-gray-400 italic">{{ t('updated') }}:</TextSubsubtitle>
8
- <RendererDateTime :value="data?.updated" class="text-gray-400 italic"/>
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 v-model:visible="visibleHistories" modal
13
- :header="t('histories')" :pt="{root:{class:'w-1/4'}}">
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="slotProps">
16
- <RendererDateTime class="italic text-gray-400 text-xs" :value="slotProps.item.date"/>
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="slotProps">
39
+ <template #content="{ item }">
19
40
  <div>
20
- <div>{{ slotProps.item.status }}</div>
21
- </div>
22
-
41
+ <div>{{ item.status }}</div>
42
+ </div>
23
43
  </template>
24
- </Timeline>
44
+ </Timeline>
25
45
  </Dialog>
26
46
  </div>
27
-
28
47
  </template>
29
48
  <script lang="ts" setup>
30
- import TextSubsubtitle from '../text/TextSubsubtitle.vue';
31
- import RendererDateTime from './RendererDateTime.vue';
32
- const visibleHistories = ref(false)
33
- const props=defineProps<{data:any}>()
34
- const events = computed(()=>{
35
- const list = [{ status: t('created'), date: props.data.created },]
36
-
37
- if(props.data.updated != props.data.created){
38
- list.push({ status: t('paidFeature'), date:''})
39
- list.push( { status: t('lastUpdate'), date: props.data.updated })
40
- }
41
- return list
42
- })
43
- const severity = computed(()=>{
44
- const stat = props.data.docStatus
45
- if(props.data.docStatus=='confirm') return "success"
46
- else if(props.data.docStatus=='void') return "danger"
47
- else if(props.data.docStatus=='draft') return "secondary"
48
- else return "warning"
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
- const viewHistories = () =>{
53
- visibleHistories.value=true
54
- console.log("histories")
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
- readonly
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<autocompletetype | undefined>();
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 (props.allowAddNew && canPerform(upperFirst(targetDocument),'create')) {
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) => {
@@ -1,6 +1,7 @@
1
1
  <template>
2
2
  <Calendar
3
3
  :pt="pt"
4
+ :dateFormat="getPrimevueCalendarDateFormat()"
4
5
  :inputId="uuid"
5
6
  :path="setting.instancepath"
6
7
  v-model="datetimevalue"
@@ -11,19 +11,23 @@
11
11
  </ButtonDefault>
12
12
  </div>
13
13
  </div>
14
- <ListView
14
+ <ListContainer
15
15
  class="p-2 dark:bg-slate-900 bg-slate-200 rounded-lg"
16
16
  :list="list"
17
- #default="{ index, item }"
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
- </ListView>
23
+ </ListContainer>
24
24
 
25
- <Dialog v-model:visible="showDialog"
26
- modal :header="t('editDetails')" :pt="{root:{class:'w-1/2'}}">
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