158 lines
4.2 KiB
Vue
158 lines
4.2 KiB
Vue
import { reactive, ref, type Ref } from 'vue';
|
||
|
||
const STORAGE_KEY = 'mes_ding_tpl_launch_pos';
|
||
|
||
export interface FloatPosition {
|
||
left: number;
|
||
top: number;
|
||
}
|
||
|
||
function readAllPositions(): Record<string, FloatPosition> {
|
||
try {
|
||
return JSON.parse(localStorage.getItem(STORAGE_KEY) || '{}') || {};
|
||
} catch {
|
||
return {};
|
||
}
|
||
}
|
||
|
||
/** 查询条件区域(BasicTable 搜索表单)右侧的默认坐标 */
|
||
export function calcDefaultPosition(btnWidth: number, btnHeight: number): FloatPosition {
|
||
const formEl =
|
||
document.querySelector<HTMLElement>('.jeecg-basic-table-form-container .ant-form') ||
|
||
document.querySelector<HTMLElement>('.jeecg-basic-table-form-container');
|
||
if (!formEl) {
|
||
return {
|
||
left: Math.max(8, window.innerWidth - btnWidth - 24),
|
||
top: 100,
|
||
};
|
||
}
|
||
const rect = formEl.getBoundingClientRect();
|
||
return {
|
||
left: Math.max(8, rect.right - btnWidth - 12),
|
||
top: Math.max(8, rect.top + (rect.height - btnHeight) / 2),
|
||
};
|
||
}
|
||
|
||
/**
|
||
* 可拖拽悬浮按钮位置:默认对齐查询区右侧,拖拽后按路由持久化。
|
||
*/
|
||
export function useDraggablePosition(routePath: Ref<string>) {
|
||
const pos = reactive<FloatPosition>({ left: 0, top: 0 });
|
||
const isDragging = ref(false);
|
||
let moved = false;
|
||
let pointerId: number | null = null;
|
||
let startX = 0;
|
||
let startY = 0;
|
||
let startLeft = 0;
|
||
let startTop = 0;
|
||
let btnWidth = 120;
|
||
let btnHeight = 36;
|
||
|
||
function setButtonSize(width: number, height: number) {
|
||
btnWidth = width;
|
||
btnHeight = height;
|
||
}
|
||
|
||
function loadPosition(path: string): boolean {
|
||
const saved = readAllPositions()[path];
|
||
if (saved && typeof saved.left === 'number' && typeof saved.top === 'number') {
|
||
pos.left = saved.left;
|
||
pos.top = saved.top;
|
||
return true;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
function savePosition(path: string) {
|
||
const all = readAllPositions();
|
||
all[path] = { left: pos.left, top: pos.top };
|
||
localStorage.setItem(STORAGE_KEY, JSON.stringify(all));
|
||
}
|
||
|
||
function applyDefaultPosition() {
|
||
const p = calcDefaultPosition(btnWidth, btnHeight);
|
||
pos.left = p.left;
|
||
pos.top = p.top;
|
||
}
|
||
|
||
function initPosition(path: string, preferDefault = false) {
|
||
if (!path) return;
|
||
if (!preferDefault && loadPosition(path)) return;
|
||
applyDefaultPosition();
|
||
}
|
||
|
||
function clampPosition() {
|
||
const maxLeft = window.innerWidth - btnWidth - 8;
|
||
const maxTop = window.innerHeight - btnHeight - 8;
|
||
pos.left = Math.min(Math.max(8, pos.left), maxLeft);
|
||
pos.top = Math.min(Math.max(8, pos.top), maxTop);
|
||
}
|
||
|
||
function onPointerMove(e: PointerEvent) {
|
||
if (pointerId !== e.pointerId) return;
|
||
const dx = e.clientX - startX;
|
||
const dy = e.clientY - startY;
|
||
if (!moved && (Math.abs(dx) > 4 || Math.abs(dy) > 4)) {
|
||
moved = true;
|
||
isDragging.value = true;
|
||
}
|
||
if (!moved) return;
|
||
pos.left = startLeft + dx;
|
||
pos.top = startTop + dy;
|
||
clampPosition();
|
||
}
|
||
|
||
function endDrag(path: string) {
|
||
document.removeEventListener('pointermove', onPointerMove);
|
||
document.removeEventListener('pointerup', onPointerUp);
|
||
document.removeEventListener('pointercancel', onPointerUp);
|
||
if (moved && path) {
|
||
savePosition(path);
|
||
}
|
||
pointerId = null;
|
||
setTimeout(() => {
|
||
isDragging.value = false;
|
||
moved = false;
|
||
}, 0);
|
||
}
|
||
|
||
function onPointerUp(e: PointerEvent) {
|
||
if (pointerId !== e.pointerId) return;
|
||
endDrag(routePath.value);
|
||
}
|
||
|
||
function onPointerDown(e: PointerEvent, el: HTMLElement | null) {
|
||
if (e.button !== 0) return;
|
||
if (el) {
|
||
const rect = el.getBoundingClientRect();
|
||
setButtonSize(rect.width, rect.height);
|
||
}
|
||
moved = false;
|
||
isDragging.value = false;
|
||
pointerId = e.pointerId;
|
||
startX = e.clientX;
|
||
startY = e.clientY;
|
||
startLeft = pos.left;
|
||
startTop = pos.top;
|
||
(e.currentTarget as HTMLElement)?.setPointerCapture?.(e.pointerId);
|
||
document.addEventListener('pointermove', onPointerMove);
|
||
document.addEventListener('pointerup', onPointerUp);
|
||
document.addEventListener('pointercancel', onPointerUp);
|
||
}
|
||
|
||
function wasDragged() {
|
||
return moved;
|
||
}
|
||
|
||
return {
|
||
pos,
|
||
isDragging,
|
||
setButtonSize,
|
||
initPosition,
|
||
applyDefaultPosition,
|
||
onPointerDown,
|
||
wasDragged,
|
||
clampPosition,
|
||
};
|
||
}
|