chore: install prettier

This commit is contained in:
Viet An
2026-05-04 15:22:27 +07:00
parent 93d29ca7d8
commit bd58e2b847
267 changed files with 22950 additions and 13581 deletions

View File

@@ -1,303 +1,447 @@
<template>
<div>
<div class="is-hidden"><img id="image" :src="image"></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>
<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>
<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>
<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>
<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
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">
<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
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
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>
<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()
</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);
}
},
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
},
computed: {
login: {
get: function () {
return this.$store.login;
},
set: function (val) {
this.$store.commit("updateLogin", { login: val });
},
},
watch: {
data: function() {
this.group = []
for (let index = 0; index < this.data.length/ (this.type==='video'? 4 : 5) ; index++) {
this.group.push(index)
}
}
media: {
get: function () {
return this.$store.media;
},
set: function (val) {
this.$store.commit("updateMedia", { media: val });
},
},
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()
},
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
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})
}
.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 });
}
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" })
} 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()
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
.then((res) => res.blob())
.then((blob) => {
const file = new File([blob], v.name, { type: "image/png" });
row.source = { file: file };
});
};
reader.readAsDataURL(response.data);
});
}
}
}
</script>
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>