cd648ad8创建于 2025年8月11日历史提交
<!-- 上传组件 -->
<template>
    <el-dialog v-model="dialog_visible" class="radius-lg" width="1168" draggable :close-on-click-modal="false" :top="dialogPositionTop ? dialogPositionTop + 'px' : ''" 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-b">附件管理</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="请输入分类名称" clearable>
                            <template #prefix>
                                <icon name="search" size="18"></icon>
                            </template>
                        </el-input>
                        <icon v-if="attachment_category_operate.is_add == '1'" name="add" size="18" class="c-pointer" @click="add_type"></icon>
                    </div>
                    <el-scrollbar height="490px">
                        <el-tree ref="treeRef" v-loading="tree_loading" :current-node-key="type_data[0].id" 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 && (attachment_category_operate.is_add == '1' || attachment_category_operate.is_edit == '1' || attachment_category_operate.is_del == '1')" 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 && attachment_category_operate.is_add == '1'" 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 v-if="attachment_category_operate.is_edit == '1'" 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 v-if="attachment_category_operate.is_del == '1'" 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 v-if="attachment_operate.is_upload == '1'" type="primary" plain @click="upload_model_open">上传{{ upload_type_name }}</el-button>
                            <el-button v-if="attachment_operate.is_del == '1'" @click="mult_del_event">删除{{ upload_type_name }}</el-button>
                            <!-- <el-cascader :show-all-levels="false" clearable></el-cascader> -->
                            <div v-if="attachment_operate.is_move == '1'" class="right-classify ml-12">
                                <transform-category :data="type_data_list" :check-img-ids="check_img_ids" :type="upload_type_name" :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.prevent="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 || limit == 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 v-if="(upload_type == 'file' && (attachment_operate.is_edit == '1' || attachment_operate.is_del == '1')) || upload_type != 'file'" class="operate">
                                                <div class="operate-content flex-row jc-sa align-c">
                                                    <div v-if="attachment_operate.is_edit == '1'" 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 v-if="attachment_operate.is_del == '1'" 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" @click.stop>
                                            <template v-if="edit_index != -1 && edit_index === index">
                                                <el-input v-model="item.original" v-focus type="text" placeholder="请输入内容" size="small" clearable @blur="edit_index = -1" @keydown="edit_input_keydown" @change="edit_input_change" />
                                            </template>
                                            <template v-else>
                                                <div class="ptb-1 plr-7 c-pointer no-select" @dblclick.prevent="edit_index = index">
                                                    {{ 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="page_size" :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-fillup" 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-xs 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-xs 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 radius-xs">
                            <template #error>
                                <div class="bg-f5 img flex-row jc-c align-c radius-xs 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="isDelete && !isEmpty(icon_value)" class="upload-del-icon" @click.stop="del_icon_event">
                        <icon name="close-fillup" color="c" size="14"></icon>
                    </div>
                    <div class="flex-col gap-10 align-c">
                        <icon :name="!isEmpty(icon_value) ? icon_value : 'add'" :size="upload_size == '100%' ? '36' : Number(size) / 2 + ''" color="c"></icon>
                        <slot></slot>
                    </div>
                </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'" class="123123" :z-index="999999" :url-list="[preview_url]" teleported :hide-on-click-modal="true" @close="preview_close"></el-image-viewer>
    <upload-model v-model="upload_model_visible" :type="upload_type" :exts="upload_type == 'img' ? ext_img_name_list : upload_type == 'video' ? ext_video_name_list : ext_file_name_list" @close-all="close_all_upload_model" @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, commonStore } from '@/store';
import { isEmpty } from 'lodash';
import search_icons from '@/assets/icons/iconfont.json';
const upload_store = uploadStore();
const common_store = commonStore();
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
 * @param isDelete{Boolean} 是否可以删除
 * @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,
    },
    dialogPositionTop: {
        type: Number,
        default: 0,
    },
    isDelete: {
        type: Boolean,
        default: true,
    },
});

const model_value_upload = defineModel({ type: Array as PropType<uploadList[]>, default: [] });
// 分类权限控制
const attachment_category_operate = computed(() => common_store.common.config.attachment_category_operate);
// 附件管理权限
const attachment_operate = computed(() => common_store.common.config.attachment_operate);

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) {
                if (icon_value.value) {
                    upload_type.value = 'icon';
                } else {
                    upload_type.value = props.type;
                }

                // 获取附件列表
                get_attachment_list('1');

                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('1');
};

// 打开上传弹窗
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: 'all',
    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.attachment_category全部插入到type_data.value,all_tree放在数组最前面
                type_data.value = [all_tree, ...res.data.attachment_category];
                type_data_list.value = res.data.attachment_category;
                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('1');
};
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) => {
            get_tree(true);
            ElMessage({
                type: 'success',
                message: '删除成功!',
            });
        });
    });
};
//#endregion 分类 ----------------------------------------------------------end

//#region 附件 ----------------------------------------------------------start
// 总页数
// const page_total = ref(0);
// 当前页
const page = ref(1);
const page_size = ref(21);
// 总数量
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,
        page_size: page_size.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 == 'all' ? '' : 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 edit_input_keydown = (event: any) => {
    // 阻止回车键默认事件
    if (event.keyCode === 13) {
        edit_index.value = -1;
    }
};

// 删除图片/视频/文件
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;
            });
        });
    });
};

// 附件批量删除
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('1');
};

//#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(() => search_icons.glyphs.filter((item) => item.name.includes(search_icon.value) || item.font_class.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', 'operation_end']);
// 确认
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;
    operation_end();
};
// 操作结束触发事件
const operation_end = () => {
    emit('operation_end');
};
// 替换标识
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_all_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');
                    }
                }
            }
        }
    } else {
        get_attachment_list('1');
    }
};
// 关闭上传弹窗回调
const close_upload_model = () => {
    get_attachment_list('1');
};
//#endregion 上传组件回调 -----------------------------------------------end
onMounted(() => {
    // 监听点击事件
    document.addEventListener('click', video_show);
    nextTick(() => {
        // 获取分类
        if (common_store.common.attachment_category.length > 0) {
            type_data_list.value = common_store.common.attachment_category;
            type_data.value = [all_tree, ...common_store.common.attachment_category];
            upload_store.set_category(common_store.common.attachment_category);
            upload_store.set_is_upload_api(true);
        } else {
            get_tree();
        }
    });
});

onUnmounted(() => {
    // 移除监听事件
    document.removeEventListener('click', video_show);
});
</script>
<style lang="scss" scoped>
@import 'index.scss';
</style>