mirror of
https://gitee.com/dromara/mayfly-go
synced 2025-11-15 05:40:25 +08:00
feat: 机器文件新增批量删除、copy、mv、rename等操作
This commit is contained in:
@@ -1,6 +1,14 @@
|
|||||||
<template>
|
<template>
|
||||||
<div id="terminalRecDialog">
|
<div id="terminalRecDialog">
|
||||||
<el-dialog :title="title" v-model="dialogVisible" :before-close="handleClose" :close-on-click-modal="false" :destroy-on-close="true" width="70%">
|
<el-dialog
|
||||||
|
:title="title"
|
||||||
|
v-if="dialogVisible"
|
||||||
|
v-model="dialogVisible"
|
||||||
|
:before-close="handleClose"
|
||||||
|
:close-on-click-modal="false"
|
||||||
|
:destroy-on-close="true"
|
||||||
|
width="70%"
|
||||||
|
>
|
||||||
<div class="toolbar">
|
<div class="toolbar">
|
||||||
<el-select @change="getUsers" v-model="operateDate" placeholder="操作日期" filterable>
|
<el-select @change="getUsers" v-model="operateDate" placeholder="操作日期" filterable>
|
||||||
<el-option v-for="item in operateDates" :key="item" :label="item" :value="item"> </el-option>
|
<el-option v-for="item in operateDates" :key="item" :label="item" :value="item"> </el-option>
|
||||||
|
|||||||
@@ -29,7 +29,10 @@ export const machineApi = {
|
|||||||
lsFile: Api.newGet('/machines/{machineId}/files/{fileId}/read-dir'),
|
lsFile: Api.newGet('/machines/{machineId}/files/{fileId}/read-dir'),
|
||||||
dirSize: Api.newGet('/machines/{machineId}/files/{fileId}/dir-size'),
|
dirSize: Api.newGet('/machines/{machineId}/files/{fileId}/dir-size'),
|
||||||
fileStat: Api.newGet('/machines/{machineId}/files/{fileId}/file-stat'),
|
fileStat: Api.newGet('/machines/{machineId}/files/{fileId}/file-stat'),
|
||||||
rmFile: Api.newDelete('/machines/{machineId}/files/{fileId}/remove'),
|
rmFile: Api.newPost('/machines/{machineId}/files/{fileId}/remove'),
|
||||||
|
cpFile: Api.newPost('/machines/{machineId}/files/{fileId}/cp'),
|
||||||
|
renameFile: Api.newPost('/machines/{machineId}/files/{fileId}/rename'),
|
||||||
|
mvFile: Api.newPost('/machines/{machineId}/files/{fileId}/mv'),
|
||||||
uploadFile: Api.newPost('/machines/{machineId}/files/{fileId}/upload?token={token}'),
|
uploadFile: Api.newPost('/machines/{machineId}/files/{fileId}/upload?token={token}'),
|
||||||
fileContent: Api.newGet('/machines/{machineId}/files/{fileId}/read'),
|
fileContent: Api.newGet('/machines/{machineId}/files/{fileId}/read'),
|
||||||
createFile: Api.newPost('/machines/{machineId}/files/{id}/create-file'),
|
createFile: Api.newPost('/machines/{machineId}/files/{id}/create-file'),
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="file-manage">
|
<div class="file-manage">
|
||||||
<el-dialog :title="title" v-model="dialogVisible" :show-close="true" :before-close="handleClose" width="50%">
|
<el-dialog v-if="dialogVisible" :title="title" v-model="dialogVisible" :show-close="true" :before-close="handleClose" width="50%">
|
||||||
<el-table :data="fileTable" stripe style="width: 100%" v-loading="loading">
|
<el-table :data="fileTable" stripe style="width: 100%" v-loading="loading">
|
||||||
<el-table-column prop="name" label="名称" min-width="70px">
|
<el-table-column prop="name" label="名称" min-width="100px">
|
||||||
<template #header>
|
<template #header>
|
||||||
<el-button class="ml0" type="primary" circle size="small" icon="Plus" @click="add()"> </el-button>
|
<el-button class="ml0" type="primary" circle size="small" icon="Plus" @click="add()"> </el-button>
|
||||||
<span class="ml10">名称</span>
|
<span class="ml10">名称</span>
|
||||||
@@ -23,7 +23,7 @@
|
|||||||
<el-input v-model="scope.row.path" :disabled="scope.row.id != null" clearable> </el-input>
|
<el-input v-model="scope.row.path" :disabled="scope.row.id != null" clearable> </el-input>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="操作" min-wdith="180px">
|
<el-table-column label="操作" min-wdith="120px">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-button v-if="scope.row.id == null" @click="addFiles(scope.row)" type="success" icon="success-filled" plain></el-button>
|
<el-button v-if="scope.row.id == null" @click="addFiles(scope.row)" type="success" icon="success-filled" plain></el-button>
|
||||||
<el-button v-if="scope.row.id != null" @click="getConf(scope.row)" type="primary" icon="tickets" plain></el-button>
|
<el-button v-if="scope.row.id != null" @click="getConf(scope.row)" type="primary" icon="tickets" plain></el-button>
|
||||||
@@ -42,13 +42,19 @@
|
|||||||
>
|
>
|
||||||
</el-pagination>
|
</el-pagination>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
|
||||||
|
<el-dialog destroy-on-close :title="fileDialog.title" v-model="fileDialog.visible" :close-on-click-modal="false" width="70%">
|
||||||
|
<machine-file :title="fileDialog.title" :machine-id="machineId" :file-id="fileDialog.fileId" :path="fileDialog.path" />
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
|
||||||
<el-dialog destroy-on-close :title="fileDialog.title" v-model="fileDialog.visible" :close-on-click-modal="false" width="65%">
|
<machine-file-content
|
||||||
<machine-file :machine-id="machineId" :file-id="fileDialog.fileId" :path="fileDialog.path" />
|
:title="fileContent.title"
|
||||||
|
v-model:visible="fileContent.contentVisible"
|
||||||
|
:machine-id="machineId"
|
||||||
|
:file-id="fileContent.fileId"
|
||||||
|
:path="fileContent.path"
|
||||||
|
/>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
|
||||||
<machine-file-content v-model:visible="fileContent.contentVisible" :machine-id="machineId" :file-id="fileContent.fileId" :path="fileContent.path" />
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -56,7 +62,6 @@
|
|||||||
import { toRefs, reactive, watch } from 'vue';
|
import { toRefs, reactive, watch } from 'vue';
|
||||||
import { ElMessage, ElMessageBox } from 'element-plus';
|
import { ElMessage, ElMessageBox } from 'element-plus';
|
||||||
import { machineApi } from '../api';
|
import { machineApi } from '../api';
|
||||||
|
|
||||||
import { FileTypeEnum } from '../enums';
|
import { FileTypeEnum } from '../enums';
|
||||||
import MachineFile from './MachineFile.vue';
|
import MachineFile from './MachineFile.vue';
|
||||||
import MachineFileContent from './MachineFileContent.vue';
|
import MachineFileContent from './MachineFileContent.vue';
|
||||||
@@ -96,9 +101,9 @@ const state = reactive({
|
|||||||
path: '',
|
path: '',
|
||||||
},
|
},
|
||||||
fileContent: {
|
fileContent: {
|
||||||
|
title: '',
|
||||||
fileId: 0,
|
fileId: 0,
|
||||||
contentVisible: false,
|
contentVisible: false,
|
||||||
dialogTitle: '',
|
|
||||||
path: '',
|
path: '',
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@@ -168,15 +173,18 @@ const getConf = async (row: any) => {
|
|||||||
state.fileDialog.fileId = row.id;
|
state.fileDialog.fileId = row.id;
|
||||||
state.fileDialog.title = row.name;
|
state.fileDialog.title = row.name;
|
||||||
state.fileDialog.path = row.path;
|
state.fileDialog.path = row.path;
|
||||||
|
state.fileDialog.title = `${props.title} => ${row.path}`;
|
||||||
state.fileDialog.visible = true;
|
state.fileDialog.visible = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
showFileContent(row.id, row.path);
|
showFileContent(row.id, row.path);
|
||||||
};
|
};
|
||||||
|
|
||||||
const showFileContent = async (fileId: number, path: string) => {
|
const showFileContent = async (fileId: number, path: string) => {
|
||||||
state.fileContent.fileId = fileId;
|
state.fileContent.fileId = fileId;
|
||||||
state.fileContent.path = path;
|
state.fileContent.path = path;
|
||||||
|
state.fileContent.title = `${props.title} => ${path}`;
|
||||||
state.fileContent.contentVisible = true;
|
state.fileContent.contentVisible = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -2,20 +2,32 @@
|
|||||||
<div class="machine-file">
|
<div class="machine-file">
|
||||||
<div>
|
<div>
|
||||||
<el-progress v-if="uploadProgressShow" style="width: 90%; margin-left: 20px" :text-inside="true" :stroke-width="20" :percentage="progressNum" />
|
<el-progress v-if="uploadProgressShow" style="width: 90%; margin-left: 20px" :text-inside="true" :stroke-width="20" :percentage="progressNum" />
|
||||||
|
|
||||||
<el-row class="mb10">
|
<el-row class="mb10">
|
||||||
<el-breadcrumb separator-icon="ArrowRight">
|
<el-breadcrumb separator-icon="ArrowRight">
|
||||||
<el-breadcrumb-item v-for="path in filePathNav">
|
<el-breadcrumb-item v-for="path in filePathNav">
|
||||||
<el-link @click="setFiles(path.path)">{{ path.name }}</el-link>
|
<el-link @click="setFiles(path.path)" style="font-weight: bold">{{ path.name }}</el-link>
|
||||||
</el-breadcrumb-item>
|
</el-breadcrumb-item>
|
||||||
</el-breadcrumb>
|
</el-breadcrumb>
|
||||||
</el-row>
|
</el-row>
|
||||||
<el-table ref="fileTableRef" height="65vh" :data="files" style="width: 100%" highlight-current-row v-loading="loading">
|
|
||||||
|
<el-table
|
||||||
|
ref="fileTableRef"
|
||||||
|
@cell-dblclick="cellDbclick"
|
||||||
|
@selection-change="handleSelectionChange"
|
||||||
|
height="65vh"
|
||||||
|
:data="filterFiles"
|
||||||
|
highlight-current-row
|
||||||
|
v-loading="loading"
|
||||||
|
>
|
||||||
|
<el-table-column type="selection" width="30" />
|
||||||
|
|
||||||
<el-table-column prop="name" label="名称" show-overflow-tooltip>
|
<el-table-column prop="name" label="名称" show-overflow-tooltip>
|
||||||
<template #header>
|
<template #header>
|
||||||
<div class="machine-file-table-header">
|
<div class="machine-file-table-header">
|
||||||
<div>
|
<div>
|
||||||
<el-button :disabled="nowPath == basePath" type="primary" circle size="small" icon="Back" @click="back()"> </el-button>
|
<el-button :disabled="nowPath == basePath" type="primary" circle size="small" icon="Back" @click="back()"> </el-button>
|
||||||
<el-button class="ml0" type="primary" circle size="small" icon="Refresh" @click="refresh()"> </el-button>
|
<el-button class="ml5" type="primary" circle size="small" icon="Refresh" @click="refresh()"> </el-button>
|
||||||
|
|
||||||
<el-upload
|
<el-upload
|
||||||
:before-upload="beforeUpload"
|
:before-upload="beforeUpload"
|
||||||
@@ -27,19 +39,78 @@
|
|||||||
name="file"
|
name="file"
|
||||||
class="machine-file-upload-exec"
|
class="machine-file-upload-exec"
|
||||||
>
|
>
|
||||||
<el-button v-auth="'machine:file:upload'" class="ml10" type="primary" circle size="small" icon="Upload"> </el-button>
|
<el-button v-auth="'machine:file:upload'" class="ml5" type="primary" circle size="small" icon="Upload" title="上传">
|
||||||
|
</el-button>
|
||||||
</el-upload>
|
</el-upload>
|
||||||
|
|
||||||
|
<el-button
|
||||||
|
:disabled="state.selectionFiles.length == 0"
|
||||||
|
v-auth="'machine:file:rm'"
|
||||||
|
@click="copyFile(state.selectionFiles)"
|
||||||
|
class="ml5"
|
||||||
|
type="primary"
|
||||||
|
circle
|
||||||
|
size="small"
|
||||||
|
icon="CopyDocument"
|
||||||
|
title="复制"
|
||||||
|
>
|
||||||
|
</el-button>
|
||||||
|
|
||||||
|
<el-button
|
||||||
|
:disabled="state.selectionFiles.length == 0"
|
||||||
|
v-auth="'machine:file:rm'"
|
||||||
|
@click="mvFile(state.selectionFiles)"
|
||||||
|
class="ml5"
|
||||||
|
type="primary"
|
||||||
|
circle
|
||||||
|
size="small"
|
||||||
|
icon="Rank"
|
||||||
|
title="移动"
|
||||||
|
>
|
||||||
|
</el-button>
|
||||||
|
|
||||||
<el-button
|
<el-button
|
||||||
v-auth="'machine:file:write'"
|
v-auth="'machine:file:write'"
|
||||||
@click="showCreateFileDialog()"
|
@click="showCreateFileDialog()"
|
||||||
class="ml10"
|
class="ml5"
|
||||||
type="primary"
|
type="primary"
|
||||||
circle
|
circle
|
||||||
size="small"
|
size="small"
|
||||||
icon="FolderAdd"
|
icon="FolderAdd"
|
||||||
|
title="新建"
|
||||||
>
|
>
|
||||||
</el-button>
|
</el-button>
|
||||||
|
|
||||||
|
<el-button
|
||||||
|
:disabled="state.selectionFiles.length == 0"
|
||||||
|
v-auth="'machine:file:rm'"
|
||||||
|
@click="deleteFile(state.selectionFiles)"
|
||||||
|
class="ml5"
|
||||||
|
type="danger"
|
||||||
|
circle
|
||||||
|
size="small"
|
||||||
|
icon="delete"
|
||||||
|
title="删除"
|
||||||
|
>
|
||||||
|
</el-button>
|
||||||
|
|
||||||
|
<el-button-group v-if="state.copyOrMvFile.paths.length > 0" size="small" class="ml5">
|
||||||
|
<el-tooltip effect="customized" raw-content placement="top">
|
||||||
|
<template #content>
|
||||||
|
<div v-for="path in state.copyOrMvFile.paths">{{ path }}</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<el-button @click="pasteFile" type="primary"
|
||||||
|
>{{ isCpFile() ? '复制' : '移动' }}粘贴{{ state.copyOrMvFile.paths.length }}</el-button
|
||||||
|
>
|
||||||
|
</el-tooltip>
|
||||||
|
|
||||||
|
<el-button icon="CloseBold" @click="cancelCopy" />
|
||||||
|
</el-button-group>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div style="width: 150px">
|
||||||
|
<el-input v-model="fileNameFilter" size="small" placeholder="名称: 输入可过滤" clearable />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -52,8 +123,16 @@
|
|||||||
<SvgIcon :size="15" name="document" />
|
<SvgIcon :size="15" name="document" />
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<span class="ml5" style="font-weight: bold">
|
<span class="ml5" style="display: inline-block; width: 300px">
|
||||||
<el-link @click="getFile(scope.row)" :underline="false">{{ scope.row.name }}</el-link>
|
<div v-if="scope.row.nameEdit">
|
||||||
|
<el-input
|
||||||
|
@keyup.enter="fileRename(scope.row)"
|
||||||
|
:ref="(el: any) => el?.focus()"
|
||||||
|
@blur="filenameBlur(scope.row)"
|
||||||
|
v-model="scope.row.name"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<el-link v-else @click="getFile(scope.row)" style="font-weight: bold" :underline="false">{{ scope.row.name }}</el-link>
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
@@ -71,7 +150,16 @@
|
|||||||
<el-table-column prop="mode" label="属性" width="110"> </el-table-column>
|
<el-table-column prop="mode" label="属性" width="110"> </el-table-column>
|
||||||
<el-table-column prop="modTime" label="修改时间" width="165" sortable> </el-table-column>
|
<el-table-column prop="modTime" label="修改时间" width="165" sortable> </el-table-column>
|
||||||
|
|
||||||
<el-table-column label="操作" width="100">
|
<el-table-column width="100">
|
||||||
|
<template #header>
|
||||||
|
<el-popover placement="top" :width="270" trigger="hover">
|
||||||
|
<template #reference>
|
||||||
|
<SvgIcon name="QuestionFilled" :size="18" class="pointer-icon mr10" />
|
||||||
|
</template>
|
||||||
|
<div>rename: 双击文件名单元格后回车</div>
|
||||||
|
</el-popover>
|
||||||
|
操作
|
||||||
|
</template>
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-link
|
<el-link
|
||||||
@click="downloadFile(scope.row)"
|
@click="downloadFile(scope.row)"
|
||||||
@@ -83,7 +171,7 @@
|
|||||||
></el-link>
|
></el-link>
|
||||||
|
|
||||||
<el-link
|
<el-link
|
||||||
@click="deleteFile(scope.row)"
|
@click="deleteFile([scope.row])"
|
||||||
v-if="!dontOperate(scope.row)"
|
v-if="!dontOperate(scope.row)"
|
||||||
v-auth="'machine:file:rm'"
|
v-auth="'machine:file:rm'"
|
||||||
type="danger"
|
type="danger"
|
||||||
@@ -147,13 +235,14 @@
|
|||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { toRefs, reactive, onMounted, computed } from 'vue';
|
import { toRefs, reactive, onMounted, computed } from 'vue';
|
||||||
import { ElMessage, ElMessageBox } from 'element-plus';
|
import { ElMessage, ElMessageBox, ElInput } from 'element-plus';
|
||||||
import { machineApi } from '../api';
|
import { machineApi } from '../api';
|
||||||
|
|
||||||
import { getSession } from '@/common/utils/storage';
|
import { getSession } from '@/common/utils/storage';
|
||||||
import config from '@/common/config';
|
import config from '@/common/config';
|
||||||
import { isTrue } from '@/common/assert';
|
import { isTrue } from '@/common/assert';
|
||||||
import MachineFileContent from './MachineFileContent.vue';
|
import MachineFileContent from './MachineFileContent.vue';
|
||||||
|
import { notBlank } from '@/common/assert';
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
machineId: { type: Number },
|
machineId: { type: Number },
|
||||||
@@ -175,7 +264,17 @@ const state = reactive({
|
|||||||
loading: true,
|
loading: true,
|
||||||
progressNum: 0,
|
progressNum: 0,
|
||||||
uploadProgressShow: false,
|
uploadProgressShow: false,
|
||||||
|
fileNameFilter: '',
|
||||||
files: [] as any,
|
files: [] as any,
|
||||||
|
selectionFiles: [] as any,
|
||||||
|
copyOrMvFile: {
|
||||||
|
paths: [] as any,
|
||||||
|
type: 'cp',
|
||||||
|
fromPath: '',
|
||||||
|
},
|
||||||
|
renameFile: {
|
||||||
|
oldname: '',
|
||||||
|
},
|
||||||
fileContent: {
|
fileContent: {
|
||||||
content: '',
|
content: '',
|
||||||
contentVisible: false,
|
contentVisible: false,
|
||||||
@@ -192,13 +291,17 @@ const state = reactive({
|
|||||||
file: null as any,
|
file: null as any,
|
||||||
});
|
});
|
||||||
|
|
||||||
const { basePath, nowPath, loading, files, progressNum, uploadProgressShow, fileContent, createFileDialog } = toRefs(state);
|
const { basePath, nowPath, loading, fileNameFilter, progressNum, uploadProgressShow, fileContent, createFileDialog } = toRefs(state);
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
state.basePath = props.path;
|
state.basePath = props.path;
|
||||||
setFiles(props.path);
|
setFiles(props.path);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const filterFiles = computed(() =>
|
||||||
|
state.files.filter((data: any) => !state.fileNameFilter || data.name.toLowerCase().includes(state.fileNameFilter.toLowerCase()))
|
||||||
|
);
|
||||||
|
|
||||||
const filePathNav = computed(() => {
|
const filePathNav = computed(() => {
|
||||||
let basePath = state.basePath;
|
let basePath = state.basePath;
|
||||||
const pathNavs = [
|
const pathNavs = [
|
||||||
@@ -233,6 +336,98 @@ const filePathNav = computed(() => {
|
|||||||
return pathNavs;
|
return pathNavs;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const handleSelectionChange = (val: any) => {
|
||||||
|
state.selectionFiles = val;
|
||||||
|
};
|
||||||
|
|
||||||
|
const isCpFile = () => {
|
||||||
|
return state.copyOrMvFile.type == 'cp';
|
||||||
|
};
|
||||||
|
|
||||||
|
const copyFile = (files: any[]) => {
|
||||||
|
setCopyOrMvFile(files);
|
||||||
|
};
|
||||||
|
|
||||||
|
const mvFile = (files: any[]) => {
|
||||||
|
setCopyOrMvFile(files, 'mv');
|
||||||
|
};
|
||||||
|
|
||||||
|
const setCopyOrMvFile = (files: any[], type = 'cp') => {
|
||||||
|
for (let file of files) {
|
||||||
|
const path = file.path;
|
||||||
|
if (!state.copyOrMvFile.paths.includes(path)) {
|
||||||
|
state.copyOrMvFile.paths.push(path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
state.copyOrMvFile.type = type;
|
||||||
|
state.copyOrMvFile.fromPath = state.nowPath;
|
||||||
|
};
|
||||||
|
|
||||||
|
const pasteFile = async () => {
|
||||||
|
const cmFile = state.copyOrMvFile;
|
||||||
|
isTrue(state.nowPath != cmFile.fromPath, '同目录下不能粘贴');
|
||||||
|
const api = isCpFile() ? machineApi.cpFile : machineApi.mvFile;
|
||||||
|
try {
|
||||||
|
state.loading = true;
|
||||||
|
await api.request({
|
||||||
|
machineId: props.machineId,
|
||||||
|
fileId: props.fileId,
|
||||||
|
path: cmFile.paths,
|
||||||
|
toPath: state.nowPath,
|
||||||
|
});
|
||||||
|
ElMessage.success('粘贴成功');
|
||||||
|
state.copyOrMvFile.paths = [];
|
||||||
|
refresh();
|
||||||
|
} finally {
|
||||||
|
state.loading = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const cancelCopy = () => {
|
||||||
|
state.copyOrMvFile.paths = [];
|
||||||
|
};
|
||||||
|
|
||||||
|
const cellDbclick = (row: any, column: any) => {
|
||||||
|
// 双击名称列可修改名称
|
||||||
|
if (column.property == 'name') {
|
||||||
|
state.renameFile.oldname = row.name;
|
||||||
|
row.nameEdit = true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const filenameBlur = (row: any) => {
|
||||||
|
const oldname = state.renameFile.oldname;
|
||||||
|
// 如果存在旧名称,则说明未回车修改文件名,则还原旧文件名
|
||||||
|
if (oldname) {
|
||||||
|
row.name = oldname;
|
||||||
|
state.renameFile.oldname = '';
|
||||||
|
}
|
||||||
|
row.nameEdit = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
const fileRename = async (row: any) => {
|
||||||
|
if (row.name == state.renameFile.oldname) {
|
||||||
|
row.nameEdit = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
notBlank(row.name, '新名称不能为空');
|
||||||
|
try {
|
||||||
|
await machineApi.renameFile.request({
|
||||||
|
machineId: props.machineId,
|
||||||
|
fileId: props.fileId,
|
||||||
|
oldname: state.nowPath + pathSep + state.renameFile.oldname,
|
||||||
|
newname: state.nowPath + pathSep + row.name,
|
||||||
|
});
|
||||||
|
ElMessage.success('重命名成功');
|
||||||
|
// 修改路径上的文件名
|
||||||
|
row.path = state.nowPath + pathSep + row.name;
|
||||||
|
state.renameFile.oldname = '';
|
||||||
|
} catch (e) {
|
||||||
|
row.name = state.renameFile.oldname;
|
||||||
|
}
|
||||||
|
row.nameEdit = false;
|
||||||
|
};
|
||||||
|
|
||||||
const showFileContent = async (path: string) => {
|
const showFileContent = async (path: string) => {
|
||||||
state.fileContent.dialogTitle = path;
|
state.fileContent.dialogTitle = path;
|
||||||
state.fileContent.path = path;
|
state.fileContent.path = path;
|
||||||
@@ -253,6 +448,7 @@ const setFiles = async (path: string) => {
|
|||||||
if (!path) {
|
if (!path) {
|
||||||
path = pathSep;
|
path = pathSep;
|
||||||
}
|
}
|
||||||
|
state.fileNameFilter = '';
|
||||||
state.loading = true;
|
state.loading = true;
|
||||||
state.files = await lsFile(path);
|
state.files = await lsFile(path);
|
||||||
state.nowPath = path;
|
state.nowPath = path;
|
||||||
@@ -350,28 +546,25 @@ function getParentPath(filePath: string) {
|
|||||||
return segments.join(pathSep);
|
return segments.join(pathSep);
|
||||||
}
|
}
|
||||||
|
|
||||||
const deleteFile = (data: any) => {
|
const deleteFile = async (files: any) => {
|
||||||
const file = data.path;
|
try {
|
||||||
ElMessageBox.confirm(`此操作将删除 [${file}], 是否继续?`, '提示', {
|
await ElMessageBox.confirm(`此操作将删除 ${files.map((x: any) => `[${x.path}]`).join('\n')}, 是否继续?`, '提示', {
|
||||||
confirmButtonText: '确定',
|
confirmButtonText: '确定',
|
||||||
cancelButtonText: '取消',
|
cancelButtonText: '取消',
|
||||||
type: 'warning',
|
type: 'warning',
|
||||||
})
|
});
|
||||||
.then(() => {
|
state.loading = true;
|
||||||
machineApi.rmFile
|
await machineApi.rmFile.request({
|
||||||
.request({
|
|
||||||
fileId: props.fileId,
|
fileId: props.fileId,
|
||||||
path: file,
|
path: files.map((x: any) => x.path),
|
||||||
machineId: props.machineId,
|
machineId: props.machineId,
|
||||||
})
|
});
|
||||||
.then(async () => {
|
|
||||||
ElMessage.success('删除成功');
|
ElMessage.success('删除成功');
|
||||||
refresh();
|
refresh();
|
||||||
});
|
} catch (e) {
|
||||||
})
|
} finally {
|
||||||
.catch(() => {
|
state.loading = false;
|
||||||
// skip
|
}
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const downloadFile = (data: any) => {
|
const downloadFile = (data: any) => {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="machine-file-content">
|
<div class="machine-file-content">
|
||||||
<el-dialog :before-close="handleClose" :title="path" v-model="dialogVisible" :close-on-click-modal="false" top="5vh" width="65%">
|
<el-dialog :before-close="handleClose" :title="title || path" v-model="dialogVisible" :close-on-click-modal="false" top="5vh" width="65%">
|
||||||
<div>
|
<div>
|
||||||
<monaco-editor :can-change-mode="true" v-model="content" :language="fileType" />
|
<monaco-editor :can-change-mode="true" v-model="content" :language="fileType" />
|
||||||
</div>
|
</div>
|
||||||
@@ -24,6 +24,7 @@ import MonacoEditor from '@/components/monaco/MonacoEditor.vue';
|
|||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
visible: { type: Boolean, default: false },
|
visible: { type: Boolean, default: false },
|
||||||
|
title: { type: String, default: '' },
|
||||||
machineId: { type: Number },
|
machineId: { type: Number },
|
||||||
fileId: { type: Number, default: 0 },
|
fileId: { type: Number, default: 0 },
|
||||||
path: { type: String, default: '' },
|
path: { type: String, default: '' },
|
||||||
|
|||||||
@@ -52,6 +52,16 @@ type MachineFileUpdateForm struct {
|
|||||||
Path string `json:"path" binding:"required"`
|
Path string `json:"path" binding:"required"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type MachineFileOpForm struct {
|
||||||
|
Path []string `json:"path" binding:"required"`
|
||||||
|
ToPath string `json:"toPath"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type MachineFileRename struct {
|
||||||
|
Oldname string `json:"oldname" binding:"required"`
|
||||||
|
Newname string `json:"newname" binding:"required"`
|
||||||
|
}
|
||||||
|
|
||||||
// 授权凭证
|
// 授权凭证
|
||||||
type AuthCertForm struct {
|
type AuthCertForm struct {
|
||||||
Id uint64 `json:"id"`
|
Id uint64 `json:"id"`
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import (
|
|||||||
"mayfly-go/pkg/biz"
|
"mayfly-go/pkg/biz"
|
||||||
"mayfly-go/pkg/ginx"
|
"mayfly-go/pkg/ginx"
|
||||||
"mayfly-go/pkg/req"
|
"mayfly-go/pkg/req"
|
||||||
|
"mayfly-go/pkg/utils/jsonx"
|
||||||
"mayfly-go/pkg/utils/timex"
|
"mayfly-go/pkg/utils/timex"
|
||||||
"mayfly-go/pkg/ws"
|
"mayfly-go/pkg/ws"
|
||||||
"sort"
|
"sort"
|
||||||
@@ -191,12 +192,48 @@ func (m *MachineFile) UploadFile(rc *req.Ctx) {
|
|||||||
func (m *MachineFile) RemoveFile(rc *req.Ctx) {
|
func (m *MachineFile) RemoveFile(rc *req.Ctx) {
|
||||||
g := rc.GinCtx
|
g := rc.GinCtx
|
||||||
fid := GetMachineFileId(g)
|
fid := GetMachineFileId(g)
|
||||||
path := g.Query("path")
|
|
||||||
|
|
||||||
m.MachineFileApp.RemoveFile(fid, path)
|
rmForm := new(form.MachineFileOpForm)
|
||||||
|
ginx.BindJsonAndValid(g, rmForm)
|
||||||
|
|
||||||
|
m.MachineFileApp.RemoveFile(fid, rmForm.Path...)
|
||||||
|
|
||||||
mi := m.MachineFileApp.GetMachine(fid)
|
mi := m.MachineFileApp.GetMachine(fid)
|
||||||
rc.ReqParam = fmt.Sprintf("%s -> 删除文件: %s", mi.GetLogDesc(), path)
|
rc.ReqParam = fmt.Sprintf("%s -> 删除文件: %s", mi.GetLogDesc(), strings.Join(rmForm.Path, " | "))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MachineFile) CopyFile(rc *req.Ctx) {
|
||||||
|
g := rc.GinCtx
|
||||||
|
fid := GetMachineFileId(g)
|
||||||
|
|
||||||
|
cpForm := new(form.MachineFileOpForm)
|
||||||
|
ginx.BindJsonAndValid(g, cpForm)
|
||||||
|
mi := m.MachineFileApp.Copy(fid, cpForm.ToPath, cpForm.Path...)
|
||||||
|
|
||||||
|
rc.ReqParam = fmt.Sprintf("%s -> 拷贝文件: %s -> %s", mi.GetLogDesc(), strings.Join(cpForm.Path, " | "), cpForm.ToPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MachineFile) MvFile(rc *req.Ctx) {
|
||||||
|
g := rc.GinCtx
|
||||||
|
fid := GetMachineFileId(g)
|
||||||
|
|
||||||
|
cpForm := new(form.MachineFileOpForm)
|
||||||
|
ginx.BindJsonAndValid(g, cpForm)
|
||||||
|
mi := m.MachineFileApp.Mv(fid, cpForm.ToPath, cpForm.Path...)
|
||||||
|
|
||||||
|
rc.ReqParam = fmt.Sprintf("%s -> 移动文件: %s -> %s", mi.GetLogDesc(), strings.Join(cpForm.Path, " | "), cpForm.ToPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MachineFile) Rename(rc *req.Ctx) {
|
||||||
|
g := rc.GinCtx
|
||||||
|
fid := GetMachineFileId(g)
|
||||||
|
|
||||||
|
rename := new(form.MachineFileRename)
|
||||||
|
ginx.BindJsonAndValid(g, rename)
|
||||||
|
biz.ErrIsNilAppendErr(m.MachineFileApp.Rename(fid, rename.Oldname, rename.Newname), "文件重命名失败: %s")
|
||||||
|
|
||||||
|
mi := m.MachineFileApp.GetMachine(fid)
|
||||||
|
rc.ReqParam = fmt.Sprintf("%s -> 文件重命名: %s", mi.GetLogDesc(), jsonx.ToStr(rename))
|
||||||
}
|
}
|
||||||
|
|
||||||
func getFileType(fm fs.FileMode) string {
|
func getFileType(fm fs.FileMode) string {
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import (
|
|||||||
"mayfly-go/internal/machine/domain/repository"
|
"mayfly-go/internal/machine/domain/repository"
|
||||||
"mayfly-go/internal/machine/infrastructure/machine"
|
"mayfly-go/internal/machine/infrastructure/machine"
|
||||||
"mayfly-go/pkg/biz"
|
"mayfly-go/pkg/biz"
|
||||||
|
"mayfly-go/pkg/logx"
|
||||||
"mayfly-go/pkg/model"
|
"mayfly-go/pkg/model"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -59,7 +60,13 @@ type MachineFile interface {
|
|||||||
UploadFile(fileId uint64, path, filename string, reader io.Reader)
|
UploadFile(fileId uint64, path, filename string, reader io.Reader)
|
||||||
|
|
||||||
// 移除文件
|
// 移除文件
|
||||||
RemoveFile(fileId uint64, path string)
|
RemoveFile(fileId uint64, path ...string)
|
||||||
|
|
||||||
|
Copy(fileId uint64, toPath string, paths ...string) *machine.Info
|
||||||
|
|
||||||
|
Mv(fileId uint64, toPath string, paths ...string) *machine.Info
|
||||||
|
|
||||||
|
Rename(fileId uint64, oldname string, newname string) error
|
||||||
}
|
}
|
||||||
|
|
||||||
func newMachineFileApp(machineFileRepo repository.MachineFile, machineRepo repository.Machine) MachineFile {
|
func newMachineFileApp(machineFileRepo repository.MachineFile, machineRepo repository.Machine) MachineFile {
|
||||||
@@ -104,7 +111,7 @@ func (m *machineFileAppImpl) Delete(id uint64) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *machineFileAppImpl) ReadDir(fid uint64, path string) []fs.FileInfo {
|
func (m *machineFileAppImpl) ReadDir(fid uint64, path string) []fs.FileInfo {
|
||||||
path, machineId := m.checkAndReturnPathMid(fid, path)
|
machineId := m.checkAndReturnMid(fid, path)
|
||||||
if !strings.HasSuffix(path, "/") {
|
if !strings.HasSuffix(path, "/") {
|
||||||
path = path + "/"
|
path = path + "/"
|
||||||
}
|
}
|
||||||
@@ -116,7 +123,7 @@ func (m *machineFileAppImpl) ReadDir(fid uint64, path string) []fs.FileInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *machineFileAppImpl) GetDirSize(fid uint64, path string) string {
|
func (m *machineFileAppImpl) GetDirSize(fid uint64, path string) string {
|
||||||
_, machineId := m.checkAndReturnPathMid(fid, path)
|
machineId := m.checkAndReturnMid(fid, path)
|
||||||
res, err := GetMachineApp().GetCli(machineId).Run(fmt.Sprintf("du -sh %s", path))
|
res, err := GetMachineApp().GetCli(machineId).Run(fmt.Sprintf("du -sh %s", path))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// 若存在目录为空,则可能会返回如下内容。最后一行即为真正目录内容所占磁盘空间大小
|
// 若存在目录为空,则可能会返回如下内容。最后一行即为真正目录内容所占磁盘空间大小
|
||||||
@@ -138,14 +145,14 @@ func (m *machineFileAppImpl) GetDirSize(fid uint64, path string) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *machineFileAppImpl) FileStat(fid uint64, path string) string {
|
func (m *machineFileAppImpl) FileStat(fid uint64, path string) string {
|
||||||
_, machineId := m.checkAndReturnPathMid(fid, path)
|
machineId := m.checkAndReturnMid(fid, path)
|
||||||
res, err := GetMachineApp().GetCli(machineId).Run(fmt.Sprintf("stat -L %s", path))
|
res, err := GetMachineApp().GetCli(machineId).Run(fmt.Sprintf("stat -L %s", path))
|
||||||
biz.ErrIsNil(err, res)
|
biz.ErrIsNil(err, res)
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *machineFileAppImpl) MkDir(fid uint64, path string) {
|
func (m *machineFileAppImpl) MkDir(fid uint64, path string) {
|
||||||
path, machineId := m.checkAndReturnPathMid(fid, path)
|
machineId := m.checkAndReturnMid(fid, path)
|
||||||
if !strings.HasSuffix(path, "/") {
|
if !strings.HasSuffix(path, "/") {
|
||||||
path = path + "/"
|
path = path + "/"
|
||||||
}
|
}
|
||||||
@@ -156,7 +163,7 @@ func (m *machineFileAppImpl) MkDir(fid uint64, path string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *machineFileAppImpl) CreateFile(fid uint64, path string) {
|
func (m *machineFileAppImpl) CreateFile(fid uint64, path string) {
|
||||||
path, machineId := m.checkAndReturnPathMid(fid, path)
|
machineId := m.checkAndReturnMid(fid, path)
|
||||||
sftpCli := m.getSftpCli(machineId)
|
sftpCli := m.getSftpCli(machineId)
|
||||||
file, err := sftpCli.Create(path)
|
file, err := sftpCli.Create(path)
|
||||||
biz.ErrIsNilAppendErr(err, "创建文件失败: %s")
|
biz.ErrIsNilAppendErr(err, "创建文件失败: %s")
|
||||||
@@ -164,7 +171,7 @@ func (m *machineFileAppImpl) CreateFile(fid uint64, path string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *machineFileAppImpl) ReadFile(fileId uint64, path string) *sftp.File {
|
func (m *machineFileAppImpl) ReadFile(fileId uint64, path string) *sftp.File {
|
||||||
path, machineId := m.checkAndReturnPathMid(fileId, path)
|
machineId := m.checkAndReturnMid(fileId, path)
|
||||||
sftpCli := m.getSftpCli(machineId)
|
sftpCli := m.getSftpCli(machineId)
|
||||||
// 读取文件内容
|
// 读取文件内容
|
||||||
fc, err := sftpCli.Open(path)
|
fc, err := sftpCli.Open(path)
|
||||||
@@ -174,7 +181,7 @@ func (m *machineFileAppImpl) ReadFile(fileId uint64, path string) *sftp.File {
|
|||||||
|
|
||||||
// 写文件内容
|
// 写文件内容
|
||||||
func (m *machineFileAppImpl) WriteFileContent(fileId uint64, path string, content []byte) {
|
func (m *machineFileAppImpl) WriteFileContent(fileId uint64, path string, content []byte) {
|
||||||
_, machineId := m.checkAndReturnPathMid(fileId, path)
|
machineId := m.checkAndReturnMid(fileId, path)
|
||||||
|
|
||||||
sftpCli := m.getSftpCli(machineId)
|
sftpCli := m.getSftpCli(machineId)
|
||||||
f, err := sftpCli.OpenFile(path, os.O_WRONLY|os.O_TRUNC|os.O_CREATE|os.O_RDWR)
|
f, err := sftpCli.OpenFile(path, os.O_WRONLY|os.O_TRUNC|os.O_CREATE|os.O_RDWR)
|
||||||
@@ -188,7 +195,7 @@ func (m *machineFileAppImpl) WriteFileContent(fileId uint64, path string, conten
|
|||||||
|
|
||||||
// 上传文件
|
// 上传文件
|
||||||
func (m *machineFileAppImpl) UploadFile(fileId uint64, path, filename string, reader io.Reader) {
|
func (m *machineFileAppImpl) UploadFile(fileId uint64, path, filename string, reader io.Reader) {
|
||||||
path, machineId := m.checkAndReturnPathMid(fileId, path)
|
machineId := m.checkAndReturnMid(fileId, path)
|
||||||
if !strings.HasSuffix(path, "/") {
|
if !strings.HasSuffix(path, "/") {
|
||||||
path = path + "/"
|
path = path + "/"
|
||||||
}
|
}
|
||||||
@@ -202,25 +209,45 @@ func (m *machineFileAppImpl) UploadFile(fileId uint64, path, filename string, re
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 删除文件
|
// 删除文件
|
||||||
func (m *machineFileAppImpl) RemoveFile(fileId uint64, path string) {
|
func (m *machineFileAppImpl) RemoveFile(fileId uint64, path ...string) {
|
||||||
path, machineId := m.checkAndReturnPathMid(fileId, path)
|
machineId := m.checkAndReturnMid(fileId, path...)
|
||||||
|
|
||||||
|
// 优先使用命令删除(速度快),sftp需要递归遍历删除子文件等
|
||||||
|
mcli := GetMachineApp().GetCli(machineId)
|
||||||
|
res, err := mcli.Run(fmt.Sprintf("rm -rf %s", strings.Join(path, " ")))
|
||||||
|
if err == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
logx.Errorf("使用命令rm删除文件失败: %s", res)
|
||||||
|
|
||||||
sftpCli := m.getSftpCli(machineId)
|
sftpCli := m.getSftpCli(machineId)
|
||||||
file, err := sftpCli.Open(path)
|
for _, p := range path {
|
||||||
biz.ErrIsNilAppendErr(err, "打开文件失败: %s")
|
err := sftpCli.RemoveAll(p)
|
||||||
fi, _ := file.Stat()
|
|
||||||
if fi.IsDir() {
|
|
||||||
err = sftpCli.RemoveDirectory(path)
|
|
||||||
// 如果文件夹有内容会删除失败,则使用rm -rf命令删除
|
|
||||||
if err != nil {
|
|
||||||
GetMachineApp().GetCli(machineId).Run(fmt.Sprintf("rm -rf %s", path))
|
|
||||||
err = nil
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
err = sftpCli.Remove(path)
|
|
||||||
}
|
|
||||||
biz.ErrIsNilAppendErr(err, "删除文件失败: %s")
|
biz.ErrIsNilAppendErr(err, "删除文件失败: %s")
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *machineFileAppImpl) Copy(fileId uint64, toPath string, paths ...string) *machine.Info {
|
||||||
|
mid := m.checkAndReturnMid(fileId, paths...)
|
||||||
|
mcli := GetMachineApp().GetCli(mid)
|
||||||
|
res, err := mcli.Run(fmt.Sprintf("cp -r %s %s", strings.Join(paths, " "), toPath))
|
||||||
|
biz.ErrIsNil(err, "文件拷贝失败: %s", res)
|
||||||
|
return mcli.GetMachine()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *machineFileAppImpl) Mv(fileId uint64, toPath string, paths ...string) *machine.Info {
|
||||||
|
mid := m.checkAndReturnMid(fileId, paths...)
|
||||||
|
mcli := GetMachineApp().GetCli(mid)
|
||||||
|
res, err := mcli.Run(fmt.Sprintf("mv %s %s", strings.Join(paths, " "), toPath))
|
||||||
|
biz.ErrIsNil(err, "文件移动失败: %s", res)
|
||||||
|
return mcli.GetMachine()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *machineFileAppImpl) Rename(fileId uint64, oldname string, newname string) error {
|
||||||
|
mid := m.checkAndReturnMid(fileId, newname)
|
||||||
|
sftpCli := m.getSftpCli(mid)
|
||||||
|
return sftpCli.Rename(oldname, newname)
|
||||||
|
}
|
||||||
|
|
||||||
// 获取sftp client
|
// 获取sftp client
|
||||||
func (m *machineFileAppImpl) getSftpCli(machineId uint64) *sftp.Client {
|
func (m *machineFileAppImpl) getSftpCli(machineId uint64) *sftp.Client {
|
||||||
@@ -232,15 +259,13 @@ func (m *machineFileAppImpl) GetMachine(fileId uint64) *machine.Info {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 校验并返回实际可访问的文件path
|
// 校验并返回实际可访问的文件path
|
||||||
func (m *machineFileAppImpl) checkAndReturnPathMid(fid uint64, inputPath string) (string, uint64) {
|
func (m *machineFileAppImpl) checkAndReturnMid(fid uint64, inputPath ...string) uint64 {
|
||||||
biz.IsTrue(fid != 0, "文件id不能为空")
|
biz.IsTrue(fid != 0, "文件id不能为空")
|
||||||
mf := m.GetById(fid)
|
mf := m.GetById(fid)
|
||||||
biz.NotNil(mf, "文件不存在")
|
biz.NotNil(mf, "文件不存在")
|
||||||
if inputPath != "" {
|
for _, path := range inputPath {
|
||||||
// 接口传入的地址需为配置路径的子路径
|
// 接口传入的地址需为配置路径的子路径
|
||||||
biz.IsTrue(strings.HasPrefix(inputPath, mf.Path), "无权访问该目录或文件")
|
biz.IsTrue(strings.HasPrefix(path, mf.Path), "无权访问该目录或文件: %s", path)
|
||||||
return inputPath, mf.MachineId
|
|
||||||
} else {
|
|
||||||
return mf.Path, mf.MachineId
|
|
||||||
}
|
}
|
||||||
|
return mf.MachineId
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,7 +39,13 @@ func InitMachineFileRouter(router *gin.RouterGroup) {
|
|||||||
|
|
||||||
req.NewPost(":machineId/files/:fileId/upload", mf.UploadFile).Log(req.NewLogSave("机器-文件上传")).RequiredPermissionCode("machine:file:upload"),
|
req.NewPost(":machineId/files/:fileId/upload", mf.UploadFile).Log(req.NewLogSave("机器-文件上传")).RequiredPermissionCode("machine:file:upload"),
|
||||||
|
|
||||||
req.NewDelete(":machineId/files/:fileId/remove", mf.RemoveFile).Log(req.NewLogSave("机器-删除文件or文件夹")).RequiredPermissionCode("machine:file:rm"),
|
req.NewPost(":machineId/files/:fileId/remove", mf.RemoveFile).Log(req.NewLogSave("机器-删除文件or文件夹")).RequiredPermissionCode("machine:file:rm"),
|
||||||
|
|
||||||
|
req.NewPost(":machineId/files/:fileId/cp", mf.CopyFile).Log(req.NewLogSave("机器-拷贝文件")).RequiredPermissionCode("machine:file:rm"),
|
||||||
|
|
||||||
|
req.NewPost(":machineId/files/:fileId/mv", mf.MvFile).Log(req.NewLogSave("机器-移动文件")).RequiredPermissionCode("machine:file:rm"),
|
||||||
|
|
||||||
|
req.NewPost(":machineId/files/:fileId/rename", mf.Rename).Log(req.NewLogSave("机器-文件重命名")).RequiredPermissionCode("machine:file:write"),
|
||||||
}
|
}
|
||||||
|
|
||||||
req.BatchSetGroup(machineFile, reqs[:])
|
req.BatchSetGroup(machineFile, reqs[:])
|
||||||
|
|||||||
@@ -121,7 +121,7 @@ func getCommonAttr(ctx context.Context, level slog.Level) []any {
|
|||||||
commonAttrs := make([]any, 0)
|
commonAttrs := make([]any, 0)
|
||||||
|
|
||||||
// 如果系统配置添加方法信息或者为错误级别时则 记录方法信息及行号
|
// 如果系统配置添加方法信息或者为错误级别时则 记录方法信息及行号
|
||||||
if config.AddSource || level == slog.LevelError {
|
if GetConfig().AddSource || level == slog.LevelError {
|
||||||
// skip [runtime.Callers, getCommonAttr, appendCommonAttr, logx.Log, logx.Info|Debug|Warn|Error..]
|
// skip [runtime.Callers, getCommonAttr, appendCommonAttr, logx.Log, logx.Info|Debug|Warn|Error..]
|
||||||
var pcs [1]uintptr
|
var pcs [1]uintptr
|
||||||
runtime.Callers(5, pcs[:])
|
runtime.Callers(5, pcs[:])
|
||||||
|
|||||||
Reference in New Issue
Block a user