@hostlink/nuxt-light 0.0.62 → 0.0.64

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/module.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "light",
3
3
  "configKey": "light",
4
- "version": "0.0.62"
4
+ "version": "0.0.64"
5
5
  }
@@ -1,7 +1,9 @@
1
1
  <script setup>
2
- import { useRuntimeConfig } from 'nuxt/app';
2
+ import { useRuntimeConfig } from 'nuxt/app'
3
3
  import { setApiUrl } from '@hostlink/light'
4
- import { q } from '../';
4
+ import { useRoute } from 'vue-router'
5
+ import { q } from '../'
6
+ const route = useRoute()
5
7
  const config = useRuntimeConfig();
6
8
  setApiUrl(config?.public?.apiBase ?? '/api/');
7
9
 
@@ -12,11 +14,8 @@ const { app } = await q({ app: ['company', 'companyLogo', 'logged', 'twoFactorAu
12
14
  <q-layout v-if="!app.logged">
13
15
  <q-page-container class="bg-grey-2" style="color:#1f1f1f">
14
16
  <q-page padding>
15
- <l-login
16
- :company="app.company"
17
- :company-logo="app.companyLogo"
18
- :twoFactorAuthentication="app.twoFactorAuthentication"
19
- ></l-login>
17
+ <l-login :company="app.company" :company-logo="app.companyLogo"
18
+ :twoFactorAuthentication="app.twoFactorAuthentication"></l-login>
20
19
  </q-page>
21
20
  </q-page-container>
22
21
  </q-layout>
@@ -2,6 +2,7 @@
2
2
  import { q } from '../';
3
3
  const props = defineProps(["modelValue"]);
4
4
 
5
+
5
6
  const file = await q("fsFile", {
6
7
  path: props.modelValue.path
7
8
  }, ["canPreview", "imagePath"])
@@ -4,12 +4,18 @@ import { useI18n } from "vue-i18n";
4
4
  import { ref, watch, computed } from 'vue';
5
5
  import { useQuasar } from 'quasar';
6
6
  import { q, m } from '../';
7
+ import {
8
+ fsListFolders, fsCreateFolder, fsDeleteFolder, fsDeleteFile, fsRenameFile, fsRenameFolder, fsReadFile,
9
+ granted
10
+
11
+ } from "@hostlink/light";
12
+
7
13
 
8
14
  const i18n = useI18n();
9
15
  const quasar = useQuasar();
10
16
  const emit = defineEmits(["input", "close"]);
11
17
 
12
- defineProps({
18
+ const props = defineProps({
13
19
  closable: Boolean,
14
20
  height: {
15
21
  type: String,
@@ -23,6 +29,10 @@ defineProps({
23
29
  default: false,
24
30
  type: Boolean,
25
31
  },
32
+ base: {
33
+ default: "/",
34
+ type: String,
35
+ },
26
36
  });
27
37
 
28
38
  const loading = ref(false);
@@ -88,10 +98,10 @@ function toggleLeftDrawer() {
88
98
  leftDrawerOpen.value = !leftDrawerOpen.value;
89
99
  }
90
100
 
91
- const path = ref("");
101
+ const path = ref(props.base);
92
102
 
93
103
  const onLazyLoad = async ({ node, key, done, fail }) => {
94
- const data = await q("fsListFolders", { path: node.path }, ["name", "path"]);
104
+ const data = await fsListFolders(node.path);
95
105
  data.map((item) => {
96
106
  item.lazy = true;
97
107
  return item;
@@ -123,7 +133,7 @@ const loadItems = async () => {
123
133
 
124
134
  let folders = [];
125
135
  if (!label.value && !localSearch.value) {
126
- folders = await q("fsListFolders", { path: path.value }, ["name", "path"]);
136
+ folders = await fsListFolders(path.value);
127
137
  folders = folders.map((item) => {
128
138
  item.type = "folder";
129
139
  item.lazy = true;
@@ -134,8 +144,6 @@ const loadItems = async () => {
134
144
 
135
145
  loading.value = false;
136
146
 
137
-
138
-
139
147
  return {
140
148
  files,
141
149
  folders,
@@ -154,8 +162,6 @@ const label = ref(null);
154
162
  const initItems = await loadItems();
155
163
  const folders = ref(initItems.folders);
156
164
 
157
-
158
-
159
165
  watch(label, () => {
160
166
  loadItems();
161
167
  })
@@ -163,13 +169,18 @@ watch(label, () => {
163
169
  const selected = ref([]);
164
170
 
165
171
  const breadcrumbs = computed(() => {
166
- let breadcrumbs = [];
172
+ let breadcrumbs = [
173
+ {
174
+ label: i18n.t("Storage"),
175
+ path: props.base,
176
+ },
177
+ ];
167
178
 
168
179
  if (path.value.toString() == "") {
169
- return [];
180
+ return breadcrumbs;
170
181
  }
171
182
 
172
- let paths = path.value.split("/");
183
+ let paths = path.value.split(props.base);
173
184
 
174
185
  let ps = [];
175
186
  for (let p of paths) {
@@ -186,6 +197,11 @@ const breadcrumbs = computed(() => {
186
197
  });
187
198
 
188
199
  const onClickRow = (evt, row, index) => {
200
+ if (row.type == "folder") {
201
+ preview.value = null;
202
+ return;
203
+ }
204
+
189
205
  preview.value = row;
190
206
  }
191
207
 
@@ -197,7 +213,6 @@ const onDblclickRow = (evt, row, index) => {
197
213
  return;
198
214
  }
199
215
  if (row.type == "file") {
200
-
201
216
  emit("input", row.path);
202
217
  }
203
218
  }
@@ -238,9 +253,9 @@ const onDeleteSelected = () => {
238
253
  }).onOk(async () => {
239
254
  for (let row of selected.value) {
240
255
  if (row.type == "folder") {
241
- await m("fsDeleteFolder", { path: row.path });
256
+ await fsDeleteFolder(row.path)
242
257
  } else {
243
- await m("fsDeleteFile", { path: row.path });
258
+ await fsDeleteFile(row.path);
244
259
  }
245
260
  }
246
261
  selected.value = [];
@@ -251,7 +266,6 @@ const onDeleteSelected = () => {
251
266
  }
252
267
 
253
268
  const onNewFolder = () => {
254
-
255
269
  quasar.dialog({
256
270
  title: "New Folder",
257
271
  prompt: {
@@ -259,8 +273,7 @@ const onNewFolder = () => {
259
273
  },
260
274
  cancel: true,
261
275
  }).onOk(async (name) => {
262
- let p = path.value + "/" + name;
263
- await m("fsCreateFolder", { path: p });
276
+ await fsCreateFolder(path.value + "/" + name)
264
277
  const items = await loadItems();
265
278
  reloadTreeFolder(path.value, items.folders);
266
279
  });
@@ -273,7 +286,7 @@ const onDeleteRow = (row) => {
273
286
  message: "Are you sure you want to delete this file?",
274
287
  cancel: true,
275
288
  }).onOk(async () => {
276
- await m("fsDeleteFile", { path: row.path });
289
+ await fsDeleteFile(row.path);
277
290
  const items = await loadItems();
278
291
  reloadTreeFolder(path.value, items.folders);
279
292
  });
@@ -283,7 +296,7 @@ const onDeleteRow = (row) => {
283
296
  message: "Are you sure you want to delete this folder?",
284
297
  cancel: true,
285
298
  }).onOk(async () => {
286
- await m("fsDeleteFolder", { path: row.path });
299
+ await fsDeleteFolder(row.path);
287
300
  const items = await loadItems();
288
301
  reloadTreeFolder(path.value, items.folders);
289
302
  });
@@ -301,9 +314,9 @@ const onRenameRow = (row) => {
301
314
  }).onOk(async (name) => {
302
315
  try {
303
316
  if (row.type == "file") {
304
- await m("fsRenameFile", { path: row.path, name });
317
+ await fsRenameFile(row.path, name)
305
318
  } else {
306
- await m("fsRenameFolder", { path: row.path, name });
319
+ await fsRenameFolder(row.path, name);
307
320
  }
308
321
  } catch (e) {
309
322
  quasar.dialog({
@@ -385,23 +398,64 @@ const filesGrid = computed(() => {
385
398
  });
386
399
  });
387
400
 
401
+ const onDownloadRow = async (row) => {
402
+
403
+ const resp = await q("fsFile", {
404
+ path: row.path
405
+ }, ["base64Content"]);
406
+
407
+ const downloadLink = document.createElement("a");
408
+ downloadLink.href = `data:application/octet-stream;base64,${resp.base64Content}`;
409
+ downloadLink.download = row.name;
410
+ downloadLink.click();
411
+
388
412
 
389
- const onDownloadRow = (row) => {
390
- // window.open("/api/fs/download?path=" + row.path);
391
413
  }
392
414
 
393
415
  const search = ref(null);
394
416
 
395
417
  const reloadStorage = async () => {
396
- path.value = "";
418
+ path.value = props.base;
397
419
 
398
420
  search.value = "";
399
421
  localSearch.value = "";
400
422
  label.value = null;
401
423
  const items = await loadItems();
402
424
  reloadTreeFolder(path.value, items.folders);
425
+ }
426
+
427
+ const permission = await granted([
428
+ 'fs.folder.create', 'fs.folder.delete', 'fs.folder.rename',
429
+ 'fs.file.delete', 'fs.file.rename', 'fs.file.upload'
430
+ ]);
431
+
432
+ const canDeleteRow = (row) => {
433
+ if (row.type == "folder" && permission.includes("fs.folder.delete")) {
434
+ return true;
435
+ }
436
+
437
+ if (row.type == "file" && permission.includes("fs.file.delete")) {
438
+ return true;
439
+ }
440
+
441
+ return false;
442
+ }
443
+
444
+ const canRenameRow = (row) => {
445
+ if (row.type == "folder" && permission.includes("fs.folder.rename")) {
446
+ return true;
447
+ }
448
+
449
+ if (row.type == "file" && permission.includes("fs.file.rename")) {
450
+ return true;
451
+ }
403
452
 
453
+ return false;
404
454
  }
455
+
456
+ /* const perm = await q("granted", {
457
+ rights: ["fs.folder.create"]
458
+ }) */
405
459
  </script>
406
460
  <template>
407
461
  <q-layout view="hHh lpR fFf" class="bg-white" container :style="{ 'min-height': height }">
@@ -435,14 +489,15 @@ const reloadStorage = async () => {
435
489
  <q-btn icon="add" outline rounded color="primary" :label="$t('New')">
436
490
  <q-menu>
437
491
  <q-list>
438
- <q-item clickable v-close-popup @click="onNewFolder">
492
+ <q-item clickable v-close-popup @click="onNewFolder" v-if="permission.includes('fs.folder.create')">
439
493
  <q-item-section avatar>
440
494
  <q-icon name="sym_o_create_new_folder"></q-icon>
441
495
  </q-item-section>
442
496
  <q-item-section>{{ $t('Folder') }}</q-item-section>
443
497
  </q-item>
444
498
  <q-separator />
445
- <q-item clickable v-close-popup @click="showUploadFiles = true">
499
+ <q-item clickable v-close-popup @click="showUploadFiles = true"
500
+ v-if="permission.includes('fs.file.upload')">
446
501
  <q-item-section avatar>
447
502
  <q-icon name="sym_o_upload_file"></q-icon>
448
503
  </q-item-section>
@@ -509,7 +564,6 @@ const reloadStorage = async () => {
509
564
 
510
565
  <q-toolbar>
511
566
  <q-breadcrumbs>
512
- <q-breadcrumbs-el :label="$t('Storage')" @click="path = ''" href="javascript:void(0)"></q-breadcrumbs-el>
513
567
  <q-breadcrumbs-el v-for="(b, index) in breadcrumbs" :label="b.label" :key="index" @click="path = b.path"
514
568
  href="javascript:void(0)"></q-breadcrumbs-el>
515
569
  </q-breadcrumbs>
@@ -583,11 +637,11 @@ const reloadStorage = async () => {
583
637
  <q-btn flat icon="sym_o_more_vert" round dense>
584
638
  <q-menu>
585
639
  <q-list>
586
- <q-item clickable v-close-popup @click="onDeleteRow(props.row)">
640
+ <q-item clickable v-close-popup @click="onDeleteRow(props.row)" v-if="canDeleteRow(props.row)">
587
641
  <q-item-section avatar>
588
642
  <q-icon name="sym_o_delete"></q-icon>
589
643
  </q-item-section>
590
- <q-item-section>{{ $t('Delete') }}</q-item-section>
644
+ <q-item-section>{{ $t('Delete') }} </q-item-section>
591
645
  </q-item>
592
646
 
593
647
  <q-item v-if="props.row.type == 'file'" clickable v-close-popup @click="onDownloadRow(props.row)">
@@ -597,7 +651,7 @@ const reloadStorage = async () => {
597
651
  <q-item-section>Download</q-item-section>
598
652
  </q-item>
599
653
 
600
- <q-item clickable v-close-popup @click="onRenameRow(props.row)">
654
+ <q-item clickable v-close-popup @click="onRenameRow(props.row)" v-if="canRenameRow(props.row)">
601
655
  <q-item-section avatar>
602
656
  <q-icon name="sym_o_edit"></q-icon>
603
657
  </q-item-section>
@@ -6,7 +6,6 @@ import { addObject, updateObject } from '../';
6
6
 
7
7
  const route = useRoute();
8
8
  const router = useRouter();
9
- const module = route.path.split("/")[1];
10
9
 
11
10
  const form = ref(null);
12
11
  const props = defineProps({
@@ -20,17 +19,26 @@ const props = defineProps({
20
19
  gutter: {
21
20
  type: String,
22
21
  default: "md"
22
+ },
23
+ submitLabel: {
24
+ type: String,
25
+ default: "Save"
26
+ },
27
+ submitIcon: {
28
+ type: String,
29
+ default: "sym_o_save"
23
30
  }
24
31
  });
25
32
 
26
33
  const que = useQuasar();
27
- const emit = defineEmits(["save"]);
34
+ const emit = defineEmits(["save", "submit"]);
28
35
  const save = async () => {
29
36
 
30
37
  let valid = await form.value.validate();
31
38
  if (!valid) return;
32
39
  if (valid) {
33
40
  emit("save");
41
+ emit('submit');
34
42
  }
35
43
 
36
44
 
@@ -82,7 +90,7 @@ const onSubmit = (e) => {
82
90
  </q-card-section>
83
91
 
84
92
  <q-card-actions align="right">
85
- <l-save-btn @click="save" />
93
+ <l-btn color="primary" :icon="submitIcon" :label="submitLabel" @click="save" />
86
94
  </q-card-actions>
87
95
  </l-card>
88
96
  </q-form>
@@ -92,11 +92,13 @@ const onDelete = async () => {
92
92
  <l-add-btn v-if="showAddBtn" />
93
93
  <l-edit-btn v-if="showEditBtn" />
94
94
  <l-delete-btn v-if="showDeleteBtn" @submit="onDelete" />
95
-
96
- <slot name="header"></slot>
97
95
  <q-toolbar-title>{{ i18n.t(title) }}</q-toolbar-title>
98
96
  </q-toolbar>
99
97
 
98
+ <div class="q-gutter-sm q-mb-sm">
99
+ <slot name="header"></slot>
100
+ </div>
101
+
100
102
  <slot></slot>
101
103
  </q-page>
102
104
  </template>
@@ -18,24 +18,9 @@ export default async function listData(name, props = {}, fields = []) {
18
18
  json.data.__args = json.data.__args || {};
19
19
  json.data.__args.limit = props.limit;
20
20
  }
21
- if (fields instanceof Array) {
22
- fields.forEach((field) => {
23
- if (field instanceof Object) {
24
- Object.entries(field).forEach(([key, value]) => {
25
- json.data[key] = toQuery(value);
26
- });
27
- } else {
28
- json.data[field] = true;
29
- }
30
- });
31
- } else if (fields instanceof Object) {
32
- json.data = Object.assign({}, fields);
33
- if (props.fields) {
34
- props.fields.forEach((field) => {
35
- json.data[field] = true;
36
- });
37
- }
38
- }
21
+ Object.entries(toQuery(fields)).forEach(([key, value]) => {
22
+ json.data[key] = value;
23
+ });
39
24
  json.meta = {
40
25
  total: true,
41
26
  key: true,
@@ -31,9 +31,10 @@ const onSave = async () => {
31
31
 
32
32
  <l-input label="Permission name" v-model="obj.value" required></l-input>
33
33
 
34
- <q-option-group type="checkbox" :options="roles" v-model="obj.roles">
35
-
36
- </q-option-group>
34
+ <q-field label="Roles" stack-label>
35
+ <q-option-group type="checkbox" :options="roles" v-model="obj.roles" inline>
36
+ </q-option-group>
37
+ </q-field>
37
38
 
38
39
  </l-form>
39
40
 
@@ -0,0 +1,65 @@
1
+ <script setup>
2
+ import { reactive } from 'vue'
3
+ import { utils, writeFileXLSX } from 'xlsx';
4
+ import { q } from '../../'
5
+ const obj = reactive({
6
+ roles: []
7
+ });
8
+
9
+ const app = await q("app", ["permissions"])
10
+ let allData = await q("listRole", ["name", "permissions"]);
11
+
12
+ let roles = allData.map((role) => {
13
+ return {
14
+ label: role.name,
15
+ value: role.name,
16
+ };
17
+ });
18
+
19
+ const submit = () => {
20
+
21
+ //filter roles
22
+ let e = allData.filter((role) => {
23
+ return obj.roles.indexOf(role.name) != -1;
24
+ });
25
+
26
+ let data = [];
27
+
28
+ //push permissions to rows
29
+ app.permissions.forEach(permission => {
30
+ let row = {
31
+ permission: permission
32
+ };
33
+
34
+ e.forEach(role => {
35
+ if (role.permissions.indexOf(permission) != -1) {
36
+ //tick checkbox
37
+ row[role.name] = "Yes"
38
+ } else {
39
+ row[role.name] = ''
40
+ }
41
+ });
42
+
43
+ data.push(row);
44
+ });
45
+
46
+
47
+ const ws = utils.json_to_sheet(data)
48
+ const wb = utils.book_new()
49
+ utils.book_append_sheet(wb, ws, "Roles")
50
+ writeFileXLSX(wb, "permission.xlsx")
51
+ }
52
+
53
+ </script>
54
+ <template>
55
+ <l-page>
56
+ <l-form submit-label="Export" submit-icon="sym_o_download" @submit="submit">
57
+ <q-field label="Roles" stack-label>
58
+ <q-option-group type="checkbox" :options="roles" v-model="obj.roles" inline>
59
+ </q-option-group>
60
+ </q-field>
61
+ </l-form>
62
+
63
+
64
+ </l-page>
65
+ </template>
@@ -20,7 +20,7 @@ const columns = [
20
20
 
21
21
  </script>
22
22
  <template>
23
- <l-page add-btn>
23
+ <l-page>
24
24
  <l-table @request="onRequest" :columns="columns" :actions="['delete']"></l-table>
25
25
  </l-page>
26
26
  </template>
@@ -62,24 +62,7 @@ const columns = [
62
62
  </q-td>
63
63
  </template>
64
64
 
65
-
66
65
  </q-table>
67
66
 
68
- <!-- q-table :data="roles">
69
-
70
- <el-table-column width="60px" #default="{ row }">
71
- <q-btn v-if="row.canDelete" flat round dense icon="sym_o_delete" @click="onDelete(row.name)" />
72
- </el-table-column>
73
- <el-table-column prop="name" label="Name" sortable width="200px"></el-table-column>
74
- <el-table-column label="Parent">
75
-
76
- <template #default="{ row }">
77
-
78
- <el-table :data="row.parents">
79
- <el-table-column prop="name" label="Name"></el-table-column>
80
- </el-table>
81
- </template>
82
- </el-table-column>
83
- </q-table -->
84
67
  </l-page>
85
68
  </template>
@@ -2,7 +2,8 @@
2
2
  import { reactive } from 'vue'
3
3
  import { m } from "../../"
4
4
  const obj = reactive({
5
- input1: 'test'
5
+ input1: 'test',
6
+ editor: 'test',
6
7
  })
7
8
  const onSave = async () => {
8
9
  console.log(obj)
@@ -15,9 +16,13 @@ const onSave = async () => {
15
16
  </script>
16
17
  <template>
17
18
  <l-page>
19
+ {{ obj }}
18
20
  <l-form v-model="obj">
19
21
  <l-input v-model="obj.input1" label="Input1" />
20
22
  <q-file v-model="obj.file" label="File" accept=".txt" />
23
+
24
+ <q-editor v-model="obj.editor" />
25
+
21
26
  </l-form>
22
27
  </l-page>
23
28
  </template>
@@ -2,6 +2,7 @@
2
2
  import { getObject, loadObject } from '../../../';
3
3
  const obj = await getObject(["user_id", "username", "first_name", "last_name", "email", "phone", "roles"]);
4
4
 
5
+ //await getObject(["user_id", { test: ["username"] }])
5
6
  /* const test = async () => {
6
7
  console.log(await loadObject("User", { user_id: obj.user_id }, ["username"]));
7
8
  }
@@ -1,7 +1,6 @@
1
1
  <script setup>
2
2
  import { q } from '../../'
3
- const my = await q("my", ["username", "first_name", "last_name", "email", "phone", "roles", "addr1", "addr2", "addr3", "join_date"])
4
-
3
+ const my = await q("my", ["user_id", "username", "first_name", "last_name", "email", "phone", "roles", "addr1", "addr2", "addr3", "join_date"])
5
4
  </script>
6
5
  <template>
7
6
  <l-page title="User profile">
@@ -19,9 +18,8 @@ const my = await q("my", ["username", "first_name", "last_name", "email", "phone
19
18
  <l-item label="Address">{{ my.addr1 }} {{ my.addr2 }} {{ my.addr3 }}</l-item>
20
19
  <l-item label="Join date">{{ my.join_date }}</l-item>
21
20
  <l-item label="Roles">{{ my.roles.join(",") }}</l-item>
22
-
23
-
24
21
  </l-list>
25
22
  </l-card>
23
+
26
24
  </l-page>
27
25
  </template>
@@ -1,6 +1,7 @@
1
1
  <script setup>
2
2
  import { reactive } from "vue"
3
- import { q, m, notify } from '../../../'
3
+ import { notify } from '../../../'
4
+ import { updatePassword } from "@hostlink/light"
4
5
 
5
6
  const obj = reactive({
6
7
  old_password: "",
@@ -9,10 +10,7 @@ const obj = reactive({
9
10
  })
10
11
 
11
12
  const onSave = async () => {
12
- if (await m("updatePassword", {
13
- old_password: obj.old_password,
14
- new_password: obj.new_password,
15
- })) {
13
+ if (await updatePassword(obj.old_password, obj.new_password)) {
16
14
  notify("Your password has been updated")
17
15
  } else {
18
16
  notify("Old password is incorrect", "red")
@@ -1,6 +1,8 @@
1
1
  <script setup>
2
2
  import { ref } from "vue"
3
+ import { useRoute } from "vue-router"
3
4
  const tab = ref("general")
5
+ const route = useRoute()
4
6
  </script>
5
7
 
6
8
  <template>
@@ -8,7 +10,7 @@ const tab = ref("general")
8
10
  <l-card>
9
11
  <q-splitter unit="px" :model-value="120">
10
12
  <template #before>
11
- <q-tabs v-model="tab" vertical >
13
+ <q-tabs v-model="tab" vertical>
12
14
  <q-route-tab name="general" icon="sym_o_info" :label="$t('General')" to="/User/setting" exact
13
15
  replace />
14
16
  <q-route-tab name="information" icon="sym_o_info" :label="$t('Information')"
@@ -17,14 +19,15 @@ const tab = ref("general")
17
19
  to="/User/setting/password" exact replace />
18
20
  <q-route-tab name="style" icon="sym_o_style" :label="$t('Style')" to="/User/setting/style" exact
19
21
  replace />
20
- <q-route-tab name="2fa" icon="sym_o_key" :label="$t('2FA')" to="/User/setting/two-factor-auth" exact replace />
22
+ <q-route-tab name="2fa" icon="sym_o_key" :label="$t('2FA')" to="/User/setting/two-factor-auth" exact
23
+ replace />
21
24
  <q-route-tab name="bio" icon="sym_o_fingerprint" :label="$t('Bio')" to="/User/setting/bio-auth"
22
25
  exact replace />
23
26
  </q-tabs>
24
27
  </template>
25
28
 
26
29
  <template #after>
27
- <router-view>
30
+ <router-view :key="route.path">
28
31
  </router-view>
29
32
  </template>
30
33
  </q-splitter>
@@ -1,7 +1,6 @@
1
1
  <script setup>
2
2
  import { useQuasar } from 'quasar';
3
- //import { useRouter, router } from 'vue-router';
4
-
3
+ import { updatePassword } from '@hostlink/light';
5
4
 
6
5
  const obj = reactive({
7
6
  old_password: "",
@@ -13,10 +12,7 @@ const qua = useQuasar();
13
12
  const router = useRouter();
14
13
 
15
14
  const onSave = async () => {
16
- if (await m("updatePassword", {
17
- old_password: obj.old_password,
18
- new_password: obj.new_password,
19
- })) {
15
+ if (await updatePassword(obj.old_password, obj.new_password)) {
20
16
  //back
21
17
  router.back();
22
18
  } else {
@@ -8,15 +8,18 @@ const columns = [
8
8
  },
9
9
  {
10
10
  label: "User",
11
- name: "username"
11
+ name: "username",
12
+ sortable: true,
13
+ searchable: true,
12
14
  },
13
15
  {
14
16
  label: "Login time",
15
17
  name: "login_dt",
16
18
  sortable: true,
17
19
  searchable: true,
20
+ searchType: "date",
18
21
  }, {
19
- label: "Login out",
22
+ label: "Logout time",
20
23
  name: "logout_dt",
21
24
  sortable: true,
22
25
  searchable: true,
@@ -52,6 +52,11 @@ function Permission_all() {
52
52
  /* webpackChunkName: "Permission-all" */ './pages/Permission/all.vue'
53
53
  )
54
54
  }
55
+ function Permission_export() {
56
+ return import(
57
+ /* webpackChunkName: "Permission-export" */ './pages/Permission/export.vue'
58
+ )
59
+ }
55
60
  function Role_add() {
56
61
  return import(/* webpackChunkName: "Role-add" */ './pages/Role/add.vue')
57
62
  }
@@ -228,6 +233,11 @@ export default [
228
233
  path: '/Permission/all',
229
234
  component: Permission_all,
230
235
  },
236
+ {
237
+ name: 'Permission-export',
238
+ path: '/Permission/export',
239
+ component: Permission_export,
240
+ },
231
241
  {
232
242
  name: 'Role-add',
233
243
  path: '/Role/add',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hostlink/nuxt-light",
3
- "version": "0.0.62",
3
+ "version": "0.0.64",
4
4
  "description": "HostLink Nuxt Light Framework",
5
5
  "repository": "@hostlink/nuxt-light",
6
6
  "license": "MIT",
@@ -34,7 +34,7 @@
34
34
  "route-gen": "node route-generate.mjs"
35
35
  },
36
36
  "dependencies": {
37
- "@hostlink/light": "^0.0.12",
37
+ "@hostlink/light": "^0.0.23",
38
38
  "@nuxt/kit": "^3.7.0",
39
39
  "@quasar/extras": "^1.16.6",
40
40
  "axios": "^1.5.0",
@@ -42,7 +42,8 @@
42
42
  "json-to-graphql-query": "^2.2.5",
43
43
  "quasar": "^2.12.5",
44
44
  "unplugin-auto-import": "^0.16.6",
45
- "vue-i18n": "^9.2.2"
45
+ "vue-i18n": "^9.2.2",
46
+ "xlsx": "^0.18.5"
46
47
  },
47
48
  "devDependencies": {
48
49
  "@nuxt/content": "^2.8.2",