<template>
|
<div>
|
<Upload
|
v-if="type == 'png'"
|
name="file"
|
multiple
|
@change="handleUploadChange"
|
:action="computedUploadUrl"
|
:showUploadList="false"
|
:accept="accept"
|
:beforeUpload="beforeUpload"
|
>
|
<a-button type="text" size="small" v-bind="{ ...getButtonProps }">
|
<PictureOutlined /> {{ title }}
|
</a-button>
|
</Upload>
|
|
<a-upload
|
v-if="type == 'file'"
|
v-model:file-list="fileListTemp"
|
:action="computedUploadUrl"
|
list-type="picture"
|
class="upload-list-inline"
|
:before-upload="beforeUpload"
|
@change="handleFileUploadChange"
|
>
|
<a-button type="text" size="small" style="margin: 0 auto">
|
<UploadOutlined />
|
附件
|
</a-button>
|
<template #iconRender>
|
<PaperClipOutlined />
|
</template>
|
<template #itemRender="{ file, fileList, actions }">
|
<a-space class="ant-upload-list-picture-card">
|
<span style="display: flex; flex-wrap: wrap">
|
<PaperClipOutlined style="margin-right: 4px" />
|
<span v-if="!file.editor" :style="file.status === 'error' ? 'color: red' : ''">
|
{{ file.name }}
|
</span>
|
<span v-else>
|
<a-input size="small" v-model:value="file.tempName"></a-input>
|
</span>
|
</span>
|
<span v-if="!file.editor">
|
<a href="javascript:;" @click="fnPreview(file)">预览</a>
|
<a href="javascript:;" @click="fnRename(file)">重命名</a>
|
<a href="javascript:;" @click="actions.remove">删除</a>
|
</span>
|
<span v-else>
|
<a href="javascript:;" @click="fnSaveRename(file)">保存</a>
|
<a href="javascript:;" @click="fnOffRename(file)">取消</a>
|
</span>
|
</a-space>
|
</template>
|
</a-upload>
|
<div id="previewContainer"></div>
|
</div>
|
</template>
|
|
<script lang="ts" setup>
|
import { computed, ref, watch } from 'vue';
|
import { PictureOutlined, UploadOutlined, PaperClipOutlined } from '@ant-design/icons-vue';
|
import { Upload } from 'ant-design-vue';
|
import { useGlobSetting } from '@/hooks/setting';
|
import { useUploadHook } from './hooks/useUploadHook';
|
|
defineOptions({ name: 'TinymceImageUpload' });
|
|
const props = defineProps({
|
fullscreen: {
|
type: Boolean,
|
},
|
disabled: {
|
type: Boolean,
|
default: false,
|
},
|
accept: {
|
type: String,
|
default: '.jpg,.jpeg,.gif,.png,.webp',
|
},
|
title: {
|
type: String,
|
default: '图片',
|
},
|
type: {
|
type: String,
|
default: 'png',
|
},
|
});
|
|
const emit = defineEmits(['uploading', 'done', 'error', 'fileListChange']);
|
let uploading = false;
|
|
const { uploadUrl: baseUrl } = useGlobSetting();
|
const { computedUploadUrl, getUploadData, generateFileUrl } = useUploadHook(baseUrl);
|
|
const fileListTemp = ref([]); // 用于附件的文件列表
|
|
const getButtonProps = computed(() => ({
|
disabled: props.disabled,
|
}));
|
const uuid = ref('');
|
|
// beforeUpload 拦截器,用于动态修改 URL
|
const beforeUpload = () => {
|
const encryptedParams = getUploadData(uuid.value);
|
const queryString = new URLSearchParams(encryptedParams).toString();
|
computedUploadUrl.value = `${baseUrl}?${queryString}`;
|
};
|
// 处理上传变化
|
const handleUploadChange = (info: Record<string, any>) => {
|
const file = info.file;
|
const status = file?.status;
|
|
if (status === 'uploading') {
|
if (!uploading) {
|
emit('uploading', file.name);
|
uploading = true;
|
}
|
} else if (status === 'done') {
|
const newUrl = generateFileUrl(file.response); // 生成文件 URL
|
debugger;
|
if (!uuid.value) {
|
uuid.value = file.response.uuid.split(';')[0];
|
}
|
emit('done', file.name, newUrl);
|
uploading = false;
|
} else if (status === 'error') {
|
emit('error');
|
uploading = false;
|
}
|
};
|
function handleFileUploadChange(info: Record<string, any>) {
|
const file = info.file;
|
const status = file?.status;
|
if (status === 'done') {
|
if (!uuid.value) {
|
uuid.value = file.response.uuid.split(';')[0];
|
}
|
uploading = false;
|
}
|
}
|
// 重命名功能
|
const fnRename = (file) => {
|
file.editor = true;
|
};
|
|
// 保存重命名
|
const fnSaveRename = (file) => {
|
file.editor = false;
|
file.name = file.tempName;
|
};
|
|
// 取消重命名
|
const fnOffRename = (file) => {
|
file.editor = false;
|
};
|
|
// 预览
|
const fnPreview = (file) => {
|
if (!file || !file.response) {
|
console.error('Invalid file or response');
|
return;
|
}
|
|
// 生成安全的文件 URL
|
const safeUrl = generateFileUrl(file.response);
|
|
// 获取文件类型(通过文件扩展名或 MIME 类型)
|
const fileExt = file.response.fileType || file.name.split('.').pop().toLowerCase(); // 获取文件扩展名
|
const isImage = ['jpg', 'jpeg', 'png', 'gif', 'webp', 'bmp'].includes(fileExt); // 判断是否为图片
|
|
if (isImage) {
|
// 直接打开图片
|
window.open(safeUrl, '_blank');
|
} else {
|
// 非图片类型使用 Office Online Viewer 或其他工具预览
|
const iframeSrc = `https://view.officeapps.live.com/op/view.aspx?src=${encodeURIComponent(safeUrl)}`;
|
window.open(iframeSrc, '_blank');
|
}
|
};
|
|
watch(
|
() => fileListTemp.value,
|
(newValue) => {
|
emit('fileListChange', fileListTemp.value);
|
},
|
);
|
</script>
|
|
<style lang="less" scoped>
|
@prefix-cls: ~'@{namespace}-tinymce-img-upload';
|
|
.@{prefix-cls} {
|
z-index: 20;
|
top: 4px;
|
right: 10px;
|
|
&.fullscreen {
|
position: fixed;
|
z-index: 10000;
|
}
|
}
|
</style>
|