Browse Source

下拉刷新和移动功能

pull/19/head
freshman-white 2 years ago
parent
commit
780c52f977
  1. 5
      src/api/http/type.ts
  2. 27
      src/api/media.ts
  3. 242
      src/components/MediaPanel.vue

5
src/api/http/type.ts

@ -23,6 +23,11 @@ export interface IWorkspaceResponse<T> {
data: T; data: T;
message: string; message: string;
} }
export interface idData{
ids?:any,
file_name?:string,
father_id:string|number
}
export type IStatus = 'WAITING' | 'DOING' | 'SUCCESS' | 'FAILED'; export type IStatus = 'WAITING' | 'DOING' | 'SUCCESS' | 'FAILED';

27
src/api/media.ts

@ -1,5 +1,5 @@
import { message } from 'ant-design-vue' import { message } from 'ant-design-vue'
import request, { IPage, IWorkspaceResponse } from '/@/api/http/request' import request, { IPage, IWorkspaceResponse, idData } from '/@/api/http/request'
const HTTP_PREFIX = '/media/api/v1' const HTTP_PREFIX = '/media/api/v1'
// Get Media Files // Get Media Files
@ -29,10 +29,21 @@ export const downloadMediaFile = async function (workspaceId: string, fileId: st
return result.data return result.data
} }
} }
// 新增或修改文件夹
// Get Media getFolder export const operateFile = async (wid: string, body:idData): Promise<IWorkspaceResponse<{ id: string }>> => {
// export const getFolder = async function (workspaceId: string): Promise<IWorkspaceResponse<any>> { const url = `${HTTP_PREFIX}/files/${wid}/folder`
// const url = `${HTTP_PREFIX}/files/${workspaceId}/folder/2` const result = await request.post(url, body)
// const result = await request.get(url) return result.data
// return result.data }
// } // 删除文件
export const deleteFile = async (wid: string, id:any): Promise<IWorkspaceResponse<{ id: string }>> => {
const url = `${HTTP_PREFIX}/files/${wid}/folder`
const result = await request.delete(url + '?id_arr=' + id)
return result.data
}
// 文件数
export const floderTreeData = async (wid: string): Promise<IWorkspaceResponse<{ id: string }>> => {
const url = `${HTTP_PREFIX}/files/${wid}/folder/tree`
const result = await request.get(url)
return result.data
}

242
src/components/MediaPanel.vue

@ -1,9 +1,10 @@
<template> <template>
<div class="header"> <div class="header">
<a-button type="primary" large class="btn-primary" @click='createFile'>创建文件夹</a-button> <a-button type="primary" large class="btn-primary" @click='openFileDialog'>创建文件夹</a-button>
<div v-show="state.selectedRowIds.length" class="other-btn"> <div v-show="state.selectedRowIds.length" class="other-btn">
<a-button large class="btn-primary">压缩并下载</a-button> <a-button large class="btn-primary">压缩并下载</a-button>
<a-button large class="btn-primary">移动</a-button> <a-button large class="btn-primary" @click="move()">移动</a-button>
<a-button large class="btn-primary" @click="deleteRow()">删除</a-button>
</div> </div>
<div class="search-content"> <div class="search-content">
@ -53,24 +54,33 @@
<a-spin :spinning="loading" tip="加载中..." size="large"> <a-spin :spinning="loading" tip="加载中..." size="large">
<div class="media-panel-wrapper"> <div class="media-panel-wrapper">
<div class="bread-content"> <div class="bread-content">
<span v-for="(item,index) in breadList" :key="item">{{ item }}<span v-if="index!=breadList.length-1" >/</span></span> <span v-for="(item,index) in breadList" :key="item" @click="jumpToPath(index)" :class="[index!=breadList.length-1?'tab-click':'']">{{ item }}<span v-if="index!=breadList.length-1" >/</span></span>
</div> </div>
<a-table :columns="columns" :data-source="mediaData.data" :scroll="{ x: '100%', y: 400 }" :row-selection="rowSelection" :pagination="paginationProp"> <a-table :columns="columns" ref='tableRef' :data-source="mediaData.data" :scroll="{ x: '100%', y: 400 }" :row-selection="rowSelection">
<template v-for="col in ['file_name']" #[col]="{ text,index }" :key="col"> <template v-for="col in ['file_name','payload','drone','create_time']" #[col]="{ text,index }" :key="col">
<div @click="goDetail(mediaData.data[index])"> <div @click="goDetail(mediaData.data[index],index)" v-if="col=='file_name'">
<img src="../assets/icons/folder.svg" v-if='mediaData.data[index].file_type==0'> <img src="../assets/icons/folder.svg" v-if='mediaData.data[index].file_type==0'>
<img src="../assets/icons/zip.svg" v-if='mediaData.data[index].file_type==2'> <img src="../assets/icons/zip.svg" v-if='mediaData.data[index].file_type==2'>
<a-image :width="30" :hight="30" v-if='mediaData.data[index].file_type==1' :src="mediaData.data[index].picture_url" :preview="{ <a-image :width="30" :hight="30" v-if='mediaData.data[index].file_type==1' :src="mediaData.data[index].picture_url" :preview="{
src: mediaData.data[index].picture_url}" src: mediaData.data[index].picture_url}"
/> />
<a-tooltip :title="text"> <template v-if="index===state.index">
<a>&nbsp;{{ text }}</a> <a-input v-model:value="state.changeName" class="edit-input space"></a-input>
<a @click="createFile(mediaData.data[index].id)" style="margin-right: 6px;"><CheckOutlined /></a>
<CloseOutlined @click.stop="cancelEdit" />
</template>
<a-tooltip :title="text" v-else>
<a class="space"> {{ text }}</a>
</a-tooltip> </a-tooltip>
</div> </div>
<div v-else>{{ text||'--' }}</div>
</template> </template>
<template #action="{ record }"> <template #action="{ record, index }">
<a-tooltip title="download"> <a-tooltip title="download">
<a class="fz18" @click="downloadMedia(record)"><DownloadOutlined /></a> <a class="fz18 space" @click="downloadMedia(record)"><DownloadOutlined /></a>
<a class="fz18 space" @click="editName(index)"><EditOutlined /></a>
<a class="fz18 space" @click="deleteRow(index)"><DeleteOutlined /></a>
<a class="fz18 space" @click="move(mediaData.data[index].id)"><LoginOutlined /></a>
</a-tooltip> </a-tooltip>
</template> </template>
</a-table> </a-table>
@ -86,7 +96,27 @@
<template #footer> <template #footer>
<div> <div>
<a-button large class="btn-primary" @click='state.folderOpen=false'>取消</a-button> <a-button large class="btn-primary" @click='state.folderOpen=false'>取消</a-button>
<a-button type="primary" large class="btn-primary" @click='state.folderOpen=true'>确定</a-button> <a-button type="primary" large class="btn-primary" @click='createFile()'>确定</a-button>
</div>
</template>
</a-modal>
<a-modal v-model:visible="state.folderTree" :closable="false" :maskClosable="false">
<template #title>
<div ref="modalTitleRef" style="width: 100%; cursor: move" class="model-title">移动到</div>
</template>
<a-directory-tree
@select="selectTree"
:tree-data="treeList"
:field-names="fieldNames"
>
<template #title="{ file_name}" >
<span >{{ file_name }}</span>
</template>
</a-directory-tree>
<template #footer>
<div>
<a-button large class="btn-primary" @click='state.folderTree=false'>取消</a-button>
<a-button type="primary" large class="btn-primary" @click='moveSubmit()'>确定</a-button>
</div> </div>
</template> </template>
</a-modal> </a-modal>
@ -95,39 +125,51 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref } from '@vue/reactivity' import { ref } from '@vue/reactivity'
import { TableState } from 'ant-design-vue/lib/table/interface' import { TableState } from 'ant-design-vue/lib/table/interface'
import { onMounted, reactive } from 'vue' import { onMounted, reactive, nextTick } from 'vue'
import { IPage } from '../api/http/type' import { IPage } from '../api/http/type'
import { ELocalStorageKey } from '../types/enums' import { ELocalStorageKey } from '../types/enums'
import { downloadFile } from '../utils/common' import { downloadFile } from '../utils/common'
import { downloadMediaFile, getMediaFiles } from '/@/api/media' import { downloadMediaFile, getMediaFiles, operateFile, deleteFile, floderTreeData } from '/@/api/media'
import { import {
ZoomInOutlined, ZoomInOutlined,
DownloadOutlined DownloadOutlined,
EditOutlined,
CheckOutlined,
CloseOutlined,
DeleteOutlined,
LoginOutlined
} from '@ant-design/icons-vue' } from '@ant-design/icons-vue'
import { message, Pagination } from 'ant-design-vue' import { message, Pagination } from 'ant-design-vue'
const workspaceId = localStorage.getItem(ELocalStorageKey.WorkspaceId)! const workspaceId = localStorage.getItem(ELocalStorageKey.WorkspaceId)
const loading = ref(false) const loading = ref(false)
const pathId = ref('')
const searchParam = reactive({ timestamp: [], type: [], name: '' }) const searchParam = reactive({ timestamp: [], type: [], name: '' })
const state = reactive({ selectedRowIds: [], folderOpen: false, fileName: '' }) const state = reactive({ rowid: '', selectedRowIds: [], folderOpen: false, fileName: '新建文件夹', fatherId: 0, changeName: '', index: '', folderTree: false })
const tableRef = ref()
//
const breadList = ref(['全部文件']) const breadList = ref(['全部文件'])
// id
const fatherids = ref([0])
//
const breadNum = ref(0) const breadNum = ref(0)
const columns = [ const columns = [
{ {
title: '文件名称', title: '文件名称',
dataIndex: 'file_name', dataIndex: 'file_name',
ellipsis: true, ellipsis: true,
width: 300,
slots: { customRender: 'file_name' } slots: { customRender: 'file_name' }
}, },
{ {
title: '拍摄负载', title: '拍摄负载',
dataIndex: 'payload', dataIndex: 'payload',
ellipsis: true, ellipsis: true,
slots: { customRender: 'payload' }
}, },
{ {
title: '大小', title: '大小',
dataIndex: 'drone' dataIndex: 'drone',
slots: { customRender: 'drone' }
}, },
{ {
title: '创建时间', title: '创建时间',
@ -137,7 +179,7 @@ const columns = [
title: '操作', title: '操作',
key: 'operation', key: 'operation',
fixed: 'right', fixed: 'right',
width: 100, width: 120,
slots: { customRender: 'action' } slots: { customRender: 'action' }
} }
@ -148,14 +190,20 @@ const body: IPage = {
page_size: 50 page_size: 50
} }
const paginationProp = reactive({ const paginationProp = reactive({
pageSizeOptions: ['20', '50', '100'], page_size: 10,
showQuickJumper: true,
showSizeChanger: true,
page_size: 50,
page: 1, page: 1,
total: 0 total: 0
}) })
const treeList = ref([])
const fieldNames = reactive({
children: 'children',
title: 'file_name',
key: 'id',
value: 'id',
})
const expandedKeys = ref<string[]>([])
const selectedKeys = ref<string[]>([])
const checkedKeys = ref<string[]>([])
type Pagination = TableState['pagination'] type Pagination = TableState['pagination']
interface MediaFile { interface MediaFile {
@ -167,6 +215,7 @@ interface MediaFile {
file_path: string, file_path: string,
create_time: string, create_time: string,
file_id: string, file_id: string,
id:number
} }
const mediaData = reactive({ const mediaData = reactive({
@ -175,13 +224,30 @@ const mediaData = reactive({
onMounted(() => { onMounted(() => {
// pathId.value = val // pathId.value = val
getFiles() nextTick(() => {
if (tableRef.value.$el) {
const tableContainer = tableRef.value.$el.querySelector('.ant-table-body')
tableContainer.addEventListener('scroll', handleScroll)
}
})
getFiles(workspaceId, paginationProp)
}) })
const handleScroll = () => {
function getFiles () { const tableContainer = tableRef.value.$el.querySelector('.ant-table-body')
const scrollPosition = tableContainer.scrollTop
const isAtTop = scrollPosition === 0
const isAtBottom = tableContainer.scrollHeight - scrollPosition === tableContainer.clientHeight
if (isAtBottom) {
//
if (paginationProp.total > mediaData.data.length) {
getFiles(workspaceId, paginationProp, state.fatherId)
}
}
}
function getFiles (...data) {
loading.value = true loading.value = true
getMediaFiles(workspaceId, paginationProp).then(res => { getMediaFiles(...data).then(res => {
mediaData.data = res.data.list mediaData.data = mediaData.data.concat(res.data.list)
paginationProp.total = res.data.pagination.total paginationProp.total = res.data.pagination.total
paginationProp.page = res.data.pagination.page paginationProp.page = res.data.pagination.page
}).finally(() => { }).finally(() => {
@ -192,7 +258,7 @@ function getFiles () {
function refreshData (page: Pagination) { function refreshData (page: Pagination) {
body.page = page?.current! body.page = page?.current!
body.page_size = page?.pageSize! body.page_size = page?.pageSize!
getFiles() getFiles(workspaceId, paginationProp)
} }
function downloadMedia (media: MediaFile) { function downloadMedia (media: MediaFile) {
@ -210,25 +276,101 @@ function downloadMedia (media: MediaFile) {
const rowSelection = { const rowSelection = {
onChange: (selectedRowKeys:any, selectedRows:any) => { onChange: (selectedRowKeys:any, selectedRows:any) => {
state.selectedRowIds = selectedRows.map((item:any) => item.father_id) state.selectedRowIds = selectedRows.map((item:any) => item.id)
}, },
} }
const createFile = () => { const openFileDialog = () => {
state.folderOpen = true state.folderOpen = true
state.fileName = '新建文件夹'
} }
const goDetail = (param:any) => { const goDetail = (param:any, index?:any) => {
if (param.file_type !== 0) { return } if (param.file_type === 0 && state.index === '') {
loading.value = true state.fatherId = param.id
breadNum.value++ loading.value = true
breadList.value[breadNum.value] = param.file_name breadNum.value++
getMediaFiles(workspaceId, paginationProp, param.father_id).then(res => { fatherids.value.push(param.id)
mediaData.data = res.data.list breadList.value[breadNum.value] = param.file_name
paginationProp.total = res.data.pagination.total mediaData.data = []
paginationProp.page = res.data.pagination.page getFiles(workspaceId, paginationProp, param.id)
}).finally(() => { }
loading.value = false }
const jumpToPath = (index:any) => {
if (index !== breadNum.value) {
breadList.value.splice(index + 1)
fatherids.value.splice(index + 1)
breadNum.value = index
state.fatherId = fatherids.value[index]
mediaData.data = []
getFiles(workspaceId, paginationProp, fatherids.value[index])
}
}
//
const createFile = (id?:any) => {
state.fileName = id ? state.changeName : state.fileName
if (!state.fileName) {
message.warning('文件夹名称不能为空')
return
}
const param = id ? { id: id, file_name: state.fileName, father_id: state.fatherId } : { file_name: state.fileName, father_id: state.fatherId }
operateFile(workspaceId, param).then(res => {
if (res.code === 0) {
state.index = ''
const msg = id ? '修改成功' : '新建成功'
message.success(msg)
state.folderOpen = false
mediaData.data = []
getFiles(workspaceId, paginationProp, param.father_id)
}
}) })
} }
//
const editName = (index:any) => {
state.index = index
state.changeName = mediaData.data[index].file_name
}
//
const cancelEdit = () => {
state.index = ''
state.changeName = ''
}
const deleteRow = (index?:any) => {
deleteFile(workspaceId, index ? mediaData.data[index].id : state.selectedRowIds).then(res => {
if (res.code === 0) {
state.selectedRowIds = []
message.success('删除成功')
mediaData.data = []
getFiles(workspaceId, paginationProp, state.fatherId)
}
})
}
//
const moveSubmit = () => {
const param = { ids: state.selectedRowIds.length ? state.selectedRowIds : [state.rowid], father_id: selectedKeys.value }
operateFile(workspaceId, param).then(res => {
if (res.code === 0) {
message.success('移动成功')
state.folderTree = false
mediaData.data = []
getFiles(workspaceId, paginationProp, state.fatherId)
}
})
}
//
const move = (id?:any) => {
state.rowid = id
floderTreeData(workspaceId).then(res => {
if (res.code === 0) {
treeList.value = res.data
console.log(treeList.value, res.data, '1212')
state.folderTree = true
}
})
}
const selectTree = (seid:any, e:any) => {
selectedKeys.value = e.node.dataRef.id
}
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
@ -238,6 +380,10 @@ const goDetail = (param:any) => {
.bread-content{ .bread-content{
background: #fff; background: #fff;
padding: 16px; padding: 16px;
.tab-click{
cursor: pointer;
color:#333;
}
} }
.media-table { .media-table {
background: #fff; background: #fff;
@ -252,6 +398,9 @@ const goDetail = (param:any) => {
height: 25px; height: 25px;
margin-right: 8px; margin-right: 8px;
} }
.space{
margin-left: 6px;
}
.header { .header {
width: 100%; width: 100%;
padding: 16px 16px 0 16px; padding: 16px 16px 0 16px;
@ -281,9 +430,12 @@ const goDetail = (param:any) => {
border: none; border: none;
} }
::v-deep{ ::v-deep{
.edit-input{
width: 100px !important;
margin-right: 10px;
}
.ant-modal-header{ .ant-modal-header{
padding: 0 0 !important; padding: 0 0 !important;
} }
} }
</style> </style>

Loading…
Cancel
Save