vr-uniapp/src/components/common/upload/index.vue

708 lines
32 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<!-- 上传组件 -->
<template>
<el-dialog v-model="dialog_visible" class="radius-lg" width="1168" draggable append-to-body>
<template #header>
<div class="title re">
<el-radio-group v-model="upload_type" is-button @change="upload_type_change">
<el-radio-button value="img" :disabled="!(const_upload_type == 'img') && isCheckConfirm">图片</el-radio-button>
<el-radio-button v-if="isIcon" value="icon" :disabled="!isIcon && isCheckConfirm">图标</el-radio-button>
<el-radio-button value="video" :disabled="!(const_upload_type == 'video') && isCheckConfirm">视频</el-radio-button>
<el-radio-button value="file" :disabled="!(const_upload_type == 'file') && isCheckConfirm">文件</el-radio-button>
</el-radio-group>
<div class="middle size-16 fw">附件管理</div>
</div>
</template>
<div class="upload-content pa-20">
<div v-if="upload_type !== 'icon'" class="flex-row gap-40">
<div class="left-content">
<div class="flex-row align-c gap-10 mb-10">
<el-input v-model="search_filter" placeholder="请输入分类名称">
<template #prefix>
<icon name="search" size="18"></icon>
</template>
</el-input>
<icon name="add" size="18" class="c-pointer" @click="add_type"></icon>
</div>
<el-scrollbar height="490px">
<el-tree ref="treeRef" v-loading="tree_loading" class="filter-tree" :data="type_data" node-key="id" highlight-current :props="defaultProps" empty-text="无数据" default-expand-all :filter-node-method="filter_node" @node-click="tree_node_event">
<template #default="{ node, data }">
<div class="custom-tree-node flex-row jc-sb gap-10 align-c w pr-10" :class="data.is_enable == 0 || node.parent.data.is_enable == 0 ? 'disabled bg-red' : ''">
<div class="flex-1 flex-width text-line-1 block">{{ data.name }}</div>
<div v-if="data.id" class="flex-row gap-10 cr-9 category-operate c-pointer">
<el-popover placement="bottom" width="70" trigger="hover">
<template #reference>
<div class="tree-operate-btn">
<icon name="ellipsis" size="14"></icon>
</div>
</template>
<div class="flex-col gap-12 tree-operate">
<div v-if="data.pid == 0" class="flex-row gap-5 c-pointer w item" @click.stop="append_type_event(data)"><icon class="icon" name="add" size="12"></icon>新增</div>
<div class="flex-row gap-5 c-pointer w item" @click.stop="edit_type_event(data)"><icon class="icon" name="edit" size="12"></icon>编辑</div>
<div class="flex-row gap-5 c-pointer w item" @click.stop="remove_type_event(node, data)"><icon class="icon" name="del" size="12"></icon>删除</div>
</div>
</el-popover>
</div>
</div>
</template>
</el-tree>
</el-scrollbar>
</div>
<div class="right-content flex-1 flex-width">
<div class="flex-row jc-sb align-c mb-15">
<div class="right-operate flex-row">
<el-button type="primary" plain @click="upload_model_open">上传{{ upload_type_name }}</el-button>
<el-button @click="mult_del_event">删除{{ upload_type_name }}</el-button>
<!-- <el-cascader :show-all-levels="false" clearable></el-cascader> -->
<div class="right-classify ml-12">
<transform-category :data="type_data_list" :check-img-ids="check_img_ids" :placeholder="upload_type_name + '移动至'" @call-back="transform_category_event"></transform-category>
</div>
</div>
<div class="right-search">
<el-input v-model="search_name" :placeholder="'请输入' + upload_type_name + '名称'" @change="get_attachment_list('1')">
<template #suffix>
<icon name="search" size="18" class="c-pointer" @click="get_attachment_list('1')"></icon>
</template>
</el-input>
</div>
</div>
<div class="img-content pr">
<!-- 574px -->
<el-scrollbar v-loading="img_loading" height="440px">
<div v-if="upload_list.length > 0" class="flex-row flex-wrap align-c gap-y-15 gap-x-10 pa-10">
<div v-for="(item, index) in upload_list" :key="index" class="item" @click="check_img_event(item)">
<el-badge :value="view_list_value.findIndex((i) => i.id === item.id) == -1 ? '' : view_list_value.findIndex((i) => i.id === item.id) + 1" class="badge flex-col gap-5 w" :hidden="view_list_value.findIndex((i) => i.id === item.id) == -1">
<div class="item-content re br-f5 radius">
<template v-if="upload_type == 'video'">
<video :src="item.url" class="w h" @error="handle_error(index)"></video>
<div v-if="item.error == true" class="bg-f5 img flex-row jc-c align-c radius h w abs top-0">
<icon name="video" size="42" color="9"></icon>
</div>
</template>
<template v-else-if="upload_type == 'file'">
<div class="bg-f5 img flex-row jc-c align-c radius h w">
<icon :name="ext_file_name_list_map.filter((ext) => ext.type == item.ext).length > 0 && ext_file_name_list_map.filter((ext) => ext.type == item.ext)[0].type == item.ext ? ext_file_name_list_map.filter((ext) => ext.type == item.ext)[0].icon : 'file'" size="42" color="9"></icon>
</div>
</template>
<template v-else>
<el-image :src="item.url" fit="contain" class="w h">
<template #error>
<div class="bg-f5 img flex-row jc-c align-c radius h w">
<icon name="error-img" size="42" color="9"></icon>
</div>
</template>
</el-image>
</template>
<div class="check-icon fill flex-row jc-c align-c" :class="view_list_value.findIndex((i) => i.id === item.id) !== -1 ? 'active' : ''">
<icon name="true-o" color="f" size="26"></icon>
</div>
<div class="operate">
<div class="operate-content flex-row jc-sa align-c">
<div class="flex-1 tc c-pointer" @click.stop="edit_event(item, index)">
<icon name="edit" class="flex-1" size="14" color="f"></icon>
</div>
<div v-if="upload_type !== 'file'" class="operate-icon flex-1 tc c-pointer" @click.stop="preview_event(item, index)">
<icon name="eye" size="14" color="f"></icon>
</div>
<div class="flex-1 tc c-pointer" @click.stop="del_event(item)">
<icon name="del" size="14" color="f"></icon>
</div>
</div>
</div>
</div>
<div class="text-line-1 name">
<template v-if="edit_index !== -1 && edit_index === index">
<el-input v-model="item.original" type="text" placeholder="请输入内容" size="small" @change="edit_input_change" />
</template>
<template v-else>
<div class="ptb-1 plr-7">
{{ item.original }}
</div>
</template>
</div>
</el-badge>
</div>
</div>
<div v-else>
<no-data height="440px"></no-data>
</div>
</el-scrollbar>
<div v-if="preview_switch_video && upload_type == 'video'">
<div class="middle clickable-area" :class="preview_url ? '' : 'hide'">
<!-- 视频预览 -->
<!-- 自动播放 -->
<video ref="videoPlayer" width="320" height="240" controls autoplay :src="preview_url"></video>
</div>
</div>
<div class="mt-10 flex-row jc-e">
<el-pagination :current-page="page" background :page-size="30" :pager-count="5" layout="prev, pager, next" :total="data_total" @current-change="current_page_change" />
</div>
</div>
</div>
</div>
<div v-else class="icon-container">
<div class="flex jc-e mb-10">
<el-input v-model="search_icon" placeholder="请输入图标名称" class="search-text" clearable></el-input>
</div>
<div class="icon-content">
<el-scrollbar height="492px">
<el-row v-if="icon_list.length > 0">
<el-col v-for="(item, index) in icon_list" :key="item.unicode" :span="4">
<div class="pa-10">
<div class="item plr-10 ptb-20 br-c radius-md tc flex-col gap-10" :class="{ active: index === icon_index }" @click="handle_select_icon(item, index)">
<i :class="`iconfont icon-${item.font_class}`"></i>
<div class="text-line-1 size-14">{{ item.name }}</div>
</div>
</div>
</el-col>
</el-row>
<div v-else>
<no-data height="500px"></no-data>
</div>
</el-scrollbar>
</div>
</div>
</div>
<template v-if="isCheckConfirm" #footer>
<span class="dialog-footer">
<el-button class="plr-28 ptb-10" @click="dialog_visible = false">取消</el-button>
<el-button class="plr-28 ptb-10" type="primary" @click="confirm_event">确定</el-button>
</span>
</template>
</el-dialog>
<template v-if="!isCustomDialog">
<div class="flex-col h">
<div v-if="model_value_upload.length > 0" class="flex-row flex-wrap gap-10 h">
<div v-for="(item, index) in model_value_upload" :key="item.id" :class="'upload-btn upload-btn-style-' + styles + ' ' + (styles == 2 ? 'br-none' : '')" :style="'height:' + upload_size + ';width:' + upload_size + ';'" @click="replace_file_event(index)">
<div class="upload-del-icon" @click.stop="del_upload_event(index)">
<icon name="close-o" color="c" size="14"></icon>
</div>
<template v-if="type == 'video'">
<video :src="item.url" class="w h"></video>
<div v-if="item.error == true" class="bg-f5 img flex-row jc-c align-c radius h w abs top-0">
<icon name="video" :size="Number(size) / 2 + ''" color="9"></icon>
</div>
</template>
<template v-else-if="type == 'file'">
<div class="bg-f5 img flex-row jc-c align-c radius h w">
<icon :name="ext_file_name_list_map.filter((ext) => ext.type == item.type).length > 0 && ext_file_name_list_map.filter((ext) => ext.type == item.type)[0].type == item.type ? ext_file_name_list_map.filter((ext) => ext.type == item.type)[0].icon : 'file'" :size="Number(size) / 2 + ''" color="9"></icon>
</div>
</template>
<template v-else>
<el-image :src="item.url" fit="contain" class="w h">
<template #error>
<div class="bg-f5 img flex-row jc-c align-c radius h w">
<icon name="error-img" :size="Number(size) / 2 + ''" color="9"></icon>
</div>
</template>
</el-image>
</template>
<template v-if="styles == 1">
<div class="upload-btn-bottom-text">替换</div>
</template>
</div>
<div v-if="limit !== model_value_upload.length" :class="'upload-btn upload-btn-style-' + styles" :style="'height:' + upload_size + ';width:' + upload_size + ';'" @click="dialog_visible = true">
<icon name="add" :size="Number(size) / 2 + ''" color="c"></icon>
</div>
</div>
<template v-else>
<div :class="'upload-btn upload-btn-style-' + styles" :style="'height:' + upload_size + ';width:' + upload_size + ';'" @click="dialog_visible = true">
<div v-if="!isEmpty(icon_value)" class="upload-del-icon" @click.stop="del_icon_event">
<icon name="close-o" color="c" size="14"></icon>
</div>
<icon :name="!isEmpty(icon_value) ? icon_value : 'add'" :size="Number(size) / 2 + ''" color="c"></icon>
</div>
</template>
<div v-if="isTips" class="size-12 cr-9">{{ tipsText }}</div>
</div>
</template>
<!-- 图片预览 -->
<el-image-viewer v-if="preview_switch_img && upload_type == 'img'" :z-index="999999" :url-list="[preview_url]" :hide-on-click-modal="true" @close="preview_close"></el-image-viewer>
<upload-model v-model="upload_model_visible" :type="upload_type" :exts="props.type == 'img' ? ext_img_name_list : props.type == 'video' ? ext_video_name_list : ext_file_name_list" @close="close_upload_model"></upload-model>
<form-upload-category v-model="upload_category_model_visible" :value="upload_category_model" :type="upload_category_type" :category-id="upload_category_id" :category-pid="upload_category_pid" @confirm="upload_category_confirm"></form-upload-category>
</template>
<script lang="ts" setup>
import { ext_img_name_list, ext_video_name_list, ext_file_name_list, ext_file_name_list_map } from './index';
import UploadAPI, { Tree } from '@/api/upload';
import { uploadStore } from '@/store';
import { isEmpty } from 'lodash';
import searchIcons from '@/assets/search-icons/iconfont.json';
const upload_store = uploadStore();
const app = getCurrentInstance();
/**
* @description: 图片上传
* @param model_value_upload{uploadList[]} 默认值
* @param visibleDialog{Boolean} 弹窗开启关闭
* @param type{String} 上传类型 默认图片 1.图片(img) 2.视频(video) 3.文件(file)
* @param isCustomDialog{Boolean} 是否自定义弹窗, 配置true后将不会显示上传按钮改为传v-model:visible-dialog=""来开启关闭弹窗,通过@update:v-model=""来获取最新数据
* @param isCheckConfirm{Boolean} 弹窗是否需要操作提交取消按钮
* @param limit{Number} 上传数量限制
* @param isTips{Boolean} 是否显示提示文字
* @param tipsText{String} 提示文字
* @param size{Number|String} 上传图片大小
* @param style{Number} 样式 0.默认样式 1.自定义样式1 2.自定义样式2
* @return {*} update:model_value_upload
*/
const props = defineProps({
type: {
type: String,
default: 'img', // img/video/file
},
isCustomDialog: {
type: Boolean,
default: false,
},
isCheckConfirm: {
type: Boolean,
default: true,
},
limit: {
type: Number,
default: 10,
},
isTips: {
type: Boolean,
default: false,
},
tipsText: {
type: String,
default: '建议尺寸690*240px',
},
size: {
type: [Number, String],
default: 72,
},
styles: {
type: [Number, String],
default: 0,
},
isIcon: {
type: Boolean,
default: false,
},
});
const model_value_upload = defineModel({ type: Array as PropType<uploadList[]>, default: [] });
const view_list_value = ref<uploadList[]>([]);
// 弹窗显示
// const dialog_visible = ref(props.visibleDialog);
const dialog_visible = defineModel('visibleDialog', { type: Boolean, default: false });
watch(
() => dialog_visible.value,
(val) => {
if (val) {
if (val === true) {
upload_type.value = props.type;
// 获取分类
get_tree();
// 获取附件列表
get_attachment_list();
icon_index.value = -1;
}
}
}
);
// 弹窗上传显示
const upload_model_visible = ref(false);
// 上传类型
const upload_type = ref(props.type);
const const_upload_type = props.type;
const upload_size = computed(() => {
const size = props.size.toString();
return size.includes('%') ? size : size + 'px';
});
// 上传类型转换成name
const upload_type_name = computed(() => {
switch (upload_type.value) {
case 'video':
return '视频';
case 'file':
return '文件';
default:
return '图片';
}
});
// 切换图片/视频/文件
const upload_type_change = (type: any) => {
if (type == 'icon') return false;
view_list_value.value = [];
get_attachment_list();
};
// 打开上传弹窗
const upload_model_open = () => {
upload_model_visible.value = true;
};
//#region 分类 ----------------------------------------------------------start
const treeRef = ref();
const defaultProps = {
children: 'items',
label: 'name',
};
// 分类查询
const search_filter = ref('');
watch(search_filter, (val) => {
treeRef.value!.filter(val);
});
const filter_node = (value: string, data: any): boolean => {
if (!value) return true;
return data.name.indexOf(value) !== -1;
};
const type_data = ref<Tree[]>([]);
const all_tree = {
id: '',
pid: '',
name: '全部',
items: [],
path: '',
is_enable: 1,
sort: '',
};
const type_data_list = ref<Tree[]>([]);
const tree_loading = ref(false);
// 查询分类列表
const get_tree = (bool: boolean = false) => {
if ((!upload_store.is_upload_api && upload_store.category.length === 0) || bool) {
upload_store.set_is_upload_api(true);
tree_loading.value = true;
UploadAPI.getTree()
.then((res) => {
// 将all_tree和res.data.category_list全部插入到type_data.value,all_tree放在数组最前面
type_data.value = [all_tree, ...res.data.category_list];
type_data_list.value = res.data.category_list;
upload_store.set_category(type_data_list.value);
tree_loading.value = false;
})
.catch(() => {
upload_store.set_is_upload_api(false);
});
} else {
type_data_list.value = upload_store.category;
type_data.value = [all_tree, ...upload_store.category];
}
};
// 分类弹窗表单数据
const upload_category_model = ref<Tree>({
id: '',
pid: '',
name: '',
path: '',
sort: 0,
is_enable: 1,
items: [],
});
// 分类弹窗操作类型
const upload_category_type = ref('add');
// 分类弹窗开关
const upload_category_model_visible = ref(false);
// 添加一级分类
const add_type = () => {
upload_category_type.value = 'add';
upload_category_model_visible.value = true;
upload_category_id.value = '';
upload_category_pid.value = '';
};
// 分类操作确认回调
const upload_category_confirm = () => {
get_tree(true);
};
const category_id = ref('');
// 左侧分类树结构节点点击事件
const tree_node_event = (data: any, a: any, b: any) => {
// 判断是否开启状态,如果关闭则不可操作
// if (data.is_enable == 0) return;
// 判断是否是子节点,如果不是子节点则不可操作
if (data.items && data.items.length > 0) return;
category_id.value = data.id;
get_attachment_list();
};
const upload_category_id = ref<number | string>('');
const upload_category_pid = ref<number | string>('');
// 添加子分类
const append_type_event = (data: Tree) => {
upload_category_type.value = 'add';
upload_category_id.value = '';
upload_category_pid.value = data.id;
upload_category_model_visible.value = true;
};
// 编辑子分类
const edit_type_event = (data: Tree) => {
upload_category_type.value = 'edit';
upload_category_id.value = data.id;
upload_category_pid.value = data.pid;
upload_category_model_visible.value = true;
upload_category_model.value = data;
};
// 删除分类Node报错node使用any
const remove_type_event = (node: any, data: Tree) => {
app?.appContext.config.globalProperties.$common.message_box('删除后不可恢复,确定继续吗?', 'warning').then(() => {
UploadAPI.delTree({ id: data.id }).then((res) => {
// const parent = node.parent;
// const children: Tree[] = parent.data.items || parent.data;
// const index = children.findIndex((d) => d.id === data.id);
// children.splice(index, 1);
get_tree(true);
ElMessage({
type: 'success',
message: '删除成功!',
});
});
});
};
//#endregion 分类 ----------------------------------------------------------end
//#region 附件 ----------------------------------------------------------start
// 总页数
// const page_total = ref(0);
// 当前页
const page = ref(1);
// 总数量
const data_total = ref(0);
// 名称查询
const search_name = ref('');
// 已上传数据的列表
const upload_list = ref<uploadList[]>([]);
const img_loading = ref(false);
// 附件列表
const get_attachment_list = (type?: string) => {
if (type) {
page.value = 1;
}
img_loading.value = true;
const new_data = {
page: page.value,
type: upload_type.value == 'img' ? 'image' : upload_type.value == 'video' ? 'video' : upload_type.value == 'file' ? 'file' : '',
keywords: search_name.value,
category_id: category_id.value,
};
UploadAPI.getAttachmentList(new_data).then((res) => {
const data = res.data;
data_total.value = data.data_total;
upload_list.value = data.data_list;
img_loading.value = false;
// 清除选中
check_img_ids.value = '';
view_list_value.value = [];
});
};
// 分页查询
const current_page_change = (val: number) => {
page.value = val;
get_attachment_list();
};
const check_img_ids = ref('');
// 选择图片
const check_img_event = (item: any) => {
const item_id = item.id;
const index = view_list_value.value.findIndex((item: any) => item.id === item_id);
if (index !== -1) {
view_list_value.value.splice(index, 1);
} else {
if (is_replace.value) {
view_list_value.value = [item];
} else {
if (props.limit == 1) {
view_list_value.value = [item];
} else {
view_list_value.value.push(item);
}
}
}
check_img_ids.value = view_list_value.value.map((item: any) => item.id).join(',');
};
// 预览开关
const preview_switch_img = ref(false);
const preview_switch_video = ref(false);
// 视频预览的路径
const preview_url = ref('');
// 预览视频
const video_show = (event: any) => {
if (!preview_switch_video.value) return;
if (!event.target.closest('.clickable-area')) {
preview_switch_video.value = false;
preview_url.value = '';
}
};
// 预览图片/视频
const preview_event = (item: any, index: number) => {
preview_url.value = item.url;
if (upload_type.value == 'img') {
preview_switch_img.value = true;
} else if (upload_type.value == 'video') {
preview_switch_video.value = true;
}
};
// 预览关闭
const preview_close = () => {
preview_switch_img.value = false;
};
const edit_index = ref(-1);
const edit_id = ref('');
// 编辑图片/视频/文件名称
const edit_event = (item: any, index: number) => {
edit_index.value = index;
edit_id.value = item.id;
};
// 输入框 输入完成
const edit_input_change = (val: string) => {
edit_index.value = -1;
UploadAPI.saveAttachmentName({ id: edit_id.value, original: val }).then((res) => {
ElMessage.success('修改成功!');
});
};
// 删除图片/视频/文件
const del_event = (item: uploadList) => {
app?.appContext.config.globalProperties.$common.message_box('删除后不可恢复,确定继续吗?', 'warning').then(() => {
// 调用删除接口,然后,更新数据
UploadAPI.delAttachment({ ids: item.id }).then((res) => {
ElMessage.success('删除成功!');
// 调用查询接口
get_attachment_list();
// 过滤已删除的文件
view_list_value.value = view_list_value.value.filter((items: any) => {
return items.id !== item.id;
});
console.log(view_list_value.value);
});
});
};
// 附件批量删除
const mult_del_event = () => {
if (check_img_ids.value) {
app?.appContext.config.globalProperties.$common.message_box('删除后不可恢复,确定继续吗?', 'warning').then(() => {
// 调用删除接口,然后,更新数据
UploadAPI.delAttachment({ ids: check_img_ids.value }).then((res) => {
ElMessage.success('删除成功!');
// 调用查询接口
get_attachment_list();
check_img_ids.value = '';
view_list_value.value = [];
});
});
} else {
ElMessage.warning('请先选择图片!');
}
};
const transform_category_event = () => {
check_img_ids.value = '';
get_attachment_list();
};
//#endregion 附件 ----------------------------------------------------------end
//#region 图标 -------------------------------------------------------------start
const icon_value = defineModel('iconValue', { type: String, default: '' });
const temp_icon_value = ref('');
const search_icon = ref('');
const icon_list = computed(() => searchIcons.glyphs.filter((item) => item.name.includes(search_icon.value)));
const icon_index = ref(-1);
const handle_select_icon = (item: any, index: number) => {
icon_index.value = index;
temp_icon_value.value = item.font_class;
};
const del_icon_event = () => {
icon_value.value = '';
};
//#endregion 图标 ----------------------------------------------------------end
const emit = defineEmits(['update:icon']);
// 确认
const confirm_event = () => {
dialog_visible.value = false;
if (props.limit == 1) {
model_value_upload.value = view_list_value.value;
} else {
if (is_replace.value) {
// 替换modelValue的replace下标下的文件
model_value_upload.value.splice(replace_index.value, 1, view_list_value.value[0]);
} else {
if (props.limit >= view_list_value.value.length + model_value_upload.value.length) {
// 数组合并
model_value_upload.value = model_value_upload.value.concat(view_list_value.value);
} else {
app?.appContext.config.globalProperties.$common.alert(`最多上传 ${props.limit} 个文件!`, 'warning');
}
}
}
if (view_list_value.value.length > 0) {
icon_value.value = '';
temp_icon_value.value = '';
icon_index.value = -1;
} else {
icon_value.value = JSON.parse(JSON.stringify(temp_icon_value.value));
}
view_list_value.value = [];
search_filter.value = '';
is_replace.value = false;
replace_index.value = -1;
};
// 替换标识
const is_replace = ref(false);
// 替换的文件的下标
const replace_index = ref(-1);
// 上传回显替换文件事件
const replace_file_event = (index: number) => {
dialog_visible.value = true;
is_replace.value = true;
replace_index.value = index;
};
// 上传回显删除事件
const del_upload_event = (index: number) => {
const new_model_val = JSON.parse(JSON.stringify(model_value_upload.value));
new_model_val.splice(index, 1);
model_value_upload.value = new_model_val;
};
const handle_error = (index: number) => {
// 当视频加载失败时触发
upload_list.value[index].error = true;
};
//#region 上传组件回调 -----------------------------------------------start
// 关闭上传弹窗回调
const close_upload_model = (data: any) => {
if (props.isCheckConfirm) {
dialog_visible.value = false;
if (data.web_image.length > 0) {
const new_web_file = {
url: data.web_image,
};
if (props.limit == 1) {
model_value_upload.value = [new_web_file];
} else {
if (is_replace.value) {
// 替换modelValue的replace下标下的文件
model_value_upload.value.splice(replace_index.value, 1, new_web_file);
} else {
if (props.limit >= view_list_value.value.length + model_value_upload.value.length) {
// 数组合并
model_value_upload.value.push(new_web_file);
} else {
app?.appContext.config.globalProperties.$common.alert(`最多上传 ${props.limit} 个文件!`, 'warning');
}
}
}
}
}
};
//#endregion 上传组件回调 -----------------------------------------------end
onMounted(() => {
// 监听点击事件
document.addEventListener('click', video_show);
get_tree();
});
onUnmounted(() => {
// 移除监听事件
document.removeEventListener('click', video_show);
});
</script>
<style lang="scss" scoped>
@import 'index.scss';
</style>