Chamilo is a learning management system focused on ease of use and accessibility
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
chamilo-lms/assets/vue/views/documents/List.vue

319 lines
9.4 KiB

<template>
<Toolbar
:handle-add="addHandler"
:handle-add-document="addDocumentHandler"
:handle-upload-document="uploadDocumentHandler"
:filters="filters"
:on-send-filter="onSendFilter"
:reset-filter="resetFilter"
/>
<q-table
dense
:rows="items"
:columns="columns"
row-key="@id"
:filter="filter"
@request="onRequest"
v-model:pagination="pagination"
:no-data-label="$t('Data unavailable')"
:no-results-label="$t('No results')"
:loading-label="$t('Loading...')"
:rows-per-page-label="$t('Records per page:')"
:rows-per-page-options="[10, 20, 50, 0]"
:loading="isLoading"
selection="multiple"
v-model:selected="selectedItems"
>
<template v-slot:body="props">
<q-tr :props="props">
<q-td auto-width>
<q-checkbox dense v-model="props.selected" />
</q-td>
<q-td key="resourceNode.title" :props="props">
<div v-if="props.row.resourceNode.resourceFile">
<a
data-fancybox="gallery"
:href="props.row.contentUrl"
>
<ResourceFileIcon :file="props.row" />
{{ props.row.title }}
</a>
</div>
<div v-else>
<a @click="handleClick(props.row)" class="cursor-pointer" >
<font-awesome-icon
icon="folder"
size="lg"
/>
{{ props.row.resourceNode.title }}
</a>
</div>
</q-td>
<q-td key="resourceNode.updatedAt" :props="props">
{{$luxonDateTime.fromISO(props.row.resourceNode.updatedAt).toRelative() }}
</q-td>
<q-td key="resourceNode.resourceFile.size" :props="props">
<span v-if="props.row.resourceNode.resourceFile">
{{
$filters.prettyBytes(props.row.resourceNode.resourceFile.size)
}}
</span>
</q-td>
<q-td key="action" :props="props">
<ActionCell
:handle-show="() => showHandler(props.row)"
:handle-edit="() => editHandler(props.row)"
:handle-delete="() => deleteHandler(props.row)"
/>
</q-td>
</q-tr>
</template>
</q-table>
</template>
<script>
import { mapActions, mapGetters } from 'vuex';
import { mapFields } from 'vuex-map-fields';
import ListMixin from '../../mixins/ListMixin';
import ActionCell from '../../components/ActionCell.vue';
import Toolbar from '../../components/Toolbar.vue';
import ResourceFileIcon from './ResourceFileIcon.vue';
import { useRoute } from 'vue-router'
import { ref, reactive, onMounted, computed } from 'vue';
import { useStore } from 'vuex';
import isEmpty from 'lodash/isEmpty';
export default {
name: 'DocumentsList',
servicePrefix: 'Documents',
components: {
Toolbar,
ActionCell,
ResourceFileIcon,
},
mixins: [ListMixin],
data() {
return {
sortBy: 'title',
sortDesc: false,
columns: [
{align: 'left', name: 'resourceNode.title', label: this.$i18n.t('Title'), field: 'resourceNode.title', sortable: true},
{align: 'left', name: 'resourceNode.updatedAt', label: this.$i18n.t('Modified'), field: 'resourceNode.updatedAt', sortable: true},
{name: 'resourceNode.resourceFile.size', label: this.$i18n.t('Size'), field: 'resourceNode.resourceFile.size', sortable: true},
{name: 'action', label: this.$i18n.t('Actions'), field: 'action', sortable: false}
],
//pageOptions: [5, 10, 15, 20, this.$i18n.t('All')],
selected: [],
isBusy: false,
options: [],
};
},
created() {
console.log('vue/views/documents/List.vue');
const route = useRoute()
let nodeId = route.params['node'];
if (!isEmpty(nodeId)) {
this.findResourceNode('/api/resource_nodes/' + nodeId);
}
this.onRequest({
pagination: this.pagination,
});
},
mounted() {
// Detect when scrolled to bottom.
/*const listElm = document.querySelector('#documents');
listElm.addEventListener('scroll', e => {
console.log('aaa');
if(listElm.scrollTop + listElm.clientHeight >= listElm.scrollHeight) {
this.onScroll();
}
});*/
//const tableScrollBody = this.$refs['selectableTable'].$el;
/* Consider debouncing the event call */
//tableScrollBody.addEventListener("scroll", this.onScroll);
//window.addEventListener('scroll', this.onScroll)
window.addEventListener('scroll', () =>{
/*if(window.top.scrollY > window.outerHeight){
if (!this.isBusy) {
this.fetchItems();
}
}*/
});
/*const tableScrollBody = this.$refs['documents'];
tableScrollBody.addEventListener("scroll", this.onScroll);*/
},
computed: {
// From crud.js list function
...mapGetters('documents', {
items: 'list',
}),
...mapGetters('resourcenode', {
resourceNode: 'getResourceNode'
}),
...mapGetters({
'isAuthenticated': 'security/isAuthenticated',
'isAdmin': 'security/isAdmin',
'isCurrentTeacher': 'security/isCurrentTeacher',
}),
//...getters
// From ListMixin
...mapFields('documents', {
deletedItem: 'deleted',
error: 'error',
isLoading: 'isLoading',
resetList: 'resetList',
totalItems: 'totalItems',
view: 'view'
}),
},
methods: {
openNew() {
this.item = {};
this.submitted = false;
this.itemDialog = true;
},
hideDialog() {
this.itemDialog = false;
this.submitted = false;
},
saveItem() {
this.submitted = true;
if (this.item.title.trim()) {
if (this.item.id) {
//this.$toast.add({severity:'success', summary: 'Successful', detail: 'Product Updated', life: 3000});
} else {
//this.products.push(this.product);
this.item.parentResourceNodeId = this.$route.params.node;
this.item.resourceLinkList = JSON.stringify([{
gid: this.$route.query.gid,
sid: this.$route.query.sid,
c_id: this.$route.query.cid,
visibility: 2, // visible by default
}]);
this.create(this.item);
//this.$toast.add({severity:'success', summary: 'Successful', detail: 'Product Created', life: 3000});
this.showMessage('Saved');
}
this.itemDialog = false;
this.item = {};
}
},
editItem(item) {
this.item = {...item};
this.itemDialog = true;
},
confirmDeleteItem(item) {
this.item = item;
this.deleteItemDialog = true;
},
confirmDeleteMultiple() {
this.deleteMultipleDialog = true;
},
deleteMultipleItems() {
console.log('deleteMultipleItems');
console.log(this.selectedItems);
this.deleteMultipleAction(this.selectedItems);
this.onRequest({
pagination: this.pagination,
});
this.deleteMultipleDialog = false;
this.selectedItems = null;
//this.$toast.add({severity:'success', summary: 'Successful', detail: 'Products Deleted', life: 3000});*/
},
async fetchItems() {
console.log('fetchItems');
/* No need to call if all items retrieved */
if (this.items.length === this.totalItems) return;
/* Enable busy state */
this.isBusy = true;
/* Missing error handling if call fails */
let currentPage = this.options.page;
console.log(currentPage);
const startIndex = currentPage++ * this.options.itemsPerPage;
const endIndex = startIndex + this.options.itemsPerPage;
console.log(this.items.length);
console.log(this.totalItems);
console.log(startIndex, endIndex);
this.options.page = currentPage;
await this.fetchNewItems(this.options);
//const newItems = await this.callDatabase(startIndex, endIndex);
/* Add new items to existing ones */
//this.items = this.items.concat(newItems);
/* Disable busy state */
this.isBusy = false;
return true;
},
onRowSelected(items) {
this.selected = items
},
selectAllRows() {
this.$refs.selectableTable.selectAllRows()
},
clearSelected() {
this.$refs.selectableTable.clearSelected()
},
async deleteSelected() {
console.log('deleteSelected');
/*for (let i = 0; i < this.selected.length; i++) {
let item = this.selected[i];
//this.deleteHandler(item);
this.deleteItem(item);
}*/
this.deleteMultipleAction(this.selected);
this.onRequest({
pagination: this.pagination,
});
/*const promises = this.selected.map(async item => {
const result = await this.deleteItem(item);
console.log('item');
return result;
});
const result = await Promise.all(promises);
console.log(result);
if (result) {
console.log(result);
//this.onUpdateOptions(this.options);
}
*/
console.log('end -- deleteSelected');
},
//...actions,
// From ListMixin
...mapActions('documents', {
getPage: 'fetchAll',
create: 'create',
deleteItem: 'del',
deleteMultipleAction: 'delMultiple'
}),
...mapActions('resourcenode', {
findResourceNode: 'findResourceNode',
}),
}
};
</script>