@simitgroup/simpleapp-generator 1.2.7 → 1.2.8
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/framework.js +3 -3
- package/dist/framework.js.map +1 -1
- package/package.json +1 -1
- package/src/framework.ts +3 -3
- package/templates/nuxt/app.vue.eta +7 -3
- package/templates/nuxt/assets/css/calendar.css._eta +21 -8
- package/templates/nuxt/assets/css/style.css._eta +0 -5
- package/templates/nuxt/assets/primevue/passthrough.ts._eta +26 -15
- package/templates/nuxt/components/calendar/CalendarByResource.vue.eta +29 -8
- package/templates/nuxt/components/event/EventDocumentViewer.vue._eta +2 -2
- package/templates/nuxt/components/event/EventNotification.vue._eta +23 -2
- package/templates/nuxt/components/header/HeaderBar.vue._eta +9 -9
- package/templates/nuxt/components/header/HeaderBreadcrumb.vue.eta +2 -2
- package/templates/nuxt/components/header/button/HeaderButtonMenuPicker.vue._eta +7 -15
- package/templates/nuxt/components/header/button/HeaderButtonProfile.vue.eta +23 -34
- package/templates/nuxt/components/list/ListView.vue.eta +10 -8
- package/templates/nuxt/components/renderer/RendererMoney.vue.eta +10 -2
- package/templates/nuxt/components/renderer/RendererViewer.vue.eta +5 -5
- package/templates/nuxt/components/simpleApp/SimpleAppAutocomplete.vue.eta +34 -9
- package/templates/nuxt/components/simpleApp/SimpleAppDocumentNo.vue.eta +7 -1
- package/templates/nuxt/components/simpleApp/SimpleAppFieldContainer.vue.eta +23 -16
- package/templates/nuxt/components/simpleApp/SimpleAppInput.vue.eta +24 -7
- package/templates/nuxt/components/simpleApp/SimpleAppInputTable.vue.eta +4 -3
- package/templates/nuxt/components/user/UserProfileListItem.vue.eta +2 -2
- package/templates/nuxt/composables/date.generate.ts.eta +16 -0
- package/templates/nuxt/composables/goTo.generate.ts.eta +1 -0
- package/templates/nuxt/composables/stringHelper.generate.ts.eta +0 -5
- package/templates/nuxt/error.vue._eta +3 -3
- package/templates/nuxt/layouts/default.vue._eta +19 -34
- package/templates/nuxt/layouts/loginlayout.vue._eta +3 -0
- package/templates/nuxt/layouts/mobile.vue._eta +29 -0
- package/templates/nuxt/nuxt.config.ts._eta +25 -15
- package/templates/nuxt/pages/[xorg]/user/{index.vue._eta → index.vue.eta} +10 -12
- package/templates/nuxt/pages/login.vue._eta +34 -0
- package/templates/nuxt/plugins/10.simpleapp-event.ts.eta +35 -33
- package/templates/nuxt/server/api/[xorg]/[...].ts.eta +7 -40
- package/templates/nuxt/server/api/profile/[...].ts.eta +3 -32
- package/templates/nuxt/simpleapp/generate/clients/SimpleAppClient.ts.eta +1 -1
- package/templates/nuxt/types/calendar.ts.eta +8 -1
- package/templates/nuxt/types/others.ts.eta +4 -1
- package/templates/project/lang/default._json +4 -1
- package/tsconfig.tsbuildinfo +1 -1
- package/templates/nuxt/pages/login.vue.eta +0 -30
- /package/templates/nuxt/pages/[xorg]/user/{[id].vue._eta → [id].vue.eta} +0 -0
- /package/templates/nuxt/pages/[xorg]/{user.vue._eta → user.vue.eta} +0 -0
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
|
|
2
2
|
<template>
|
|
3
|
-
<span>
|
|
3
|
+
<span v-if="showCurrency"> {{ Intl.NumberFormat( useI18n().defaultLocale,{
|
|
4
4
|
style:'currency',
|
|
5
5
|
currency: getUserProfile()?.currency,
|
|
6
6
|
currencyDisplay: 'symbol',
|
|
7
7
|
}).format(modelValue) }}</span>
|
|
8
|
+
<span v-else> {{ modelValue.toLocaleString(useI18n().defaultLocale,options) }}</span>
|
|
8
9
|
</template>
|
|
9
10
|
<script lang="ts" setup>
|
|
10
11
|
/**
|
|
@@ -13,5 +14,12 @@
|
|
|
13
14
|
* last change 2024-02-04
|
|
14
15
|
* author: Ks Tan
|
|
15
16
|
*/
|
|
16
|
-
|
|
17
|
+
|
|
18
|
+
const options = {
|
|
19
|
+
style: 'decimal', // Other options: 'currency', 'percent', etc.
|
|
20
|
+
minimumFractionDigits: 2,
|
|
21
|
+
maximumFractionDigits: 2,
|
|
22
|
+
};
|
|
23
|
+
const modelValue = defineModel<number>({required:true})
|
|
24
|
+
const props = defineProps<{showCurrency?:boolean}>()
|
|
17
25
|
</script>
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<a @click="openViewer" class="text-primary-700 hover:text-primary-500 cursor-pointer">
|
|
2
|
+
<a @click="openViewer" class="text-primary-700 dark:text-primary-400 hover:text-primary-500 cursor-pointer">
|
|
3
3
|
<slot name="default">
|
|
4
|
-
<div >{{ value[fields[0]] }}</div>
|
|
4
|
+
<div v-if="fields">{{ value[fields[0]] }}</div>
|
|
5
5
|
</slot>
|
|
6
6
|
</a>
|
|
7
7
|
</template>
|
|
@@ -12,10 +12,10 @@
|
|
|
12
12
|
* last change 2024-02-04
|
|
13
13
|
* author: Ks Tan
|
|
14
14
|
*/
|
|
15
|
-
|
|
15
|
+
import { RendererSetting } from '~/types';
|
|
16
16
|
const props = defineProps<{
|
|
17
|
-
fields
|
|
18
|
-
setting:
|
|
17
|
+
fields?:string[],
|
|
18
|
+
setting:RendererSetting,
|
|
19
19
|
value:any
|
|
20
20
|
}>()
|
|
21
21
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<AutoComplete v-model="modelValue" v-if="!readonly" ref="autocompleteinput"
|
|
3
3
|
forceSelection optionLabel="label"
|
|
4
|
-
@focus="
|
|
4
|
+
@focus="setFocus"
|
|
5
5
|
@item-select="pickAutoComplete"
|
|
6
6
|
@complete="getListFromAutocompleteApi"
|
|
7
7
|
:placeholder="t('keyword')"
|
|
@@ -17,7 +17,25 @@
|
|
|
17
17
|
@blur="onBlurAutocomplete"
|
|
18
18
|
:inputId="inputId" :path="setting.instancepath"
|
|
19
19
|
:readonly="readonly"
|
|
20
|
-
|
|
20
|
+
>
|
|
21
|
+
<template #header>
|
|
22
|
+
<slot name="header">
|
|
23
|
+
<div class="flex flex-row font font-bold dark:text-white">
|
|
24
|
+
<div class="w w-1/3">{{ t(codefield) ?? t('code') }}</div>
|
|
25
|
+
<div class="w w-2/3" >{{ t(labelfield) ?? t('label') }}</div>
|
|
26
|
+
</div>
|
|
27
|
+
</slot>
|
|
28
|
+
</template>
|
|
29
|
+
<template #option="{index,option}">
|
|
30
|
+
<slot name="option" :index="index" :option="option">
|
|
31
|
+
<div class="flex flex-row dark:text-white">
|
|
32
|
+
<div class="w w-1/3" >{{ option.code }}</div>
|
|
33
|
+
<div class="w w-2/3" >{{ option.label }}</div>
|
|
34
|
+
</div>
|
|
35
|
+
</slot>
|
|
36
|
+
</template>
|
|
37
|
+
<!-- </slot> -->
|
|
38
|
+
</AutoComplete>
|
|
21
39
|
<div v-else class="p-3 border rounded-lg border-gray-300 dark:border-blue-900/40 ">
|
|
22
40
|
<span :readonly="readonly" class="cursor-pointer text-primary-600 dark:text-primary-400 "
|
|
23
41
|
tabindex="0" @click="openViewer(true)">{{ modelValue && modelValue.label ? modelValue.label:'-' }}</span>
|
|
@@ -44,6 +62,12 @@ allowAddNew:true,showNull:true
|
|
|
44
62
|
const path = '$'+props.setting.instancepath
|
|
45
63
|
const modifiedpath = path.replaceAll('/','.')
|
|
46
64
|
const queryresult = jsonpath.query(props.setting.defaultValue,modifiedpath)[0]
|
|
65
|
+
const remotedoc = getDocument(props.setting.fieldsetting['x-foreignkey'])
|
|
66
|
+
const schema:SchemaType = <SchemaType>remotedoc?.docClass.getSchema()
|
|
67
|
+
|
|
68
|
+
const labelfield = schema['x-simpleapp-config'].documentTitle as string
|
|
69
|
+
const codefield = schema['x-simpleapp-config'].uniqueKey as string
|
|
70
|
+
const docname = props.setting.fieldsetting['x-foreignkey']
|
|
47
71
|
|
|
48
72
|
const emptyautocomplete = computed(():autocompletetype=> queryresult)
|
|
49
73
|
|
|
@@ -124,15 +148,16 @@ const emitChanges = () =>{
|
|
|
124
148
|
|
|
125
149
|
}
|
|
126
150
|
|
|
151
|
+
|
|
152
|
+
const setFocus = (ev:any) => {
|
|
153
|
+
if(!isMobile()) ev.target.select()
|
|
154
|
+
}
|
|
155
|
+
|
|
127
156
|
//pop up records
|
|
128
|
-
const openViewer = (readonly:boolean) =>{
|
|
129
|
-
const remotedoc = getDocument(props.setting.fieldsetting['x-foreignkey'])
|
|
157
|
+
const openViewer = (readonly:boolean) =>{
|
|
130
158
|
|
|
131
159
|
if(remotedoc){
|
|
132
|
-
|
|
133
|
-
const labelfield = schema['x-simpleapp-config'].documentTitle as string
|
|
134
|
-
const codefield = schema['x-simpleapp-config'].uniqueKey as string
|
|
135
|
-
const docname = props.setting.fieldsetting['x-foreignkey']
|
|
160
|
+
|
|
136
161
|
$event('ViewRecord',{
|
|
137
162
|
_id: modelValue.value?._id as string,
|
|
138
163
|
eventId: randomUUID(),
|
|
@@ -157,7 +182,7 @@ const openViewer = (readonly:boolean) =>{
|
|
|
157
182
|
}
|
|
158
183
|
modelValue.value = {...autocompleteitem.value}
|
|
159
184
|
emitChanges()
|
|
160
|
-
|
|
185
|
+
|
|
161
186
|
|
|
162
187
|
}
|
|
163
188
|
})
|
|
@@ -3,11 +3,12 @@
|
|
|
3
3
|
|
|
4
4
|
<div class="flex flex-row w-full">
|
|
5
5
|
<InputText
|
|
6
|
+
@focus="setFocus"
|
|
6
7
|
:readonly="readonly"
|
|
7
8
|
v-model="modelValue"
|
|
8
9
|
:placeholder="placeholder"
|
|
9
10
|
:pt="pt"
|
|
10
|
-
:class=" !pt ? 'flex-1 w-full rounded-lg '+ ( props.readonly?'':'
|
|
11
|
+
:class=" !pt ? 'flex-1 w-full rounded-lg '+ ( props.readonly?'':'rounded-tr-none rounded-br-none') : ''"
|
|
11
12
|
/>
|
|
12
13
|
<span class="" v-if="!readonly">
|
|
13
14
|
<button type="button" @click="toggle" tabindex="-1"
|
|
@@ -72,6 +73,11 @@ const loadDocFormats = async () =>{
|
|
|
72
73
|
}
|
|
73
74
|
}
|
|
74
75
|
|
|
76
|
+
|
|
77
|
+
const setFocus = (ev:any) => {
|
|
78
|
+
if(!isMobile()) ev.target.select()
|
|
79
|
+
}
|
|
80
|
+
|
|
75
81
|
onMounted(()=>{
|
|
76
82
|
loadDocFormats()
|
|
77
83
|
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div v-if="schema" class="
|
|
3
|
-
<
|
|
4
|
-
<label v-else
|
|
5
|
-
<label v-else
|
|
2
|
+
<div v-if="schema" :class="getLayoutClass()">
|
|
3
|
+
<label v-if="hidelabel"></label>
|
|
4
|
+
<label v-else :for="uuid" :class="getLabelClass()" @click="console.log(inputType)">{{ fieldlabel }} <span v-if="props.setting.isrequired && fieldlabel" class="text-danger-600">*</span></label>
|
|
5
|
+
<!-- <label v-else-if="error" class="simpleapp-input-label text-danger-600 overflow-hidden" :for="uuid">{{ fieldlabel }} <span v-if="props.setting.isrequired && fieldlabel" class="text-danger-600">*</span></label>
|
|
6
|
+
<label v-else :for="uuid" class="simpleapp-input-label whitespace-nowrap text-gray-500 truncate">{{ fieldlabel }} <span v-if="props.setting.isrequired && fieldlabel" class="text-danger-600">*</span></label> -->
|
|
6
7
|
|
|
7
8
|
<!-- <div :uuid="uuid" >{{ modelValue }}</div> -->
|
|
8
9
|
<!-- <div v-if="typeof modelValue =='object' && typeof modelValue['_id']!='undefined' && typeof modelValue['label']!='undefined' && readonly ==true " :uuid="uuid" class="simpleapp-value-readonly">{{ modelValue['label'] }}</div> -->
|
|
@@ -34,6 +35,7 @@ const fieldcontainerclass = ref(defaultcssclass)
|
|
|
34
35
|
let instancepath = ref('')
|
|
35
36
|
const props = defineProps<{
|
|
36
37
|
label?: string,
|
|
38
|
+
inputType: string,
|
|
37
39
|
description?: string,
|
|
38
40
|
instancepath?:string,
|
|
39
41
|
hidelabel?:boolean,
|
|
@@ -45,17 +47,27 @@ const props = defineProps<{
|
|
|
45
47
|
const readonly = computed(()=>{
|
|
46
48
|
return props.readonly ?? props.setting.readonly ?? false
|
|
47
49
|
})
|
|
48
|
-
|
|
49
|
-
//
|
|
50
|
-
// }else if(props.setting.readonly !==undefined){
|
|
51
|
-
// readonly.value=props.readonly
|
|
52
|
-
// }
|
|
53
|
-
// console.log("props.setting.format",props.setting.format)
|
|
54
|
-
const modelValue = defineModel()
|
|
50
|
+
|
|
51
|
+
const modelValue = defineModel<any>() //this model value support all kind of data, string, number, autocomplete and etc
|
|
55
52
|
const readonlyclass="simpleapp-value-readonly"
|
|
56
53
|
// console.log('props.setting',modelValue.value,props.setting)
|
|
57
54
|
let schema:any
|
|
58
55
|
|
|
56
|
+
const getLayoutClass = () => `simpleapp-input-container flex ${ props.inputType == 'checkbox' ? " flex-row gap-4 mt-1 ml-1 " : "flex flex-col "}`
|
|
57
|
+
|
|
58
|
+
const getLabelClass = () => {
|
|
59
|
+
let class1= "simpleapp-input-label text-left text-gray-500 "
|
|
60
|
+
if(!isMobile()) class1 += "whitespace-nowrap truncate"
|
|
61
|
+
else if (props.inputType == 'checkbox' ) class1 += " ml-1 dark:text-grey-200"
|
|
62
|
+
else if (props.inputType != 'autocomplete' && modelValue.value) class1 += "-mb-4 ml-1 z-50 text-xs dark:text-grey-100"
|
|
63
|
+
else if (props.inputType == 'autocomplete' && modelValue.value?.label) class1 += "-mb-4 ml-1 z-50 text-xs dark:text-grey-100"
|
|
64
|
+
else if (props.inputType == 'number' && modelValue.value !== undefined) class1 += "-mb-4 ml-1 z-50 text-xs dark:text-grey-100"
|
|
65
|
+
else class1 += "-mb-4 ml-1 z-50 text-xs dark:text-grey-100 hidden"
|
|
66
|
+
return class1
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
|
|
59
71
|
const fielddesc = computed(()=>{
|
|
60
72
|
return props.description ?? ''
|
|
61
73
|
})
|
|
@@ -116,8 +128,3 @@ watch(props.setting.errors,(newvalue,oldvalue)=>{
|
|
|
116
128
|
})
|
|
117
129
|
|
|
118
130
|
</script>
|
|
119
|
-
<style scoped>
|
|
120
|
-
.simpleapp-input-container{
|
|
121
|
-
@apply flex flex-col
|
|
122
|
-
}
|
|
123
|
-
</style>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<SimpleAppFieldContainer :hidelabel="hidelabel" v-model="modelValue"
|
|
3
|
-
:label="label" :description="description" :pt="pt"
|
|
3
|
+
:label="label" :description="description" :pt="pt" :inputType="inputType"
|
|
4
4
|
:setting="setting" :instancepath="instancepath" :error="error" #default="slotprops">
|
|
5
5
|
<Checkbox v-if="inputType ==SimpleAppInputType.checkbox" :readonly="isReadonly" :pt="pt"
|
|
6
6
|
:inputId="slotprops.uuid" :path="setting.instancepath"
|
|
@@ -93,6 +93,7 @@
|
|
|
93
93
|
<Password
|
|
94
94
|
v-else-if="inputType == SimpleAppInputType.password"
|
|
95
95
|
:type="type" v-model="(modelValue as string)" :pt="pt"
|
|
96
|
+
@focus="setFocus"
|
|
96
97
|
:readonly="isReadonly" class="flex flex-col"
|
|
97
98
|
:inputId="slotprops.uuid" :path="setting.instancepath"
|
|
98
99
|
:placeholder="placeholder"
|
|
@@ -117,6 +118,7 @@
|
|
|
117
118
|
<!-- simple component -->
|
|
118
119
|
<InputNumber v-else-if="inputType == SimpleAppInputType.number"
|
|
119
120
|
:type="type" v-model="(modelValue as number)"
|
|
121
|
+
@focus="setFocus"
|
|
120
122
|
:readonly="isReadonly"
|
|
121
123
|
:pt="pt"
|
|
122
124
|
:class="!pt ? 'w-full flex flex-col' :''"
|
|
@@ -125,7 +127,8 @@
|
|
|
125
127
|
:placeholder="placeholder"
|
|
126
128
|
/>
|
|
127
129
|
<Textarea v-else-if="inputType == SimpleAppInputType.textarea"
|
|
128
|
-
|
|
130
|
+
v-model="(modelValue as string)"
|
|
131
|
+
:autofocus="autofocus"
|
|
129
132
|
:readonly="isReadonly"
|
|
130
133
|
:pt="pt"
|
|
131
134
|
:type="type"
|
|
@@ -136,7 +139,9 @@
|
|
|
136
139
|
v-bind="(componentProps as TextareaProps)"
|
|
137
140
|
/>
|
|
138
141
|
<InputText v-else
|
|
139
|
-
v-model="(modelValue as string)"
|
|
142
|
+
v-model="(modelValue as string)"
|
|
143
|
+
@focus="setFocus"
|
|
144
|
+
:autofocus="autofocus"
|
|
140
145
|
:readonly="isReadonly"
|
|
141
146
|
:pt="pt"
|
|
142
147
|
:type="type"
|
|
@@ -186,6 +191,7 @@ const props = withDefaults( defineProps<{
|
|
|
186
191
|
instancepath?:string,
|
|
187
192
|
hidelabel?: boolean
|
|
188
193
|
readonly?: boolean
|
|
194
|
+
autofocus?:boolean
|
|
189
195
|
pt?:any,
|
|
190
196
|
placeholder?:string
|
|
191
197
|
componentProps?: InputNumberProps | InputSwitchProps | InputTextProps | TextareaProps | DropdownProps | CalendarProps | RatingProps
|
|
@@ -221,6 +227,9 @@ const updateDate = (value:any)=>{
|
|
|
221
227
|
|
|
222
228
|
}
|
|
223
229
|
|
|
230
|
+
const setFocus = (ev:any) => {
|
|
231
|
+
if(!isMobile()) ev.target.select()
|
|
232
|
+
}
|
|
224
233
|
|
|
225
234
|
const getListOptions = () =>{
|
|
226
235
|
|
|
@@ -244,6 +253,7 @@ const getListOptions = () =>{
|
|
|
244
253
|
|
|
245
254
|
const emits = defineEmits(['change','update:modelValue','update:docNoFormat'])
|
|
246
255
|
|
|
256
|
+
|
|
247
257
|
watch(modelValue ,(newvalue:any)=>{
|
|
248
258
|
|
|
249
259
|
if([SimpleAppInputType.date,SimpleAppInputType.calendar].includes(props.inputType)){
|
|
@@ -259,7 +269,16 @@ watch(modelValue ,(newvalue:any)=>{
|
|
|
259
269
|
emits('change',modelValue.value)
|
|
260
270
|
emits('update:modelValue',modelValue.value)
|
|
261
271
|
})
|
|
262
|
-
|
|
272
|
+
onMounted(()=>{
|
|
273
|
+
if([SimpleAppInputType.date,SimpleAppInputType.calendar].includes(props.inputType)){
|
|
274
|
+
if(modelValue.value){
|
|
275
|
+
datevalue.value = moment(modelValue.value as string ).format('YYYY-MM-DD')
|
|
276
|
+
}else{
|
|
277
|
+
datevalue.value = ''
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
}
|
|
281
|
+
})
|
|
263
282
|
|
|
264
283
|
/************ start autocomplete only ***************/
|
|
265
284
|
|
|
@@ -272,6 +291,4 @@ watch(modelValue ,(newvalue:any)=>{
|
|
|
272
291
|
const triggerDocNoFormatChange=(formatdata:any)=>{
|
|
273
292
|
emits('update:docNoFormat',formatdata)
|
|
274
293
|
}
|
|
275
|
-
</script>
|
|
276
|
-
<style scoped>
|
|
277
|
-
</style>
|
|
294
|
+
</script>
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
<DataTable v-bind="$attrs" stripedRows resizableColumns
|
|
3
3
|
class="simpleapp-datatable p-datatable-sm" :value="modelValue">
|
|
4
4
|
<template #empty> <div class="text-center">No record found.</div> </template>
|
|
5
|
-
<template #header >
|
|
6
|
-
<div>
|
|
7
|
-
<Button
|
|
5
|
+
<template #header v-if="!setting.readonly && !readonly">
|
|
6
|
+
<div >
|
|
7
|
+
<Button icon="pi pi-plus" @click="addNew()" class="simpleapp-datatable-add btn-primary" type="button">Add</Button>
|
|
8
8
|
</div>
|
|
9
9
|
</template>
|
|
10
10
|
<slot>
|
|
@@ -35,6 +35,7 @@ const props = defineProps<{
|
|
|
35
35
|
// columns:InputTableColumn[],
|
|
36
36
|
setting:any,
|
|
37
37
|
getField:Function,
|
|
38
|
+
readonly?:boolean
|
|
38
39
|
}>()
|
|
39
40
|
|
|
40
41
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<!-- <ul role="list" class="divide-y divide-gray-100">
|
|
3
3
|
<li v-for="person in people" :key="person.email" class="flex justify-between gap-x-6 py-5"> -->
|
|
4
|
-
<div class="flex justify-between gap-x-6 py-5 cursor-pointer">
|
|
4
|
+
<div class="flex justify-between gap-x-6 py-5 cursor-pointer" @click="emits('click',data)">
|
|
5
5
|
<div class="flex min-w-0 gap-x-4">
|
|
6
6
|
<img class="h-12 w-12 flex-none rounded-full bg-gray-50" :src="`${getAvatarLink(data.email,32)}`" alt="" />
|
|
7
7
|
<div class="min-w-0 flex-auto">
|
|
@@ -38,7 +38,7 @@ import moment from 'moment'
|
|
|
38
38
|
const props = defineProps<{
|
|
39
39
|
data:any
|
|
40
40
|
}>()
|
|
41
|
-
|
|
41
|
+
const emits = defineEmits(['click'])
|
|
42
42
|
|
|
43
43
|
|
|
44
44
|
const datedifferent = computed(()=>{
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import moment from "moment";
|
|
2
|
+
|
|
3
|
+
export const dateExists = (date:Date,listDate:Date[]) => {
|
|
4
|
+
const existsrecord = listDate.find(item=>{
|
|
5
|
+
return date.getTime()===item.getTime()
|
|
6
|
+
})
|
|
7
|
+
return existsrecord===undefined ? false :true
|
|
8
|
+
}
|
|
9
|
+
export const getMoment = (startTime:string)=> moment(startTime)
|
|
10
|
+
export const lastDateOfMonth = (datestr:string) => moment(datestr).endOf('month').format('YYYY-MM-DD');
|
|
11
|
+
export const today = () => moment().format('YYYY-MM-DD')
|
|
12
|
+
export const dateToString = (date:Date) => moment(date).format('YYYY-MM-DD')
|
|
13
|
+
export const dateToDateTimeString = (date:Date)=> moment(date).format('YYYY-MM-DD HH:mm:ss')
|
|
14
|
+
export const toLocalDate = (dateiso8601:string)=> new Date(String(dateiso8601)).toLocaleDateString()
|
|
15
|
+
|
|
16
|
+
|
|
@@ -16,10 +16,5 @@ export const getAvatarLink = (email:string, size:number):string=>{
|
|
|
16
16
|
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
export const toLocalDate = (dateiso8601:string)=> new Date(String(dateiso8601)).toLocaleDateString()
|
|
20
19
|
export const t = (txt:string,options?:any):string => !txt || txt.trim()=='' ? '' : useNuxtApp().$i18n.t(txt,options)
|
|
21
|
-
export const today = () => moment().format('YYYY-MM-DD')
|
|
22
|
-
export const dateToString = (date:Date) => moment(date).format('YYYY-MM-DD')
|
|
23
|
-
export const getMoment = (startTime:string)=> moment(startTime)
|
|
24
|
-
export const lastDateOfMonth = (datestr:string) => moment(datestr).endOf('month').format('YYYY-MM-DD');
|
|
25
20
|
export const upperFirst = (str:string) => _.upperFirst(str)
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div class="
|
|
3
|
-
<div class="bg-white border rounded-md flex items-center justify-center mx-4 md:w-2/3">
|
|
2
|
+
<div class="w w-full items-center justify-center py-12 bg bg-gray-500">
|
|
3
|
+
<div class="bg-white dark:bg-gray-600 p-1 border rounded-md flex items-center justify-center mx-4 w-7/8 md:w-2/3">
|
|
4
4
|
<div class="flex flex-col items-center py-16">
|
|
5
5
|
|
|
6
6
|
<div class="flex flex-row">
|
|
7
|
-
<div class="w w-
|
|
7
|
+
<div class="w w-full ">
|
|
8
8
|
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="-13.59 -13.59 480.17 480.17" xml:space="preserve" fill="#000000" stroke="#000000" stroke-width="0.00452986"><g id="SVGRepo_bgCarrier" stroke-width="0"></g><g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g><g id="SVGRepo_iconCarrier"> <g> <g> <g> <path style="fill:#010002;" d="M0,0v452.986h452.986V0H0z M403.223,24.655c8.132,0,14.668,6.558,14.668,14.625 c0,8.111-6.536,14.711-14.668,14.711c-8.089,0-14.668-6.601-14.668-14.711C388.576,31.234,395.134,24.655,403.223,24.655z M352.035,24.655c8.046,0,14.647,6.558,14.647,14.625c0,8.111-6.601,14.711-14.647,14.711c-8.132,0-14.668-6.601-14.668-14.711 C337.389,31.234,343.903,24.655,352.035,24.655z M417.955,418.624H35.053V85.701h382.903V418.624z"></path> <path style="fill:#010002;" d="M226.493,398.952c80.394,0,145.495-65.101,145.495-145.43s-65.101-145.495-145.495-145.495 c-80.373,0-145.516,65.165-145.516,145.495C80.977,333.873,146.12,398.952,226.493,398.952z M142.044,198.516l29.444-29.444 l55.005,55.027l54.984-55.027l29.379,29.444L255.894,253.5l54.984,54.941l-29.423,29.444l-54.962-54.962l-55.005,54.984 l-29.444-29.444l54.984-54.941L142.044,198.516z"></path> </g> </g> <g> </g> <g> </g> <g> </g> <g> </g> <g> </g> <g> </g> <g> </g> <g> </g> <g> </g> <g> </g> <g> </g> <g> </g> <g> </g> <g> </g> <g> </g> </g> </g></svg>
|
|
9
9
|
</div>
|
|
10
10
|
<div>
|
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div class="h-full flex flex-row"
|
|
3
|
-
<div>
|
|
4
|
-
<
|
|
5
|
-
|
|
6
|
-
<div class="
|
|
7
|
-
<
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
2
|
+
<div class="h-full flex flex-row">
|
|
3
|
+
<div class="flex flex-col justify justify-between">
|
|
4
|
+
<div >
|
|
5
|
+
<HeaderButtonMenuPicker class="cursor-pointer p-2 text-6xl "></HeaderButtonMenuPicker>
|
|
6
|
+
<div class="" v-for="item in menus">
|
|
7
|
+
<div class="">
|
|
8
|
+
<NuxtLink
|
|
9
|
+
:class="`pi ${item.iconClass} p-2 text-6xl cursor-pointer`"
|
|
10
|
+
:to="getDocumentUrl(item.path)"
|
|
11
|
+
></NuxtLink>
|
|
12
|
+
</div>
|
|
13
|
+
</div>
|
|
14
|
+
</div>
|
|
15
|
+
<HeaderButtonProfile class="p-6"/>
|
|
13
16
|
</div>
|
|
14
17
|
<div class="flex-1">
|
|
15
18
|
<HeaderBar />
|
|
@@ -17,33 +20,15 @@
|
|
|
17
20
|
<slot></slot>
|
|
18
21
|
</div>
|
|
19
22
|
</div>
|
|
20
|
-
|
|
21
|
-
<div v-if="getCurrentXorg()" class="border flex flex-row h-20 fixed left-0 w-full justify justify-between bottom-0 z-50 bg-white dark:bg-gray-800" >
|
|
22
|
-
|
|
23
|
-
<div v-for="item in menus">
|
|
24
|
-
<NuxtLink
|
|
25
|
-
:class="`pi ${item.iconClass} p-2 text-6xl cursor-pointer`"
|
|
26
|
-
:to="getDocumentUrl(item.path)"
|
|
27
|
-
></NuxtLink>
|
|
28
|
-
</div>
|
|
29
|
-
<HeaderButtonMenuPicker class="p-2 text-6xl cursor-pointer"></HeaderButtonMenuPicker>
|
|
30
|
-
</div>
|
|
31
|
-
<div class="flex flex-col h-screen ">
|
|
32
|
-
|
|
33
|
-
<HeaderBar />
|
|
34
|
-
<UserInvitation/>
|
|
35
|
-
<slot></slot>
|
|
36
|
-
|
|
37
|
-
</div>
|
|
38
|
-
</div>
|
|
23
|
+
|
|
39
24
|
</template>
|
|
40
25
|
<script setup lang="ts">
|
|
41
26
|
const menus=[
|
|
42
27
|
// {iconClass:'pi-bars',path:'managestudents/profile'},
|
|
43
|
-
{iconClass:'pi-home',path:''},
|
|
44
|
-
{iconClass:'pi-users',path:'managestudents/profile'},
|
|
45
|
-
{iconClass:'pi-calendar',path:`manageclasses`},
|
|
28
|
+
{iconClass:'pi-home text-white',path:''},
|
|
29
|
+
{iconClass:'pi-users text-white',path:'managestudents/profile'},
|
|
30
|
+
{iconClass:'pi-calendar text-white',path:`manageclasses`},
|
|
46
31
|
// {iconClass:'pi-database',path:'managedata'},
|
|
47
|
-
{iconClass:'pi-chart-pie',path:'reports'},
|
|
32
|
+
{iconClass:'pi-chart-pie text-white',path:'reports'},
|
|
48
33
|
]
|
|
49
34
|
</script>
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="h-screen flex flex-col">
|
|
3
|
+
<div class="flex flex-col grow">
|
|
4
|
+
<slot></slot>
|
|
5
|
+
</div>
|
|
6
|
+
<!-- fixed -->
|
|
7
|
+
<div v-if="getCurrentXorg()" class="flex h-20 border-t-2 dark:border-t-gray-700 text-4xl flex-row left-0 w-full justify justify-between bottom-0 z-50 bg-white dark:bg-gray-600 pl-2 pr-2" >
|
|
8
|
+
<NuxtLink v-for="item in menus"
|
|
9
|
+
:class="`pi ${item.iconClass} pb-6 pt-6 cursor-pointer inline-block align-middle`"
|
|
10
|
+
:to="getDocumentUrl(item.path)"
|
|
11
|
+
></NuxtLink>
|
|
12
|
+
<HeaderButtonMenuPicker class=" cursor-pointer"></HeaderButtonMenuPicker>
|
|
13
|
+
<HeaderButtonProfile class=""/>
|
|
14
|
+
<UserInvitation/>
|
|
15
|
+
</div>
|
|
16
|
+
<!-- <HeaderBar class="border flex flex-row h-10 fixed left-0 w-full justify justify-between top-0 z-50 bg-white dark:bg-gray-800"/> -->
|
|
17
|
+
|
|
18
|
+
</div>
|
|
19
|
+
</template>
|
|
20
|
+
<script setup lang="ts">
|
|
21
|
+
const menus=[
|
|
22
|
+
// {iconClass:'pi-bars',path:'managestudents/profile'},
|
|
23
|
+
{iconClass:'pi-home text-white',path:''},
|
|
24
|
+
// {iconClass:'pi-users text-white',path:'managestudents/profile'},
|
|
25
|
+
// {iconClass:'pi-calendar text-white',path:`manageclasses`},
|
|
26
|
+
// {iconClass:'pi-database',path:'managedata'},
|
|
27
|
+
// {iconClass:'pi-chart-pie text-white',path:'reports'},
|
|
28
|
+
]
|
|
29
|
+
</script>
|
|
@@ -6,7 +6,11 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import path from 'path'
|
|
8
8
|
export default defineNuxtConfig({
|
|
9
|
-
|
|
9
|
+
colorMode: {
|
|
10
|
+
classSuffix: ''
|
|
11
|
+
|
|
12
|
+
},
|
|
13
|
+
|
|
10
14
|
runtimeConfig:{
|
|
11
15
|
public:{
|
|
12
16
|
APP_URL: process.env.APP_URL,
|
|
@@ -26,16 +30,19 @@ export default defineNuxtConfig({
|
|
|
26
30
|
tailwindcss: {
|
|
27
31
|
// Options
|
|
28
32
|
},
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
33
|
+
devServer: {
|
|
34
|
+
host: "0.0.0.0",
|
|
35
|
+
},
|
|
32
36
|
modules: [
|
|
33
37
|
// "@hebilicious/authjs-nuxt",
|
|
38
|
+
'@nuxtjs/color-mode',
|
|
39
|
+
'@nuxtjs/device',
|
|
34
40
|
'@nuxtjs/i18n',
|
|
35
41
|
'@sidebase/nuxt-auth',
|
|
36
42
|
'nuxt-primevue',
|
|
43
|
+
// '@nuxtjs/pwa', //cannot turn on, will cause nuxt cant start
|
|
37
44
|
// "nuxt-security", //temporary avoid nuxt-security cause cors
|
|
38
|
-
'@vueuse/nuxt',
|
|
45
|
+
'@vueuse/nuxt',
|
|
39
46
|
'@nuxtjs/tailwindcss',
|
|
40
47
|
['@pinia/nuxt',{
|
|
41
48
|
autoImports: [
|
|
@@ -44,10 +51,13 @@ tailwindcss: {
|
|
|
44
51
|
['defineStore', 'definePiniaStore'], // import { defineStore as definePiniaStore } from 'pinia'
|
|
45
52
|
],
|
|
46
53
|
}],
|
|
47
|
-
|
|
54
|
+
|
|
48
55
|
|
|
49
56
|
|
|
50
|
-
],
|
|
57
|
+
],
|
|
58
|
+
device: {
|
|
59
|
+
refreshOnResize: true
|
|
60
|
+
},
|
|
51
61
|
i18n: {
|
|
52
62
|
lazy: true,
|
|
53
63
|
langDir: "lang/",
|
|
@@ -70,13 +80,14 @@ tailwindcss: {
|
|
|
70
80
|
iso: "cn",
|
|
71
81
|
name: "Chinese",
|
|
72
82
|
file: "cn.ts",
|
|
83
|
+
|
|
73
84
|
},
|
|
74
85
|
],
|
|
75
86
|
defaultLocale: "df",
|
|
76
87
|
},
|
|
77
88
|
primevue: {
|
|
78
89
|
options: {
|
|
79
|
-
unstyled: true,
|
|
90
|
+
//unstyled: true,
|
|
80
91
|
ripple: true,
|
|
81
92
|
inputStyle: 'filled'
|
|
82
93
|
},
|
|
@@ -85,7 +96,7 @@ tailwindcss: {
|
|
|
85
96
|
exclude: ['chart']
|
|
86
97
|
},
|
|
87
98
|
directives: {
|
|
88
|
-
include: ['Ripple', 'Tooltip','BadgeDirective']
|
|
99
|
+
include: ['Ripple', 'Tooltip','BadgeDirective','FocusTrap']
|
|
89
100
|
},
|
|
90
101
|
cssLayerOrder: 'tailwind-base, primevue, tailwind-utilities',
|
|
91
102
|
importPT: { as: 'SimpleAppPT', from: path.resolve(__dirname,'./assets/primevue/passthrough.ts') },
|
|
@@ -96,7 +107,7 @@ tailwindcss: {
|
|
|
96
107
|
|
|
97
108
|
// },
|
|
98
109
|
auth: {
|
|
99
|
-
globalAppMiddleware:
|
|
110
|
+
globalAppMiddleware: false
|
|
100
111
|
},
|
|
101
112
|
// security: {
|
|
102
113
|
// corsHandler:{
|
|
@@ -127,13 +138,12 @@ tailwindcss: {
|
|
|
127
138
|
'primeicons/primeicons.css',
|
|
128
139
|
path.resolve(__dirname,'./assets/css/style.css'),
|
|
129
140
|
path.resolve(__dirname,'./assets/css/calendar.css'),
|
|
130
|
-
],
|
|
141
|
+
],
|
|
142
|
+
},
|
|
131
143
|
|
|
132
144
|
// devtools: { enabled: true },
|
|
133
145
|
// build: {
|
|
134
146
|
// // transpile: ["primevue"]
|
|
135
|
-
// },
|
|
136
|
-
|
|
137
|
-
|
|
147
|
+
// },
|
|
138
148
|
|
|
139
|
-
|
|
149
|
+
)
|