feat(文件管理): 文件管理修改
This commit is contained in:
@@ -4,7 +4,7 @@ import os
|
|||||||
|
|
||||||
exclude = ["venv"] # 需要排除的文件目录
|
exclude = ["venv"] # 需要排除的文件目录
|
||||||
for root, dirs, files in os.walk('.'):
|
for root, dirs, files in os.walk('.'):
|
||||||
dirs[:] = [d for d in set(dirs) - set(exclude)]
|
dirs[:] = list(set(dirs) - set(exclude))
|
||||||
if 'migrations' in dirs:
|
if 'migrations' in dirs:
|
||||||
dir = dirs[dirs.index('migrations')]
|
dir = dirs[dirs.index('migrations')]
|
||||||
for root_j, dirs_j, files_j in os.walk(os.path.join(root, dir)):
|
for root_j, dirs_j, files_j in os.walk(os.path.join(root, dir)):
|
||||||
|
|||||||
@@ -289,8 +289,7 @@ class Dictionary(CoreModel):
|
|||||||
(7, "images"),
|
(7, "images"),
|
||||||
)
|
)
|
||||||
label = models.CharField(max_length=100, blank=True, null=True, verbose_name="字典名称", help_text="字典名称")
|
label = models.CharField(max_length=100, blank=True, null=True, verbose_name="字典名称", help_text="字典名称")
|
||||||
value = models.CharField(max_length=200, blank=True, null=True, verbose_name="字典编号",
|
value = models.CharField(max_length=200, blank=True, null=True, verbose_name="字典编号",help_text="字典编号/实际值")
|
||||||
help_text="字典编号/实际值")
|
|
||||||
parent = models.ForeignKey(
|
parent = models.ForeignKey(
|
||||||
to="self",
|
to="self",
|
||||||
related_name="sublist",
|
related_name="sublist",
|
||||||
@@ -359,7 +358,11 @@ def media_file_name(instance, filename):
|
|||||||
|
|
||||||
class FileList(CoreModel):
|
class FileList(CoreModel):
|
||||||
name = models.CharField(max_length=200, null=True, blank=True, verbose_name="名称", help_text="名称")
|
name = models.CharField(max_length=200, null=True, blank=True, verbose_name="名称", help_text="名称")
|
||||||
url = models.FileField(upload_to=media_file_name)
|
url = models.FileField(upload_to=media_file_name, null=True, blank=True,)
|
||||||
|
file_url = models.CharField(max_length=255, blank=True, verbose_name="文件地址", help_text="文件地址")
|
||||||
|
engine = models.CharField(max_length=100, default='local', blank=True, verbose_name="引擎", help_text="引擎")
|
||||||
|
mime_type = models.CharField(max_length=100, blank=True, verbose_name="Mime类型", help_text="Mime类型")
|
||||||
|
size = models.CharField(max_length=36, blank=True, verbose_name="文件大小", help_text="文件大小")
|
||||||
md5sum = models.CharField(max_length=36, blank=True, verbose_name="文件md5", help_text="文件md5")
|
md5sum = models.CharField(max_length=36, blank=True, verbose_name="文件md5", help_text="文件md5")
|
||||||
|
|
||||||
def save(self, *args, **kwargs):
|
def save(self, *args, **kwargs):
|
||||||
@@ -368,6 +371,11 @@ class FileList(CoreModel):
|
|||||||
for chunk in self.url.chunks():
|
for chunk in self.url.chunks():
|
||||||
md5.update(chunk)
|
md5.update(chunk)
|
||||||
self.md5sum = md5.hexdigest()
|
self.md5sum = md5.hexdigest()
|
||||||
|
if not self.size:
|
||||||
|
self.size = self.url.size
|
||||||
|
if not self.file_url:
|
||||||
|
url = media_file_name(self,self.name)
|
||||||
|
self.file_url = f'media/{url}'
|
||||||
super(FileList, self).save(*args, **kwargs)
|
super(FileList, self).save(*args, **kwargs)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
|||||||
@@ -1,5 +1,12 @@
|
|||||||
|
import hashlib
|
||||||
|
import mimetypes
|
||||||
|
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
|
from rest_framework.decorators import action
|
||||||
|
|
||||||
|
from application import dispatch
|
||||||
from dvadmin.system.models import FileList
|
from dvadmin.system.models import FileList
|
||||||
|
from dvadmin.utils.json_response import DetailResponse
|
||||||
from dvadmin.utils.serializers import CustomModelSerializer
|
from dvadmin.utils.serializers import CustomModelSerializer
|
||||||
from dvadmin.utils.viewset import CustomModelViewSet
|
from dvadmin.utils.viewset import CustomModelViewSet
|
||||||
|
|
||||||
@@ -8,15 +15,52 @@ class FileSerializer(CustomModelSerializer):
|
|||||||
url = serializers.SerializerMethodField(read_only=True)
|
url = serializers.SerializerMethodField(read_only=True)
|
||||||
|
|
||||||
def get_url(self, instance):
|
def get_url(self, instance):
|
||||||
return f'media/{str(instance.url)}'
|
# return 'media/' + str(instance.url)
|
||||||
|
return instance.file_url or (f'media/{str(instance.url)}')
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = FileList
|
model = FileList
|
||||||
fields = "__all__"
|
fields = "__all__"
|
||||||
|
|
||||||
def create(self, validated_data):
|
def create(self, validated_data):
|
||||||
validated_data['name'] = str(self.initial_data.get('file'))
|
file_engine = dispatch.get_system_config_values("fileStorageConfig.file_engine") or 'local'
|
||||||
validated_data['url'] = self.initial_data.get('file')
|
file_backup = dispatch.get_system_config_values("fileStorageConfig.file_backup")
|
||||||
|
file = self.initial_data.get('file')
|
||||||
|
file_size = file.size
|
||||||
|
validated_data['name'] = str(file)
|
||||||
|
validated_data['size'] = file_size
|
||||||
|
md5 = hashlib.md5()
|
||||||
|
for chunk in file.chunks():
|
||||||
|
md5.update(chunk)
|
||||||
|
validated_data['md5sum'] = md5.hexdigest()
|
||||||
|
validated_data['engine'] = file_engine
|
||||||
|
validated_data['mime_type'] = file.content_type
|
||||||
|
if file_backup:
|
||||||
|
validated_data['url'] = file
|
||||||
|
if file_engine == 'oss':
|
||||||
|
from dvadmin_cloud_storage.views.aliyun import ali_oss_upload
|
||||||
|
file_path = ali_oss_upload(file)
|
||||||
|
if file_path:
|
||||||
|
validated_data['file_url'] = file_path
|
||||||
|
else:
|
||||||
|
raise ValueError("上传失败")
|
||||||
|
elif file_engine == 'cos':
|
||||||
|
from dvadmin_cloud_storage.views.tencent import tencent_cos_upload
|
||||||
|
file_path = tencent_cos_upload(file)
|
||||||
|
if file_path:
|
||||||
|
validated_data['file_url'] = file_path
|
||||||
|
else:
|
||||||
|
raise ValueError("上传失败")
|
||||||
|
else:
|
||||||
|
validated_data['url'] = file
|
||||||
|
# 审计字段
|
||||||
|
try:
|
||||||
|
request_user = self.request.user
|
||||||
|
validated_data['dept_belong_id'] = request_user.dept.id
|
||||||
|
validated_data['creator'] = request_user.id
|
||||||
|
validated_data['modifier'] = request_user.id
|
||||||
|
except:
|
||||||
|
pass
|
||||||
return super().create(validated_data)
|
return super().create(validated_data)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,18 +1,25 @@
|
|||||||
<template>
|
<template>
|
||||||
<fs-page style="padding: 10px">
|
<fs-page>
|
||||||
<el-card :body-style="{height:'100%'}">
|
<el-row style="margin: 10px">
|
||||||
<el-tabs tab-position="left" class="demo-tabs" style="height: 70vh">
|
<el-col :span="6" :offset="18">
|
||||||
<el-tab-pane label="全部">
|
<el-input
|
||||||
<div>
|
class="w-60"
|
||||||
<el-row>
|
placeholder="请输入名称"
|
||||||
<el-col :soan="6" :offset="18">
|
v-model="fileParams.name"
|
||||||
这里放搜索框
|
@keyup.enter="getData"
|
||||||
|
clearable
|
||||||
|
@blur="getData"
|
||||||
|
>
|
||||||
|
<template #append>
|
||||||
|
<el-button :icon="Search" @click="getData">
|
||||||
|
</el-button>
|
||||||
|
</template>
|
||||||
|
</el-input>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
</div>
|
<el-row :gutter="10" style="height: 65vh;margin: 10px">
|
||||||
<div>
|
|
||||||
<el-row :gutter="10">
|
|
||||||
<el-col :span="3" v-for="(item,index) in fileList" :key="index">
|
<el-col :span="3" v-for="(item,index) in fileList" :key="index">
|
||||||
|
<el-card>
|
||||||
<el-image
|
<el-image
|
||||||
style="width: 150px; height: 150px"
|
style="width: 150px; height: 150px"
|
||||||
:src="formatImgUrl(item.url)"
|
:src="formatImgUrl(item.url)"
|
||||||
@@ -22,7 +29,8 @@
|
|||||||
fit="fill"
|
fit="fill"
|
||||||
/>
|
/>
|
||||||
<div>
|
<div>
|
||||||
<div> <el-text>{{item.name}}</el-text></div>
|
<el-text>{{ item.name }}</el-text>
|
||||||
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<el-popover
|
<el-popover
|
||||||
placement="bottom"
|
placement="bottom"
|
||||||
@@ -37,9 +45,10 @@
|
|||||||
:column="2"
|
:column="2"
|
||||||
border
|
border
|
||||||
>
|
>
|
||||||
<el-descriptions-item label="文件名称">{{item.name}}</el-descriptions-item>
|
<el-descriptions-item label="文件名称">{{ item.name }}</el-descriptions-item>
|
||||||
<el-descriptions-item label="创建人">{{item.creator_name}}</el-descriptions-item>
|
<el-descriptions-item label="创建人">{{ item.creator_name }}</el-descriptions-item>
|
||||||
<el-descriptions-item label="创建时间">{{item.create_datetime}}</el-descriptions-item>
|
<el-descriptions-item label="存储引擎">{{ item.engine }}</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="创建时间">{{ item.create_datetime }}</el-descriptions-item>
|
||||||
</el-descriptions>
|
</el-descriptions>
|
||||||
</div>
|
</div>
|
||||||
</el-popover>
|
</el-popover>
|
||||||
@@ -48,54 +57,87 @@
|
|||||||
<el-button type="text">删除</el-button>
|
<el-button type="text">删除</el-button>
|
||||||
</template>
|
</template>
|
||||||
</el-popconfirm>
|
</el-popconfirm>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</el-col>
|
|
||||||
</el-row>
|
|
||||||
</div>
|
|
||||||
</el-tab-pane>
|
|
||||||
<el-tab-pane label="Config">Config</el-tab-pane>
|
|
||||||
<el-tab-pane label="Role">Role</el-tab-pane>
|
|
||||||
<el-tab-pane label="Task">Task</el-tab-pane>
|
|
||||||
</el-tabs>
|
|
||||||
<el-divider></el-divider>
|
|
||||||
<el-row>
|
|
||||||
<el-col :span="12" :offset="12">
|
|
||||||
这里放分页
|
|
||||||
</el-col>
|
|
||||||
</el-row>
|
|
||||||
</el-card>
|
</el-card>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
<el-divider></el-divider>
|
||||||
|
<el-row style="margin-left: 10px">
|
||||||
|
<el-col :span="12" >
|
||||||
|
<el-pagination
|
||||||
|
v-model:current-page="pageConfig.page"
|
||||||
|
v-model:page-size="pageConfig.limit"
|
||||||
|
background
|
||||||
|
:page-sizes="[5, 10, 20, 50]"
|
||||||
|
layout="total, sizes, prev, pager, next, jumper"
|
||||||
|
:total="pageConfig.total"
|
||||||
|
@size-change="handleSizeChange"
|
||||||
|
@current-change="handleCurrentChange"
|
||||||
|
/>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
</fs-page>
|
</fs-page>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import {DelObj, GetList} from "./api";
|
import {DelObj, GetList, GetMimeType} from "./api";
|
||||||
import {ref,onMounted} from "vue";
|
import {ref, onMounted,reactive} from "vue";
|
||||||
import {getBaseURL} from "/@/utils/baseUrl";
|
import {getBaseURL} from "/@/utils/baseUrl";
|
||||||
import {ElMessage} from "element-plus";
|
import {ElMessage} from "element-plus";
|
||||||
|
import { Delete, Edit, Search, Share, Upload } from '@element-plus/icons-vue'
|
||||||
|
const fileParams = reactive({name:''})
|
||||||
const fileList = ref([])
|
const fileList = ref([])
|
||||||
const getData = function (){
|
const mimeType = ref([])
|
||||||
GetList({}).then((res:any)=>{
|
const pageConfig = reactive({
|
||||||
const {data} = res
|
page:1,
|
||||||
|
limit:10,
|
||||||
|
total:0
|
||||||
|
})
|
||||||
|
const getData = function () {
|
||||||
|
let params = {
|
||||||
|
page:pageConfig.page,
|
||||||
|
limit:pageConfig.limit,
|
||||||
|
name:fileParams.name
|
||||||
|
}
|
||||||
|
GetList(params).then((res: any) => {
|
||||||
|
const {data,page,limit,total} = res
|
||||||
|
pageConfig.page = page
|
||||||
|
pageConfig.limit=limit
|
||||||
|
pageConfig.total=total
|
||||||
fileList.value = data
|
fileList.value = data
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const onDel = function (item:any) {
|
const getMimeType = function () {
|
||||||
DelObj(item.id).then((res:any)=>{
|
GetMimeType().then((res: any) => {
|
||||||
|
const {data} = res
|
||||||
|
mimeType.value = data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const onDel = function (item: any) {
|
||||||
|
DelObj(item.id).then((res: any) => {
|
||||||
ElMessage.success("删除成功!");
|
ElMessage.success("删除成功!");
|
||||||
getData()
|
getData()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
const formatImgUrl = function (src:string) {
|
const formatImgUrl = function (src: string) {
|
||||||
return getBaseURL()+src
|
return getBaseURL() + src
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const handleSizeChange = function (val: any) {
|
||||||
onMounted(()=>{
|
pageConfig.limit = val
|
||||||
getData()
|
getData()
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleCurrentChange = function (val: any) {
|
||||||
|
pageConfig.page = val
|
||||||
|
getData()
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
getData()
|
||||||
|
getMimeType()
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
<style scoped>
|
<style scoped>
|
||||||
@@ -110,7 +152,8 @@ onMounted(()=>{
|
|||||||
.el-tabs--left .el-tabs__content {
|
.el-tabs--left .el-tabs__content {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
.el-tabs__nav-scroll{
|
|
||||||
|
.el-tabs__nav-scroll {
|
||||||
border-right: 1px solid #efefef;
|
border-right: 1px solid #efefef;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
Reference in New Issue
Block a user