Recv/public/src/route/admin/components/UploadFiles.vue

390 lines
8.0 KiB
Vue

<template>
<div class="uploadFiles">
<div class="pure-menu pure-menu-horizontal toolbar">
<ul class="pure-menu-list">
<li class="pure-menu-item"><a href="#" class="pure-menu-link" @click.prevent="startAssign()"><fa icon="user"></fa> {{ $t('admin.uploads.assign') }}</a></li>
<li class="pure-menu-item"><a href="#" class="pure-menu-link" @click.prevent="startDelete()"><fa icon="trash-alt"></fa> {{ $t('admin.delete') }}</a></li>
</ul>
</div>
<div v-if="showAssign" class="confirmToolbar pure-form pure-form-horizontal">
<select v-model="assignUser">
<option v-for="user in assignUsers" v-if="user.id !== group.lastUpload.userId" :value="user.id">{{ user.name }}</option>
</select>
<button class="pure-button pure-button-primary" @click.prevent="confirmAssign()" :disabled="!hasAssignUser"><fa icon="spinner" spin v-if="assigning"></fa> {{ $t('admin.uploads.assignApply') }}</button>
<button class="pure-button" @click.prevent="cancelAssign()">{{ $t('admin.cancel') }}</button>
</div>
<div v-if="showDelete" class="confirmToolbar pure-form pure-form-horizontal">
<button class="pure-button pure-button-confirm-delete" @click.prevent="confirmDelete()" :disabled="!isAnySelected"><fa icon="spinner" spin v-if="deleting"></fa> {{ $t('admin.deleteApply') }}</button>
<button class="pure-button" @click.prevent="cancelDelete()">{{ $t('admin.cancel') }}</button>
<button class="pure-button separator" @click.prevent="selectAll()"><fa :icon="['far', 'check-square']"></fa></button>
<button class="pure-button" @click.prevent="selectNone()"><fa :icon="['far', 'square']"></fa></button>
</div>
<template v-for="upload in group.uploads">
<template v-for="file in orderedFiles(upload.files)">
<div class="pure-g file" @click.prevent="fileClick(upload, file)" :title="file.name">
<div class="pure-u-1-2 filename">
<input type="checkbox" v-if="showDelete" v-bind:checked="getSelected(upload, file)" @input="(v) => setSelected(upload, file, v)" />
<a :href="getDownloadUrl(file)"><img :src="getFileIconUrl(file.name)" class="icon"> {{ file.name }}</a>
</div>
<div class="pure-u-1-4 date">
{{ upload.created | formatDateTime }}
</div>
<div class="pure-u-1-4 size">
{{ file.size | formatSizeSI }}
</div>
</div>
</template>
</template>
</div>
</template>
<script>
import axios from 'axios';
import shared from '../../../shared';
import orderBy from 'lodash/orderBy';
import forEach from 'lodash/forEach';
export default {
props: ['group', 'assignUsers'],
data()
{
return {
showDelete: false,
deleting: false,
showAssign: false,
assigning: false,
assignUser: null,
selection: {}
}
},
computed: {
hasAssignUser()
{
var self = this;
return self.assignUser !== null;
},
isAnySelected()
{
var self = this;
for (var fileId in self.selection)
{
if (self.selection.hasOwnProperty(fileId) && self.selection[fileId])
return true;
}
return false;
}
},
methods: {
orderedFiles(files)
{
return orderBy(files, ['name'], ['asc']);
},
getFileIconUrl(filename)
{
var ext = this.getExtension(filename);
if (ext == '')
ext = '_blank';
return '/images/fileicons/16px/' + ext + '.png';
},
getExtension(filename)
{
var parts = filename.split('.');
return parts.length > 0 ? parts.pop() : '';
},
getDownloadUrl(file)
{
return '/admin/download/' + encodeURIComponent(file.id) + '/' + encodeURIComponent(file.name);
},
getSelected(upload, file)
{
var self = this;
let uniqueId = upload.id + ';' + file.id;
if (typeof self.selection[uniqueId] === 'undefined')
self.$set(self.selection, uniqueId, true);
return self.selection[uniqueId];
},
setSelected(upload, file, value)
{
var self = this;
let uniqueId = upload.id + ';' + file.id;
if (typeof self.selection[uniqueId] === 'undefined')
self.$set(self.selection, uniqueId, value);
else
self.selection[uniqueId] = value;
},
fileClick(upload, file)
{
var self = this;
if (self.showDelete)
self.setSelected(upload, file, !self.getSelected(upload, file));
else
location.href = self.getDownloadUrl(file);
},
startDelete()
{
var self = this;
if (self.showDelete)
self.cancelDelete();
else
{
self.showDelete = !self.showDelete;
self.showAssign = false;
}
},
confirmDelete()
{
var self = this;
if (self.deleting)
return;
let deleteFiles = [];
forEach(self.group.uploads, (upload) =>
{
forEach(upload.files, (file) =>
{
if (self.getSelected(upload, file))
{
deleteFiles.push({
uploadId: upload.id,
fileId: file.id
});
}
});
});
self.deleting = true;
axios.delete('/admin/fileuploads/', {
data: deleteFiles,
headers: {
Authorization: 'Bearer ' + shared.adminToken
}})
.then((response) =>
{
self.$emit('files-deleted', deleteFiles);
})
.catch((error) => { shared.$emit('apiError', error, this.$router) })
.then(() =>
{
self.deleting = false;
self.showDelete = false;
self.selection = {};
});
},
setAllSelected(value)
{
var self = this;
for (var fileId in self.selection)
{
if (self.selection.hasOwnProperty(fileId))
self.selection[fileId] = value;
}
},
selectAll()
{
var self = this;
self.setAllSelected(true);
},
selectNone()
{
var self = this;
self.setAllSelected(false);
},
cancelDelete()
{
var self = this;
self.showDelete = false
self.selection = {};
},
startAssign()
{
var self = this;
if (self.showAssign)
self.cancelAssign();
else
{
self.showAssign = !self.showAssign;
self.showDelete = false;
}
},
confirmAssign()
{
var self = this;
if (self.assigning)
return;
let userId = self.assignUser;
if (!userId)
return;
let codeId = self.group.lastUpload.codeId;
self.assignUser = null;
self.assigning = false;
axios.post('/admin/assign/code', {
id: codeId,
userId: userId
}, {
headers: {
Authorization: 'Bearer ' + shared.adminToken
}
})
.then((response) =>
{
self.$emit('code-assigned', codeId, userId);
})
.catch((error) => { shared.$emit('apiError', error, this.$router) })
.then(() =>
{
self.assigning = false;
self.showAssign = false;
})
},
cancelAssign()
{
var self = this;
self.showAssign = false;
self.assignUser = null;
}
}
}
</script>
<style lang="scss">
.file
{
border: solid 1px transparent;
font-size: 75%;
padding: .5rem;
vertical-align: middle;
cursor: pointer;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
a
{
color: black;
text-decoration: none;
}
.icon
{
display: inline-block;
vertical-align: middle;
}
.date
{
text-align: right;
}
.size
{
color: #808080;
text-align: right;
}
&:hover
{
background-color: #d3e9f8;
border: solid 1px #a7d3f1;
}
}
.upload
{
background-color: #fafafa;
border-bottom: solid 1px #f4f4f4;
padding: .2rem;
}
.codedescription
{
font-weight: bold;
}
.toolbar
{
border-bottom: solid 2px #f0f0f0;
}
.confirmToolbar
{
margin-top: .5rem;
margin-bottom: .5rem;
font-size: 75%;
}
.separator
{
margin-left: 2rem;
}
</style>