Initial commit
This commit is contained in:
303
app/components/media/Imagebox.vue
Normal file
303
app/components/media/Imagebox.vue
Normal file
@@ -0,0 +1,303 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="is-hidden"><img id="image" :src="image"></div>
|
||||
<div class="field is-grouped is-grouped-multiline">
|
||||
<div class="control">
|
||||
<div class="file is-primary">
|
||||
<label class="file-label">
|
||||
<input class="file-input" type="file" :id="docid" multiple name="resume" @change="doChange">
|
||||
<a class="button is-primary is-rounded is-small" :class="loading? 'is-loading' : null">
|
||||
<SvgIcon v-bind="{name: 'add5.svg', type: 'white', size: 18}"></SvgIcon>
|
||||
<span class="fs-14 ml-1">Tải lên từ máy tính</span>
|
||||
</a>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div :class="`control ${showUrl? '' : 'is-expanded'}`">
|
||||
<a class="button is-dark is-rounded is-small" @click="displayInput()">
|
||||
<SvgIcon v-bind="{name: 'add5.svg', type: 'white', size: 18}"></SvgIcon>
|
||||
<span class="fs-14 ml-1">Tải lên từ đường dẫn</span>
|
||||
</a>
|
||||
</div>
|
||||
<div class="control is-expanded" v-if="showUrl">
|
||||
<input class="input is-small is-rounded" id="url" v-model="url" style="width: 250px;" type="text" placeholder="Nhập đường dẫn vào đây">
|
||||
<a class="button is-primary is-small px-4 ml-3" @click="checkUrl()">
|
||||
<SvgIcon v-bind="{name: 'upload.svg', type: 'white', size: 22}"></SvgIcon>
|
||||
</a>
|
||||
<a class="ml-4" @click="showUrl=false">
|
||||
<SvgIcon v-bind="{name: 'close.svg', type: 'dark', size: 22}"></SvgIcon>
|
||||
</a>
|
||||
</div>
|
||||
<div class="control">
|
||||
<input class="input is-small is-rounded" v-model="search" style="width: 250px;" type="text" placeholder="Tìm kiếm" @keyup="beginSearch">
|
||||
</div>
|
||||
<div class="control">
|
||||
<span class="is-clickable" @click="mode='image'">
|
||||
<SvgIcon v-bind="{name: 'image3.svg', type: 'dark', size: 25}"></SvgIcon>
|
||||
</span>
|
||||
</div>
|
||||
<div class="control">
|
||||
<span class="is-clickable" @click="mode='list'">
|
||||
<SvgIcon v-bind="{name: 'list.png', type: 'dark', size: 25}"></SvgIcon>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<DataView class="mt-3" v-bind="vbind" v-if="mode==='list'"></DataView>
|
||||
<div class="tile is-ancestor mx-0 px-0 pt-3" v-else>
|
||||
<div class="tile is-vertical">
|
||||
<div class="tile is-parent" v-for="(v,i) in group" :key="i">
|
||||
<article class="tile is-child" v-for="(k,j) in getData(i)" :key="j" @mouseover="focus=k">
|
||||
<div class="image px-2 pb-2" v-if="k.file && type==='image'">
|
||||
<nuxt-img :src="`${path}download?name=${k.file}`" :id="'commentImage' + k.id"></nuxt-img>
|
||||
<div class="text-image" v-if="focus===k">
|
||||
<a class="button is-primary is-small" @click="selectMedia(k)">
|
||||
<SvgIcon v-bind="{name: 'checked.svg', type: 'white', size: 22}"></SvgIcon>
|
||||
</a>
|
||||
<a class="button is-primary is-small ml-2" @click="editImage(k)">
|
||||
<SvgIcon v-bind="{name: 'crop.svg', type: 'white', size: 22}"></SvgIcon>
|
||||
</a>
|
||||
<a class="button is-primary is-small ml-2" @click="copyMedia(k, 'image')">
|
||||
<SvgIcon v-bind="{name: 'copy.svg', type: 'white', size: 22}"></SvgIcon>
|
||||
</a>
|
||||
<a class="button is-danger is-small ml-2" @click="deleteMedia(k, 'file')">
|
||||
<SvgIcon v-bind="{name: 'bin1.svg', type: 'white', size: 22}"></SvgIcon>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ml-2 mr-2" v-else-if="k.file && type==='video'">
|
||||
<vue-plyr>
|
||||
<video :src="path + 'static/videos/' + k.file">
|
||||
<source :src="path + 'static/videos/' + k.file" type="video/mp4" size="720">
|
||||
</video>
|
||||
<div class="mt-2" v-if="focus===k">
|
||||
<a class="button is-primary" @click="selectMedia(k)">
|
||||
<SvgIcon v-bind="{name: 'check3.svg', type: 'primary', size: 22}"></SvgIcon>
|
||||
</a>
|
||||
</div>
|
||||
</vue-plyr>
|
||||
</div>
|
||||
<div class="ml-2 mr-2" v-else-if="k.file && type==='file'">
|
||||
{{k.file}}
|
||||
<div class="mt-2" v-if="focus===k">
|
||||
<a class="button is-primary" @click="selectMedia(k)">
|
||||
<SvgIcon v-bind="{name: 'check3.svg', type: 'primary', size: 22}"></SvgIcon>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<Modal @close="showmodal=undefined" v-bind="showmodal" @image="updateImage" @files="getFiles" v-if="showmodal"/>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
props: ['source'],
|
||||
data() {
|
||||
return {
|
||||
file: undefined,
|
||||
image: undefined,
|
||||
showmodal: undefined,
|
||||
data: [],
|
||||
group: [],
|
||||
focus: undefined,
|
||||
type: 'image',
|
||||
selected: undefined,
|
||||
loading: false,
|
||||
path: this.$getpath(),
|
||||
showUrl: false,
|
||||
url: undefined,
|
||||
search: undefined,
|
||||
mode: 'image',
|
||||
timer: undefined,
|
||||
vbind: {api: 'file', setting: 'image-fields'},
|
||||
dataFiles: [],
|
||||
files: [],
|
||||
docid: this.$id()
|
||||
}
|
||||
},
|
||||
async created() {
|
||||
let found = this.$findapi('file')
|
||||
found.params = {filter: {user: this.login.id}, sort: '-create_time', type__code: this.type}
|
||||
let result = await this.$getapi([found])
|
||||
this.data = result[0].data.rows
|
||||
},
|
||||
watch: {
|
||||
data: function() {
|
||||
this.group = []
|
||||
for (let index = 0; index < this.data.length/ (this.type==='video'? 4 : 5) ; index++) {
|
||||
this.group.push(index)
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
login: {
|
||||
get: function() {return this.$store.login},
|
||||
set: function(val) {this.$store.commit("updateLogin", {login: val})}
|
||||
},
|
||||
media: {
|
||||
get: function() {return this.$store.media},
|
||||
set: function(val) {this.$store.commit("updateMedia", {media: val})}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
doChange() {
|
||||
this.dataFiles = []
|
||||
let fileList = document.getElementById(this.docid).files
|
||||
this.files = Array.from(fileList)
|
||||
if(this.files.length===0) return
|
||||
this.files.map(v=>{
|
||||
let file = this.$upload(v, this.vtype, this.$store.login.id)
|
||||
this.dataFiles.push(file)
|
||||
})
|
||||
this.showmodal = {component: 'media/UploadProgress', title: 'Upload files', width: '700px', height: '200px', vbind: {files: this.dataFiles}}
|
||||
this.clearFileList()
|
||||
},
|
||||
clearFileList() {
|
||||
const fileInput = document.getElementById(this.docid)
|
||||
const dt = new DataTransfer()
|
||||
fileInput.files = dt.files
|
||||
},
|
||||
getFiles(files) {
|
||||
this.data = files.concat(this.data)
|
||||
setTimeout(()=>this.showmodal=undefined, 3000)
|
||||
},
|
||||
beginSearch(e) {
|
||||
if(this.timer) clearTimeout(this.timer)
|
||||
this.timer = setTimeout(() => this.startSearch(e.target.value), 150)
|
||||
},
|
||||
async startSearch(value) {
|
||||
let filter = {user: this.login.id}
|
||||
if(!this.$empty(value)) filter.name__icontains = value.toLowerCase()
|
||||
this.data = await this.$getdata('file', filter)
|
||||
},
|
||||
displayInput() {
|
||||
this.showUrl = true
|
||||
this.url = undefined
|
||||
setTimeout(()=>document.getElementById('url').focus(), 100)
|
||||
},
|
||||
checkUrl() {
|
||||
if(this.$empty(this.url)) return this.$snackbar(`Đường dẫn không hợp lệ`, undefined, 'Error')
|
||||
let self = this
|
||||
this.loading = true
|
||||
this.$axios.get(this.url, {responseType:"blob" })
|
||||
.then(function(response) {
|
||||
var reader = new window.FileReader()
|
||||
reader.onload = (e) => {
|
||||
self.image = e.target.result
|
||||
setTimeout(()=> self.doUpload(e.target.result), 100)
|
||||
}
|
||||
reader.readAsDataURL(response.data)
|
||||
self.loading = false
|
||||
})
|
||||
.catch(e => {
|
||||
self.$buefy.toast.open({duration: 3000, message: `Đường dẫn không hợp lệ`, type: 'is-danger'})
|
||||
self.loading = false
|
||||
})
|
||||
},
|
||||
doUpload() {
|
||||
const image = document.getElementById('image')
|
||||
const canvas = document.createElement('canvas')
|
||||
canvas.width = image.width
|
||||
canvas.height = image.height
|
||||
const ctx = canvas.getContext('2d')
|
||||
ctx.drawImage(image, 0, 0)
|
||||
if(canvas) canvas.toBlob(blod=>this.saveAs(blod))
|
||||
},
|
||||
async saveAs(blod) {
|
||||
var form = new FormData();
|
||||
const fileName = this.$dayjs(new Date()).format("YYYYMMDDhhmmss") + '-' + this.$id() + '.png'
|
||||
form.append('filename', fileName)
|
||||
form.append('name', `${this.$id()}.png`)
|
||||
form.append('file', blod)
|
||||
form.append('type', 'image')
|
||||
form.append('size', 100)
|
||||
form.append('user', this.$store.login.id)
|
||||
let result = await this.$insertapi('upload', form)
|
||||
if(result==='error') return
|
||||
this.updateImage(result.rows[0])
|
||||
this.showUrl = false
|
||||
},
|
||||
async uploadImage(file) {
|
||||
this.loading = true
|
||||
let result = await this.$insertapi('upload', file.form)
|
||||
this.data.splice(0, 0, result.rows[0])
|
||||
this.loading = false
|
||||
},
|
||||
getData(i) {
|
||||
if(this.type==='video') {
|
||||
var list = this.data.slice(i*5, i*5+5)
|
||||
for (let index = 0; index < 5; index++) {
|
||||
if(list.length<index+1) list.push({file: undefined})
|
||||
}
|
||||
} else {
|
||||
list = this.data.slice(i*6, i*6+6)
|
||||
for (let index = 0; index < 6; index++) {
|
||||
if(list.length<index+1) list.push({file: undefined})
|
||||
}
|
||||
}
|
||||
return list
|
||||
},
|
||||
selectMedia(v) {
|
||||
let copy = this.media? this.$copy(this.media) : {}
|
||||
copy.type = 'image'
|
||||
copy.open = false
|
||||
copy.select = v
|
||||
this.media = copy
|
||||
let row = this.$copy(v)
|
||||
if(this.source) {
|
||||
let params = {name: v.file, type: 'file'}
|
||||
this.$axios.get(`${this.path}download/`, {params: params, responseType:"blob" })
|
||||
.then(function (response) {
|
||||
var reader = new window.FileReader()
|
||||
reader.onload = (e) => {
|
||||
fetch(e.target.result)
|
||||
.then(res => res.blob())
|
||||
.then(blob => {
|
||||
const file = new File([blob], v.name,{ type: "image/png" })
|
||||
row.source = {file: file}
|
||||
})
|
||||
}
|
||||
reader.readAsDataURL(response.data)
|
||||
})
|
||||
}
|
||||
this.$emit('modalevent', {name: 'selectimage', data: row})
|
||||
},
|
||||
editImage(v) {
|
||||
this.loading = true
|
||||
this.selected = v
|
||||
let self = this
|
||||
let params = {name: v.file, type: 'file'}
|
||||
this.$axios.get(`${this.path}download/`, {params: params, responseType:"blob" })
|
||||
.then(function (response) {
|
||||
var reader = new window.FileReader()
|
||||
reader.onload = (e) => {
|
||||
self.image = e.target.result
|
||||
self.showmodal = {component: 'media/CropImage', width: '65%', title: 'Cắt hình ảnh', vbind: {selected: self.selected, image: self.image}}
|
||||
}
|
||||
reader.readAsDataURL(response.data)
|
||||
self.loading = false
|
||||
})
|
||||
},
|
||||
copyMedia(v) {
|
||||
this.$copyToClipboard(`${this.path}download/?name=${v.file}`)
|
||||
},
|
||||
deleteMedia(v, name) {
|
||||
let self = this
|
||||
var remove = async function() {
|
||||
let result = await self.$deleteapi(name, v.id)
|
||||
let idx = self.data.findIndex(x=>x.id===v.id)
|
||||
self.$delete(self.data, idx)
|
||||
}
|
||||
this.$buefy.dialog.confirm({
|
||||
message: 'Bạn muốn xóa file: ' + v.file,
|
||||
onConfirm: () => remove()})
|
||||
},
|
||||
updateImage(v) {
|
||||
this.data.splice(0, 0, v)
|
||||
this.showmodal = undefined
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
Reference in New Issue
Block a user