useCachePreload.ts
import { ref, onMounted } from 'vue';
function useCachePreload<T>(loadFunction: () => T, { cacheTime = 30 * 60 * 1000 } = {}) {
const loading = ref(false);
const data = ref<any>(null);
const lastLoadTime = ref(0);
const loadData = async () => {
loading.value = true;
try {
if (Date.now() - lastLoadTime.value < cacheTime && data.value) {
return;
}
const newData = await loadFunction();
data.value = newData;
lastLoadTime.value = Date.now();
} catch (error) {
} finally {
loading.value = false;
}
};
onMounted(loadData);
return {
loading,
data,
loadData
};
}
export default useCachePreload;
useChart.ts
import type { EChartsOption } from 'echarts';
import * as echarts from 'echarts/core';
import {
BarChart,
LineChart,
PieChart,
MapChart,
PictorialBarChart,
RadarChart,
ScatterChart
} from 'echarts/charts';
import {
TitleComponent,
TooltipComponent,
GridComponent,
PolarComponent,
AriaComponent,
ParallelComponent,
LegendComponent,
RadarComponent,
ToolboxComponent,
DataZoomComponent,
VisualMapComponent,
TimelineComponent,
CalendarComponent,
GraphicComponent
} from 'echarts/components';
import { SVGRenderer, CanvasRenderer } from "echarts/renderers";
echarts.use([
LegendComponent,
TitleComponent,
TooltipComponent,
GridComponent,
PolarComponent,
AriaComponent,
ParallelComponent,
BarChart,
LineChart,
PieChart,
MapChart,
RadarChart,
PictorialBarChart,
RadarComponent,
ToolboxComponent,
DataZoomComponent,
VisualMapComponent,
TimelineComponent,
CalendarComponent,
GraphicComponent,
ScatterChart
]);
export enum RenderType {
SVGRenderer = 'SVGRenderer',
CanvasRenderer = 'CanvasRenderer'
}
export enum ThemeType {
Light = 'light',
Dark = 'dark',
Default = 'default'
}
export default function useChart(elRef: Ref<HTMLDivElement>, autoChartSize = false, animation: boolean = false, render: RenderType = RenderType.SVGRenderer, theme: ThemeType = ThemeType.Default) {
echarts.use(render === RenderType.SVGRenderer ? SVGRenderer : CanvasRenderer)
let chartInstance: echarts.ECharts | null = null;
const initCharts = () => {
const el = unref(elRef)
if (!el || !unref(el)) {
return
}
chartInstance = echarts.init(el, theme);
}
const setOption = (option: EChartsOption) => {
nextTick(() => {
if (!chartInstance) {
initCharts();
if (!chartInstance) return;
}
chartInstance.setOption(option)
hideLoading()
})
}
function getInstance(): echarts.ECharts | null {
if (!chartInstance) {
initCharts();
}
return chartInstance;
}
function resize() {
chartInstance?.resize();
}
function watchEl() {
if (animation) { elRef.value.style.transition = 'width 1s, height 1s' }
const resizeObserver = new ResizeObserver((entries => resize()))
resizeObserver.observe(elRef.value);
}
function showLoading() {
if (!chartInstance) {
initCharts();
}
chartInstance?.showLoading()
}
function hideLoading() {
if (!chartInstance) {
initCharts();
}
chartInstance?.hideLoading()
}
onMounted(() => {
window.addEventListener('resize', resize)
if (autoChartSize) watchEl();
})
onUnmounted(() => {
window.removeEventListener('resize', resize)
})
return {
setOption,
getInstance,
showLoading,
hideLoading
}
}
useConfirm.ts
import { ElMessageBox, ElMessage } from "element-plus";
import { ResultEnum } from '/@/enums/httpEnum';
const useConfirm = (
api: (params: any) => Promise<any>,
params: any = {},
message: string,
confirmType: 'warning'
) => {
return new Promise((resolve, reject) => {
ElMessageBox.confirm(`${message}`, "温馨提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: confirmType,
draggable: true
}).then(async () => {
const res = await api(params);
if (!res) return reject(false);
ElMessage({
type: "success",
message: `操作成功!`
});
resolve(true);
});
});
};
export default useConfirm;
useDraggable.ts
import { ref, onMounted, onUnmounted } from 'vue'
/**
* 让元素具有可拖拽功能的 hook
* @param {HTMLElement} element - 要设置为可拖拽的元素
* @returns {Object} 包含拖拽相关状态和方法的对象
*/
function useDraggable(element) {
// 初始时,元素的位置
const initialPosition = { x: 0, y: 0 }
// 鼠标按下时的位置
const mouseDownPosition = { x: 0, y: 0 }
// 元素是否正在被拖拽
const isDragging = ref(false)
// 鼠标按下事件处理函数
const handleMouseDown = (event: { preventDefault: () => void
event.preventDefault()
isDragging.value = true
mouseDownPosition.x = event.clientX
mouseDownPosition.y = event.clientY
initialPosition.x = element.offsetLeft
initialPosition.y = element.offsetTop
document.addEventListener('mousemove', handleMouseMove)
document.addEventListener('mouseup', handleMouseUp)
}
// 鼠标移动事件处理函数
const handleMouseMove = (event: { clientX: number
if (isDragging.value) {
const deltaX = event.clientX - mouseDownPosition.x
const deltaY = event.clientY - mouseDownPosition.y
element.style.left = initialPosition.x + deltaX + 'px'
element.style.top = initialPosition.y + deltaY + 'px'
}
}
// 鼠标抬起事件处理函数
const handleMouseUp = () => {
isDragging.value = false
document.removeEventListener('mousemove', handleMouseMove)
document.removeEventListener('mouseup', handleMouseUp)
}
// 组件挂载时为元素添加鼠标按下事件监听
onMounted(() => {
element.addEventListener('mousedown', handleMouseDown)
})
// 组件卸载时移除事件监听
onUnmounted(() => {
element.removeEventListener('mousedown', handleMouseDown)
})
// 返回复制状态和复制操作
return {
isDragging
}
}
export default useDraggable
useSelection.ts
import { ref, computed } from "vue";
const useSelection = (rowKey: string = 'guid') => {
const isSelected = ref<boolean>(false);
const selectedList = ref<{ [key: string]: any }[]>([]);
const selectedListIds = computed((): string[] => {
return selectedList.value.map(item => item[rowKey]);
});
const selectListCount = computed((): number => {
return selectedList.value.length;
});
const onSelectionChange = (rowArr: { [key: string]: any }[]) => {
rowArr.length ? (isSelected.value = true) : (isSelected.value = false);
selectedList.value = rowArr;
};
return {
isSelected,
selectedList,
selectedListIds,
selectListCount,
onSelectionChange
};
};
export default useSelection;
useTable.ts
import { computed, reactive, toRefs } from "vue";
const DEFAULT_PAGE_SIZE = 10;
export namespace Table {
export interface Pagination {
pageIndex: number;
pageSize: number;
total: number;
}
export interface StateProps {
loading: Boolean;
searchParam: Object;
totalParam: Object;
tableData: any[];
pages: Pagination;
}
}
export const useTable = (
api: (params: any) => Promise<any>,
initParam: object = {},
immediate: boolean = true,
isShowPage: boolean = true,
onError?: (error: any) => void
) => {
const state = reactive<Table.StateProps>({
loading: false,
searchParam: {},
totalParam: {},
tableData: [],
pages: {
pageIndex: 1,
pageSize: DEFAULT_PAGE_SIZE,
total: 0
}
});
const pageParam = computed(() => {
return {
pageIndex: state.pages.pageIndex,
pageSize: state.pages.pageSize
};
});
const getTableList = async () => {
if (!api) return;
state.loading = true;
try {
Object.assign(state.totalParam, initParam, isShowPage ? pageParam.value : {});
const { pages, data } = await api({ ...state.totalParam });
state.tableData = data ?? [];
isShowPage && updatePages(pages);
} catch (error) {
onError && onError(error);
} finally {
state.loading = false;
}
};
const isImmediate = immediate ?? true;
onMounted(() => isImmediate && getTableList());
const updatePages = (pages: Table.Pagination) => {
Object.assign(state.pages, pages);
};
const onSearch = () => {
state.pages.pageIndex = 1;
getTableList();
};
const onReset = () => {
state.pages.pageIndex = 1;
getTableList();
};
const onRefresh = () => {
getTableList();
};
const onPageChange = (pages: TableDemoPageType) => {
state.pages.pageIndex = pages.pageIndex;
state.pages.pageSize = pages.pageSize;
getTableList();
};
return {
...toRefs(state),
getTableList,
onPageChange,
onSearch,
onReset,
onRefresh
}
};
export default useTable;