添加MP3,MP4上传功能

This commit is contained in:
yangjun 2025-08-26 09:07:44 +08:00
parent 04fcc7e7db
commit 70d5555465
10 changed files with 1635 additions and 117 deletions

BIN
src/assets/upload/mp3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

BIN
src/assets/upload/mp4.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

View File

@ -0,0 +1,443 @@
<template>
<div class="clearfix">
<a-upload-dragger
:listType="listType"
accept="image/*"
:multiple="multiple"
:action="uploadUrl"
:headers="headers"
:data="{ biz: bizPath }"
v-model:fileList="uploadFileList"
:beforeUpload="beforeUpload"
:disabled="disabled"
:showUploadList="false"
@change="handleChange"
@preview="handlePreview"
>
<div v-if="uploadVisible">
<div v-if="listType == 'picture-card'">
<div class="upload-area" style="padding: 20px;">
<p class="upload-text">点击或者拖拽上传</p>
<p class="upload-hint">
<div class="upload-icon">
<img src="../../../../../assets/upload/picture.png"style="width: 40px; height: 40px;" />
</div>
<span class="divider">文件大小不超过10MB</span>
<span class="divider">|</span>
<a-tooltip placement="top">
<template #title>
这里是格式说明的具体内容
</template>
<span class="divider">
<QuestionCircleOutlined style="margin-right: 0px;" />
格式说明
</span>
</a-tooltip>
</p>
</div>
</div>
<a-button v-if="listType == 'picture'" :disabled="disabled">
<UploadOutlined></UploadOutlined>
{{ text }}
</a-button>
</div>
</a-upload-dragger>
<div class="custom-upload-list" v-if="uploadFileList.length > 0">
<div v-for="(file, index) in uploadFileList" :key="file.uid" >
<div style="margin-top: 20px;">
<img :src="file.url?file.url:file.r" style="width: 200px; height: 200px;" >
</div>
<div style="margin-top: 20px;">
{{ file.name }}
</div>
<div style="margin-top: 20px;">
<a-button type="link" @click="handlePreview(file)">预览</a-button>
<a-button type="link" danger @click="removeFile(index)" v-if="!props.disabled">删除</a-button>
</div>
</div>
</div>
<a-modal
:open="previewVisible"
:width="modalWidth"
:bodyStyle="{ padding: 0, display: 'flex', justifyContent: 'center', alignItems: 'center' }"
:footer="null"
@cancel="handleCancel"
>
<img
ref="previewImgRef"
class="preview-img"
:src="previewImage"
@load="handleImageLoad"
/>
</a-modal>
</div>
</template>
<script lang="ts">
import { defineComponent, PropType, ref, reactive, watchEffect, computed, unref, watch, onMounted, nextTick } from 'vue';
import { LoadingOutlined, UploadOutlined } from '@ant-design/icons-vue';
import { useRuleFormItem } from '/@/hooks/component/useFormItem';
import { propTypes } from '/@/utils/propTypes';
import { useAttrs } from '/@/hooks/core/useAttrs';
import { useMessage } from '/@/hooks/web/useMessage';
import { getFileAccessHttpUrl, getHeaders, getRandom } from '/@/utils/common/compUtils';
import { uploadUrl } from '/@/api/common/api';
import { getToken } from '/@/utils/auth';
const { createMessage, createErrorModal } = useMessage();
export default defineComponent({
name: 'JImageUpload',
components: { LoadingOutlined, UploadOutlined },
inheritAttrs: false,
props: {
//
value: propTypes.oneOfType([propTypes.string, propTypes.array]),
//
listType: {
type: String,
required: false,
default: 'picture-card',
},
//
text: {
type: String,
required: false,
default: '上传',
},
//
bizPath: {
type: String,
required: false,
default: 'temp',
},
//
disabled: {
type: Boolean,
required: false,
default: false,
},
//
fileMax: {
type: Number,
required: false,
default: 1,
},
},
emits: ['options-change', 'change', 'update:value'],
setup(props, { emit, refs }) {
const emitData = ref<any[]>([]);
const attrs = useAttrs();
const [state] = useRuleFormItem(props, 'value', 'change', emitData);
//
const getFileName = (path) => {
if (path.lastIndexOf('\\') >= 0) {
let reg = new RegExp('\\\\', 'g');
path = path.replace(reg, '/');
}
return path.substring(path.lastIndexOf('/') + 1);
};
//token
const headers = getHeaders();
//
const loading = ref<boolean>(false);
//
const initTag = ref<boolean>(true);
//
let uploadFileList = ref<any[]>([]);
//
const previewImage = ref<string | undefined>('');
//
const previewVisible = ref<boolean>(false);
//
const multiple = computed(() => {
return props['fileMax'] > 1 || props['fileMax'] === 0;
});
//
const uploadVisible = computed(() => {
if (props['fileMax'] === 0) {
return true;
}
return uploadFileList.value.length < props['fileMax'];
});
function removeFile(index) {
uploadFileList.value.splice(index, 1);
}
/**
* 监听value变化
*/
watch(
() => props.value,
(val, prevCount) => {
//update-begin---author:liusq ---date:20230601 forissues/556JImageUploadvalue------------
if (val && val instanceof Array) {
val = val.join(',');
}
if (initTag.value == true) {
initFileList(val);
}
},
{ immediate: true }
//update-end---author:liusq ---date:20230601 forissues/556JImageUploadvalue------------
);
/**
* 初始化文件列表
*/
function initFileList(paths) {
if (!paths || paths.length == 0) {
uploadFileList.value = [];
return;
}
let files = [];
let arr = paths.split(',');
arr.forEach((value) => {
let url = getFileAccessHttpUrl(value);
files.push({
uid: getRandom(10),
name: getFileName(value),
status: 'done',
url: url,
response: {
status: 'history',
message: value,
},
});
});
uploadFileList.value = files;
}
/**
* 上传前校验
*/
function beforeUpload(file) {
let fileType = file.type;
console.log("🚀 ~ beforeUpload ~ fileType:", fileType)
if (fileType.indexOf('image') < 0) {
createMessage.info('请上传图片');
uploadFileList.value = [];
return false;
}
}
/**
* 文件上传结果回调
*/
function handleChange({ file, fileList, event }) {
console.log("🚀 ~ handleChange ~ file:", file)
let fileType = file.type;
if (fileType.indexOf('image') < 0) {
uploadFileList.value = [];
return false;
}
initTag.value = false;
// update-begin--author:liaozhiyang---date:20231116---forissues/846
// uploadFileList.value = fileList;
if (file.status === 'error') {
createMessage.error(`${file.name} 上传失败.`);
}
// update-begin--author:liaozhiyang---date:20240704---forTV360X-1640
if (file.status === 'done' && file.response.success === false) {
const failIndex = uploadFileList.value.findIndex((item) => item.uid === file.uid);
if (failIndex != -1) {
uploadFileList.value.splice(failIndex, 1);
}
createMessage.warning(file.response.message);
return;
}
// update-end--author:liaozhiyang---date:20240704---forTV360X-1640
let fileUrls = [];
let noUploadingFileCount = 0;
if (file.status != 'uploading') {
fileList.forEach((file) => {
if (file.status === 'done') {
fileUrls.push(file.response.message);
}
if (file.status != 'uploading') {
noUploadingFileCount++;
}
});
if (file.status === 'removed') {
handleDelete(file);
}
if (noUploadingFileCount == fileList.length) {
state.value = fileUrls.join(',');
emit('update:value', fileUrls.join(','));
// update-begin---author:wangshuai ---date:20221121 for[issues/248]使,------------
nextTick(() => {
initTag.value = true;
});
// update-end---author:wangshuai ---date:20221121 for[issues/248]使,------------
}
}
for (let i = 0; i < uploadFileList.value.length; i++) {
if (uploadFileList.value[i].status === 'done') {
uploadFileList.value[i].url = getFileAccessHttpUrl(uploadFileList.value[i].response.message);
}
}
// update-end--author:liaozhiyang---date:20231116---forissues/846
}
/**
* 删除图片
*/
function handleDelete(file) {
//
console.log(file);
}
const previewImgRef = ref<HTMLImageElement | null>(null);
const modalWidth = ref('auto');
/**
* 预览图片
*/
async function handlePreview(file) {
if (!file.url && !file.preview) {
file.preview = (await getBase64(file.originFileObj)) as string;
}
previewImage.value = file.url || file.preview;
previewVisible.value = true;
}
function getBase64(file: File) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = () => resolve(reader.result);
reader.onerror = error => reject(error);
});
}
function getAvatarView() {
if (uploadFileList.length > 0) {
let url = uploadFileList[0].url;
return getFileAccessHttpUrl(url, null);
}
}
function handleCancel() {
previewVisible.value = false;
}
//
const handleImageLoad = () => {
if (!previewImgRef.value) return;
const img = previewImgRef.value;
const maxWidth = window.innerWidth * 0.9; // 90%
const maxHeight = window.innerHeight * 0.8; // 80%
//
const ratio = Math.min(maxWidth / img.naturalWidth, maxHeight / img.naturalHeight, 1);
modalWidth.value = `${img.naturalWidth * ratio}px`;
};
return {
state,
attrs,
previewImage,
previewVisible,
uploadFileList,
multiple,
headers,
loading,
uploadUrl,
beforeUpload,
uploadVisible,
handlePreview,
handleCancel,
handleChange,
handleImageLoad,
previewImgRef,
modalWidth,
props,
removeFile
};
},
});
</script>
<style scoped>
.ant-upload-select-picture-card i {
font-size: 32px;
color: #999;
}
.ant-upload-select-picture-card .ant-upload-text {
margin-top: 8px;
color: #666;
}
/* 确保 Modal 内容区域填满 */
.imgView .ant-modal-body {
height: 80vh; /* 限制模态框高度,避免超出屏幕 */
display: flex;
align-items: center;
justify-content: center;
}
/* 图片容器 */
.img-container {
max-width: 100%;
max-height: 100%;
display: flex;
align-items: center;
justify-content: center;
}
/* 图片自适应 */
.preview-img {
max-width: 100%;
max-height: 100%;
object-fit: contain; /* 保持比例,不拉伸 */
}
:deep(.ant-upload-wrapper .ant-upload-drag .ant-upload) {
padding: 0px !important;
}
:deep(.ant-upload-drag ) {
border: 0px !important;
}
.upload-text {
font-size: 16px;
color: rgba(74, 69, 69, 0.85);
margin-bottom: 8px;
}
.upload-icon {
margin: 16px;
}
.divider{
font-size:12px;color:rgb(189, 189, 189);
}
:deep(.ant-upload-wrapper .ant-upload-list.ant-upload-list-picture-card .ant-upload-list-item){
position: relative;
height: 240px !important;
padding: 8px;
border: 0px solid #d9d9d9;
border-radius: 4px;
text-align: center;
background: #f1f7ff;
display: flex;
justify-content: center;
flex-direction: column;
}
:deep(.ant-upload-wrapper .ant-upload-list.ant-upload-list-picture-card .ant-upload-list-item .ant-upload-list-item-thumbnail){
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
width: 200px !important;
height: 200px !important;
line-height: 60px;
text-align: center;
flex: none;
}
:deep(.ant-upload-wrapper .ant-upload-list .ant-upload-list-item .ant-upload-list-item-name) {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
line-height: 1.5714285714285714;
transition: all 0.3s;
margin-top: -20px;
}
</style>

View File

@ -0,0 +1,583 @@
<template>
<div ref="containerRef" :class="`${prefixCls}-container`">
<a-upload-dragger
accept="audio/mp3"
:headers="headers"
:multiple="multiple"
:action="uploadUrl"
:fileList="fileList"
:disabled="disabled"
v-bind="bindProps"
:beforeUpload="beforeUpload"
:showUploadList="false"
@remove="onRemove"
@change="onFileChange"
@preview="onFilePreview"
>
<template v-if="isImageMode">
<div v-if="!isMaxCount">
<Icon icon="ant-design:plus-outlined" />
<div class="ant-upload-text">{{ text }}123</div>
</div>
</template>
<div class="upload-area" style="padding: 20px;" v-else-if="uploadVisible" :disabled="buttonDisabled">
<p class="upload-text">点击或者拖拽上传</p>
<p class="upload-hint">
<div class="upload-icon">
<img src="../../../../../../assets/upload/mp3.png" style="width: 40px; height: 40px;" />
</div>
<span class="divider">文件大小不超过10MB</span>
<span class="divider">|</span>
<a-tooltip placement="top">
<template #title>
这里是格式说明的具体内容
</template>
<span class="divider">
<QuestionCircleOutlined style="margin-right: 0px;" />
格式说明
</span>
</a-tooltip>
</p>
</div>
</a-upload-dragger>
<!-- 文件回显 -->
<div class="custom-upload-list" v-if="fileList.length > 0">
<div v-for="(file, index) in fileList" :key="file.uid" >
<div style="margin-top: 20px;">
<audio ref="audioPlayer" controls :src="file.url"></audio>
</div>
<div style="margin-top: 20px;">
{{ file.name }}
</div>
<div style="margin-top: 20px;" v-if="!props.disabled">
<a-button type="link" danger @click="removeFile(index)">删除</a-button>
</div>
</div>
</div>
</div>
</template>
<script lang="ts" setup>
import { ref, reactive, computed, watch, nextTick, createApp,unref } from 'vue';
import { Icon } from '/@/components/Icon';
import { getToken } from '/@/utils/auth';
import { uploadUrl } from '/@/api/common/api';
import { propTypes } from '/@/utils/propTypes';
import { useMessage } from '/@/hooks/web/useMessage';
import { createImgPreview } from '/@/components/Preview/index';
import { useAttrs } from '/@/hooks/core/useAttrs';
import { useDesign } from '/@/hooks/web/useDesign';
import { UploadTypeEnum } from './upload.data';
import { getFileAccessHttpUrl, getHeaders } from '/@/utils/common/compUtils';
import UploadItemActions from './components/UploadItemActions.vue';
import { InboxOutlined } from '@ant-design/icons-vue';
const { createMessage, createConfirm } = useMessage();
const { prefixCls } = useDesign('j-upload');
const attrs = useAttrs();
const emit = defineEmits(['change', 'update:value']);
const props = defineProps({
value: propTypes.oneOfType([propTypes.string, propTypes.array]),
text: propTypes.string.def('上传'),
fileType: propTypes.string.def(UploadTypeEnum.all),
/*这个属性用于控制文件上传的业务路径*/
bizPath: propTypes.string.def('temp'),
/**
* 是否返回url
* true仅返回url
* false返回fileName filePath fileSize
*/
returnUrl: propTypes.bool.def(true),
//
maxCount: propTypes.number.def(0),
buttonVisible: propTypes.bool.def(true),
multiple: propTypes.bool.def(true),
//
mover: propTypes.bool.def(true),
//
download: propTypes.bool.def(true),
//
removeConfirm: propTypes.bool.def(false),
beforeUpload: propTypes.func,
disabled: propTypes.bool.def(false),
//
replaceLastOne: propTypes.bool.def(false),
});
const headers = getHeaders();
const fileList = ref<any[]>([]);
const uploadGoOn = ref<boolean>(true);
// refs
const containerRef = ref();
//
const isMaxCount = computed(() => props.maxCount > 0 && fileList.value.length >= props.maxCount);
//
const isImageMode = computed(() => props.fileType === UploadTypeEnum.image);
//
const buttonDisabled = computed(()=>{
if(props.disabled === true){
return true;
}
if(isMaxCount.value === true){
if(props.replaceLastOne === true){
return false
}else{
return true;
}
}
return false
});
// props attrs
const bindProps = computed(() => {
//update-begin-author:liusq date:20220411 for: [issue/455]accept
const bind: any = Object.assign({}, props, unref(attrs));
//update-end-author:liusq date:20220411 for: [issue/455]accept
bind.name = 'file';
bind.listType = isImageMode.value ? 'picture-card' : 'text';
bind.class = [bind.class, { 'upload-disabled': props.disabled }];
bind.data = { biz: props.bizPath, ...bind.data };
//update-begin-author:taoyan date:20220407 for: beforeUpload return false
if (!bind.beforeUpload) {
bind.beforeUpload = onBeforeUpload;
}
//update-end-author:taoyan date:20220407 for: beforeUpload return false
//
if (isImageMode.value && !bind.accept) {
bind.accept = 'image/*';
}
return bind;
});
function removeFile(index) {
fileList.value.splice(index, 1);
}
watch(
() => props.value,
(val) => {
if (Array.isArray(val)) {
if (props.returnUrl) {
parsePathsValue(val.join(','));
} else {
parseArrayValue(val);
}
} else {
//update-begin---author:liusq ---date:20230914 for[issues/5327]UploadreturnUrlfalse'[object Object]' ------------
if (props.returnUrl) {
parsePathsValue(val);
} else {
val && parseArrayValue(JSON.parse(val));
}
//update-end---author:liusq ---date:20230914 for[issues/5327]UploadreturnUrlfalse'[object Object]' ------------
}
},
{ immediate: true }
);
watch(fileList, () => nextTick(() => addActionsListener()), { immediate: true });
const antUploadItemCls = 'ant-upload-list-item';
// Listener
function addActionsListener() {
if (!isImageMode.value) {
return;
}
const uploadItems = containerRef.value ? containerRef.value.getElementsByClassName(antUploadItemCls) : null;
if (!uploadItems || uploadItems.length === 0) {
return;
}
for (const uploadItem of uploadItems) {
let hasActions = uploadItem.getAttribute('data-has-actions') === 'true';
if (!hasActions) {
uploadItem.addEventListener('mouseover', onAddActionsButton);
}
}
}
//
function onAddActionsButton(event) {
const getUploadItem = () => {
for (const path of event.path) {
if (path.classList.contains(antUploadItemCls)) {
return path;
} else if (path.classList.contains(`${prefixCls}-container`)) {
return null;
}
}
return null;
};
const uploadItem = getUploadItem();
if (!uploadItem) {
return;
}
const actions = uploadItem.getElementsByClassName('ant-upload-list-item-actions');
if (!actions || actions.length === 0) {
return;
}
//
const div = document.createElement('div');
div.className = 'upload-actions-container';
createApp(UploadItemActions, {
element: uploadItem,
fileList: fileList,
mover: props.mover,
download: props.download,
emitValue: emitValue,
}).mount(div);
actions[0].appendChild(div);
uploadItem.setAttribute('data-has-actions', 'true');
uploadItem.removeEventListener('mouseover', onAddActionsButton);
}
//
function parsePathsValue(paths) {
if (!paths || paths.length == 0) {
fileList.value = [];
return;
}
let list: any[] = [];
for (const item of paths.split(',')) {
let url = getFileAccessHttpUrl(item);
list.push({
uid: uidGenerator(),
name: getFileName(item),
status: 'done',
url: url,
response: { status: 'history', message: item },
});
}
fileList.value = list;
}
//
function parseArrayValue(array) {
if (!array || array.length == 0) {
fileList.value = [];
return;
}
let list: any[] = [];
for (const item of array) {
let url = getFileAccessHttpUrl(item.filePath);
list.push({
uid: uidGenerator(),
name: item.fileName,
url: url,
status: 'done',
response: { status: 'history', message: item.filePath },
});
}
fileList.value = list;
}
/**
* 上传前校验
*/
function beforeUpload(file) {
let fileType = file.type;
console.log("🚀 ~ beforeUpload ~ fileType:", fileType)
if (fileType.indexOf('audio') < 0) {
createMessage.info('请上传MP3文件');
fileList.value = [];
return false;
}
}
//
function onBeforeUpload(file) {
uploadGoOn.value = true;
if (isImageMode.value) {
if (file.type.indexOf('image') < 0) {
createMessage.warning('请上传图片');
uploadGoOn.value = false;
return false;
}
}
// beforeUpload
if (typeof props.beforeUpload === 'function') {
return props.beforeUpload(file);
}
return true;
}
//
function onRemove() {
if (props.removeConfirm) {
return new Promise((resolve) => {
createConfirm({
title: '删除',
content: `确定要删除这${isImageMode.value ? '张图片' : '个文件'}吗?`,
iconType: 'warning',
onOk: () => resolve(true),
onCancel: () => resolve(false),
});
});
}
return true;
}
// uploadchange
function onFileChange(info) {
console.log("🚀 ~ onFileChange ~ info:", info.file)
var file = info.file;
let fileType = file.type;
if (fileType.indexOf('audio') < 0) {
fileList.value = [];
return false;
}
if (!info.file.status && uploadGoOn.value === false) {
info.fileList.pop();
}
let fileListTemp = info.fileList;
//
if (props.maxCount > 0) {
let count = fileListTemp.length;
if (count >= props.maxCount) {
let diffNum = props.maxCount - fileListTemp.length;
if (diffNum >= 0) {
fileListTemp = fileListTemp.slice(-props.maxCount);
} else {
return;
}
}
}
if (info.file.status === 'done') {
let successFileList = [];
if (info.file.response.success) {
successFileList = fileListTemp.map((file) => {
if (file.response) {
let reUrl = file.response.message;
file.url = getFileAccessHttpUrl(reUrl);
}
return file;
});
}else{
successFileList = fileListTemp.filter(item=>{
return item.uid!=info.file.uid;
});
createMessage.error(`${info.file.name} 上传失败.`);
}
fileListTemp = successFileList;
} else if (info.file.status === 'error') {
createMessage.error(`${info.file.name} 上传失败.`);
}
// update-begin--author:liaozhiyang---date:20240628---forissues/1273JUploadbeforeUpload
// beforeUpload falsestatus
info.file.status && (fileList.value = fileListTemp);
// update-end--author:liaozhiyang---date:20240628---forissues/1273JUploadbeforeUpload
if (info.file.status === 'done' || info.file.status === 'removed') {
//returnUrltrue
if (props.returnUrl) {
handlePathChange();
} else {
//returnUrlfalse
let newFileList: any[] = [];
for (const item of fileListTemp) {
if (item.status === 'done') {
let fileJson = {
fileName: item.name,
filePath: item.response.message,
fileSize: item.size,
};
newFileList.push(fileJson);
}else{
return;
}
}
//update-begin---author:liusq ---date:20230914 for[issues/5327]UploadreturnUrlfalse'[object Object]' ------------
emitValue(JSON.stringify(newFileList));
//update-end---author:liusq ---date:20230914 for[issues/5327]UploadreturnUrlfalse'[object Object]' ------------
}
}
}
function handlePathChange() {
let uploadFiles = fileList.value;
let path = '';
if (!uploadFiles || uploadFiles.length == 0) {
path = '';
}
let pathList: string[] = [];
for (const item of uploadFiles) {
if (item.status === 'done') {
pathList.push(item.response.message);
} else {
return;
}
}
if (pathList.length > 0) {
path = pathList.join(',');
}
emitValue(path);
}
//
function onFilePreview(file) {
if (isImageMode.value) {
createImgPreview({ imageList: [file.url], maskClosable: true });
} else {
window.open(file.url);
}
}
function emitValue(value) {
emit('change', value);
emit('update:value', value);
}
function uidGenerator() {
return '-' + parseInt(Math.random() * 10000 + 1, 10);
}
function getFileName(path) {
if (path.lastIndexOf('\\') >= 0) {
let reg = new RegExp('\\\\', 'g');
path = path.replace(reg, '/');
}
return path.substring(path.lastIndexOf('/') + 1);
}
//
const uploadVisible = computed(() => {
if (props['maxCount'] === 0) {
return true;
}
return fileList.value.length < props['maxCount'];
});
defineExpose({
addActionsListener,
});
</script>
<style lang="less">
//noinspection LessUnresolvedVariable
@prefix-cls: ~'@{namespace}-j-upload';
.@{prefix-cls} {
&-container {
position: relative;
.upload-disabled {
.ant-upload-list-item {
.anticon-close {
display: none;
}
.anticon-delete {
display: none;
}
}
/* update-begin-author:taoyan date:2022-5-24 for:VUEN-1093详情界面 图片下载按钮显示不全*/
.upload-download-handler {
right: 6px !important;
}
/* update-end-author:taoyan date:2022-5-24 for:VUEN-1093详情界面 图片下载按钮显示不全*/
}
.ant-upload-text-icon {
color: @primary-color;
}
.ant-upload-list-item {
.upload-actions-container {
position: absolute;
top: -31px;
left: -18px;
z-index: 11;
width: 84px;
height: 84px;
line-height: 28px;
text-align: center;
pointer-events: none;
a {
opacity: 0.9;
margin: 0 5px;
cursor: pointer;
transition: opacity 0.3s;
.anticon {
color: #fff;
font-size: 16px;
}
&:hover {
opacity: 1;
}
}
.upload-mover-handler,
.upload-download-handler {
position: absolute;
pointer-events: auto;
}
.upload-mover-handler {
width: 100%;
bottom: 0;
}
.upload-download-handler {
top: -4px;
right: -4px;
}
}
}
}
}
.ant-upload-wrapper .ant-upload-drag .ant-upload {
padding: 0px !important;
}
.ant-upload-drag {
border: 0px !important;
}
.upload-text {
font-size: 16px;
color: rgba(74, 69, 69, 0.85);
margin-bottom: 8px;
}
.upload-icon {
margin: 16px;
}
.divider{
font-size:12px;color:rgb(189, 189, 189);
}
:deep(.ant-upload-wrapper .ant-upload-list.ant-upload-list-picture-card .ant-upload-list-item){
position: relative;
height: 240px !important;
padding: 8px;
border: 1px solid #d9d9d9;
border-radius: 4px;
text-align: center;
background: #f1f7ff;
display: flex;
justify-content: center;
flex-direction: column;
}
:deep(.ant-upload-wrapper .ant-upload-list.ant-upload-list-picture-card .ant-upload-list-item .ant-upload-list-item-thumbnail){
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
width: 200px !important;
height: 200px !important;
line-height: 60px;
text-align: center;
flex: none;
}
:deep(.ant-upload-wrapper .ant-upload-list .ant-upload-list-item .ant-upload-list-item-name) {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
line-height: 1.5714285714285714;
transition: all 0.3s;
margin-top: -20px;
}
.custom-upload-list {
border: 0px dashed #d9d9d9;
border-radius: 6px;
padding: 10px;
background: #f1f7ff;
text-align: center;
}
</style>

View File

@ -0,0 +1,593 @@
<template>
<div ref="containerRef" :class="`${prefixCls}-container`">
<a-upload-dragger
accept="video/mp4"
:headers="headers"
:multiple="multiple"
:action="uploadUrl"
:fileList="fileList"
:disabled="disabled"
v-bind="bindProps"
:beforeUpload="beforeUpload"
:showUploadList="false"
@remove="onRemove"
@change="onFileChange"
@preview="onFilePreview"
>
<template v-if="isImageMode">
<div v-if="!isMaxCount">
<Icon icon="ant-design:plus-outlined" />
<div class="ant-upload-text">{{ text }}123</div>
</div>
</template>
<div class="upload-area" style="padding: 20px;" v-else-if="uploadVisible" :disabled="buttonDisabled">
<p class="upload-text">点击或者拖拽上传</p>
<p class="upload-hint">
<div class="upload-icon">
<img src="../../../../../../assets/upload/mp4.png" style="width: 40px; height: 40px;" />
</div>
<span class="divider">文件大小不超过10MB</span>
<span class="divider">|</span>
<a-tooltip placement="top">
<template #title>
这里是格式说明的具体内容
</template>
<span class="divider">
<QuestionCircleOutlined style="margin-right: 0px;" />
格式说明
</span>
</a-tooltip>
</p>
</div>
</a-upload-dragger>
<!-- 文件回显 -->
<div class="custom-upload-list" v-if="fileList.length > 0">
<div v-for="(file, index) in fileList" :key="file.uid" >
<div style="margin-top: 20px;">
<video controls style="max-width: 100%; max-height: 300px;">
<source :src="transUrl(file.url)" type="video/mp4">
您的浏览器不支持视频播放
</video>
</div>
<div style="margin-top: 20px;">
{{ file.name }}
</div>
<div style="margin-top: 20px;" v-if="!props.disabled">
<a-button type="link" danger @click="removeFile(index)">删除</a-button>
</div>
</div>
</div>
</div>
</template>
<script lang="ts" setup>
import { ref, reactive, computed, watch, nextTick, createApp,unref } from 'vue';
import { Icon } from '/@/components/Icon';
import { getToken } from '/@/utils/auth';
import { uploadUrl } from '/@/api/common/api';
import { propTypes } from '/@/utils/propTypes';
import { useMessage } from '/@/hooks/web/useMessage';
import { createImgPreview } from '/@/components/Preview/index';
import { useAttrs } from '/@/hooks/core/useAttrs';
import { useDesign } from '/@/hooks/web/useDesign';
import { UploadTypeEnum } from './upload.data';
import { getFileAccessHttpUrl, getHeaders } from '/@/utils/common/compUtils';
import UploadItemActions from './components/UploadItemActions.vue';
import { InboxOutlined } from '@ant-design/icons-vue';
const { createMessage, createConfirm } = useMessage();
const { prefixCls } = useDesign('j-upload');
const attrs = useAttrs();
const emit = defineEmits(['change', 'update:value']);
const props = defineProps({
value: propTypes.oneOfType([propTypes.string, propTypes.array]),
text: propTypes.string.def('上传'),
fileType: propTypes.string.def(UploadTypeEnum.all),
/*这个属性用于控制文件上传的业务路径*/
bizPath: propTypes.string.def('temp'),
/**
* 是否返回url
* true仅返回url
* false返回fileName filePath fileSize
*/
returnUrl: propTypes.bool.def(true),
//
maxCount: propTypes.number.def(0),
buttonVisible: propTypes.bool.def(true),
multiple: propTypes.bool.def(true),
//
mover: propTypes.bool.def(true),
//
download: propTypes.bool.def(true),
//
removeConfirm: propTypes.bool.def(false),
beforeUpload: propTypes.func,
disabled: propTypes.bool.def(false),
//
replaceLastOne: propTypes.bool.def(false),
});
const headers = getHeaders();
const fileList = ref<any[]>([]);
const uploadGoOn = ref<boolean>(true);
// refs
const containerRef = ref();
//
const isMaxCount = computed(() => props.maxCount > 0 && fileList.value.length >= props.maxCount);
//
const isImageMode = computed(() => props.fileType === UploadTypeEnum.image);
//
const buttonDisabled = computed(()=>{
if(props.disabled === true){
return true;
}
if(isMaxCount.value === true){
if(props.replaceLastOne === true){
return false
}else{
return true;
}
}
return false
});
// props attrs
const bindProps = computed(() => {
//update-begin-author:liusq date:20220411 for: [issue/455]accept
const bind: any = Object.assign({}, props, unref(attrs));
//update-end-author:liusq date:20220411 for: [issue/455]accept
bind.name = 'file';
bind.listType = isImageMode.value ? 'picture-card' : 'text';
bind.class = [bind.class, { 'upload-disabled': props.disabled }];
bind.data = { biz: props.bizPath, ...bind.data };
//update-begin-author:taoyan date:20220407 for: beforeUpload return false
if (!bind.beforeUpload) {
bind.beforeUpload = onBeforeUpload;
}
//update-end-author:taoyan date:20220407 for: beforeUpload return false
//
if (isImageMode.value && !bind.accept) {
bind.accept = 'image/*';
}
return bind;
});
function removeFile(index) {
fileList.value.splice(index, 1);
}
watch(
() => props.value,
(val) => {
if (Array.isArray(val)) {
if (props.returnUrl) {
parsePathsValue(val.join(','));
} else {
parseArrayValue(val);
}
} else {
//update-begin---author:liusq ---date:20230914 for[issues/5327]UploadreturnUrlfalse'[object Object]' ------------
if (props.returnUrl) {
parsePathsValue(val);
} else {
val && parseArrayValue(JSON.parse(val));
}
//update-end---author:liusq ---date:20230914 for[issues/5327]UploadreturnUrlfalse'[object Object]' ------------
}
},
{ immediate: true }
);
watch(fileList, () => nextTick(() => addActionsListener()), { immediate: true });
const antUploadItemCls = 'ant-upload-list-item';
// Listener
function addActionsListener() {
if (!isImageMode.value) {
return;
}
const uploadItems = containerRef.value ? containerRef.value.getElementsByClassName(antUploadItemCls) : null;
if (!uploadItems || uploadItems.length === 0) {
return;
}
for (const uploadItem of uploadItems) {
let hasActions = uploadItem.getAttribute('data-has-actions') === 'true';
if (!hasActions) {
uploadItem.addEventListener('mouseover', onAddActionsButton);
}
}
}
/**
* 上传前校验
*/
function beforeUpload(file) {
let fileType = file.type;
console.log("🚀 ~ beforeUpload ~ fileType:", fileType)
if (fileType.indexOf('video') < 0) {
createMessage.info('请上传MP4文件');
fileList.value = [];
return false;
}
}
//
function onAddActionsButton(event) {
const getUploadItem = () => {
for (const path of event.path) {
if (path.classList.contains(antUploadItemCls)) {
return path;
} else if (path.classList.contains(`${prefixCls}-container`)) {
return null;
}
}
return null;
};
const uploadItem = getUploadItem();
if (!uploadItem) {
return;
}
const actions = uploadItem.getElementsByClassName('ant-upload-list-item-actions');
if (!actions || actions.length === 0) {
return;
}
//
const div = document.createElement('div');
div.className = 'upload-actions-container';
createApp(UploadItemActions, {
element: uploadItem,
fileList: fileList,
mover: props.mover,
download: props.download,
emitValue: emitValue,
}).mount(div);
actions[0].appendChild(div);
uploadItem.setAttribute('data-has-actions', 'true');
uploadItem.removeEventListener('mouseover', onAddActionsButton);
}
//
function parsePathsValue(paths) {
if (!paths || paths.length == 0) {
fileList.value = [];
return;
}
let list: any[] = [];
for (const item of paths.split(',')) {
let url = getFileAccessHttpUrl(item);
list.push({
uid: uidGenerator(),
name: getFileName(item),
status: 'done',
url: url,
response: { status: 'history', message: item },
});
}
fileList.value = list;
}
function transUrl(record) {
console.log("🚀 ~ transUrl ~ record:", record)
if (record == 'local') {
return getFileAccessHttpUrl(record)
} else {
return record
}
}
//
function parseArrayValue(array) {
if (!array || array.length == 0) {
fileList.value = [];
return;
}
let list: any[] = [];
for (const item of array) {
let url = getFileAccessHttpUrl(item.filePath);
list.push({
uid: uidGenerator(),
name: item.fileName,
url: url,
status: 'done',
response: { status: 'history', message: item.filePath },
});
}
fileList.value = list;
}
//
function onBeforeUpload(file) {
uploadGoOn.value = true;
if (isImageMode.value) {
if (file.type.indexOf('image') < 0) {
createMessage.warning('请上传图片');
uploadGoOn.value = false;
return false;
}
}
// beforeUpload
if (typeof props.beforeUpload === 'function') {
return props.beforeUpload(file);
}
return true;
}
//
function onRemove() {
if (props.removeConfirm) {
return new Promise((resolve) => {
createConfirm({
title: '删除',
content: `确定要删除这${isImageMode.value ? '张图片' : '个文件'}吗?`,
iconType: 'warning',
onOk: () => resolve(true),
onCancel: () => resolve(false),
});
});
}
return true;
}
// uploadchange
function onFileChange(info) {
var file = info.file;
let fileType = file.type;
if (fileType.indexOf('video') < 0) {
fileList.value = [];
return false;
}
if (!info.file.status && uploadGoOn.value === false) {
info.fileList.pop();
}
let fileListTemp = info.fileList;
//
if (props.maxCount > 0) {
let count = fileListTemp.length;
if (count >= props.maxCount) {
let diffNum = props.maxCount - fileListTemp.length;
if (diffNum >= 0) {
fileListTemp = fileListTemp.slice(-props.maxCount);
} else {
return;
}
}
}
if (info.file.status === 'done') {
let successFileList = [];
if (info.file.response.success) {
successFileList = fileListTemp.map((file) => {
if (file.response) {
let reUrl = file.response.message;
file.url = getFileAccessHttpUrl(reUrl);
}
return file;
});
}else{
successFileList = fileListTemp.filter(item=>{
return item.uid!=info.file.uid;
});
createMessage.error(`${info.file.name} 上传失败.`);
}
fileListTemp = successFileList;
} else if (info.file.status === 'error') {
createMessage.error(`${info.file.name} 上传失败.`);
}
// update-begin--author:liaozhiyang---date:20240628---forissues/1273JUploadbeforeUpload
// beforeUpload falsestatus
info.file.status && (fileList.value = fileListTemp);
// update-end--author:liaozhiyang---date:20240628---forissues/1273JUploadbeforeUpload
if (info.file.status === 'done' || info.file.status === 'removed') {
//returnUrltrue
if (props.returnUrl) {
handlePathChange();
} else {
//returnUrlfalse
let newFileList: any[] = [];
for (const item of fileListTemp) {
if (item.status === 'done') {
let fileJson = {
fileName: item.name,
filePath: item.response.message,
fileSize: item.size,
};
newFileList.push(fileJson);
}else{
return;
}
}
//update-begin---author:liusq ---date:20230914 for[issues/5327]UploadreturnUrlfalse'[object Object]' ------------
emitValue(JSON.stringify(newFileList));
//update-end---author:liusq ---date:20230914 for[issues/5327]UploadreturnUrlfalse'[object Object]' ------------
}
}
}
function handlePathChange() {
let uploadFiles = fileList.value;
let path = '';
if (!uploadFiles || uploadFiles.length == 0) {
path = '';
}
let pathList: string[] = [];
for (const item of uploadFiles) {
if (item.status === 'done') {
pathList.push(item.response.message);
} else {
return;
}
}
if (pathList.length > 0) {
path = pathList.join(',');
}
emitValue(path);
}
//
function onFilePreview(file) {
if (isImageMode.value) {
createImgPreview({ imageList: [file.url], maskClosable: true });
} else {
window.open(file.url);
}
}
function emitValue(value) {
emit('change', value);
emit('update:value', value);
}
function uidGenerator() {
return '-' + parseInt(Math.random() * 10000 + 1, 10);
}
function getFileName(path) {
if (path.lastIndexOf('\\') >= 0) {
let reg = new RegExp('\\\\', 'g');
path = path.replace(reg, '/');
}
return path.substring(path.lastIndexOf('/') + 1);
}
//
const uploadVisible = computed(() => {
if (props['maxCount'] === 0) {
return true;
}
return fileList.value.length < props['maxCount'];
});
defineExpose({
addActionsListener,
});
</script>
<style lang="less">
//noinspection LessUnresolvedVariable
@prefix-cls: ~'@{namespace}-j-upload';
.@{prefix-cls} {
&-container {
position: relative;
.upload-disabled {
.ant-upload-list-item {
.anticon-close {
display: none;
}
.anticon-delete {
display: none;
}
}
/* update-begin-author:taoyan date:2022-5-24 for:VUEN-1093详情界面 图片下载按钮显示不全*/
.upload-download-handler {
right: 6px !important;
}
/* update-end-author:taoyan date:2022-5-24 for:VUEN-1093详情界面 图片下载按钮显示不全*/
}
.ant-upload-text-icon {
color: @primary-color;
}
.ant-upload-list-item {
.upload-actions-container {
position: absolute;
top: -31px;
left: -18px;
z-index: 11;
width: 84px;
height: 84px;
line-height: 28px;
text-align: center;
pointer-events: none;
a {
opacity: 0.9;
margin: 0 5px;
cursor: pointer;
transition: opacity 0.3s;
.anticon {
color: #fff;
font-size: 16px;
}
&:hover {
opacity: 1;
}
}
.upload-mover-handler,
.upload-download-handler {
position: absolute;
pointer-events: auto;
}
.upload-mover-handler {
width: 100%;
bottom: 0;
}
.upload-download-handler {
top: -4px;
right: -4px;
}
}
}
}
}
.ant-upload-wrapper .ant-upload-drag .ant-upload {
padding: 0px !important;
}
.ant-upload-drag {
border: 0px !important;
}
.upload-text {
font-size: 16px;
color: rgba(74, 69, 69, 0.85);
margin-bottom: 8px;
}
.upload-icon {
margin: 16px;
}
.divider{
font-size:12px;color:rgb(189, 189, 189);
}
:deep(.ant-upload-wrapper .ant-upload-list.ant-upload-list-picture-card .ant-upload-list-item){
position: relative;
height: 240px !important;
padding: 8px;
border: 1px solid #d9d9d9;
border-radius: 4px;
text-align: center;
background: #f1f7ff;
display: flex;
justify-content: center;
flex-direction: column;
}
:deep(.ant-upload-wrapper .ant-upload-list.ant-upload-list-picture-card .ant-upload-list-item .ant-upload-list-item-thumbnail){
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
width: 200px !important;
height: 200px !important;
line-height: 60px;
text-align: center;
flex: none;
}
:deep(.ant-upload-wrapper .ant-upload-list .ant-upload-list-item .ant-upload-list-item-name) {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
line-height: 1.5714285714285714;
transition: all 0.3s;
margin-top: -20px;
}
.custom-upload-list {
border: 0px dashed #d9d9d9;
border-radius: 6px;
padding: 10px;
background: #f1f7ff;
text-align: center;
}
</style>

View File

@ -35,7 +35,7 @@
</JFormContainer>
</div>
<div style="padding: 14px;background-color: #fff;border-radius: 10px;box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);">
<JFormContainer :disabled="disabled">
<JFormContainer >
<template #detail>
<a-form ref="formRef" class="antd-modal-form" :labelCol="labelCol" :wrapperCol="wrapperCol" :colon="false"
name="ConfigService2DirectiveForm" style="padding: 20px 0px;">
@ -75,7 +75,7 @@
<a-form-item label="收费价格(元)" v-bind="validateInfos.tollPrice" id="ConfigServiceDirectiveForm-tollPrice"
name="tollPrice">
<a-input-number v-model:value="formData.tollPrice" placeholder="请输入收费价格" style="width: 100%" :min="0"
:max="99999.99" :precision="2" @keydown="onPriceKeydown" />
:max="99999.99" :precision="2" @keydown="onPriceKeydown" :disabled="disabled" />
</a-form-item>
</a-col>
<a-col :span="12">
@ -89,21 +89,21 @@
<a-form-item label="提成价格(元)" v-bind="validateInfos.comPrice" id="ConfigServiceDirectiveForm-comPrice"
name="comPrice">
<a-input-number v-model:value="formData.comPrice" placeholder="请输入提成价格" style="width: 100%" :min="0"
:max="99999.99" :precision="2" @keydown="onPriceKeydown" />
:max="99999.99" :precision="2" @keydown="onPriceKeydown" :disabled="disabled" />
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="是否启用" v-bind="validateInfos.izEnabled" id="ConfigServiceDirectiveForm-izEnabled"
name="izEnabled">
<j-dict-select-tag type='radio' v-model:value="formData.izEnabled" dictCode="iz_enabled"
placeholder="请选择是否启用"  allowClear />
placeholder="请选择是否启用"  allowClear :disabled="disabled"/>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="服务时长" v-bind="validateInfos.serviceDuration"
id="ConfigServiceDirectiveForm-serviceDuration" name="serviceDuration">
<a-input-number v-model:value="formData.serviceDuration" :min="5" :max="55" :step="5" addon-after="分钟"
placeholder="请输入服务时长(分钟)" allow-clear @keydown="onDurationKeydown" />
placeholder="请输入服务时长(分钟)" allow-clear @keydown="onDurationKeydown" :disabled="disabled" />
</a-form-item>
</a-col>
</a-row>
@ -115,124 +115,19 @@
</a-row>
<a-row style="padding: 0px 20px;">
<a-col :span="24" v-show="directiveMediaBtnValue == 0">
<a-upload-dragger name="file" v-model:fileList="fileList" :multiple="false" :show-upload-list="false"
:before-upload="beforeUpload" style="background-color: #F6FAFF;">
<div class="upload-area">
<p class="upload-text">点击或者拖拽上传</p>
<div class="upload-icon">
<img src="./pictype.png" alt="MP3 icon" style="width: 40px; height: 40px;" />
</div>
<p class="upload-hint">
<span>文件大小不超过10MB</span>
<span class="divider">|</span>
<a-tooltip placement="top">
<template #title>
这里是格式说明的具体内容
</template>
<span>
<QuestionCircleOutlined style="margin-right: 0px;" />
格式说明
</span>
</a-tooltip>
</p>
</div>
</a-upload-dragger>
<JImageUploadtz v-model:value="formData.previewFile" maxCount="1" :disabled="disabled"/>
</a-col>
<a-col :span="24" v-show="directiveMediaBtnValue == 1">
<a-upload-dragger name="file" v-model:fileList="fileList" :multiple="false" :show-upload-list="false"
:before-upload="beforeUpload" style="background-color: #F6FAFF;">
<div class="upload-area">
<p class="upload-text">点击或者拖拽上传</p>
<div class="upload-icon">
<img src="./pictype.png" alt="MP3 icon" style="width: 40px; height: 40px;" />
</div>
<p class="upload-hint">
<span>文件大小不超过10MB</span>
<span class="divider">|</span>
<a-tooltip placement="top">
<template #title>
这里是格式说明的具体内容
</template>
<span>
<QuestionCircleOutlined style="margin-right: 0px;" />
格式说明
</span>
</a-tooltip>
</p>
</div>
</a-upload-dragger>
<JImageUploadtz v-model:value="formData.previewFileSmall" maxCount="1" :disabled="disabled"/>
</a-col>
<a-col :span="24" v-show="directiveMediaBtnValue == 2">
<a-upload-dragger name="file" v-model:fileList="fileList" :multiple="false" :show-upload-list="false"
:before-upload="beforeUpload" style="background-color: #F6FAFF;">
<div class="upload-area">
<p class="upload-text">点击或者拖拽上传</p>
<div class="upload-icon">
<img src="./mp3type.png" alt="MP3 icon" style="width: 40px; height: 40px;" />
</div>
<p class="upload-hint">
<span>文件大小不超过10MB</span>
<span class="divider">|</span>
<a-tooltip placement="top">
<template #title>
这里是格式说明的具体内容
</template>
<span>
<QuestionCircleOutlined style="margin-right: 0px;" />
格式说明
</span>
</a-tooltip>
</p>
</div>
</a-upload-dragger>
<JUploadMP3 v-model:value="formData.mp3File" maxCount="1" :disabled="disabled"/>
</a-col>
<a-col :span="24" v-show="directiveMediaBtnValue == 3">
<a-upload-dragger name="file" v-model:fileList="fileList" :multiple="false" :show-upload-list="false"
:before-upload="beforeUpload" style="background-color: #F6FAFF;">
<div class="upload-area">
<p class="upload-text">点击或者拖拽上传</p>
<div class="upload-icon">
<img src="./mp4type.png" alt="MP3 icon" style="width: 40px; height: 40px;" />
</div>
<p class="upload-hint">
<span>文件大小不超过10MB</span>
<span class="divider">|</span>
<a-tooltip placement="top">
<template #title>
这里是格式说明的具体内容
</template>
<span>
<QuestionCircleOutlined style="margin-right: 0px;" />
格式说明
</span>
</a-tooltip>
</p>
</div>
</a-upload-dragger>
<JUploadMP4 v-model:value="formData.mp4File" maxCount="1" fileType="mp4" :disabled="disabled"/>
</a-col>
<a-col :span="24" v-show="directiveMediaBtnValue == 4">
<a-upload-dragger name="file" v-model:fileList="fileList" :multiple="false" :show-upload-list="false"
:before-upload="beforeUpload" style="background-color: #F6FAFF;">
<div class="upload-area">
<p class="upload-text">点击或者拖拽上传</p>
<div class="upload-icon">
<img src="./pictype.png" alt="MP3 icon" style="width: 40px; height: 40px;" />
</div>
<p class="upload-hint">
<span>文件大小不超过10MB</span>
<span class="divider">|</span>
<a-tooltip placement="top">
<template #title>
这里是格式说明的具体内容
</template>
<span>
<QuestionCircleOutlined style="margin-right: 0px;" />
格式说明
</span>
</a-tooltip>
</p>
</div>
</a-upload-dragger>
<JImageUploadtz v-model:value="formData.immediateFile" maxCount="1" :disabled="disabled"/>
</a-col>
</a-row>
<a-row style="padding: 20px;">
@ -248,7 +143,7 @@
</div>
<div>
<a-textarea v-model:value="formData.serviceContent" placeholder="请输入服务指令描述" :maxlength="200"
:rows="3" :autosize="{ minRows: 3 }" :showCount="true" />
:rows="3" :autosize="{ minRows: 3 }" :showCount="true" :disabled="disabled"/>
</div>
</div>
</div>
@ -267,7 +162,9 @@ import { defHttp } from '/@/utils/http/axios';
import { useMessage } from '/@/hooks/web/useMessage';
import JDictSelectTag from '/@/components/Form/src/jeecg/components/JDictSelectTag.vue';
import { JCheckbox } from '/@/components/Form';
import JUpload from '/@/components/Form/src/jeecg/components/JUpload/JUpload.vue';
import JUploadMP3 from '../../../../components/Form/src/jeecg/components/JUpload/JUploadMP3.vue';
import JUploadMP4 from '../../../../components/Form/src/jeecg/components/JUpload/JUploadMP4.vue';
import JImageUploadtz from '/@/components/Form/src/jeecg/components/JImageUploadtz.vue';
import JImageUpload from '/@/components/Form/src/jeecg/components/JImageUpload.vue';
import { getValueType } from '/@/utils';
import { saveOrUpdate, syncMediaForBiz, syncMediaForAllBiz } from '../ConfigServiceDirective.api';
@ -278,6 +175,7 @@ import { env } from 'process';
import DirectiveRadioCom from './DirectiveRadioCom.vue'
import { QuestionCircleOutlined } from '@ant-design/icons-vue';
import { DownOutlined } from '@ant-design/icons-vue';
import { uploadUrl } from '/@/api/common/api';
const showDescription = ref(false);
@ -376,6 +274,7 @@ const formData = reactive<Record<string, any>>({
mp4File: '',
previewFile: '',
immediateFile: '',
previewFileSmall:'',
});
const { createMessage } = useMessage();
const labelCol = ref<any>({ xs: { span: 24 }, sm: { span: 4 } });

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.9 KiB