DawnLauncher/src/pages/item/components/Content.vue

927 lines
26 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div
id="item-content"
class="pl-2 pr-[4px] h-full w-full flex-1 overflow-x-hidden"
:style="{
maxHeight: height + 'px',
width: store.setting.classification.layout === 'top' ? 'auto' : '100%',
}"
@contextmenu="contextmenu"
@dragstart="dragstart"
@dragover="dragover"
@dragleave="dragleave"
@drop="drop($event, null)"
>
<!-- 只选中了父级分类 -->
<template v-if="!store.selectedClassificationChildId">
<!-- 有子级分类 -->
<template
v-if="hasChildClassification(store.selectedClassificationParentId)"
>
<div
v-for="(classification, index) of getClassificationChildList(
store.selectedClassificationParentId
)"
:key="'classification-child-' + classification.id + '-item-' + index"
class="item-container"
:classification-id="classification.id"
@drop="drop($event, classification.id)"
>
<p
:style="{
filter: store.setting.appearance.fontShadow
? 'drop-shadow(1px 1px 1px ' +
store.setting.appearance.fontShadowColor +
')'
: undefined,
fontSize:
store.setting.subClassification.itemAreaNameFontSize + 'px',
fontWeight:
store.setting.subClassification.itemAreaNameFontWeight,
lineHeight:
store.setting.subClassification.itemAreaNameFontLineHeight +
'rem',
textAlign: store.setting.subClassification.itemAreaNameAlign,
marginRight:
store.setting.subClassification.itemAreaNameAlign === 'right'
? '4px'
: undefined,
}"
>
{{ classification.name }}
</p>
<ItemList
class="pt-1"
:data="getShowItemListByClassificationId(classification.id)"
:classification-id="classification.id"
></ItemList>
</div>
</template>
<!-- 无子级分类 -->
<div
v-else
class="item-container"
:classification-id="store.selectedClassificationParentId"
@drop="drop($event, store.selectedClassificationParentId)"
>
<ItemList
:data="
getShowItemListByClassificationId(
store.selectedClassificationParentId
)
"
:classification-id="store.selectedClassificationParentId"
></ItemList>
</div>
</template>
<!-- 选中了子分类 -->
<div
v-else
class="item-container"
:classification-id="store.selectedClassificationChildId"
@drop="drop($event, store.selectedClassificationChildId)"
>
<ItemList
:data="
getShowItemListByClassificationId(store.selectedClassificationChildId)
"
:classification-id="store.selectedClassificationChildId"
></ItemList>
</div>
</div>
</template>
<script setup lang="ts">
import {
ref,
onMounted,
onUnmounted,
onBeforeMount,
watch,
onUpdated,
nextTick,
} from "vue";
import Sortable, { MultiDrag, SortableEvent } from "sortablejs";
import SimpleBar from "simplebar";
import "simplebar/dist/simplebar.css";
import {
getLocalSetting,
setLocalSetting,
deleteLocalSetting,
} from "../../../utils/localSetting";
import {
getSelectedClassificationId,
hasChildClassification,
getClassificationChildList,
getClassificationById,
} from "../../classification/js";
import {
addItem,
updateItem,
deleteItem,
convertItemList,
getItemListByClassificationId,
getShowItemListByClassificationId,
getItemById,
updateItemOrder,
itemRemoveStyle,
itemHoverStyle,
allItemRemoveStyle,
deleteItemByClassificationId,
setItemWidth,
run,
removeInvalidItem,
showItemList,
} from "../js";
import ItemList from "./List.vue";
import { Item } from "../../../../types/item";
import { getClassElement } from "../../../utils/style";
import { convert } from "../../../../commons/utils/common";
import { scrollToTop, findElement, unlistens } from "../../../utils/common";
import { useMainStore } from "../../../store";
// pinia
const store = useMainStore();
// 开发时会重复挂载插件导致页面错误
try {
// 拖拽控件支持多选
Sortable.mount(new MultiDrag());
} catch (e) {}
// 锁定项目 解锁项目
let lockItem = getLocalSetting<boolean>("lockItem") ?? false;
// 监听布局
watch(
() => store.setting.classification.layout,
() => {
// 刷新DOM完毕执行
nextTick(() => {
// 监听页面大小
resize();
// 设置项目宽度
setItemWidth();
// 创建项目拖拽对象
createItemSortable();
// 清除批量操作
clearBatchOperation();
// 滚动到顶部
scrollToTop(itemContentSimpleBar);
});
}
);
// 监听选中的父级分类
watch(
() => store.selectedClassificationParentId,
() => {
// 刷新DOM完毕执行
nextTick(() => {
// 设置项目宽度
setItemWidth();
// 创建项目拖拽对象
createItemSortable();
// 清除批量操作
clearBatchOperation();
// 滚动到顶部
scrollToTop(itemContentSimpleBar);
});
}
);
// 监听选中的子级分类
watch(
() => store.selectedClassificationChildId,
() => {
// 刷新DOM完毕执行
nextTick(() => {
// 设置项目宽度
setItemWidth();
// 创建项目拖拽对象
createItemSortable();
// 清除批量操作
clearBatchOperation();
// 滚动到顶部
scrollToTop(itemContentSimpleBar);
});
}
);
/**
* 获取项目列表
*/
async function getItemList() {
store.itemMap = convertItemList(window.item.list());
}
// 创建项目滚动条
let itemContentSimpleBar: SimpleBar | null = null;
function createSimpleBar() {
// 项目区域
let element = document.getElementById("item-content");
if (element) {
// 创建滚动条
if (!SimpleBar.instances.get(element)) {
itemContentSimpleBar = new SimpleBar(element);
// 获取scroll
let scroll = itemContentSimpleBar.getScrollElement();
if (scroll) {
// 监听滚动
scroll.addEventListener(
"wheel",
(e) => {
if (
scroll &&
store.setting.classification.autoSwitchClassification
) {
const delta = Math.sign(e.deltaY);
if (delta === -1 && scroll.scrollTop === 0) {
// 上
store.classificationWheelEvent = e;
} else if (delta === 1) {
// 下
if (
scroll.scrollTop + scroll.clientHeight ===
scroll.scrollHeight
) {
store.classificationWheelEvent = e;
}
}
}
},
{ passive: false, capture: true }
);
}
} else {
if (itemContentSimpleBar) {
itemContentSimpleBar.recalculate();
}
}
}
}
// 项目拖拽对象列表
let itemSortableList: Array<Sortable> = [];
// 项目拖拽排序
function createItemSortable() {
// 如果存在先销毁
for (const sortable of itemSortableList) {
if (sortable) {
sortable.destroy();
}
}
itemSortableList = [];
// 循环每个项目区域
let itemListElementList = document.getElementsByClassName("item-list");
for (let i = 0; i < itemListElementList.length; i++) {
// element
let element = itemListElementList[i];
// 分类ID
let classificationId = parseInt(element.getAttribute("classification-id")!);
// 查询分类
let classification = getClassificationById(classificationId);
// 只有普通分类才可以拖拽排序
if (!classification || classification.type !== 0) {
continue;
}
// 如果锁定分类的话就不创建拖拽对象
if (!lockItem) {
// 创建
itemSortableList.push(
Sortable.create(element as HTMLElement, {
group: store.selectedClassificationChildId
? "classification-child-" + store.selectedClassificationChildId
: "classification-parent-" + store.selectedClassificationParentId,
draggable: ".item",
animation: 0,
forceFallback: true,
fallbackTolerance: 4,
multiDrag: store.itemBatchOperation,
// 多选选择
onSelect(e) {
itemSortableBatchOpertionDataSet(e, "Add");
},
// 取消多选
onDeselect(e) {
itemSortableBatchOpertionDataSet(e, "Delete");
},
onStart() {
store.itemSorting = true;
if (!store.itemBatchOperation) {
allItemRemoveStyle();
}
},
async onEnd(event) {
if (
event.newIndex !== null &&
event.newIndex !== undefined &&
event.oldIndex !== null &&
event.oldIndex !== undefined
) {
let fromIdList = [];
if (!store.itemBatchOperation) {
// 普通操作
// from 分类ID
let fromClassificationId = parseInt(
event.from.getAttribute("classification-id")!
);
let fromClassification =
getClassificationById(fromClassificationId);
if (fromClassification) {
let itemList =
getItemListByClassificationId(fromClassificationId);
if (itemList) {
let copyItemList = JSON.parse(JSON.stringify(itemList));
// 可能会存在自定义排序的情况,所以需要按照指定的排序方式获取项目
const currentItem = showItemList(
copyItemList,
fromClassification
)[event.oldIndex];
fromIdList.push(currentItem.id);
}
}
} else {
// 批量操作
for (const value of store.itemBatchOperationDataArray) {
fromIdList.push(value);
}
}
// to 分类ID
let toClassificationId = store.mouseoverClassificationId
? store.mouseoverClassificationId
: parseInt(event.to.getAttribute("classification-id")!);
// 目标分类必须是普通分类
let toClassification = getClassificationById(toClassificationId);
if (toClassification && toClassification.type === 0) {
// 更新数据库排序
let res = window.item.updateOrder(
fromIdList,
toClassificationId,
store.mouseoverClassificationId ? null : event.newIndex
);
if (res) {
updateItemOrder(
fromIdList,
toClassificationId,
store.mouseoverClassificationId ? null : event.newIndex
);
}
}
}
store.itemSorting = false;
// 清除批量操作
clearBatchOperation();
// 刷新DOM完毕执行
nextTick(() => {
// 设置项目宽度
setItemWidth();
});
},
})
);
} else {
// 将所有元素设置为可拖拽,项目拖出时需要用到
let itemListElement = element.getElementsByClassName("item");
for (let i = 0; i < itemListElement.length; i++) {
const element = itemListElement[i];
element.setAttribute("draggable", "true");
}
}
}
}
// 批量操作选中项目
function itemSortableBatchOpertionDataSet(e: SortableEvent, type: string) {
let strItemId = e.item.getAttribute("item-id");
if (strItemId) {
let itemId = parseInt(strItemId);
if (type === "Add") {
if (!store.itemBatchOperationDataArray.includes(itemId)) {
store.itemBatchOperationDataArray.push(itemId);
}
} else {
let index = store.itemBatchOperationDataArray.indexOf(itemId);
if (index >= 0) {
store.itemBatchOperationDataArray.splice(index, 1);
}
}
}
}
// 监听右键菜单选中ID
watch(
() => store.itemRightMenuItemId,
(newValue) => {
if (!store.itemBatchOperation) {
let elementList = document.getElementsByClassName("item");
for (let i = 0; i < elementList.length; i++) {
itemRemoveStyle(elementList[i], "item");
}
if (newValue) {
let elemenet = document.getElementById("item-" + newValue);
if (elemenet) {
itemHoverStyle(elemenet, "item");
}
}
}
}
);
// 清除批量操作
function clearBatchOperation() {
store.itemBatchOperation = false;
store.itemBatchOperationDataArray = [];
}
// dragstart
function dragstart(e: any) {
// 如果项目在拖拽排序中则不能拖出
if (store.itemSorting) {
return;
}
// 获取项目
let item: Item | null = null;
let itemElement = findElement(e.target, "item");
if (itemElement) {
let id = itemElement.getAttribute("item-id");
if (id) {
item = getItemById(parseInt(id));
}
}
// 查询当前分类
let classification = item
? getClassificationById(item.classificationId)
: null;
// 只有关联文件夹或设置了锁定分类,可以拖出
if ((classification && classification.type === 1) || lockItem) {
// 设置拖出标识
store.itemDragOut = true;
if (item) {
store.itemDragOutData = item;
window.item.dragOut(convert(item));
} else {
store.itemDragOut = false;
}
}
e.preventDefault();
e.stopPropagation();
}
// dragover
function dragover(e: any) {
// 如果项目在拖拽排序中直接返回
if (store.itemSorting) {
return;
}
// 从程序外拖动文件到项目图标上时用此项目打开文件 或者 拖出
if (store.setting.item.useItemOpen || store.itemDragOut) {
// 选中效果
let target = findElement(e.target, "item");
// 取消选中效果
let itemList = document.getElementsByClassName("item");
for (let i = 0; i < itemList.length; i++) {
const element = itemList[i] as HTMLElement;
if (element.style.backgroundColor && element !== target) {
itemRemoveStyle(element, "item");
}
}
// 选中效果
if (target) {
itemHoverStyle(target, "item");
}
}
e.preventDefault();
e.stopPropagation();
}
// dragleave
function dragleave(e: any) {
// 解决拖出速度过快时有几率没有删除项目选中样式
if (
e.relatedTarget &&
e.relatedTarget.tagName &&
e.relatedTarget.tagName.toString().toLowerCase() !== "img" &&
e.relatedTarget.tagName.toString().toLowerCase() !== "p"
) {
let flag = false;
for (const className of e.relatedTarget.classList) {
if (className === "item") {
flag = true;
}
}
if (!flag) {
// 取消选中效果
allItemRemoveStyle();
}
}
e.preventDefault();
e.stopPropagation();
}
// drop
function drop(e: any, classificationId: number | null) {
// 如果项目在拖拽排序中直接返回
if (store.itemSorting) {
return;
}
// 尝试获取项目
let item: Item | null = null;
let itemElement = findElement(e.target, "item");
if (itemElement) {
let id = itemElement.getAttribute("item-id");
if (id) {
item = getItemById(parseInt(id));
}
}
// 获取文件列表
let pathList = [];
for (const file of e.dataTransfer.files) {
pathList.push(file.path);
}
// 从程序外拖动文件到项目图标上时用此项目打开文件
if (store.setting.item.useItemOpen && item && pathList.length > 0) {
// 如果相同路径则不打开
if (pathList.length === 1 && pathList[0] === item.data.target) {
return;
}
let params = "";
for (let i = 0; i < pathList.length; i++) {
if (i > 0) {
params += " ";
}
params += '"' + pathList[i] + '"';
}
if (item.data.params) {
params += " " + item.data.params;
}
let copyItem: Item = convert(item);
copyItem.data.params = params;
// 运行
run("main", "open", copyItem);
} else if (store.itemDragOut) {
// 拖出
if (
store.itemDragOutData &&
item &&
store.itemDragOutData.type === 0 &&
item.type === 0
) {
// 如果不是同一个项目就可以使用某个程序打开此文件
if (item.id !== store.itemDragOutData.id) {
let params = '"' + store.itemDragOutData.data.target + '"';
if (item.data.params) {
params += " " + item.data.params;
}
let copyItem: Item = convert(item);
copyItem.data.params = params;
// 运行
run("main", "open", copyItem);
}
}
} else {
if (pathList.length > 0) {
// 如果分类ID为空尝试获取当前选中的分类ID
if (!classificationId) {
// 获取当前选中的分类ID
let selectedClassificationId = getSelectedClassificationId();
// 判断是否是父级分类
if (
selectedClassificationId &&
hasChildClassification(selectedClassificationId)
) {
// 获取最后一个子分类ID
let childList = getClassificationChildList(selectedClassificationId);
classificationId = childList[childList.length - 1].id;
} else {
classificationId = selectedClassificationId;
}
}
// 如果分类ID不为空
if (classificationId) {
// 查询分类
let classification = getClassificationById(classificationId);
if (classification && classification.type === 0) {
window.item.drop(classificationId, pathList);
}
}
}
}
e.preventDefault();
e.stopPropagation();
}
// 页面高度
let height = ref(0);
// 初始化页面尺寸
resize();
// 监听页面大小
function resize() {
// 刷新DOM完毕执行
nextTick(() => {
// 设置项目宽度
setItemWidth();
// 页面高度 - 34标题栏固定高度
let h = document.documentElement.clientHeight - 34;
// 分类布局为顶部时需要加上分类的高度
if (store.setting.classification.layout === "top") {
let element = document.getElementById("classification-list");
if (element) {
h -= element.getBoundingClientRect().height;
}
}
height.value = h;
});
}
// 监听鼠标右键
async function contextmenu(e: any) {
e.preventDefault();
e.stopPropagation();
// 当前项目
let item: Item | null = null;
// 判断是在哪个区域右键
if (getClassElement(e, "item")) {
// 项目右键
// 获取项目ID
let element = getClassElement(e, "item");
// 项目ID
let id = parseInt(element.getAttribute("item-id"));
// 获取项目
item = convert(getItemById(id));
// 记录右键选中的ID
store.itemRightMenuItemId = id;
}
// 获取当前项目在页面的所属分类
let pageClassificationId = null;
let itemListElement = getClassElement(e, "item-list");
if (itemListElement) {
pageClassificationId = parseInt(
itemListElement.getAttribute("classification-id")
);
}
// 弹出菜单
window.item.showRightMenu({
classificationId: getSelectedClassificationId(),
item,
lockItem,
batchOperation: store.itemBatchOperation,
batchSelectedIdList: convert(store.itemBatchOperationDataArray),
x: e.screenX,
y: e.screenY,
type: "main",
pageClassificationId,
});
}
// beforeMount
onBeforeMount(async () => {
// 查询项目列表
await getItemList();
// 刷新DOM完毕执行
nextTick(() => {
// 设置项目宽度
setItemWidth();
// 创建项目拖拽对象
createItemSortable();
});
});
// updated
onUpdated(() => {
// 刷新DOM完毕执行
nextTick(() => {
// 设置项目宽度
setItemWidth();
// 项目滚动条
createSimpleBar();
});
});
// 监听
let listens: Array<Function> = [];
// moutned
onMounted(() => {
// resize
window.addEventListener("resize", resize);
// 刷新DOM完毕执行
nextTick(() => {
// 设置项目宽度
setItemWidth();
// 项目滚动条
createSimpleBar();
// 创建项目拖拽对象
createItemSortable();
});
// 监听新增项目
listens.push(
window.item.onAdd((data) => {
// 项目列表
let itemList: Array<Item> = data.itemList;
// 是否清空原项目
let clear: boolean = data.clear;
// 分类ID
let classificationId: number | null = data.classificationId;
if (clear && classificationId) {
deleteItemByClassificationId(classificationId);
}
// 添加项目
for (const item of itemList) {
addItem(item);
}
// 清空批量操作
clearBatchOperation();
// 刷新DOM完毕执行
nextTick(() => {
// 创建项目拖拽对象
createItemSortable();
// 设置项目宽度
setItemWidth();
});
})
);
// 监听更新项目
listens.push(
window.item.onUpdate((data) => {
updateItem(data.item);
// 删除无效项目
removeInvalidItem(data.item.id);
// 刷新DOM完毕执行
nextTick(() => {
// 设置项目宽度
setItemWidth();
});
})
);
// 监听删除项目
listens.push(
window.item.onDelete((data) => {
let itemIdList: Array<number> = data;
for (const id of itemIdList) {
deleteItem(id);
// 删除无效项目
removeInvalidItem(id);
}
// 清空批量操作
clearBatchOperation();
// 刷新DOM完毕执行
nextTick(() => {
// 创建项目拖拽对象
createItemSortable();
// 设置项目宽度
setItemWidth();
});
})
);
// 监听锁定/解锁项目
listens.push(
window.item.onLock((data) => {
if (!lockItem) {
setLocalSetting("lockItem", "true");
lockItem = true;
} else {
deleteLocalSetting("lockItem");
lockItem = false;
}
// 刷新DOM完毕执行
nextTick(() => {
// 创建项目拖拽对象
createItemSortable();
});
})
);
// 监听批量操作
listens.push(
window.item.onBatchOperation((data) => {
store.itemBatchOperation = data;
store.itemBatchOperationDataArray = [];
// 刷新DOM完毕执行
nextTick(() => {
// 创建项目拖拽对象
createItemSortable();
});
})
);
// 监听转换路径
listens.push(
window.item.onConvertPath((data) => {
let dataList: Array<{
id: number;
target: string;
}> = data;
for (const data of dataList) {
let item = getItemById(data.id);
if (item) {
item.data.target = data.target;
}
}
// 清空批量操作
clearBatchOperation();
})
);
// 监听刷新图标
listens.push(
window.item.onRefreshIcon((data) => {
let dataList: Array<{
id: number;
icon: string;
}> = data;
for (const data of dataList) {
let item = getItemById(data.id);
if (item) {
item.data.icon = data.icon;
item.data.htmlIcon = null;
}
}
// 清空批量操作
clearBatchOperation();
})
);
// 监听移动项目
listens.push(
window.item.onMove((data) => {
updateItemOrder(data.idList, data.toClassificationId, null);
// 清空批量操作
clearBatchOperation();
// 刷新DOM完毕执行
nextTick(() => {
// 设置项目宽度
setItemWidth();
// 创建项目拖拽对象
createItemSortable();
});
})
);
// 监听批量操作全选
listens.push(
window.item.onBatchOperationSelectAll((data) => {
// 全选
if (
!store.selectedClassificationChildId &&
hasChildClassification(store.selectedClassificationParentId)
) {
let classificationList = getClassificationChildList(
store.selectedClassificationParentId
);
for (const classification of classificationList) {
if (classification.type === 0) {
let itemList = getItemListByClassificationId(classification.id);
for (const item of itemList) {
if (!store.itemBatchOperationDataArray.includes(item.id)) {
store.itemBatchOperationDataArray.push(item.id);
}
}
}
}
} else {
let classificationId = getSelectedClassificationId();
if (classificationId) {
let classification = getClassificationById(classificationId);
if (classification && classification.type === 0) {
let itemList = getItemListByClassificationId(
getSelectedClassificationId()
);
for (const item of itemList) {
if (!store.itemBatchOperationDataArray.includes(item.id)) {
store.itemBatchOperationDataArray.push(item.id);
}
}
}
}
}
})
);
// 监听项目右键菜单关闭
listens.push(
window.item.onRightMenuClose((data) => {
store.itemRightMenuItemId = null;
store.searchItemRightMenuItemId = null;
})
);
// 监听项目资源管理器菜单
listens.push(
window.item.onExplorerMenu((data) => {
if (data.type === "main") {
store.itemRightMenuItemId = data.id;
} else if (data.type === "search") {
store.searchItemRightMenuItemId = data.id;
}
})
);
// 监听取消项目拖拽
listens.push(
window.item.onCancelDragOut((data) => {
store.itemDragOutData = null;
store.itemDragOut = false;
})
);
// 监听更新打开次数
listens.push(
window.item.onUpdateOpenInfo((data) => {
let item = getItemById(data.id);
if (item) {
if (data.type === "main" || data.type === "search") {
item.data.openNumber = data.openNumber;
item.data.lastOpen = data.lastOpen;
} else if (data.type === "quickSearch") {
item.data.quickSearchOpenNumber = data.quickSearchOpenNumber;
item.data.quickSearchLastOpen = data.quickSearchLastOpen;
}
}
})
);
// 监听无效项目
listens.push(
window.item.onCheckInvalid((data) => {
store.invalidItemIdList = data;
})
);
});
// unmounted
onUnmounted(() => {
// resize
window.removeEventListener("resize", resize);
// 删除监听
unlistens(listens);
});
</script>
../../../../types/item