add new export option with permissions close #13
This commit is contained in:
@@ -24,6 +24,20 @@
|
||||
@update:model-value="(val) => toggleBit(index, 2, val)"
|
||||
>{{ i18n.global.t('delete') }}</q-checkbox
|
||||
>
|
||||
<q-checkbox
|
||||
v-if="permission.permissionNumber > 3"
|
||||
class="q-mx-md"
|
||||
:model-value="isFlagSet(permission.permission, 1 << 3)"
|
||||
@update:model-value="(val) => toggleBit(index, 3, val)"
|
||||
>{{ i18n.global.t('import') }}</q-checkbox
|
||||
>
|
||||
<q-checkbox
|
||||
v-if="permission.permissionNumber > 4"
|
||||
class="q-mx-md"
|
||||
:model-value="isFlagSet(permission.permission, 1 << 4)"
|
||||
@update:model-value="(val) => toggleBit(index, 4, val)"
|
||||
>{{ i18n.global.t('export') }}</q-checkbox
|
||||
>
|
||||
</div>
|
||||
</q-card>
|
||||
</q-card>
|
||||
@@ -47,6 +61,7 @@ const localPermission = ref(
|
||||
props.permissions.map((e) => ({
|
||||
name: e.name,
|
||||
permission: e.permission ?? 0,
|
||||
permissionNumber: e.name === 'members' ? 5 : 3,
|
||||
})),
|
||||
);
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ export const useUserStore = defineStore('user', {
|
||||
};
|
||||
},
|
||||
isPermittedTo: (state: UserState) => {
|
||||
return (name: string, type: 'read' | 'write' | 'delete'): boolean => {
|
||||
return (name: string, type: 'read' | 'write' | 'delete' | 'import' | 'export'): boolean => {
|
||||
const permission = state.user?.permissions?.find((r: Permission) => r.name === name);
|
||||
switch (type) {
|
||||
case 'read':
|
||||
@@ -33,6 +33,10 @@ export const useUserStore = defineStore('user', {
|
||||
return permission?.permission ? (permission.permission & (1 << 1)) === 2 : false;
|
||||
case 'delete':
|
||||
return permission?.permission ? (permission.permission & (1 << 2)) === 4 : false;
|
||||
case 'import':
|
||||
return permission?.permission ? (permission.permission & (1 << 3)) === 8 : false;
|
||||
case 'export':
|
||||
return permission?.permission ? (permission.permission & (1 << 4)) === 16 : false;
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
@@ -4,6 +4,7 @@ import type { Member, Members } from 'src/vueLib/models/member';
|
||||
import { useNotify } from 'src/vueLib/general/useNotify';
|
||||
import { i18n } from 'boot/lang';
|
||||
import { useResponsibleTable } from '../responsible/ResponsibleTable';
|
||||
import { appName } from 'src/vueLib/models/settings';
|
||||
|
||||
export function useMemberTable() {
|
||||
const members = ref<Members>([]);
|
||||
@@ -253,6 +254,47 @@ export function useMemberTable() {
|
||||
});
|
||||
}
|
||||
|
||||
function exportCsv() {
|
||||
const comma = ';';
|
||||
// Extract only columns that have a field (not icons/options)
|
||||
const exportableColumns = columns.value.filter(
|
||||
(col) => typeof col.field === 'string' && col.field !== 'cake' && col.field !== 'option',
|
||||
) as { field: keyof Member; label: string }[];
|
||||
|
||||
// Build CSV header row
|
||||
const header = exportableColumns.map((col) => col.field).join(comma);
|
||||
|
||||
// Build CSV rows
|
||||
const data = members.value.map((member) =>
|
||||
exportableColumns
|
||||
.map((col) => {
|
||||
const value = member[col.field];
|
||||
// handle nested objects (e.g. responsiblePerson)
|
||||
if (typeof value === 'object' && value !== null) {
|
||||
if ('firstName' in value && 'lastName' in value)
|
||||
return `"${value.firstName} ${value.lastName}"`;
|
||||
return `"${JSON.stringify(value)}"`;
|
||||
}
|
||||
return `"${value ?? ''}"`;
|
||||
})
|
||||
.join(comma),
|
||||
);
|
||||
|
||||
// Combine into CSV string
|
||||
const csv = [header, ...data].join('\n');
|
||||
|
||||
// Create blob and trigger download
|
||||
const BOM = '\uFEFF';
|
||||
const blob = new Blob([BOM + csv], { type: 'text/csv;charset=utf-8;' });
|
||||
const url = URL.createObjectURL(blob);
|
||||
const link = document.createElement('a');
|
||||
link.href = url;
|
||||
link.setAttribute('download', i18n.global.t(appName.value) + '.csv');
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
document.body.removeChild(link);
|
||||
}
|
||||
|
||||
return {
|
||||
members,
|
||||
responsibles,
|
||||
@@ -263,5 +305,6 @@ export function useMemberTable() {
|
||||
updateMembers,
|
||||
isXDaysBeforeAnnualDate,
|
||||
disableColumns,
|
||||
exportCsv,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
<q-tooltip>{{ $t('selectMemberOptions') }}</q-tooltip>
|
||||
</q-btn>
|
||||
<q-btn
|
||||
v-if="user.isPermittedTo('members', 'write')"
|
||||
v-if="user.isPermittedTo('members', 'import')"
|
||||
dense
|
||||
flat
|
||||
icon="upload"
|
||||
@@ -51,6 +51,15 @@
|
||||
>
|
||||
<q-tooltip>{{ $t('importCSV') }}</q-tooltip>
|
||||
</q-btn>
|
||||
<q-btn
|
||||
v-if="user.isPermittedTo('members', 'export')"
|
||||
dense
|
||||
flat
|
||||
icon="download"
|
||||
@click="exportCsv"
|
||||
>
|
||||
<q-tooltip>{{ $t('exportCSV') }}</q-tooltip>
|
||||
</q-btn>
|
||||
</q-btn-group>
|
||||
<div v-if="selectOption && selected.length > 0">
|
||||
<q-btn
|
||||
@@ -240,6 +249,7 @@ const {
|
||||
updateMembers,
|
||||
isXDaysBeforeAnnualDate,
|
||||
disableColumns,
|
||||
exportCsv,
|
||||
} = useMemberTable();
|
||||
|
||||
//load on mounting page
|
||||
|
||||
Reference in New Issue
Block a user