🎨 添加图库和客服插件(有问题-待修改)
This commit is contained in:
456
src/plugin/picturelibrary/view/components/imageLibrary.vue
Normal file
456
src/plugin/picturelibrary/view/components/imageLibrary.vue
Normal file
@@ -0,0 +1,456 @@
|
||||
<template>
|
||||
<div class="image-library">
|
||||
<div class="image-library-2" style="width: 180px;;border-right: solid 1px var(--el-border-color);">
|
||||
<el-tree
|
||||
:data="categories"
|
||||
node-key="id"
|
||||
:props="defaultProps"
|
||||
@node-click="handleNodeClick"
|
||||
>
|
||||
<template #default="{ node, data }">
|
||||
<span>{{ data.name }}</span>
|
||||
<span style="float: right; margin-left: 25px">
|
||||
<el-dropdown @command="(command) => handleCommand(data, command)">
|
||||
<span class="el-dropdown-link"><b>...</b></span>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item command="add">添加分类</el-dropdown-item>
|
||||
<el-dropdown-item command="edit" v-if="data.id > 0">编辑分类</el-dropdown-item>
|
||||
<el-dropdown-item command="delete" v-if="data.id > 0">删除分类</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
</span>
|
||||
</template>
|
||||
</el-tree>
|
||||
</div>
|
||||
<div>
|
||||
<div class="top-buttons" style="margin-left: 15px;">
|
||||
<el-button @click="useSelectedImages" type="primary">使用选中的文件</el-button>
|
||||
<el-button @click="openUploadDialog" type="primary">上传文件</el-button>
|
||||
<el-button @click="confirmDeleteImages">删除文件</el-button>
|
||||
<el-input
|
||||
v-model="keyword"
|
||||
class="keyword"
|
||||
placeholder="请输入文件名"
|
||||
style="margin-left: 10px;"
|
||||
/>
|
||||
<el-button
|
||||
type="primary"
|
||||
icon="search"
|
||||
@click="getSearchData"
|
||||
>查询</el-button>
|
||||
</div>
|
||||
<div class="flex flex-wrap gap-4">
|
||||
<div v-for="image in images" :key="image.ID" class="block">
|
||||
<el-image v-if="image.tag !== 'mp4'" :src="image.url" @click="toggleImageSelection(image)" :class="{ selected: isSelected(image) }" style="width: 96px;height: 96px;"></el-image>
|
||||
<video v-else controls style="width: 96%; height: 96px;" @click="toggleImageSelection(image)" :class="{ selected: isSelected(image) }">
|
||||
<source :src="image.url" />
|
||||
</video>
|
||||
<div class="overflow-hidden text-nowrap overflow-ellipsis text-center w-full">{{image.name}}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<el-pagination @current-change="pageChange" background layout="prev, pager, next" :page-size="18" :total="totalPage" style="float: right"/>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 添加分类弹窗 -->
|
||||
<el-dialog v-model="isAddCategoryDialogVisible" @close="closeAddCategoryDialog" title="添加分类">
|
||||
<el-form>
|
||||
<el-form-item label="上级分类">
|
||||
<el-tree-select
|
||||
v-model="cat_id"
|
||||
:data="categories"
|
||||
check-strictly
|
||||
:props="defaultProps"
|
||||
:render-after-expand="false"
|
||||
style="width: 240px"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="分类名称">
|
||||
<el-input v-model="cat_name" placeholder="分类名称"></el-input>
|
||||
</el-form-item>
|
||||
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click="closeAddCategoryDialog">取消</el-button>
|
||||
<el-button type="primary" @click="confirmAddCategory">确定</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
<!-- 删除确认弹窗 -->
|
||||
<el-dialog v-model="isDeleteImagesDialogVisible" @close="closeDeleteImagesDialog" title="删除文件" width="350">
|
||||
<span>确定要删除选中的文件吗?</span>
|
||||
<template #footer>
|
||||
<el-button @click="closeDeleteImagesDialog">取消</el-button>
|
||||
<el-button type="danger" @click="deleteImages">确定</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
<!-- 上传图片弹窗 -->
|
||||
<el-dialog v-model="isUploadDialogVisible" title="上传文件">
|
||||
<el-form>
|
||||
<el-form-item label="上传分类">
|
||||
<el-tree-select
|
||||
v-model="selectedCategory"
|
||||
check-strictly
|
||||
:data="categories"
|
||||
node-key="id"
|
||||
:props="defaultProps"
|
||||
placeholder="请选择分类"
|
||||
>
|
||||
<template #default="{ node, data }">
|
||||
<span>{{ data.name }}</span>
|
||||
</template>
|
||||
</el-tree-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="选择文件">
|
||||
<el-upload
|
||||
ref="uploadRef"
|
||||
action=""
|
||||
multiple
|
||||
:on-change="handleChange"
|
||||
:on-remove="handleRemove"
|
||||
:file-list="fileList"
|
||||
list-type="picture-card"
|
||||
:auto-upload="false">
|
||||
<el-icon><Plus /></el-icon>
|
||||
</el-upload>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click="closeUploadDialog">取消</el-button>
|
||||
<el-button type="primary" @click="submitUpload">确定</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, defineEmits, onMounted } from 'vue';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import { Plus } from '@element-plus/icons-vue'
|
||||
import { getCategoryListApi,getFileListApi,addCategoryApi,deleteCategoryApi,deleteFilesApi,uploadHandlerApi } from '@/plugin/picturelibrary/api/api.js'
|
||||
import {getUrl, isVideoExt} from "@/utils/image";
|
||||
|
||||
const emit = defineEmits(['select']);
|
||||
|
||||
const cat_id = ref(0)
|
||||
const selectedImage = ref(null);
|
||||
const selectedImages = ref([]);
|
||||
const images = ref([])
|
||||
const categories = ref([])
|
||||
|
||||
const isAddCategoryDialogVisible = ref(false)
|
||||
const cat_name = ref('')
|
||||
const isDeleteImagesDialogVisible = ref(false)
|
||||
const isUploadDialogVisible = ref(false)
|
||||
const selectedCategory = ref(null)
|
||||
const fileList = ref([])
|
||||
const selectedParentCategory = ref(null)
|
||||
const totalPage = ref(0)
|
||||
const editId = ref(0)
|
||||
const searchCatId = ref(0)
|
||||
const page = ref(1)
|
||||
const pageSize = ref(18)
|
||||
const keyword = ref('')
|
||||
const props = defineProps({
|
||||
multiple: Boolean, // 接收父组件传递的multiple参数
|
||||
});
|
||||
|
||||
const defaultProps = {
|
||||
children: 'children',
|
||||
label: 'name',
|
||||
value: 'id'
|
||||
}
|
||||
|
||||
const pageChange = (index) => {
|
||||
page.value = index
|
||||
getPicList()
|
||||
}
|
||||
|
||||
const getSearchData = () => {
|
||||
getPicList()
|
||||
}
|
||||
|
||||
const getPicList = async () => {
|
||||
try {
|
||||
const response = await getFileListApi({page:page.value,limit:pageSize.value,cid:searchCatId.value,keyword:keyword.value})
|
||||
if(response.code === 0){
|
||||
if(response.data.list){
|
||||
images.value = response.data.list
|
||||
totalPage.value = response.data.total
|
||||
}
|
||||
}
|
||||
else{
|
||||
ElMessage.error(response.msg);
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
ElMessage.error('请求失败');
|
||||
}
|
||||
}
|
||||
|
||||
const fetchCategories = async (name = '顶级分类') => {
|
||||
let data = {
|
||||
name: name,
|
||||
id: 0,
|
||||
pid: 0,
|
||||
children:[]
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await getCategoryListApi({})
|
||||
if(response.code === 0){
|
||||
if(response.data.list){
|
||||
response.data.list.unshift(data)
|
||||
categories.value = response.data.list
|
||||
}
|
||||
else{
|
||||
categories.value = [data]
|
||||
}
|
||||
}
|
||||
else{
|
||||
ElMessage.error('分类数据获取失败');
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error fetching categories:', error)
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
fetchCategories()
|
||||
getPicList()
|
||||
})
|
||||
|
||||
const toggleImageSelection = (image) => {
|
||||
const index = selectedImages.value.findIndex(img => img.ID === image.ID);
|
||||
if (index > -1) {
|
||||
selectedImages.value.splice(index, 1);
|
||||
} else {
|
||||
selectedImages.value.push(image);
|
||||
}
|
||||
}
|
||||
|
||||
const isSelected = (image) => {
|
||||
return selectedImages.value.some(img => img.ID === image.ID);
|
||||
}
|
||||
|
||||
const useSelectedImages = () => {
|
||||
if (selectedImages.value.length > 0) {
|
||||
if(!props.multiple && selectedImages.value.length > 1){
|
||||
ElMessage.error('只能选择一个文件');
|
||||
return
|
||||
}
|
||||
const urls = selectedImages.value.map(img => img);
|
||||
emit('select', urls);
|
||||
selectedImages.value = []
|
||||
|
||||
} else {
|
||||
ElMessage.error('请选择一个或多个文件');
|
||||
}
|
||||
}
|
||||
|
||||
const openUploadDialog = () => {
|
||||
isUploadDialogVisible.value = true
|
||||
}
|
||||
|
||||
const closeUploadDialog = () => {
|
||||
isUploadDialogVisible.value = false
|
||||
selectedCategory.value = null
|
||||
fileList.value = []
|
||||
}
|
||||
const fileTypeList = ref(['image/gif', 'image/jpeg', 'image/png', 'video/mp4', 'video/x-msvideo', 'video/x-ms-wmv','video/mpeg','video/x-ms-asf'])
|
||||
const submitUpload = async () => {
|
||||
if (selectedCategory.value !== null && fileList.value.length > 0) {
|
||||
try {
|
||||
const formData = new FormData();
|
||||
fileList.value.forEach(file => {
|
||||
formData.append('files', file.raw);
|
||||
});
|
||||
formData.append('cat_id', selectedCategory.value);
|
||||
|
||||
try {
|
||||
const response = await uploadHandlerApi(formData);
|
||||
if(response.code === 0){
|
||||
ElMessage.success('文件上传成功');
|
||||
closeUploadDialog();
|
||||
selectedCategory.value = null
|
||||
}
|
||||
else{
|
||||
ElMessage.error('文件上传失败');
|
||||
}
|
||||
} catch (error) {
|
||||
ElMessage.error('文件上传失败');
|
||||
}
|
||||
} catch (error) {
|
||||
ElMessage.error('上传失败,请重试');
|
||||
}
|
||||
} else {
|
||||
ElMessage.error('请选择分类和文件');
|
||||
}
|
||||
}
|
||||
|
||||
const deleteImages = async () => {
|
||||
if (selectedImages.value.length > 0) {
|
||||
const response = await deleteFilesApi(selectedImages.value)
|
||||
if(response.code === 0){
|
||||
ElMessage.success('删除成功');
|
||||
selectedImages.value = [];
|
||||
isDeleteImagesDialogVisible.value = false;
|
||||
getPicList()
|
||||
}
|
||||
else{
|
||||
ElMessage.error('文件删除失败');
|
||||
isDeleteImagesDialogVisible.value = false;
|
||||
}
|
||||
|
||||
} else {
|
||||
ElMessage.error('请选择一张或多张图片');
|
||||
}
|
||||
}
|
||||
|
||||
const confirmDeleteImages = () => {
|
||||
if (selectedImages.value.length > 0) {
|
||||
isDeleteImagesDialogVisible.value = true;
|
||||
} else {
|
||||
ElMessage.error('请选择一个或多个文件');
|
||||
}
|
||||
}
|
||||
|
||||
const addCategory = (cat) => {
|
||||
isAddCategoryDialogVisible.value = true;
|
||||
cat_id.value = cat.id
|
||||
}
|
||||
|
||||
const editCategory = (category) => {
|
||||
cat_id.value = category.pid
|
||||
cat_name.value = category.name
|
||||
editId.value = category.id
|
||||
isAddCategoryDialogVisible.value = true;
|
||||
|
||||
}
|
||||
|
||||
const deleteCategory = async (category) => {
|
||||
try {
|
||||
const response = await deleteCategoryApi({cat_id:category.id})
|
||||
if(response.code === 0){
|
||||
ElMessage.success('删除成功');
|
||||
fetchCategories()
|
||||
getPicList()
|
||||
}
|
||||
else{
|
||||
ElMessage.error(response.data.msg);
|
||||
}
|
||||
} catch (error) {
|
||||
ElMessage.error('删除分类失败,请重试');
|
||||
}
|
||||
}
|
||||
|
||||
const closeAddCategoryDialog = () => {
|
||||
isAddCategoryDialogVisible.value = false
|
||||
cat_name.value = ''
|
||||
selectedParentCategory.value = null
|
||||
}
|
||||
|
||||
const confirmAddCategory = async () => {
|
||||
if (cat_name.value.trim()) {
|
||||
const newCategory = {
|
||||
name: cat_name.value.trim(),
|
||||
pid: cat_id.value,
|
||||
id:editId.value
|
||||
};
|
||||
try {
|
||||
const response = await addCategoryApi(newCategory);
|
||||
if(response.code === 0){
|
||||
ElMessage.success('添加成功');
|
||||
fetchCategories()
|
||||
getPicList()
|
||||
closeAddCategoryDialog();
|
||||
}
|
||||
else{
|
||||
ElMessage.error(response.msg);
|
||||
}
|
||||
} catch (error) {
|
||||
ElMessage.error('分类添加失败,请重试');
|
||||
}
|
||||
} else {
|
||||
ElMessage.error('分类名称不能为空');
|
||||
}
|
||||
}
|
||||
|
||||
const handleNodeClick = (node) => {
|
||||
searchCatId.value = node.id
|
||||
getPicList()
|
||||
}
|
||||
const handleCommand = (category,command) => {
|
||||
if (command === 'add') {
|
||||
addCategory(category);
|
||||
} else if (command === 'edit') {
|
||||
editCategory(category);
|
||||
} else if (command === 'delete') {
|
||||
deleteCategory(category);
|
||||
}
|
||||
}
|
||||
|
||||
const handleChange = (uploadFile, uploadFiles) => {
|
||||
uploadFiles.forEach(file => {
|
||||
if(fileTypeList.value.includes(file.raw.type) === false){
|
||||
ElMessage.error('图片或视频格式有误');
|
||||
fileList.value = []
|
||||
}
|
||||
else{
|
||||
fileList.value = uploadFiles;
|
||||
console.log('fileList:', fileList.value.length);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
const handleRemove = (file, fileList) => {
|
||||
// fileList.value = fileList;
|
||||
console.log('Remove:', file, fileList);
|
||||
}
|
||||
|
||||
const closeDeleteImagesDialog = () => {
|
||||
isDeleteImagesDialogVisible.value = false
|
||||
}
|
||||
|
||||
const dummyRequest = ({ onSuccess }) => {
|
||||
setTimeout(() => {
|
||||
onSuccess('ok');
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
const uploadRef = ref(null)
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.image-library {
|
||||
display: flex;
|
||||
}
|
||||
.image-library-2 {
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
.el-dropdown-link {
|
||||
cursor: pointer;
|
||||
}
|
||||
.top-buttons {
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.selected {
|
||||
border: 3px solid #409eff;
|
||||
}
|
||||
|
||||
.block {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
box-sizing: border-box;
|
||||
vertical-align: top;
|
||||
padding: 2px;
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
margin-left: 15px;
|
||||
}
|
||||
</style>
|
30
src/plugin/picturelibrary/view/index.vue
Normal file
30
src/plugin/picturelibrary/view/index.vue
Normal file
@@ -0,0 +1,30 @@
|
||||
<template>
|
||||
<div class="picturelibrary">
|
||||
在此处书写页面代码
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import { routerName } from '@/plugin/picturelibrary/api/api.js'
|
||||
|
||||
const data = ref({})
|
||||
|
||||
defineOptions({
|
||||
name: 'PictureLibrary'
|
||||
})
|
||||
|
||||
const useApi = async() =>{
|
||||
const res = await routerName(data.value)
|
||||
if(res.code === 0){
|
||||
console.log(res.data)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.picturelibrary {
|
||||
|
||||
}
|
||||
</style>
|
Reference in New Issue
Block a user