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.
375 lines
8.8 KiB
375 lines
8.8 KiB
<template> |
|
<div class="flex gap-12 wrap file-container"> |
|
<div |
|
v-for="(item, index) in fileList" |
|
:key="index" |
|
class="item pointer" |
|
> |
|
<template v-if="item.type && item.type.indexOf('image') > -1"> |
|
<div |
|
class="img-box" |
|
:style="{ |
|
backgroundImage: `url(${VITE_API_URL}/file/stream/${item.filepath})`, |
|
}" |
|
@click="filePreview(item)" |
|
></div> |
|
<a |
|
class="remove-btn" |
|
@click="remove(index)" |
|
v-if="removeEnable" |
|
> |
|
<img src="\imgs\close.png"/> |
|
</a> |
|
</template> |
|
<div |
|
class="item flex end v-center column text-center" |
|
:title="item.orgiinFilename" |
|
@click="filePreview(item)" |
|
v-else |
|
> |
|
<icon :name="getIconName(item.type)" :size="40" /> |
|
<span class="filename">{{ item.orgiinFilename }}</span> |
|
<a |
|
class="remove-btn" |
|
@click.stop="remove(index)" |
|
v-if="removeEnable" |
|
> |
|
<img src="\imgs\close.png"/> |
|
</a> |
|
</div> |
|
</div> |
|
</div> |
|
|
|
</template> |
|
<script setup> |
|
|
|
import { watch } from "vue"; |
|
|
|
const { VITE_API_URL } = process.env; |
|
const props = defineProps({ |
|
files: { |
|
type: Array, |
|
default: () => [], |
|
}, |
|
removeEnable: { |
|
type: Boolean, |
|
default: false, |
|
}, |
|
}); |
|
const emit = defineEmits(["update:files"]); |
|
|
|
const fileList = ref(props.files); |
|
|
|
watch( |
|
() => props.files, |
|
(files) => { |
|
fileList.value = files; |
|
} |
|
); |
|
|
|
const activeFile = ref({}); |
|
const fileRrror = ref(false); |
|
const rotate = ref(0); |
|
const scale = ref(0); |
|
const translateX = ref(0); |
|
const translateY = ref(0); |
|
let moveFlag = false; |
|
let initialX = 0; |
|
let initialY = 0; |
|
function prev() { |
|
const index = fileList.value.indexOf(activeFile.value); |
|
if (index === 0) { |
|
filePreview(fileList.value[fileList.value.length - 1]); |
|
} else { |
|
filePreview(fileList.value[index - 1]); |
|
} |
|
} |
|
function next() { |
|
const index = fileList.value.indexOf(activeFile.value); |
|
if (index === fileList.value.length - 1) { |
|
filePreview(fileList.value[0]); |
|
} else { |
|
filePreview(fileList.value[index + 1]); |
|
} |
|
} |
|
const preview = ref(false); |
|
watch(preview, (val) => { |
|
|
|
}) |
|
|
|
function filePreview(file) { |
|
preview.value = true; |
|
fileRrror.value = false; |
|
activeFile.value = file; |
|
rotate.value = 0; |
|
scale.value = 1; |
|
translateX.value = 0; |
|
translateY.value = 0; |
|
moveFlag = false; |
|
|
|
} |
|
|
|
function wheel(event) { |
|
if (activeFile.value.type.indexOf("image") === -1) { |
|
return; |
|
} |
|
if (event.deltaY > 0 && scale.value > 0.5) { |
|
scale.value -= 0.1; |
|
} |
|
if (event.deltaY < 0) { |
|
scale.value += 0.1; |
|
} |
|
} |
|
|
|
function mousedown() { |
|
moveFlag = true; |
|
initialX = event.clientX; |
|
initialY = event.clientY; |
|
} |
|
function mousemove(event) { |
|
if (!moveFlag) { |
|
return; |
|
} |
|
if (rotate.value % 360 === 0) { |
|
translateX.value += event.clientX - initialX; |
|
translateY.value += event.clientY - initialY; |
|
} |
|
if (rotate.value === 90) { |
|
translateY.value -= event.clientX - initialX; |
|
translateX.value += event.clientY - initialY; |
|
} |
|
if (rotate.value === 180) { |
|
translateX.value -= event.clientX - initialX; |
|
translateY.value -= event.clientY - initialY; |
|
} |
|
if (rotate.value === 270) { |
|
translateY.value += event.clientX - initialX; |
|
translateX.value -= event.clientY - initialY; |
|
} |
|
initialX = event.clientX; |
|
initialY = event.clientY; |
|
} |
|
|
|
function mouseup(event) { |
|
moveFlag = false; |
|
} |
|
|
|
function rotateLeft() { |
|
if (rotate.value === 360) { |
|
rotate.value = 0; |
|
} else { |
|
rotate.value += 90; |
|
} |
|
} |
|
|
|
function rotateRight() { |
|
if (rotate.value === 0) { |
|
rotate.value = 270; |
|
} else { |
|
rotate.value -= 90; |
|
} |
|
} |
|
|
|
function getIconName(filetype) { |
|
if (!filetype) { |
|
return "el-icon-document"; |
|
} |
|
if (filetype.indexOf("image") > -1) { |
|
return "el-icon-Picture"; |
|
} |
|
if (filetype === "application/pdf") { |
|
return "local-icon-pdf"; |
|
} |
|
if (filetype.indexOf("audio") > -1) { |
|
return "local-icon-mp3"; |
|
} |
|
if (filetype.indexOf("word") > -1) { |
|
return "local-icon-doc"; |
|
} |
|
if ( |
|
filetype.indexOf("excel") > -1 || |
|
filetype.indexOf("spreadsheetml.sheet") > -1 |
|
) { |
|
return "local-icon-xls"; |
|
} |
|
if ( |
|
filetype.indexOf("video") > -1 |
|
) { |
|
return "local-icon-mp4"; |
|
} |
|
return "el-icon-document"; |
|
} |
|
|
|
function remove(index) { |
|
fileList.value.splice(index, 1); |
|
emit("update:files", fileList.value); |
|
} |
|
|
|
function download() { |
|
window.open(`${VITE_API_URL}/api/file/stream/${activeFile.value.filepath}`); |
|
} |
|
|
|
function getDocFilepath() { |
|
if ( |
|
activeFile.value.type === "application/msword" && |
|
activeFile.value.docxFilepath |
|
) { |
|
return `${VITE_API_URL}/api/file/stream/${activeFile.value.docxFilepath}`; |
|
} |
|
return `${VITE_API_URL}/api/file/stream/${activeFile.value.filepath}`; |
|
} |
|
</script> |
|
<style lang="scss" scoped> |
|
.file-container { |
|
min-height: 80px; |
|
.item { |
|
width: 80px; |
|
height: 80px; |
|
margin-bottom: 12px; |
|
border-radius: 2px; |
|
color: var(--primary-color); |
|
position: relative; |
|
&:hover { |
|
background-color: #ededed; |
|
span.filename { |
|
font-weight: 700; |
|
} |
|
} |
|
span.filename { |
|
line-height: 1.2; |
|
font-size: 12px; |
|
width: 100%; |
|
white-space: nowrap; |
|
text-overflow: ellipsis; |
|
margin-top: 10px; |
|
overflow: hidden; |
|
} |
|
.img-box { |
|
width: 80px; |
|
height: 80px; |
|
background-size: cover; |
|
background-position: center; |
|
border-radius: 2px; |
|
&:hover { |
|
outline: 2px solid #ff9800; |
|
} |
|
} |
|
.remove-btn { |
|
position: absolute; |
|
top: -10px; |
|
right: -10px; |
|
display: block; |
|
border-radius: 50%; |
|
height: 20px; |
|
background-color: #fff; |
|
&:hover { |
|
color: red; |
|
cursor: pointer; |
|
} |
|
} |
|
} |
|
} |
|
.file-preview-wrapper { |
|
.file-list { |
|
width: 15vw; |
|
height: 100vh; |
|
padding: 16px 8px; |
|
background-color: #fff; |
|
box-sizing: border-box; |
|
section { |
|
padding: 8px 16px; |
|
border: 2px solid transparent; |
|
&:hover { |
|
color: var(--primary-color); |
|
font-weight: 700; |
|
} |
|
&[active="true"] { |
|
border-color: var(--primary-color); |
|
} |
|
span { |
|
width: calc(100% - 32px); |
|
overflow: hidden; |
|
white-space: nowrap; |
|
text-overflow: ellipsis; |
|
} |
|
} |
|
} |
|
.file-content { |
|
width: 86vw; |
|
position: relative; |
|
|
|
.img-container { |
|
height: 100vh; |
|
img { |
|
max-height: 100%; |
|
display: block; |
|
&:hover { |
|
cursor: pointer; |
|
} |
|
} |
|
} |
|
.error { |
|
background-color: #fff; |
|
img { |
|
width: 500px; |
|
} |
|
} |
|
} |
|
.close-btn { |
|
position: absolute; |
|
top: 12px; |
|
right: 8px; |
|
background-color: transparent; |
|
border: none; |
|
color: #fff; |
|
&:hover { |
|
color: red; |
|
} |
|
} |
|
.rotate-left-btn { |
|
position: absolute; |
|
top: 12px; |
|
right: 118px; |
|
background-color: transparent; |
|
border: none; |
|
color: #fff; |
|
} |
|
.rotate-right-btn { |
|
position: absolute; |
|
top: 12px; |
|
right: 68px; |
|
background-color: transparent; |
|
border: none; |
|
color: #fff; |
|
} |
|
.left-btn { |
|
position: absolute; |
|
top: 50%; |
|
left: 0; |
|
transform: translateY(-50%); |
|
background-color: transparent; |
|
border: none; |
|
color: #fff; |
|
} |
|
.right-btn { |
|
position: absolute; |
|
top: 50%; |
|
right: 0; |
|
transform: translateY(-50%); |
|
background-color: transparent; |
|
border: none; |
|
color: #fff; |
|
} |
|
.download-btn { |
|
position: absolute; |
|
bottom: 16px; |
|
right: 18px; |
|
} |
|
.file-number { |
|
position: absolute; |
|
top: 16px; |
|
left: 18px; |
|
color: #fff; |
|
} |
|
} |
|
</style> |