Recv/public/src/route/admin/Uploads.vue

334 lines
8.0 KiB
Vue

<template>
<div id="uploads">
<div v-if="uploads !== null" class="list">
<div v-for="group in groupedUploads">
<template v-for="(upload, index) in group.uploads">
<div class="properties" v-if="index == 0">
<div class="pure-g">
<div class="pure-u-1-1"><span class="text codedescription">{{ upload.codedescription || upload.codeId }}</span></div>
<div class="pure-u-1-3"><span class="text">{{ upload.codeId }}</span></div>
<div class="pure-u-1-3">
<span class="text" v-if="hasAuth('viewAllUploads')" :class="{ userDeleted: !upload.username }">
{{ upload.username || $t('admin.uploads.userDeleted') }}
</span>
</div>
<div class="pure-u-1-3 right"><span class="text">{{ upload.created | formatDateTime }}</span></div>
</div>
</div>
<div class="pure-menu pure-menu-horizontal" v-if="index == 0">
<ul class="pure-menu-list">
<li class="pure-menu-item"><a href="#" class="pure-menu-link" @click.prevent="showAssign = !showAssign"><fa icon="user"></fa> {{ $t('admin.uploads.assign') }}</a></li>
<li class="pure-menu-item" v-if="confirmDelete == upload.codeId"><a href="#" class="pure-menu-link" @click.prevent="cancelDelete"><fa icon="ban"></fa> {{ $t('admin.cancel') }}</a></li>
<li class="pure-menu-item"><a href="#" class="pure-menu-link" :class="{ confirmDelete: confirmDelete == upload.codeId }" @click.prevent="deleteClick(upload.codeId)"><fa icon="trash-alt"></fa> {{ $t('admin.delete') }}</a></li>
</ul>
</div>
<div v-if="showAssign" class="assign pure-form pure-form-horizontal">
<select v-model="assignUser">
<option v-for="user in assignUsers" v-if="user.id !== upload.userId" :value="user.id">{{ user.name }}</option>
</select>
<button class="pure-button pure-button-primary" @click.prevent="assignCode(upload.codeId)">{{ $t('admin.uploads.assignApply') }}</button>
<button class="pure-button" @click.prevent="showAssign = false">{{ $t('admin.cancel') }}</button>
</div>
<div class="file" v-for="file in upload.files" :title="file.name">
<a :href="getDownloadUrl(file)">
<img :src="getFileIconUrl(file.name)" class="icon">
<span class="filename">{{ file.name }}</span>
<span class="size">{{ file.size | formatSizeSI }}</span>
</a>
</div>
</template>
</div>
<div v-if="uploads.length == 0" class="nodata">
{{ $t('admin.empty') }}
</div>
</div>
<div v-else class="loading">
{{ $t('admin.loading') }}
</div>
</div>
</template>
<script>
import orderBy from 'lodash/orderBy';
import findIndex from 'lodash/findIndex';
import forEach from 'lodash/forEach';
import axios from 'axios';
import shared from '../../shared';
export default {
data()
{
return {
uploads: null,
confirmDelete: null,
showAssign: false,
assignUser: null,
assignUsers: []
};
},
created()
{
var self = this;
if (!shared.adminToken)
{
self.$router.push('/admin');
return;
}
axios.get('/admin/uploads', {
headers: {
Authorization: 'Bearer ' + shared.adminToken
}
})
.then((response) =>
{
self.uploads = orderBy(response.data, ['created'], ['desc']);
})
.catch((error) => { shared.$emit('apiError', error, this.$router) });
axios.get('/admin/assign/users', {
headers: {
Authorization: 'Bearer ' + shared.adminToken
}
})
.then((response) =>
{
self.assignUsers = orderBy(response.data, ['name'], ['asc']);
})
.catch((error) => { shared.$emit('apiError', error, this.$router) });
},
computed: {
groupedUploads()
{
let self = this;
let codes = {};
// Get unique codes and their highest upload time
forEach(self.uploads, (upload) =>
{
if (!codes.hasOwnProperty(upload.codeId))
{
codes[upload.codeId] = {
maxCreated: upload.created,
uploads: [upload]
};
}
else
// uploads is sorted by created descending, so no need to update maxCreated
codes[upload.codeId].uploads.push(upload);
});
return orderBy(codes, ['maxCreated'], ['desc']);
}
},
methods: {
hasAuth(token)
{
return shared.user !== null && shared.user.auth.indexOf(token) > -1;
},
getFileIconUrl(filename)
{
var ext = this.getExtension(filename);
if (ext == '')
ext = '_blank';
return '/images/fileicons/32px/' + 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);
},
deleteClick(codeId)
{
var self = this;
if (self.confirmDelete == codeId)
{
self.confirmDelete = null;
axios.delete('/admin/codeuploads/' + encodeURIComponent(codeId), {
headers: {
Authorization: 'Bearer ' + shared.adminToken
}})
.then((response) =>
{
})
.catch((error) => { shared.$emit('apiError', error, this.$router) });
}
else
{
self.confirmDelete = codeId;
}
},
cancelDelete()
{
var self = this;
self.confirmDelete = null;
},
assignCode(codeId)
{
var self = this;
let userId = self.assignUser;
if (!userId)
return;
self.assignUser = null;
self.showAssign = false;
axios.post('/admin/assign/code', {
id: codeId,
userId: userId
}, {
headers: {
Authorization: 'Bearer ' + shared.adminToken
}
})
.then((response) =>
{
if (self.hasAuth('viewAllUploads'))
{
let username = null;
forEach(self.assignUsers, (user) =>
{
if (user.id == userId)
username = user.name;
})
self.updateCodeUser(codeId, userId, username);
}
else
self.removeCodeUploads(codeId);
})
.catch((error) => { shared.$emit('apiError', error, this.$router) })
},
removeCodeUploads(codeId)
{
var self = this;
for (let i = self.uploads.length - 1; i >= 0; i--)
{
if (self.uploads[i].codeId == codeId)
self.uploads.splice(i, 1);
}
},
updateCodeUser(codeId, userId, username)
{
var self = this;
forEach(self.uploads, (upload) =>
{
if (upload.codeId == codeId)
{
upload.userId = userId;
upload.username = username;
}
});
}
}
}
</script>
<style lang="scss">
.file
{
display: inline-block;
width: 10rem;
padding: .5rem;
margin-top: .5rem;
border: solid 1px transparent;
font-size: 75%;
text-align: center;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
a
{
color: black;
text-decoration: none;
}
.icon
{
display: block;
margin-bottom: .5rem;
margin-left: auto;
margin-right: auto;
}
.filename, .size
{
display: block;
}
.size
{
color: #808080;
}
&:hover
{
background-color: #d3e9f8;
border: solid 1px #a7d3f1;
}
}
.properties
{
background-color: #f4f4f4;
padding: .2rem;
}
.codedescription
{
font-weight: bold;
}
.assign
{
margin-top: .5rem;
}
</style>