update 重命名接口、右键菜单开发

This commit is contained in:
2026-03-24 11:18:14 +08:00
parent 789992bde6
commit 37457577a9
3 changed files with 158 additions and 44 deletions

View File

@@ -24,6 +24,8 @@
<script lang="ts" setup>
import { ref, watch } from 'vue';
import Dialog from '@/components/common/dialog/index.vue';
import { dataRenameFileApi } from '@/api/data/data';
import { ElMessage } from 'element-plus';
const props = defineProps({
modelValue: {
@@ -36,7 +38,7 @@ const props = defineProps({
},
fileNameField: {
type: String,
default: 'fileName',
default: 'originalName',
},
fileData: {
type: Object,
@@ -87,9 +89,22 @@ const handleClose = () => {
// 提交重命名
const handleSubmit = () => {
// todo 调用重命名接口
emit('finish');
// 关闭对话框
handleClose();
// 调用重命名接口
const params = {
fileId: currentFileId.value,
newName: fileName.value + fileSuffix.value,
};
dataRenameFileApi(params)
.then((res: any) => {
if (res.code === 200) {
ElMessage.success('重命名成功');
emit('finish');
// 关闭对话框
handleClose();
}
})
.catch((err: any) => {
handleClose();
});
};
</script>

View File

@@ -7,9 +7,8 @@
...$attrs,
...(needContextMenu
? {
'menu-config': menuConfig,
'menu-config': triggerMenuConfig,
'row-class-name': rowClassName,
'onMenu-click': handleMenuClick,
'onCell-menu': handleContextMenu,
}
: {}),
@@ -38,6 +37,26 @@
:fileData="currentRenameData"
@finish="renameFinishFun"
/>
<teleport to="body">
<div
v-if="contextMenuVisible"
class="file-table-context-menu"
:style="{ left: `${contextMenuPosition.x}px`, top: `${contextMenuPosition.y}px` }"
>
<div
v-for="(action, index) in contextMenuActions"
:key="`${action.title}_${index}`"
class="menu-item"
:class="{ 'menu-item--danger': action.type === 'danger' }"
@click="handleContextActionClick(action)"
>
<el-icon v-if="getMenuIcon(action)" class="menu-item-icon">
<component :is="getMenuIcon(action)" />
</el-icon>
<span class="menu-item-title">{{ action.title }}</span>
</div>
</div>
</teleport>
</div>
</template>
@@ -47,7 +66,8 @@ import BaseTable from '@/components/common/table/baseTable.vue';
import FilePreview from '@/components/common/filePreview/index.vue';
import { downloadFileById } from '@/utils/file';
import FileTypeChange from '@/components/common/fileTable/fileTypeChange.vue';
import { ElMessage } from 'element-plus';
import { ElMessage, ElMessageBox } from 'element-plus';
import { View, Download, Delete, EditPen, Refresh } from '@element-plus/icons-vue';
import { dataDelFileApi } from '@/api/data/data';
import FileRename from '@/components/common/fileTable/fileRename.vue';
@@ -59,7 +79,7 @@ const props = defineProps({
// 操作栏默认列表
defaultActions: {
type: Array,
default: () => ['preview', 'download', 'delete'],
default: () => [], // 'preview', 'download', 'delete', 'rename', 'refresh'
},
// 文件id的字段 1用于操作文件 2用于在右键时高亮当前行, 默认查找顺序id -> fileId -> uuid
fileIdField: {
@@ -71,10 +91,10 @@ const props = defineProps({
type: String,
default: 'fileName',
},
// 是否需要右键菜单,默认需要【待开发】
// 是否需要右键菜单,默认需要
needContextMenu: {
type: Boolean,
default: false,
default: true,
},
// 文件标签字段【待开发】
fileTagField: {
@@ -133,6 +153,15 @@ const defaultActionList = computed(() => [
},
]
: []),
...(props.defaultActions?.includes('refresh')
? [
{
title: '刷新',
type: 'primary',
click: () => fileTableRef.value.resetFun(),
},
]
: []),
]);
const deleteFileFun = async (id: number) => {
@@ -161,29 +190,37 @@ const renameFun = (id: any, row: any) => {
renameVisible.value = true;
};
const renameFinishFun = () => {
// dzh todo 刷新数据
// 刷新数据
fileTableRef.value.resetFun();
};
// #endregion
// #region ---------------------------右键菜单模块---------------------------
// 当前右键操作的行
const currentHighlightRowId = ref('');
const menuConfig = ref({
const currentContextRow = ref<any>(null);
const contextMenuVisible = ref(false);
const contextMenuPosition = ref({ x: 0, y: 0 });
const contextMenuActions = ref<any[]>([]);
const triggerMenuConfig = ref<any>({
enabled: true,
body: {
options: [
[
{ code: 'copy', name: '复制', prefixConfig: { icon: 'vxe-icon-copy' } },
{ code: 'edit', name: '编辑', prefixConfig: { icon: 'vxe-icon-edit' } },
{ code: 'delete', name: '删除', prefixConfig: { icon: 'vxe-icon-delete' } },
],
],
options: [[]],
},
});
const handleContextMenu = ({ row, $event }: { row: any; $event: any }) => {
$event.preventDefault();
currentContextRow.value = row;
currentHighlightRowId.value = row[props.fileIdField] || row.fileId || row.uuid; // 每行的唯一标识
contextMenuActions.value = allActionList.value.filter(
(action: any) => !(action.hide && action.hide(row))
);
contextMenuPosition.value = {
x: $event.clientX,
y: $event.clientY,
};
contextMenuVisible.value = true;
};
// 添加行样式计算
const rowClassName = ({ row }: { row: any }) => {
@@ -191,25 +228,52 @@ const rowClassName = ({ row }: { row: any }) => {
return currentHighlightRowId.value === rowId && rowId ? 'highlight-row' : '';
};
const handleMenuClick = ({ menu, row }: { menu: any; row: any }) => {
// 根据点击的菜单项执行不同操作
switch (menu.code) {
case 'copy':
console.info('copy', row);
break;
case 'edit':
console.info('edit', row);
break;
case 'delete':
console.info('delete', row);
const handleContextActionClick = (action: any) => {
const row = currentContextRow.value;
if (!row) {
contextMenuVisible.value = false;
currentHighlightRowId.value = '';
return;
}
if (action?.click) {
const tableData = fileTableRef.value?.tableData || [];
const currentRowId = row[props.fileIdField] || row.fileId || row.uuid;
const rowIndex = tableData.findIndex((item: any) => {
const id = item[props.fileIdField] || item.fileId || item.uuid;
return id === currentRowId;
});
const tip = (action.confirmTipFun && action.confirmTipFun(row, rowIndex)) || action.confirmTip;
if (tip) {
ElMessageBox.confirm(tip, '提示', {
type: 'warning',
})
.then(() => {
action.click(row, rowIndex);
})
.catch(() => {});
} else {
action.click(row, rowIndex);
}
}
contextMenuVisible.value = false;
currentHighlightRowId.value = '';
};
const getMenuIcon = (action: any) => {
if (action?.icon) return action.icon;
const title = String(action?.title || '');
if (title.includes('预览')) return View;
if (title.includes('下载')) return Download;
if (title.includes('删除')) return Delete;
if (title.includes('重命名')) return EditPen;
if (title.includes('刷新')) return Refresh;
return null;
};
// 全局点击处理
const handleGlobalClick = (event: any) => {
// 检查点击是否在菜单内
const menuEl = document.querySelector('.vxe-table--context-menu-wrapper');
const menuEl = document.querySelector('.file-table-context-menu');
if (menuEl && !menuEl.contains(event.target)) {
contextMenuVisible.value = false;
currentHighlightRowId.value = '';
}
};
@@ -262,4 +326,36 @@ defineExpose({
background-color: var(--el-color-primary-light-9) !important;
}
}
.file-table-context-menu {
position: fixed;
z-index: 3000;
min-width: 120px;
padding: 4px 0;
background: #fff;
border: 1px solid var(--el-border-color-light);
border-radius: 4px;
box-shadow: var(--el-box-shadow-light);
.menu-item {
display: flex;
align-items: center;
gap: 6px;
padding: 8px 12px;
color: var(--el-text-color-primary);
cursor: pointer;
user-select: none;
&:hover {
background-color: var(--el-fill-color-light);
}
}
.menu-item-icon {
font-size: 14px;
}
.menu-item-title {
line-height: 1;
}
.menu-item--danger {
color: var(--el-color-danger);
}
}
</style>

View File

@@ -68,6 +68,7 @@ const actionList = [
{
title: t('通用.还原'),
type: 'primary',
icon: 'RefreshLeft',
click: (row: any) => {
clickRestore('single', row);
},
@@ -151,17 +152,19 @@ const clickRestore = (type?: any, row?: any) => {
confirmButtonText: '确认',
cancelButtonText: '取消',
type: 'warning',
}).then(async () => {
const ids = type === 'single' ? [row.id] : chosenData.value.map((item: any) => item.id);
const params = { ids };
restoreFromRecycleApi(params).then((res: any) => {
if (res && res.code === 200) {
ElMessage.success('还原成功');
chosenData.value = [];
baseTableRef.value.resetFun(); // 刷新数据
}
});
});
})
.then(async () => {
const ids = type === 'single' ? [row.id] : chosenData.value.map((item: any) => item.id);
const params = { ids };
restoreFromRecycleApi(params).then((res: any) => {
if (res && res.code === 200) {
ElMessage.success('还原成功');
chosenData.value = [];
baseTableRef.value.resetFun(); // 刷新数据
}
});
})
.catch(() => {});
};
</script>