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,
|
|||
|
|
};
|
|||
|
|
}
|