@simitgroup/simpleapp-generator 1.1.1 → 1.1.3
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 +2 -2
- package/dist/framework.js.map +1 -1
- package/dist/generate.d.ts.map +1 -1
- package/dist/generate.js +22 -46
- package/dist/generate.js.map +1 -1
- package/dist/processors/jsonschemabuilder.js +9 -0
- package/dist/processors/jsonschemabuilder.js.map +1 -1
- package/dist/storage.d.ts +1 -0
- package/dist/storage.d.ts.map +1 -1
- package/dist/storage.js +2 -1
- package/dist/storage.js.map +1 -1
- package/package.json +1 -1
- package/src/framework.ts +2 -2
- package/src/generate.ts +29 -51
- package/src/processors/jsonschemabuilder.ts +12 -2
- package/src/storage.ts +2 -1
- package/templates/basic/nuxt/pages.[id].vue.eta +3 -2
- package/templates/basic/nuxt/pages.form.vue.eta +226 -0
- package/templates/basic/nuxt/pages.landing.vue.eta +19 -43
- package/templates/basic/nuxt/pages.new.vue.eta +7 -210
- package/templates/basic/nuxt/pages.viewer.vue.eta +21 -0
- package/templates/basic/nuxt/simpleapp.generate.client.ts.eta +2 -1
- package/templates/nest/src/simpleapp/services/docno.service.ts.eta +1 -1
- package/templates/nuxt/app.vue.eta +5 -1
- package/templates/nuxt/assets/css/style.css._eta +33 -15
- package/templates/nuxt/assets/primevue/passthrough.ts._eta +14 -7
- package/templates/nuxt/components/debug/DebugDocumentData.vue.eta +23 -22
- package/templates/nuxt/components/docPage/DocPageList.vue.eta +117 -0
- package/templates/nuxt/components/event/EventDocumentViewer.vue.eta +72 -0
- package/templates/nuxt/components/header/HeaderBar.vue.eta +12 -10
- package/templates/nuxt/components/header/HeaderBreadcrumb.vue.eta +76 -0
- package/templates/nuxt/components/header/button/HeaderButtonMenuPicker.vue.eta +5 -7
- package/templates/nuxt/components/header/button/HeaderButtonProfile.vue.eta +39 -8
- package/templates/nuxt/components/list/ListView.vue.eta +4 -2
- package/templates/nuxt/components/renderer/RendererForeignKey.vue.eta +22 -3
- package/templates/nuxt/components/simpleApp/SimpleAppAutocomplete.vue.eta +163 -0
- package/templates/nuxt/components/simpleApp/SimpleAppDocumentNo.vue.eta +8 -8
- package/templates/nuxt/components/simpleApp/SimpleAppFieldContainer.vue.eta +21 -7
- package/templates/nuxt/components/simpleApp/SimpleAppInput.vue.eta +24 -63
- package/templates/nuxt/components/table/TableDocuments.vue.eta +15 -9
- package/templates/nuxt/components/user/UserButtonCreateTenant.vue.eta +25 -3
- package/templates/nuxt/components/user/UserProfileListItem.vue.eta +41 -41
- package/templates/nuxt/components/user/UserTenantPicker.vue.eta +26 -14
- package/templates/nuxt/composables/getDocument.generate.ts.eta +1 -1
- package/templates/nuxt/composables/getUserStore.generate.ts.eta +4 -1
- package/templates/nuxt/composables/stringHelper.generate.ts.eta +5 -1
- package/templates/nuxt/composables/themes.generate.ts.eta +1 -0
- package/templates/nuxt/i18n.config.ts.eta +5 -0
- package/templates/nuxt/lang/cn.ts._eta +9 -0
- package/templates/nuxt/lang/df.ts.eta +22 -0
- package/templates/nuxt/lang/en.ts._eta +6 -0
- package/templates/nuxt/layouts/{documentlist.vue.eta → documentlist.vue.eta.disabled} +1 -1
- package/templates/nuxt/nuxt.config.ts.eta +49 -16
- package/templates/nuxt/pages/[xorg]/docnoformat.vue.eta +11 -81
- package/templates/nuxt/pages/[xorg]/organization/[id]/branches/new.vue +1 -1
- package/templates/nuxt/pages/[xorg]/organization.vue.eta +10 -0
- package/templates/nuxt/pages/[xorg]/profile.vue.eta +3 -0
- package/templates/nuxt/pages/[xorg]/user.vue.eta +5 -0
- package/templates/nuxt/pages/index.vue._eta +19 -56
- package/templates/nuxt/pages/profile.vue.eta +12 -12
- package/templates/nuxt/plugins/10.simpleapp-event.ts.eta +3 -0
- package/templates/nuxt/plugins/20.simpleapp-userstore.ts.eta +1 -1
- package/templates/nuxt/simpleapp/generate/clients/SimpleAppClient.ts.eta +5 -4
- package/templates/nuxt/simpleapp/generate/commons/documents.ts.eta +4 -1
- package/templates/nuxt/tailwind.config.ts._eta +18 -17
- package/templates/nuxt/types/events.ts.eta +12 -0
- package/templates/nuxt/types/index.ts.eta +2 -1
- package/templates/nuxt/types/others.ts.eta +4 -1
- package/templates/nuxt/types/schema.ts.eta +183 -0
- package/templates/nuxt/types/simpleappinput.ts.eta +1 -0
- package/templates/project/jsonschemas/invoice.json._eta +3 -3
- package/templates/project/jsonschemas/product.json._eta +2 -2
- package/templates/project/sharelibs/money.ts.eta +2 -3
- package/tsconfig.tsbuildinfo +1 -1
- /package/templates/nuxt/layouts/{sidelist.vue.eta → sidelist.vue.eta.disabled} +0 -0
- /package/templates/nuxt/layouts/{sidelistcrud.vue.eta → sidelistcrud.vue.eta.disabled} +0 -0
|
@@ -1,7 +1,11 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
|
|
2
|
+
[disabled] ,[readonly]{
|
|
3
|
+
@apply bg-gray-300 dark:bg-gray-900
|
|
3
4
|
}
|
|
4
5
|
|
|
6
|
+
[aria-selected=true]{
|
|
7
|
+
@apply bg-primary-100
|
|
8
|
+
}
|
|
5
9
|
|
|
6
10
|
[data-pc-group-section=pagebutton]{
|
|
7
11
|
@apply p-2 m-0 rounded-none border
|
|
@@ -9,27 +13,41 @@
|
|
|
9
13
|
[data-pc-section=pagebutton]{
|
|
10
14
|
@apply p-3 m-0 border
|
|
11
15
|
}
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
input {
|
|
19
|
+
@apply bg-opacity-0 bg-black
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
.route-link-list {
|
|
23
|
+
@apply hover:bg-secondary-200 dark:hover:bg-gray-800
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
.router-link-exact-active{
|
|
27
|
+
@apply bg-primary-100 dark:bg-gray-800 block
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
.title-text{
|
|
32
|
+
@apply text-xl font-bold text-gray-700
|
|
33
|
+
}
|
|
34
|
+
.subtitle-text{
|
|
35
|
+
@apply text-base text-gray-500
|
|
36
|
+
}
|
|
37
|
+
|
|
12
38
|
.btn {
|
|
13
|
-
@apply font-medium
|
|
39
|
+
@apply font-medium text-gray-50 dark:text-gray-300 border
|
|
14
40
|
}
|
|
15
41
|
|
|
16
42
|
.btn-primary {
|
|
17
|
-
@apply bg-primary-600 hover:bg-primary-400
|
|
43
|
+
@apply btn bg-primary-600 hover:bg-primary-400 dark:!bg-primary-700 dark:hover:bg-primary-800
|
|
18
44
|
}
|
|
19
45
|
.btn-secondary {
|
|
20
|
-
@apply bg-secondary-600 hover:bg-secondary-400
|
|
46
|
+
@apply btn bg-secondary-600 hover:bg-secondary-400
|
|
21
47
|
}
|
|
22
48
|
.btn-danger {
|
|
23
|
-
@apply bg-danger-600 hover:bg-danger-400
|
|
49
|
+
@apply btn bg-danger-600 hover:bg-danger-400 dark:bg-danger-700 dark:hover:bg-danger-800
|
|
24
50
|
}
|
|
25
51
|
.btn-warn {
|
|
26
|
-
@apply bg-warning-600 hover:bg-warning-400
|
|
52
|
+
@apply btn bg-warning-600 hover:bg-warning-400
|
|
27
53
|
}
|
|
28
|
-
|
|
29
|
-
[disabled] ,[readonly]{
|
|
30
|
-
@apply bg-gray-300
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
[aria-selected=true]{
|
|
34
|
-
@apply bg-primary-100
|
|
35
|
-
}
|
|
@@ -13,22 +13,29 @@ const CustomTailwind = usePassThrough(
|
|
|
13
13
|
content:{class:'flex flex-row-reverse w-full'},
|
|
14
14
|
buttonContainer:{class:'hidden'},
|
|
15
15
|
},
|
|
16
|
-
card:{
|
|
17
|
-
|
|
16
|
+
card:{
|
|
17
|
+
root:{class:'shadow p-4 rounded-2xl m-2'},
|
|
18
|
+
// title:{class:''},
|
|
19
|
+
// header:{class:''}
|
|
20
|
+
},
|
|
21
|
+
tabpanel:{
|
|
22
|
+
headerTitle:{class:'m-0 p-0'},
|
|
23
|
+
},
|
|
18
24
|
selectbutton:{
|
|
19
25
|
root:{class:'flex flex-row gap-1'},
|
|
20
26
|
button: ({ context }) => ({
|
|
21
|
-
class: ['text-center border rounded p-2 cursor-pointer hover:bg-primary-400 hover:text-white', context.active ? 'bg-primary-600 text-white' : '']
|
|
27
|
+
class: ['text-center border-gray-400 dark:border-gray-700 text-gray-50 dark:text-gray-300 rounded-lg p-2 cursor-pointer hover:bg-primary-400 dark:hover:bg-primary-800 hover:text-white', context.active ? 'bg-primary-600 dark:bg-primary-700 text-white' : '']
|
|
22
28
|
}),
|
|
23
29
|
label:{class: 'text-sm'},
|
|
24
30
|
},
|
|
25
|
-
button:{root:{class: 'focus:outline-none transition duration-150 ease-in-out rounded
|
|
31
|
+
button:{root:{class: 'focus:outline-none transition duration-150 ease-in-out rounded p-2 m-1 border dark:border-gray-600'}},
|
|
26
32
|
dialog:{root:{class:['border p-2']}},
|
|
27
33
|
autocomplete:{
|
|
28
|
-
|
|
29
|
-
|
|
34
|
+
root:{class:'border border-gray-300 dark:!border-blue-900/40 rounded-lg flex flex-row'},
|
|
35
|
+
input:{class:'w-full p-2 font-sans rounded-lg rounded-tr-none rounded-br-none transition-colors duration-200 appearance-none hover:border-blue-500 focus:outline-none focus:outline-offset-0 focus:shadow-[0_0_0_0.2rem_rgba(191,219,254,1)] dark:focus:shadow-[0_0_0_0.2rem_rgba(147,197,253,0.5)] text-base'},
|
|
36
|
+
loadingIcon:{class:'hidden'},
|
|
30
37
|
dropdownbutton: {
|
|
31
|
-
root:'
|
|
38
|
+
root:' btn-primary dark:shadow-primary-800 dark:border-primary-900 text-white rounded-lg flex flex-row p-3 rounded-tl-none rounded-bl-none '
|
|
32
39
|
}
|
|
33
40
|
},
|
|
34
41
|
sidebar:{
|
|
@@ -1,3 +1,24 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="p-0 top-0 absolute left-1/2 text-right bg-yellow-200" v-if="isdebug=='1'">
|
|
3
|
+
<Button @click="visible=true" class=" text-white bg-warning-800">
|
|
4
|
+
<i class="pi pi-code"></i>
|
|
5
|
+
{{ label }}</Button>
|
|
6
|
+
<Sidebar v-model:visible="visible" class="text-red-100">
|
|
7
|
+
|
|
8
|
+
<template #header >
|
|
9
|
+
<h1 class="text-gray-700 text-lg font-bold content-center">{{ label }} Data</h1>
|
|
10
|
+
</template>
|
|
11
|
+
<template #default>
|
|
12
|
+
<pre class="border rounder-lg m-0 p-0 dark:bg-gray-500">{{ modelValue }}
|
|
13
|
+
</pre>
|
|
14
|
+
</template>
|
|
15
|
+
|
|
16
|
+
</Sidebar>
|
|
17
|
+
|
|
18
|
+
</div>
|
|
19
|
+
|
|
20
|
+
</template>
|
|
21
|
+
|
|
1
22
|
<script setup lang="ts">
|
|
2
23
|
/**
|
|
3
24
|
* This file was automatically generated by simpleapp generator during initialization.
|
|
@@ -14,28 +35,8 @@ import {ref} from 'vue'
|
|
|
14
35
|
const modelValue = defineModel()
|
|
15
36
|
const isdebug = ref(useRuntimeConfig().public.DEBUGDATA)
|
|
16
37
|
const visible = ref(false)
|
|
17
|
-
const props = defineProps<{label?:string}>()
|
|
18
|
-
const
|
|
38
|
+
const props = withDefaults(defineProps<{label?:string}>(),{label:'label'})
|
|
39
|
+
const buttonlabel = computed(()=>props.label??'debug')
|
|
19
40
|
const op = ref();
|
|
20
41
|
|
|
21
42
|
</script>
|
|
22
|
-
<template>
|
|
23
|
-
<div class="floatright" v-if="isdebug=='1'">
|
|
24
|
-
<Button @click="visible=true" >{{ label }}</Button>
|
|
25
|
-
<Sidebar v-model:visible="visible">
|
|
26
|
-
<pre class="pb-2">{{ modelValue }}</pre>
|
|
27
|
-
</Sidebar>
|
|
28
|
-
|
|
29
|
-
</div>
|
|
30
|
-
|
|
31
|
-
</template>
|
|
32
|
-
<style scoped>
|
|
33
|
-
.floatright{
|
|
34
|
-
position: fixed;
|
|
35
|
-
right: 0;
|
|
36
|
-
background-color: antiquewhite;
|
|
37
|
-
font-size: large;
|
|
38
|
-
top: 20;
|
|
39
|
-
z-index: 999999;
|
|
40
|
-
}
|
|
41
|
-
</style>
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
/**
|
|
3
|
+
* This file was automatically generated by simpleapp generator during initialization.
|
|
4
|
+
* DO NOT MODIFY IT BY HAND.
|
|
5
|
+
* last change 2023-09-09
|
|
6
|
+
* author: Ks Tan
|
|
7
|
+
*/
|
|
8
|
+
import {ref} from 'vue'
|
|
9
|
+
import _ from 'lodash'
|
|
10
|
+
import { SimpleAppClient } from '~/simpleapp/generate/clients/SimpleAppClient' //'../SimpleAppClient';
|
|
11
|
+
|
|
12
|
+
import {SearchBody,CellSetting} from '~/types'
|
|
13
|
+
const props = withDefaults(defineProps<{
|
|
14
|
+
document:SimpleAppClient<any,any>
|
|
15
|
+
columns:CellSetting[]
|
|
16
|
+
layoutClass?:string
|
|
17
|
+
col1Class?:string
|
|
18
|
+
col2Class?:string
|
|
19
|
+
sorts?: string[][]
|
|
20
|
+
}>(),{
|
|
21
|
+
layoutClass:'grid grid-cols-2',
|
|
22
|
+
col1Class:'p-4',
|
|
23
|
+
col2Class:'p-4'
|
|
24
|
+
})
|
|
25
|
+
const resourcename = ref( _.upperFirst(props.document.getDocName()))
|
|
26
|
+
const visible = ref(false)
|
|
27
|
+
const doc = props.document
|
|
28
|
+
const data = doc.getReactiveData()
|
|
29
|
+
const disabled=ref(false)
|
|
30
|
+
const recordlist = ref();
|
|
31
|
+
const router = useRouter()
|
|
32
|
+
const route = useRoute()
|
|
33
|
+
const filters = ref()
|
|
34
|
+
const popuptitle = ref("New "+doc.getDocName())
|
|
35
|
+
const systemwindows = ref(false)
|
|
36
|
+
const {$event,$listen} = useNuxtApp()
|
|
37
|
+
|
|
38
|
+
const refresh = () => {
|
|
39
|
+
const searchbody: SearchBody = {
|
|
40
|
+
fields: getWantedFields(props.columns),
|
|
41
|
+
sorts:props.sorts
|
|
42
|
+
}
|
|
43
|
+
console.log('searchbody',searchbody)
|
|
44
|
+
doc.search(searchbody).then((res:any) => {
|
|
45
|
+
console.log("refreshrefreshrefresh",recordlist.value)
|
|
46
|
+
recordlist.value = res;
|
|
47
|
+
disabled.value=false
|
|
48
|
+
});
|
|
49
|
+
};
|
|
50
|
+
const newData = () => {
|
|
51
|
+
router.push({ path: getDocumentUrl(doc.getDocName(),'new') })
|
|
52
|
+
doc.setNew()
|
|
53
|
+
visible.value=true;
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
onNuxtReady(()=>{
|
|
60
|
+
refresh()
|
|
61
|
+
})
|
|
62
|
+
$listen('RefreshDocumentList',(data)=>{
|
|
63
|
+
if(data.documentName == doc.getDocName()){
|
|
64
|
+
refresh()
|
|
65
|
+
}
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
const getWantedFields = (selectedCols:CellSetting[]) =>{
|
|
69
|
+
let cols:string[] = []
|
|
70
|
+
|
|
71
|
+
selectedCols.forEach((item)=>{
|
|
72
|
+
|
|
73
|
+
if(typeof item=='string'){
|
|
74
|
+
cols.push(item)
|
|
75
|
+
}else if(typeof item =='object'){
|
|
76
|
+
if(item.field !='*'){
|
|
77
|
+
cols.push(item.field)
|
|
78
|
+
}
|
|
79
|
+
if(item.moreFields && item.moreFields.length>0){
|
|
80
|
+
cols = cols.concat(item.moreFields)
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
})
|
|
84
|
+
return cols
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const selectRow = (data:any) =>{
|
|
88
|
+
console.log("select row",data)
|
|
89
|
+
goTo(doc.getDocName(),data._id)
|
|
90
|
+
}
|
|
91
|
+
</script>
|
|
92
|
+
|
|
93
|
+
<template>
|
|
94
|
+
<div class="simpleapp-crudsimple">
|
|
95
|
+
<h1 v-if="systemwindows" class="error-text text-center">* system administration screen</h1>
|
|
96
|
+
<div :class="layoutClass">
|
|
97
|
+
<div v-if="recordlist" :class="col1Class">
|
|
98
|
+
<TableDocuments :value="recordlist" :columns="columns" :title="doc.getDocName()" @select-row="selectRow">
|
|
99
|
+
<template #toolbar>
|
|
100
|
+
<div class="w-full text-left">
|
|
101
|
+
<Button class=" btn-primary" @click="newData" v-tooltip="'Add new(ctrl+enter)'" v-if="canPerform(resourcename,'create')">{{ t('new') }}</Button>
|
|
102
|
+
</div>
|
|
103
|
+
</template>
|
|
104
|
+
<template #additionaltoolbar>
|
|
105
|
+
<Button class="bg-secondary-600 hover:bg-secondary-400 text-white" @click="refresh()" type="button" >{{ t('refresh') }}</Button>
|
|
106
|
+
</template>
|
|
107
|
+
</TableDocuments>
|
|
108
|
+
|
|
109
|
+
</div>
|
|
110
|
+
<div :class="col2Class">
|
|
111
|
+
<slot>
|
|
112
|
+
undefine page content
|
|
113
|
+
</slot>
|
|
114
|
+
</div>
|
|
115
|
+
</div>
|
|
116
|
+
</div>
|
|
117
|
+
</template>
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<Dialog v-model:visible="visible"
|
|
3
|
+
@update:visible="closeDialog"
|
|
4
|
+
:pt="{root:{class:'w-5/6 h-5/6'}}"
|
|
5
|
+
:modal="true"
|
|
6
|
+
:close-on-escape="false" >
|
|
7
|
+
<template #header>
|
|
8
|
+
<div class="flex flex-row">
|
|
9
|
+
<Chip v-for="(v,index) in allview" :label="v.label" @remove="deleteTab" :removable="index == allview.length-1"/>
|
|
10
|
+
</div>
|
|
11
|
+
</template>
|
|
12
|
+
<template #default>
|
|
13
|
+
<div v-for="(v,index) in allview">
|
|
14
|
+
<component v-if="index == allview.length-1" :is="defineAsyncComponent(v.viewer)" :_id="v._id" :readonly="v.readonly" @after-create="callback(v,$event)"></component>
|
|
15
|
+
</div>
|
|
16
|
+
</template>
|
|
17
|
+
</Dialog>
|
|
18
|
+
</template>
|
|
19
|
+
<script setup lang="ts">
|
|
20
|
+
import { onKeyStroke } from '@vueuse/core'
|
|
21
|
+
|
|
22
|
+
import { useDialog } from 'primevue/usedialog';
|
|
23
|
+
import {defineAsyncComponent} from 'vue'
|
|
24
|
+
import { ViewRecord } from '~/types';
|
|
25
|
+
// import TabView from 'primevue/tabview';
|
|
26
|
+
import Chip from 'primevue/chip';
|
|
27
|
+
|
|
28
|
+
const tabindex =ref(0)
|
|
29
|
+
const activetabindex=ref(0)
|
|
30
|
+
const findindex = ref(0)
|
|
31
|
+
const dialog = useDialog()
|
|
32
|
+
const {$listen,} = useNuxtApp()
|
|
33
|
+
const visible = ref(false)
|
|
34
|
+
const _id = ref('')
|
|
35
|
+
const ViewRecordComponent = ref()
|
|
36
|
+
const readonly = ref<boolean>()
|
|
37
|
+
const allview = ref<ViewRecord[]>([])
|
|
38
|
+
|
|
39
|
+
const callback = (v:ViewRecord,data:any)=>{
|
|
40
|
+
if(v.afterCreate){
|
|
41
|
+
v.afterCreate(data)
|
|
42
|
+
}
|
|
43
|
+
deleteTab()
|
|
44
|
+
}
|
|
45
|
+
onKeyStroke('Escape', (e) => {
|
|
46
|
+
e.preventDefault()
|
|
47
|
+
deleteTab()
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
const deleteTab=()=>{
|
|
51
|
+
|
|
52
|
+
const index = allview.value.length- 1
|
|
53
|
+
allview.value.splice(index,1)
|
|
54
|
+
|
|
55
|
+
if(allview.value.length==0){
|
|
56
|
+
visible.value=false
|
|
57
|
+
return
|
|
58
|
+
}else{
|
|
59
|
+
activetabindex.value = activetabindex.value >0 ? activetabindex.value - 1 : 0
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
const closeDialog = ()=>{
|
|
63
|
+
allview.value=[]
|
|
64
|
+
}
|
|
65
|
+
$listen('ViewRecord',(setting)=>{
|
|
66
|
+
visible.value=true
|
|
67
|
+
allview.value.push(setting)
|
|
68
|
+
activetabindex.value = allview.value.length-1
|
|
69
|
+
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
</script>
|
|
@@ -8,32 +8,34 @@
|
|
|
8
8
|
<template>
|
|
9
9
|
<!-- <header> -->
|
|
10
10
|
<!-- <MegaMenu :model="getMenus()" orientation="horizontal" /> -->
|
|
11
|
-
<
|
|
11
|
+
<client-only>
|
|
12
|
+
<div class="flex flex-row">
|
|
12
13
|
|
|
13
14
|
|
|
14
15
|
<div class="flex-1 flex flex-row gap-2 p-2">
|
|
15
16
|
<div class="">
|
|
16
|
-
<HeaderButtonMenuPicker/>
|
|
17
|
-
|
|
18
|
-
</div>
|
|
19
|
-
<div class="">
|
|
20
|
-
<HeaderButtonHome/>
|
|
21
|
-
</div>
|
|
17
|
+
<HeaderButtonMenuPicker/>
|
|
18
|
+
</div>
|
|
22
19
|
|
|
20
|
+
<!-- <div class="">
|
|
21
|
+
<HeaderButtonHome/>
|
|
22
|
+
</div> -->
|
|
23
|
+
<HeaderBreadcrumb class="hidden md:block" v-if="useRoute().fullPath!='/'"></HeaderBreadcrumb>
|
|
23
24
|
</div>
|
|
24
25
|
<div class="flex-1 flex flex-row-reverse gap-2 p-2">
|
|
25
26
|
|
|
26
27
|
<div class=" text-right">
|
|
27
|
-
<HeaderButtonProfile/>
|
|
28
|
+
<HeaderButtonProfile/>
|
|
28
29
|
</div>
|
|
29
30
|
|
|
30
|
-
<div class="">
|
|
31
|
+
<!-- <div class="">
|
|
31
32
|
<HeaderSelectBranch/>
|
|
32
|
-
</div>
|
|
33
|
+
</div> -->
|
|
33
34
|
</div>
|
|
34
35
|
|
|
35
36
|
|
|
36
37
|
|
|
37
38
|
</div>
|
|
39
|
+
</client-only>
|
|
38
40
|
<!-- </header> -->
|
|
39
41
|
</template>
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import OverlayPanel from 'primevue/overlaypanel';
|
|
3
|
+
const op = ref()
|
|
4
|
+
|
|
5
|
+
const home = ref({
|
|
6
|
+
icon: 'pi pi-home',
|
|
7
|
+
url: '/'
|
|
8
|
+
|
|
9
|
+
});
|
|
10
|
+
const items = computed(()=>{
|
|
11
|
+
const fullpath = useRoute().fullPath
|
|
12
|
+
let path = fullpath
|
|
13
|
+
const params = useRoute().params
|
|
14
|
+
const name = useRoute().meta.name
|
|
15
|
+
const data = []
|
|
16
|
+
const patharr = fullpath.split('/').filter((item)=>item!='')
|
|
17
|
+
let pathurl = ''
|
|
18
|
+
for(let i=0; i< patharr.length;i++){
|
|
19
|
+
const p = patharr[i]
|
|
20
|
+
pathurl = `${pathurl}/${p}`
|
|
21
|
+
let pathlabel = ''
|
|
22
|
+
if(i==0 && params['xorg']){
|
|
23
|
+
|
|
24
|
+
pathlabel = getUserProfile().branchName
|
|
25
|
+
data.push ({ label: pathlabel })
|
|
26
|
+
}else{
|
|
27
|
+
pathlabel = t(p)
|
|
28
|
+
data.push ({ label: pathlabel , url:pathurl})
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
}
|
|
33
|
+
if(params['xorg']){
|
|
34
|
+
|
|
35
|
+
path = path.replace('/'+params['xorg'],'')
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return data
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
const showSwitcher=(event:any)=>{
|
|
42
|
+
op.value.toggle(event)
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const getBranches = ()=>{
|
|
46
|
+
const orgId = getUserProfile().orgId
|
|
47
|
+
const tenantId=getUserProfile().tenantId
|
|
48
|
+
return getUserProfile().branches.filter((item:any)=>{return item.branch.tenantId == tenantId && item.branch.orgId == orgId})
|
|
49
|
+
}
|
|
50
|
+
</script>
|
|
51
|
+
<template>
|
|
52
|
+
<Breadcrumb :home="home" :model="items" class="!p-0 border-none ">
|
|
53
|
+
<template #item="{ item }">
|
|
54
|
+
<NuxtLink :to="item.url" v-if="item.url" :active-class="'-'" :exact-active-class="'-'">
|
|
55
|
+
<span :class="item.icon"></span>{{ item.label }}
|
|
56
|
+
</NuxtLink>
|
|
57
|
+
<div v-else>
|
|
58
|
+
<span class="cursor-pointer" @click="showSwitcher">{{ item.label }}</span>
|
|
59
|
+
<OverlayPanel ref="op">
|
|
60
|
+
<div>
|
|
61
|
+
<ul class="flex flex-col">
|
|
62
|
+
<li v-for="b in getBranches()" class="p-1 route-link-list ">
|
|
63
|
+
<NuxtLink :to="'/'+b['xOrg']" >
|
|
64
|
+
{{ b['branch']['branchCode']}} - {{ b['branch']['branchName']}}
|
|
65
|
+
</NuxtLink>
|
|
66
|
+
</li>
|
|
67
|
+
</ul>
|
|
68
|
+
</div>
|
|
69
|
+
</OverlayPanel>
|
|
70
|
+
</div>
|
|
71
|
+
|
|
72
|
+
</template>
|
|
73
|
+
<template #separator> <span class="pi pi-chevron-right"></span></template>
|
|
74
|
+
</Breadcrumb>
|
|
75
|
+
|
|
76
|
+
</template>
|
|
@@ -3,18 +3,19 @@ import Dialog from 'primevue/dialog';
|
|
|
3
3
|
import {ref} from 'vue'
|
|
4
4
|
import {MenuData} from '~/types'
|
|
5
5
|
const visible = ref(false)
|
|
6
|
-
|
|
6
|
+
|
|
7
7
|
// const emit = defineEmits(['select'])
|
|
8
8
|
const selectMenu = (menu:MenuData) =>{
|
|
9
9
|
navigateTo(menu.url)
|
|
10
10
|
visible.value=false
|
|
11
|
+
|
|
11
12
|
// emit('select',menu)
|
|
12
13
|
}
|
|
13
14
|
</script>
|
|
14
15
|
<template>
|
|
15
16
|
<div>
|
|
16
17
|
|
|
17
|
-
<button class="text-center border-none cursor-pointer" v-if="
|
|
18
|
+
<button class="text-center border-none cursor-pointer" v-if="getCurrentXorg()" @click="visible=true">
|
|
18
19
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6">
|
|
19
20
|
<path stroke-linecap="round" stroke-linejoin="round" d="M3.75 6.75h16.5M3.75 12h16.5m-16.5 5.25h16.5" />
|
|
20
21
|
</svg>
|
|
@@ -22,17 +23,14 @@ const selectMenu = (menu:MenuData) =>{
|
|
|
22
23
|
|
|
23
24
|
<Dialog v-model:visible="visible" modal header="Pick Document" :pt="{dialog:{ class:' bg-primary-800 ' }}">
|
|
24
25
|
<div class="">
|
|
25
|
-
<Button v-for="menu in
|
|
26
|
+
<Button v-for="menu in getMenus()" @click="selectMenu(menu)" >
|
|
26
27
|
<div v-if="menu.isolationType == 'none'" class="text-warning-600 hover:text-warning-500">
|
|
27
28
|
* {{ camelCaseToWords(menu.label) }}
|
|
28
29
|
</div>
|
|
29
30
|
<div v-else class="">{{ camelCaseToWords(menu.label) }}</div>
|
|
30
31
|
</Button>
|
|
31
32
|
</div>
|
|
32
|
-
</Dialog>
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
33
|
+
</Dialog>
|
|
36
34
|
</div>
|
|
37
35
|
</template>
|
|
38
36
|
<style scoped>
|
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import Avatar from 'primevue/avatar';
|
|
3
|
+
import Dropdown from 'primevue/dropdown';
|
|
3
4
|
import OverlayPanel from 'primevue/overlaypanel';
|
|
4
5
|
import {ref} from 'vue'
|
|
5
6
|
|
|
7
|
+
|
|
8
|
+
const { locale,setLocale,locales } = useI18n()
|
|
9
|
+
const mylocale = ref(locale)
|
|
6
10
|
const userprofileoverlay = ref();
|
|
11
|
+
const colors = [{value:'light', name:'Light'},{value:'dark', name:'Dark'}]
|
|
7
12
|
const toggle = (event:any) => {
|
|
8
13
|
userprofileoverlay.value.toggle(event);
|
|
9
14
|
}
|
|
@@ -21,6 +26,11 @@ const toFrontpage = () =>{
|
|
|
21
26
|
userprofileoverlay.value.toggle();
|
|
22
27
|
navigateTo('/')
|
|
23
28
|
}
|
|
29
|
+
const saveLocale=async (v:string)=>{
|
|
30
|
+
await setLocale(v)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
|
|
24
34
|
|
|
25
35
|
</script>
|
|
26
36
|
|
|
@@ -29,10 +39,10 @@ const toFrontpage = () =>{
|
|
|
29
39
|
<div class=" w-[120px] truncate ...">
|
|
30
40
|
|
|
31
41
|
<div class="flex flex-row-reverse cursor-pointer border-none w-full" @click="toggle">
|
|
32
|
-
<p>{{
|
|
42
|
+
<p>{{ getProfileFullName() }}</p>
|
|
33
43
|
<!-- <Avatar :image="getUserStore().getAvatarLink(32)" class="" size="normal" shape="circle" /> -->
|
|
34
44
|
<div class="w-8 h-8 bg-cover bg-center rounded-md">
|
|
35
|
-
<img :src="getAvatarLink(
|
|
45
|
+
<img :src="getAvatarLink(getProfileEmail(),32)" alt="" class="h-full w-full overflow-hidden object-cover rounded-full border-2 border-white dark:border-gray-700 shadow" />
|
|
36
46
|
</div>
|
|
37
47
|
</div>
|
|
38
48
|
|
|
@@ -42,21 +52,42 @@ const toFrontpage = () =>{
|
|
|
42
52
|
<div class="py-2 transition duration-150 ease-in-out z-10 absolute top-0 right-0 bottom-0 left-0" id="modal">
|
|
43
53
|
<div role="alert" class="container mx-auto w-full md:w-full max-w-lg">
|
|
44
54
|
<div class="relative p-4 md:p-8 bg-white dark:bg-gray-800 shadow-md rounded border border-gray-400">
|
|
45
|
-
<div class="w-full flex items-center justify-start text-gray-600 dark:text-gray-400 mb-5
|
|
55
|
+
<div class="w-full flex items-center justify-start text-gray-600 dark:text-gray-400 mb-5" >
|
|
46
56
|
<div class="w-12 h-12 bg-cover bg-center rounded-md">
|
|
47
|
-
<img :src="getAvatarLink(
|
|
57
|
+
<img :src="getAvatarLink(getProfileEmail(),32)" alt="" class="h-full w-full overflow-hidden object-cover rounded-full border-2 border-white dark:border-gray-700 shadow" />
|
|
48
58
|
</div>
|
|
49
|
-
<div class="flex flex-col
|
|
59
|
+
<div class="flex flex-col" >
|
|
50
60
|
<h1 class="text-left text-gray-800 dark:text-gray-100 font-lg font-bold tracking-normal leading-tight ml-2">{{ getUserProfile().fullName }}</h1>
|
|
51
61
|
<p class="text-gray-400 dark:text-gray-100 font-normal text-base tracking-normal ml-2 mr-4">{{getUserProfile().group }}</p>
|
|
52
62
|
</div>
|
|
53
63
|
|
|
54
64
|
</div>
|
|
65
|
+
<!-- language -->
|
|
66
|
+
<div class="col-span-full">
|
|
67
|
+
<label for="pick-lang" class="block text-sm font-medium leading-6 text-gray-900 dark:text-gray-300">{{ t('language') }}</label>
|
|
68
|
+
<div class="mt-2">
|
|
69
|
+
<Dropdown inputId="pick-lang" @update:model-value="saveLocale" v-model="mylocale" option-value="code" option-label="name" :options="locales" >
|
|
70
|
+
</Dropdown>
|
|
71
|
+
<!-- <select v-model="$colorMode.preference" id="picklang">
|
|
72
|
+
<option value="light">Light</option>
|
|
73
|
+
<option value="dark">Dark</option>
|
|
74
|
+
</select> -->
|
|
75
|
+
</div>
|
|
76
|
+
</div>
|
|
77
|
+
<div class="mt-3 col-span-full">
|
|
78
|
+
<label for="pick-theme" class="block text-sm font-medium leading-6 text-gray-900 dark:text-gray-300">{{ t('theme') }}</label>
|
|
79
|
+
<div class="mt-2">
|
|
80
|
+
<Dropdown inputId="pick-theme" v-model="$colorMode.preference" option-value="value" option-label="name" :options="colors" >
|
|
81
|
+
</Dropdown>
|
|
82
|
+
|
|
83
|
+
</div>
|
|
84
|
+
</div>
|
|
85
|
+
|
|
55
86
|
|
|
56
|
-
<div class="flex items-center justify-start w-full">
|
|
57
|
-
<button class="focus:outline-none transition duration-150 ease-in-out hover:bg-gray-600 bg-gray-700 rounded text-white px-8 py-2 text-sm" @click="
|
|
87
|
+
<div class="mt-3 flex items-center justify-start w-full">
|
|
88
|
+
<button class="focus:outline-none transition duration-150 ease-in-out hover:bg-gray-600 bg-gray-700 rounded text-white px-8 py-2 text-sm" @click="toProfile">{{ t('profile') }}</button>
|
|
58
89
|
<!-- <button class="focus:outline-none transition duration-150 ease-in-out bg-gray-600 rounded text-white px-8 py-2 text-sm" @click="toFrontpage">Pick Tenant</button> -->
|
|
59
|
-
<button class="focus:outline-none ml-3 bg-warning-100 dark:bg-warning-700 dark:border-warning-700 dark:hover:bg-warning-600 transition duration-150 text-gray-600 dark:text-gray-400 ease-in-out hover:border-gray-400 hover:bg-gray-300 border rounded px-8 py-2 text-sm" @click="logout()">
|
|
90
|
+
<button class="focus:outline-none ml-3 bg-warning-100 dark:bg-warning-700 dark:border-warning-700 dark:hover:bg-warning-600 transition duration-150 text-gray-600 dark:text-gray-400 ease-in-out hover:border-gray-400 hover:bg-gray-300 border rounded px-8 py-2 text-sm" @click="logout()">{{ t('logout') }}</button>
|
|
60
91
|
</div>
|
|
61
92
|
</div>
|
|
62
93
|
</div>
|
|
@@ -13,8 +13,10 @@
|
|
|
13
13
|
<li v-for="item in filterlist">
|
|
14
14
|
<div :class="getSelectedCSS(item)">
|
|
15
15
|
<NuxtLink :to="`${url}/${item[idField]}`">
|
|
16
|
-
<
|
|
17
|
-
|
|
16
|
+
<slot>
|
|
17
|
+
<div class="mr-2">{{item[titleField] }}</div>
|
|
18
|
+
<div class="font font-bold text-right">{{item[subTitleField]}}</div>
|
|
19
|
+
</slot>
|
|
18
20
|
</NuxtLink>
|
|
19
21
|
</div>
|
|
20
22
|
|
|
@@ -1,11 +1,30 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<
|
|
2
|
+
<span v-if="setting?.collection" @click="viewRecord" class="text-primary-700 hover:text-primary-500 cursor-pointer">
|
|
3
3
|
{{modelValue?.label}}
|
|
4
|
-
</
|
|
4
|
+
</span>
|
|
5
5
|
<span v-else>{{modelValue?.label || modelValue}}</span>
|
|
6
6
|
</template>
|
|
7
7
|
<script setup lang="ts">
|
|
8
|
-
const modelValue = defineModel()
|
|
9
8
|
|
|
9
|
+
|
|
10
|
+
const modelValue = defineModel<{label:string,_id:string}>()
|
|
10
11
|
const props = defineProps<{setting:any}>()
|
|
12
|
+
const {$event} = useNuxtApp()
|
|
13
|
+
const viewer=ref()
|
|
14
|
+
const viewRecord = () => {
|
|
15
|
+
viewer.value = getDocument(props.setting.collection)?.viewer
|
|
16
|
+
|
|
17
|
+
// getDocumentUrl(setting.collection,modelValue ? modelValue['_id']:'')
|
|
18
|
+
//getDocumentUrl(setting.collection,modelValue ? modelValue['_id']:'')
|
|
19
|
+
$event('ViewRecord',{
|
|
20
|
+
_id: modelValue.value?._id as string,
|
|
21
|
+
label: modelValue.value?.label as string,
|
|
22
|
+
eventId: crypto.randomUUID(),
|
|
23
|
+
documentName: props.setting.collection,
|
|
24
|
+
viewer: viewer.value,
|
|
25
|
+
readonly:true
|
|
26
|
+
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
}
|
|
11
30
|
</script>
|