@simitgroup/simpleapp-generator 1.0.23 → 1.0.24
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +48 -0
- package/dist/createproject.js +1 -1
- package/dist/createproject.js.map +1 -1
- package/dist/framework.js +20 -16
- package/dist/framework.js.map +1 -1
- package/dist/generate.js +38 -16
- package/dist/generate.js.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/processors/jsonschemabuilder.js +9 -9
- package/dist/processors/jsonschemabuilder.js.map +1 -1
- package/package.json +1 -1
- package/src/framework.ts +37 -30
- package/src/generate.ts +37 -21
- package/src/index.ts +2 -1
- package/src/processors/jsonschemabuilder.ts +9 -9
- package/src/type.ts +1 -0
- package/templates/basic/apischema.eta +8 -4
- package/templates/basic/controller.eta +21 -5
- package/templates/basic/jsonschema.eta +2 -0
- package/templates/basic/model.eta +2 -6
- package/templates/basic/module.eta +2 -0
- package/templates/basic/pageindex.vue.eta +28 -15
- package/templates/basic/pageindexwithid.vue.eta +13 -1
- package/templates/basic/service.eta +11 -9
- package/templates/basic/simpleappclient.eta +9 -8
- package/templates/basic/type.eta +2 -1
- package/templates/nest/SimpleAppController.eta +5 -5
- package/templates/nest/SimpleAppService.eta +87 -31
- package/templates/nest/TenantMiddleware.eta +30 -0
- package/templates/nest/User.eta +80 -0
- package/templates/nest/app.module.eta +14 -3
- package/templates/nest/inputvalidation-exception.eta +6 -0
- package/templates/nest/nest.main.eta +2 -0
- package/templates/nuxt/components.crudsimple.vue.eta +61 -48
- package/templates/nuxt/components.debugdocdata.vue.eta +12 -4
- package/templates/nuxt/components.eventmonitor.vue.eta +17 -11
- package/templates/nuxt/components.menus.vue.eta +14 -12
- package/templates/nuxt/composables.getautocomplete.ts.eta +7 -1
- package/templates/nuxt/composables.getmenus.ts.eta +9 -2
- package/templates/nuxt/env.eta +2 -0
- package/templates/nuxt/layouts.default.vue.eta +10 -3
- package/templates/nuxt/nuxt.config.ts.eta +4 -1
- package/templates/nuxt/pages.index.vue.eta +8 -0
- package/templates/nuxt/plugins.simpleapp.ts.eta +10 -1
- package/templates/nuxt/server.api.ts.eta +14 -5
- package/src/createproject.ts +0 -121
- package/src/index2.ts-old +0 -132
- package/src/installdependency.sh +0 -5
- package/src/installnest.ts +0 -0
- package/src/installnuxt.ts +0 -0
- package/templates/basic/backend.config.eta +0 -1
- package/templates/basic/beforesave.eta +0 -7
- package/templates/basic/controller2.eta +0 -86
- package/templates/basic/frontend.config.eta +0 -1
- package/templates/basic/model-converter.etabackup +0 -21
- package/templates/basic/readme.eta +0 -3
- package/templates/basic/service.etabackupe +0 -106
- package/templates/basic/type.etabackup +0 -23
- package/templates/basic/uischema.eta +0 -13
|
@@ -4,10 +4,18 @@ import { Model } from 'mongoose';
|
|
|
4
4
|
import Ajv from 'ajv';
|
|
5
5
|
import addFormats from 'ajv-formats';
|
|
6
6
|
import foreignkeys from '../dicts/foreignkeys.json';
|
|
7
|
+
|
|
7
8
|
import {
|
|
8
9
|
NotFoundException,
|
|
9
10
|
InternalServerErrorException,
|
|
10
11
|
} from '@nestjs/common/exceptions';
|
|
12
|
+
import { User } from './User';
|
|
13
|
+
|
|
14
|
+
export enum IsolationType {
|
|
15
|
+
'org' = 'org',
|
|
16
|
+
'tenant' = 'tenant',
|
|
17
|
+
'branch' = 'branch',
|
|
18
|
+
}
|
|
11
19
|
@Injectable()
|
|
12
20
|
export class SimpleAppService<T extends { _id?: string }> {
|
|
13
21
|
protected jsonschema = { type: 'object', properties: {}, required: [] };
|
|
@@ -16,11 +24,19 @@ export class SimpleAppService<T extends { _id?: string }> {
|
|
|
16
24
|
protected documentName = 'category';
|
|
17
25
|
protected documentType = 'CAT';
|
|
18
26
|
protected LIMITPERPAGE = 20;
|
|
27
|
+
protected isolationtype: IsolationType = IsolationType.org;
|
|
28
|
+
protected isolationFilter: any = {};
|
|
19
29
|
protected data: T = { _id: '' } as T;
|
|
20
|
-
|
|
30
|
+
private doc: Model<T>; //set private to prevent developer break data isolation control
|
|
21
31
|
protected errorlist = [];
|
|
22
|
-
constructor(
|
|
32
|
+
constructor(
|
|
33
|
+
newdoc: Model<T>,
|
|
34
|
+
isolationtype: IsolationType = IsolationType.org,
|
|
35
|
+
) {
|
|
23
36
|
this.doc = newdoc;
|
|
37
|
+
this.isolationtype = isolationtype;
|
|
38
|
+
|
|
39
|
+
// this.tenantdoc = tenantdoc
|
|
24
40
|
}
|
|
25
41
|
getRecordId = (): string => this.data._id;
|
|
26
42
|
setSchema = (newschema) => (this.jsonschema = newschema);
|
|
@@ -34,9 +50,27 @@ export class SimpleAppService<T extends { _id?: string }> {
|
|
|
34
50
|
this.data = { ...newdata };
|
|
35
51
|
return this;
|
|
36
52
|
};
|
|
53
|
+
getIsolationFilter = () => {
|
|
54
|
+
let isolationFilter = {};
|
|
55
|
+
switch (this.isolationtype) {
|
|
56
|
+
case 'branch':
|
|
57
|
+
isolationFilter = User.getInstance().getBranchFilter();
|
|
58
|
+
break;
|
|
59
|
+
case 'tenant':
|
|
60
|
+
isolationFilter = User.getInstance().getTenantFilter();
|
|
61
|
+
break;
|
|
62
|
+
case 'org':
|
|
63
|
+
default:
|
|
64
|
+
isolationFilter = User.getInstance().getOrgFilter();
|
|
65
|
+
break;
|
|
66
|
+
}
|
|
67
|
+
return isolationFilter;
|
|
68
|
+
};
|
|
37
69
|
async list() {
|
|
38
70
|
try {
|
|
39
|
-
|
|
71
|
+
//console.log("this.isolationFilter",this.getIsolationFilter())
|
|
72
|
+
const products = await this.doc.find(this.getIsolationFilter());
|
|
73
|
+
// console.log(products)
|
|
40
74
|
const productlist = products.map((p: T) => {
|
|
41
75
|
return p;
|
|
42
76
|
});
|
|
@@ -53,6 +87,8 @@ export class SimpleAppService<T extends { _id?: string }> {
|
|
|
53
87
|
filter1[this.documentIdentityCode] = { $regex: keyword };
|
|
54
88
|
filter2[this.documentIdentityName] = { $regex: keyword };
|
|
55
89
|
const filterobj = { $or: [filter1, filter2] };
|
|
90
|
+
|
|
91
|
+
Object.assign(filterobj, this.getIsolationFilter());
|
|
56
92
|
const projections = {
|
|
57
93
|
id: `\$_id`,
|
|
58
94
|
label: `\$${this.documentIdentityCode}`,
|
|
@@ -69,31 +105,37 @@ export class SimpleAppService<T extends { _id?: string }> {
|
|
|
69
105
|
throw new InternalServerErrorException(err.message);
|
|
70
106
|
}
|
|
71
107
|
}
|
|
72
|
-
async
|
|
108
|
+
async search(filters: Object) {
|
|
73
109
|
try {
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
110
|
+
Object.assign(filters, this.getIsolationFilter());
|
|
111
|
+
const products = await this.doc.find(filters);
|
|
112
|
+
const productlist = products.map((p: T) => {
|
|
113
|
+
return p;
|
|
114
|
+
});
|
|
115
|
+
// console.log(products);
|
|
116
|
+
return productlist;
|
|
77
117
|
} catch (err) {
|
|
78
|
-
//error
|
|
79
118
|
throw new InternalServerErrorException(err.message);
|
|
80
119
|
}
|
|
81
|
-
|
|
82
|
-
if (!this.data) {
|
|
83
|
-
//data not found
|
|
84
|
-
throw new NotFoundException('Document Not found:');
|
|
85
|
-
}
|
|
86
|
-
//console.log('this.data', this.data);
|
|
87
|
-
return this.data;
|
|
88
120
|
// return this;
|
|
89
121
|
}
|
|
122
|
+
async findById(id: string) {
|
|
123
|
+
const data = await this.search({ _id: id });
|
|
124
|
+
if (data.length == 1) {
|
|
125
|
+
// console.log('data0', data[0]);
|
|
126
|
+
return data[0];
|
|
127
|
+
} else {
|
|
128
|
+
return null;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
90
131
|
|
|
91
132
|
async create() {
|
|
92
133
|
let result;
|
|
93
134
|
|
|
94
135
|
try {
|
|
136
|
+
Object.assign(this.data, User.getInstance().getCreateFilter());
|
|
95
137
|
delete this.data._id;
|
|
96
|
-
this.validateData(this.data);
|
|
138
|
+
this.validateData(this.data);
|
|
97
139
|
const newdoc = new this.doc(this.data);
|
|
98
140
|
result = await newdoc.save();
|
|
99
141
|
} catch (err) {
|
|
@@ -103,14 +145,14 @@ export class SimpleAppService<T extends { _id?: string }> {
|
|
|
103
145
|
}
|
|
104
146
|
async update() {
|
|
105
147
|
const id: string = this.getRecordId();
|
|
148
|
+
Object.assign(this.data, User.getInstance().getUpdateFilter());
|
|
106
149
|
this.findIdThenUpdate(id, this.data);
|
|
107
150
|
}
|
|
108
151
|
async delete() {
|
|
109
|
-
|
|
110
152
|
const id: string = this.getRecordId();
|
|
111
153
|
const dependency = await this.getRelatedRecords(id);
|
|
112
154
|
if (!dependency) {
|
|
113
|
-
|
|
155
|
+
return await this.findIdThenDelete(id);
|
|
114
156
|
} else {
|
|
115
157
|
return dependency;
|
|
116
158
|
}
|
|
@@ -121,10 +163,10 @@ export class SimpleAppService<T extends { _id?: string }> {
|
|
|
121
163
|
validateData(data: T) {
|
|
122
164
|
const ajv = new Ajv({ allErrors: true });
|
|
123
165
|
addFormats(ajv);
|
|
124
|
-
ajv.addFormat('
|
|
125
|
-
ajv.addFormat('
|
|
126
|
-
ajv.addFormat('x-text'
|
|
127
|
-
ajv.addFormat('x-html'
|
|
166
|
+
ajv.addFormat('x-document-no', /.*$/);
|
|
167
|
+
ajv.addFormat('x-document-name', /.*$/);
|
|
168
|
+
ajv.addFormat('x-text', /.*$/);
|
|
169
|
+
ajv.addFormat('x-html', /.*$/);
|
|
128
170
|
ajv.addKeyword({
|
|
129
171
|
keyword: 'x-foreignkey',
|
|
130
172
|
type: 'string',
|
|
@@ -135,28 +177,36 @@ export class SimpleAppService<T extends { _id?: string }> {
|
|
|
135
177
|
for (let i = 0; i < this.errorlist.length; i++) {
|
|
136
178
|
erromsg.push(this.errorlist[i].message);
|
|
137
179
|
}
|
|
180
|
+
console.log("pre-validation:",erromsg)
|
|
138
181
|
throw new InternalServerErrorException(erromsg.join('\n'));
|
|
139
182
|
}
|
|
140
183
|
const validate = ajv.compile(this.jsonschema);
|
|
141
184
|
const valid = validate(data);
|
|
185
|
+
//console.log(validate.errors);
|
|
142
186
|
if (!valid) {
|
|
143
|
-
//console.log(validate.errors);
|
|
187
|
+
// console.log(validate.errors);
|
|
144
188
|
const erromsg: string[] = [];
|
|
145
189
|
for (let i = 0; i < validate.errors.length; i++) {
|
|
146
190
|
erromsg.push(validate.errors[i].message);
|
|
147
191
|
}
|
|
192
|
+
console.log("ajv erromsg: ",erromsg)
|
|
148
193
|
throw new InternalServerErrorException(erromsg.join('\n'));
|
|
149
194
|
}
|
|
150
195
|
this.hook('post-validation', data);
|
|
151
196
|
}
|
|
152
197
|
|
|
153
|
-
async findIdThenDelete(id: string) {
|
|
198
|
+
async findIdThenDelete(id: string): Promise<any> {
|
|
154
199
|
// const data = await this.findById(id);
|
|
155
200
|
try {
|
|
156
201
|
//console.log('deletedeletedeletedelete');
|
|
157
202
|
const dependency = await this.getRelatedRecords(id);
|
|
158
203
|
if (!dependency) {
|
|
159
|
-
|
|
204
|
+
let filter = this.getIsolationFilter();
|
|
205
|
+
filter['_id'] = id;
|
|
206
|
+
const deleteresult = await this.doc.deleteOne(filter);
|
|
207
|
+
// this.doc.findByIdAndDelete(id)
|
|
208
|
+
|
|
209
|
+
//this.doc.findByIdAndDelete(id);
|
|
160
210
|
return deleteresult;
|
|
161
211
|
} else {
|
|
162
212
|
return Promise.reject(dependency);
|
|
@@ -166,20 +216,26 @@ export class SimpleAppService<T extends { _id?: string }> {
|
|
|
166
216
|
}
|
|
167
217
|
}
|
|
168
218
|
|
|
169
|
-
async
|
|
170
|
-
|
|
219
|
+
updateOne = async (data: T) => {
|
|
220
|
+
this.doc.updateOne(data);
|
|
221
|
+
};
|
|
222
|
+
|
|
223
|
+
findIdThenUpdate = async (id: string, data: T) => {
|
|
224
|
+
const existingdata = await this.findById(id);
|
|
171
225
|
|
|
172
226
|
try {
|
|
173
|
-
|
|
227
|
+
Object.assign(data, User.getInstance().getUpdateFilter());
|
|
228
|
+
Object.assign(existingdata, data);
|
|
174
229
|
this.validateData(data);
|
|
175
|
-
|
|
176
|
-
|
|
230
|
+
let filter = this.getIsolationFilter();
|
|
231
|
+
filter['_id'] = id;
|
|
232
|
+
const result = await this.doc.findOneAndUpdate(filter, data);
|
|
177
233
|
|
|
178
234
|
return result;
|
|
179
235
|
} catch (err) {
|
|
180
236
|
throw new InternalServerErrorException(err.message);
|
|
181
237
|
}
|
|
182
|
-
}
|
|
238
|
+
};
|
|
183
239
|
|
|
184
240
|
//find what foreign key constraint
|
|
185
241
|
async getRelatedRecords(id: string) {
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
|
|
2
|
+
import { Injectable, NestMiddleware,Scope } from '@nestjs/common';
|
|
3
|
+
import { Request, Response, NextFunction } from 'express';
|
|
4
|
+
import {User} from './User'
|
|
5
|
+
|
|
6
|
+
@Injectable({
|
|
7
|
+
scope: Scope.REQUEST
|
|
8
|
+
})
|
|
9
|
+
export class TenantMiddleware implements NestMiddleware {
|
|
10
|
+
use(req: Request, res: Response, next: NextFunction) {
|
|
11
|
+
req.headers['x-org']
|
|
12
|
+
if(req.headers['x-org']){
|
|
13
|
+
const u = User.getInstance()
|
|
14
|
+
try{
|
|
15
|
+
u.setXorg(req.headers['x-org'].toString())
|
|
16
|
+
u.setUser('user1')
|
|
17
|
+
//console.log(u.getInfo())
|
|
18
|
+
// u.uid='user1'
|
|
19
|
+
next();
|
|
20
|
+
}catch{
|
|
21
|
+
return res.status(401).send("Invalid x-org or user info")
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
}else{
|
|
25
|
+
return res.status(401).send("undefine header string x-org")
|
|
26
|
+
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { Injectable, Scope } from '@nestjs/common';
|
|
2
|
+
import Base64URL from '@darkwolf/base64url'
|
|
3
|
+
|
|
4
|
+
@Injectable({
|
|
5
|
+
scope: Scope.REQUEST
|
|
6
|
+
})
|
|
7
|
+
export class User {
|
|
8
|
+
private static instance: User;
|
|
9
|
+
protected uid:string=''
|
|
10
|
+
protected uname:string=''
|
|
11
|
+
protected email:string=''
|
|
12
|
+
protected xOrg:string=''
|
|
13
|
+
protected tenantId:number=0
|
|
14
|
+
protected orgId:number=0
|
|
15
|
+
protected branchId:number=0
|
|
16
|
+
constructor() {}
|
|
17
|
+
public static getInstance(): User {
|
|
18
|
+
if (!User.instance) {
|
|
19
|
+
User.instance = new User();
|
|
20
|
+
}
|
|
21
|
+
return User.instance;
|
|
22
|
+
}
|
|
23
|
+
setUser = (uid:string)=>{
|
|
24
|
+
User.getInstance().uid=uid
|
|
25
|
+
}
|
|
26
|
+
getInfo=()=>{
|
|
27
|
+
return User.getInstance()
|
|
28
|
+
}
|
|
29
|
+
getBranchFilter=()=>{
|
|
30
|
+
return {
|
|
31
|
+
tenantId:User.getInstance().tenantId,
|
|
32
|
+
orgId: User.getInstance().orgId,
|
|
33
|
+
branchId:User.getInstance().branchId
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
getTenantFilter=()=>{
|
|
37
|
+
return {tenantId:User.getInstance().tenantId}
|
|
38
|
+
}
|
|
39
|
+
getOrgFilter=()=>{
|
|
40
|
+
return {tenantId:User.getInstance().tenantId,orgId: User.getInstance().orgId}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
getCreateFilter=()=>{
|
|
44
|
+
const u = User.getInstance()
|
|
45
|
+
return {
|
|
46
|
+
tenantId:u.tenantId,
|
|
47
|
+
orgId: u.orgId,
|
|
48
|
+
branchId:u.branchId,
|
|
49
|
+
createdby: u.uid,
|
|
50
|
+
updatedby: u.uid,
|
|
51
|
+
created: new Date().getTime().toString(),
|
|
52
|
+
updated: new Date().getTime().toString()
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
getUpdateFilter=()=>{
|
|
56
|
+
const u = User.getInstance()
|
|
57
|
+
return {
|
|
58
|
+
updatedby: u.uid,
|
|
59
|
+
updated: new Date().getTime().toString()
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
setXorg = (xorg)=>{
|
|
63
|
+
try{
|
|
64
|
+
const decodedText:string = Base64URL.decodeText(xorg)
|
|
65
|
+
const arrXorg = decodedText.split('-')
|
|
66
|
+
|
|
67
|
+
if(arrXorg.length==3){
|
|
68
|
+
const u = User.getInstance()
|
|
69
|
+
u.tenantId = Number(arrXorg[0])
|
|
70
|
+
u.orgId = Number(arrXorg[1])
|
|
71
|
+
u.branchId = Number(arrXorg[2])
|
|
72
|
+
}else{
|
|
73
|
+
throw "invalid x-org"
|
|
74
|
+
}
|
|
75
|
+
}catch(err){
|
|
76
|
+
throw err
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
}
|
|
80
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { Module } from '@nestjs/common';
|
|
1
|
+
import { Module,MiddlewareConsumer,NestModule } from '@nestjs/common';
|
|
2
2
|
import { MongooseModule } from '@nestjs/mongoose';
|
|
3
3
|
import { ConfigModule } from '@nestjs/config';
|
|
4
|
-
|
|
4
|
+
import {TenantMiddleware} from './class/TenantMiddleware'
|
|
5
5
|
<% for(let i=0;i<it.length; i++){ %>
|
|
6
6
|
import {<%= it[i].docname %>Module} from './docs/<%= it[i].doctype %>/<%= it[i].doctype %>.module'
|
|
7
7
|
<%}%>
|
|
@@ -12,4 +12,15 @@ import {<%= it[i].docname %>Module} from './docs/<%= it[i].doctype %>/<%= it[i].
|
|
|
12
12
|
controllers: [],
|
|
13
13
|
providers: [],
|
|
14
14
|
})
|
|
15
|
-
export class AppModule {
|
|
15
|
+
export class AppModule implements NestModule{
|
|
16
|
+
configure(consumer: MiddlewareConsumer) {
|
|
17
|
+
consumer
|
|
18
|
+
.apply(TenantMiddleware)
|
|
19
|
+
// .exclude('/api-yaml')
|
|
20
|
+
// .exclude('/api-json')
|
|
21
|
+
// .exclude('/api')
|
|
22
|
+
.forRoutes('*')
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -9,6 +9,8 @@ async function bootstrap() {
|
|
|
9
9
|
.setTitle(process.env.PROJECT_NAME)
|
|
10
10
|
.setDescription(process.env.PROJECT_DESCRIPTION)
|
|
11
11
|
.setVersion(process.env.PROJECT_VERSION)
|
|
12
|
+
.addApiKey({in:'header',name:'x-org',type:'apiKey',description:'base 64 url encode. example: MS0xLTE'},'x-org')
|
|
13
|
+
.addSecurityRequirements('x-org')
|
|
12
14
|
.build();
|
|
13
15
|
const document = SwaggerModule.createDocument(app, config);
|
|
14
16
|
SwaggerModule.setup('api', app, document, {
|
|
@@ -1,32 +1,10 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<div class="simpleapp-crudsimple">
|
|
3
|
-
<button class="bg-primary" type="reset" @click="newData">New</button>
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
<SimpleAppDatatable
|
|
7
|
-
@row-dblclick="editRecord"
|
|
8
|
-
v-model="recordlist"
|
|
9
|
-
:setting="{}"
|
|
10
|
-
:columns="listColumns"
|
|
11
|
-
></SimpleAppDatatable>
|
|
12
|
-
|
|
13
|
-
<DebugDocumentData v-model="data"/>
|
|
14
|
-
</div>
|
|
15
|
-
|
|
16
|
-
<Dialog v-model:visible="visible" modal header="Header" class="crudsimple-dialog" :autoZIndex="false" :style="{zIndex:100, width: '80vw' }">
|
|
17
|
-
<SimpleAppForm :document="obj" :title="title" #default="o">
|
|
18
|
-
<div class="simpleapp-tool-bar" >
|
|
19
|
-
<button class="bg-default" :disabled="disabled" @click="newData" type="reset">New</button>
|
|
20
|
-
<button class="bg-primary" :disabled="disabled" @click="saveData" type="submit">Save</button>
|
|
21
|
-
<button class="bg-danger" :disabled="disabled" @click="deleteData($event)">Delete</button>
|
|
22
|
-
<ProgressSpinner v-if="disabled==true" style="width: 2rem; height: 2rem" ></ProgressSpinner>
|
|
23
|
-
<ConfirmPopup></ConfirmPopup>
|
|
24
|
-
</div>
|
|
25
|
-
<slot :data="o.data" :getField="o.getField" name="default"></slot>
|
|
26
|
-
</SimpleAppForm>
|
|
27
|
-
</Dialog>
|
|
28
|
-
</template>
|
|
29
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
|
+
*/
|
|
30
8
|
|
|
31
9
|
import { SimpleAppClient } from '@simitgroup//simpleapp-vue-component/src/SimpleAppClient';
|
|
32
10
|
import SimpleAppForm from '@simitgroup/simpleapp-vue-component/src/components/SimpleAppForm.vue';
|
|
@@ -34,7 +12,6 @@ import SimpleAppDatatable from '@simitgroup/simpleapp-vue-component/src/componen
|
|
|
34
12
|
import Dialog from 'primevue/dialog';
|
|
35
13
|
import axios from 'axios'
|
|
36
14
|
import ProgressSpinner from 'primevue/progressspinner';
|
|
37
|
-
|
|
38
15
|
import ConfirmPopup from 'primevue/confirmpopup';
|
|
39
16
|
import { useConfirm } from "primevue/useconfirm";
|
|
40
17
|
|
|
@@ -42,6 +19,7 @@ const confirm = useConfirm();
|
|
|
42
19
|
const props = defineProps<{
|
|
43
20
|
document:SimpleAppClient<any,any>
|
|
44
21
|
listColumns:string[]
|
|
22
|
+
path:string
|
|
45
23
|
title:string
|
|
46
24
|
}>()
|
|
47
25
|
const visible = ref(false)
|
|
@@ -49,14 +27,12 @@ const obj = props.document
|
|
|
49
27
|
const data = obj.getReactiveData()
|
|
50
28
|
const disabled=ref(false)
|
|
51
29
|
const recordlist = ref();
|
|
52
|
-
const
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
}
|
|
59
|
-
|
|
30
|
+
const router = useRouter()
|
|
31
|
+
const route = useRoute()
|
|
32
|
+
const filters = ref()
|
|
33
|
+
defineShortcuts({
|
|
34
|
+
'ctrl_i': () => newData()
|
|
35
|
+
})
|
|
60
36
|
const refresh = () => {
|
|
61
37
|
obj.list().then((res:any) => {
|
|
62
38
|
recordlist.value = res;
|
|
@@ -64,23 +40,27 @@ const refresh = () => {
|
|
|
64
40
|
});
|
|
65
41
|
};
|
|
66
42
|
const newData = () => {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
43
|
+
router.push({ path: `${props.path}` })
|
|
44
|
+
obj.setNew()
|
|
45
|
+
visible.value=true;
|
|
70
46
|
};
|
|
71
47
|
|
|
72
|
-
const
|
|
73
|
-
|
|
74
|
-
|
|
48
|
+
const triggerEdit = (event: any) => {
|
|
49
|
+
let id = event.data._id.toString()
|
|
50
|
+
editRecord(event.data._id);
|
|
51
|
+
router.push({ path: `${props.path}/${id}` })
|
|
52
|
+
};
|
|
53
|
+
const editRecord = (id:string) => {
|
|
54
|
+
obj.getById(id);
|
|
75
55
|
visible.value=true
|
|
76
56
|
};
|
|
77
57
|
|
|
78
58
|
const saveData = () => {
|
|
79
59
|
disabled.value=true
|
|
80
60
|
if (data.value._id == "") {
|
|
81
|
-
obj.create().then(()=>{visible.value=false}).
|
|
61
|
+
obj.create().then(()=>{visible.value=false}).finally(() => refresh());
|
|
82
62
|
} else {
|
|
83
|
-
obj.update().then(()=>visible.value=false).
|
|
63
|
+
obj.update().then(()=>visible.value=false).finally(() => refresh());
|
|
84
64
|
}
|
|
85
65
|
};
|
|
86
66
|
const deleteData = (event:Event) => {
|
|
@@ -97,14 +77,47 @@ const deleteData = (event:Event) => {
|
|
|
97
77
|
});
|
|
98
78
|
},
|
|
99
79
|
reject: () => {
|
|
100
|
-
setCsrf()
|
|
101
80
|
console.log("Cancel delete")
|
|
102
81
|
}
|
|
103
|
-
})
|
|
104
|
-
|
|
82
|
+
})
|
|
105
83
|
};
|
|
84
|
+
|
|
85
|
+
if (route.params.id) {
|
|
86
|
+
const recordid:string = route.params.id.toString()
|
|
87
|
+
editRecord(recordid)
|
|
88
|
+
}
|
|
89
|
+
|
|
106
90
|
refresh();
|
|
107
91
|
</script>
|
|
92
|
+
|
|
93
|
+
<template>
|
|
94
|
+
<div class="simpleapp-crudsimple">
|
|
95
|
+
<button class="bg-primary" @click="newData" v-tooltip="'Add new(ctrl+i)'" >New</button>
|
|
96
|
+
<SimpleAppDatatable
|
|
97
|
+
@row-dblclick="triggerEdit"
|
|
98
|
+
v-model="recordlist"
|
|
99
|
+
:setting="{}"
|
|
100
|
+
:columns="listColumns"
|
|
101
|
+
>
|
|
102
|
+
</SimpleAppDatatable>
|
|
103
|
+
|
|
104
|
+
<DebugDocumentData v-model="data"/>
|
|
105
|
+
</div>
|
|
106
|
+
|
|
107
|
+
<Dialog v-model:visible="visible" modal header="Header" class="crudsimple-dialog" :autoZIndex="false" :style="{zIndex:100, width: '80vw' }">
|
|
108
|
+
<SimpleAppForm :document="obj" :title="title" #default="o">
|
|
109
|
+
<div class="simpleapp-tool-bar" >
|
|
110
|
+
<button class="bg-default" :disabled="disabled" @click="newData" type="button">New</button>
|
|
111
|
+
<button class="bg-primary" :disabled="disabled" @click="saveData" type="submit">Save</button>
|
|
112
|
+
<button class="bg-danger" :disabled="disabled" @click="deleteData($event)" type="button">Delete</button>
|
|
113
|
+
<ProgressSpinner v-if="disabled==true" style="width: 2rem; height: 2rem" ></ProgressSpinner>
|
|
114
|
+
<ConfirmPopup></ConfirmPopup>
|
|
115
|
+
</div>
|
|
116
|
+
<slot :data="o.data" :getField="o.getField" name="default"></slot>
|
|
117
|
+
</SimpleAppForm>
|
|
118
|
+
</Dialog>
|
|
119
|
+
</template>
|
|
120
|
+
|
|
108
121
|
<style scoped>
|
|
109
122
|
.crudsimple-dialog{
|
|
110
123
|
z-index: 100;
|
|
@@ -1,14 +1,22 @@
|
|
|
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
|
+
|
|
9
|
+
const modelValue = defineModel()
|
|
10
|
+
const isdebug = ref(useRuntimeConfig().public.DEBUGDATA)
|
|
11
|
+
</script>
|
|
1
12
|
<template>
|
|
2
|
-
<div class="floatright">
|
|
13
|
+
<div class="floatright" v-if="isdebug=='1'">
|
|
3
14
|
<h3>data in json</h3>
|
|
4
15
|
<pre>
|
|
5
16
|
{{ modelValue }}
|
|
6
17
|
</pre>
|
|
7
18
|
</div>
|
|
8
19
|
</template>
|
|
9
|
-
<script setup lang="ts">
|
|
10
|
-
const modelValue = defineModel()
|
|
11
|
-
</script>
|
|
12
20
|
<style scoped>
|
|
13
21
|
.floatright{
|
|
14
22
|
position: fixed;
|
|
@@ -1,14 +1,10 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<Toast group="default"/>
|
|
3
|
-
<Toast group="list">
|
|
4
|
-
<template #message="p">
|
|
5
|
-
<ol>
|
|
6
|
-
<li v-for="(item,index) in p.message.detail" :key="index">{{item.instancePath}} {{ item.message }}</li>
|
|
7
|
-
</ol>
|
|
8
|
-
</template>
|
|
9
|
-
</Toast>
|
|
10
|
-
</template>
|
|
11
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
|
+
*/
|
|
12
8
|
|
|
13
9
|
import { useToast, } from 'primevue/usetoast';
|
|
14
10
|
import type { ToastMessageOptions } from 'primevue/toast';
|
|
@@ -76,4 +72,14 @@ const prepareMsg=(data:any,msgtype:string):string=>{
|
|
|
76
72
|
|
|
77
73
|
}
|
|
78
74
|
|
|
79
|
-
</script>
|
|
75
|
+
</script>
|
|
76
|
+
<template>
|
|
77
|
+
<Toast group="default"/>
|
|
78
|
+
<Toast group="list">
|
|
79
|
+
<template #message="p">
|
|
80
|
+
<ol>
|
|
81
|
+
<li v-for="(item,index) in p.message.detail" :key="index">{{item.instancePath}} {{ item.message }}</li>
|
|
82
|
+
</ol>
|
|
83
|
+
</template>
|
|
84
|
+
</Toast>
|
|
85
|
+
</template>
|
|
@@ -1,18 +1,20 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
/**
|
|
3
|
+
* This file was automatically generated by simpleapp generator during initialization.
|
|
4
|
+
* You may modify it by hand
|
|
5
|
+
* last change 2023-09-10
|
|
6
|
+
* author: Ks Tan
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
// import MegaMenu from 'primevue/megamenu';
|
|
10
|
+
import Menubar from 'primevue/menubar';
|
|
11
|
+
const route = useRoute()
|
|
12
|
+
const menus = getMenus(route.params.xorg)
|
|
13
|
+
</script>
|
|
1
14
|
<template>
|
|
2
15
|
<header>
|
|
3
16
|
<!-- <MegaMenu :model="getMenus()" orientation="horizontal" /> -->
|
|
4
|
-
<Menubar :model="
|
|
5
|
-
<template #start>
|
|
6
|
-
<h1>[Logo Container]</h1>
|
|
7
|
-
</template>
|
|
8
|
-
<template #end>
|
|
9
|
-
<InputText placeholder="Search" type="text" />
|
|
10
|
-
</template>
|
|
17
|
+
<Menubar :model="menus">
|
|
11
18
|
</Menubar>
|
|
12
19
|
</header>
|
|
13
20
|
</template>
|
|
14
|
-
<script setup lang="ts">
|
|
15
|
-
// import MegaMenu from 'primevue/megamenu';
|
|
16
|
-
import Menubar from 'primevue/menubar';
|
|
17
|
-
|
|
18
|
-
</script>
|
|
@@ -1,4 +1,10 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* This file was automatically generated by simpleapp generator during initialization.
|
|
3
|
+
* DO NOT MODIFY IT BY HAND.
|
|
4
|
+
* last change 2023-09-09
|
|
5
|
+
* author: Ks Tan
|
|
6
|
+
*/
|
|
7
|
+
|
|
2
8
|
import * as o from "../simpleapp/openapi";
|
|
3
9
|
|
|
4
10
|
const getAutoComplete = (apiname: string): any => {
|
|
@@ -1,8 +1,15 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* This file was automatically generated by simpleapp generator during initialization.
|
|
3
|
+
* DO NOT MODIFY IT BY HAND.
|
|
4
|
+
* last change 2023-09-10
|
|
5
|
+
* author: Ks Tan
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
export const getMenus =(xorg:string)=>[
|
|
2
9
|
{label: 'Cruds',icon: 'pi pi-fw pi-pencil',items:[
|
|
3
10
|
<% for(let i=0;i<it.length; i++){ %>
|
|
4
11
|
<% let obj = it[i]%>
|
|
5
|
-
{label: '<%=obj.docname.toLowerCase()%>', to
|
|
12
|
+
{label: '<%=obj.docname.toLowerCase()%>', to:`/${xorg}/<%=obj.docname.toLowerCase()%>`},
|
|
6
13
|
<%}%>
|
|
7
14
|
]},
|
|
8
15
|
{label: 'Profile',icon: 'pi pi-fw pi-user'},
|