Files
simple-element-plus-template/src/hooks/CommonHooks.js
2026-08-18 17:59:01 +08:00

308 lines
7.8 KiB
JavaScript

import { provide, inject, onBeforeUnmount, onMounted, ref, watch, nextTick } from 'vue'
import { isFunction, isNumber, uniqueId } from 'lodash-es'
import { useGlobalSearchParamStore } from '@/stores/GlobalSearchParamStore'
import { $coreHideLoading, $coreShowLoading } from '@/utils'
import { GLOBAL_LOADING } from '@/config'
import Sortable from 'sortablejs'
const defaultPageProcessor = (searchResult, searchParam) => {
const resultData = searchResult?.resultData || searchResult
const pageObj = searchResult?.page || resultData?.page || searchResult?.pageSetting || resultData?.pageSetting
if (pageObj && searchParam.value) {
if (searchParam.value.page) {
Object.assign(searchParam.value.page, pageObj)
} else if (searchParam.value.pageSetting) {
Object.assign(searchParam.value.pageSetting, pageObj)
}
}
}
/**
* 通用搜索表格表单封装
* @param {CommonTableAndSearchForm} param 参数
* @return {CommonTableAndSearchResult} 返回数据
*/
export const useTableAndSearchForm = ({
searchMethod,
defaultParam = {},
dataProcessor = searchResult => searchResult.resultData,
pageProcessor = defaultPageProcessor,
saveParam = true
}) => {
const globalSearchParamStore = useGlobalSearchParamStore()
const tableData = ref([])
const loading = ref(false)
const searchParam = ref(saveParam ? globalSearchParamStore.getCurrentParam(defaultParam) : defaultParam)
const searchTableItems = async (pageNumber, newParams = {}, saveConfig) => {
if (isNumber(pageNumber) && searchParam.value) {
if (searchParam.value.page) {
searchParam.value.page.pageNumber = pageNumber
} else if (searchParam.value.pageSetting) {
searchParam.value.pageSetting.pageNumber = pageNumber
}
}
loading.value = true
saveParam && globalSearchParamStore.saveCurrentParam(searchParam.value, saveConfig)
const searchResult = await searchMethod({ ...searchParam.value, ...newParams })
.finally(() => { loading.value = false })
loading.value = false
if (searchResult.success && searchResult.resultData) {
tableData.value = isFunction(dataProcessor) && dataProcessor?.(searchResult, searchParam)
pageProcessor?.(searchResult, searchParam)
}
return searchResult
}
return {
tableData,
loading,
searchParam,
searchMethod: searchTableItems
}
}
export const useInitLoadOnce = (loader, config = {}) => {
const initLoading = ref(false)
const initLoadOnce = async () => {
if (!initLoading.value) {
try {
initLoading.value = true
if (config.loading ?? GLOBAL_LOADING) {
$coreShowLoading()
}
await loader()
} finally {
initLoading.value = false
if (config.loading ?? GLOBAL_LOADING) {
$coreHideLoading()
}
}
}
}
return {
initLoading,
initLoadOnce
}
}
export const useDateStr = (watchFn) => {
const dateStr = ref(new Date().getTime())
watchFn && watch(watchFn, (update) => {
if (update) {
dateStr.value = new Date().getTime()
}
})
return { dateStr }
}
export const useGlobalSaveSearchParam = (defaultParam) => {
const globalSearchParamStore = useGlobalSearchParamStore()
const searchParam = ref(globalSearchParamStore.getCurrentParam(defaultParam))
return {
searchParam,
/**
* @param [path]
*/
saveSearchParam: (path) => {
globalSearchParamStore.saveCurrentParam(searchParam.value, path)
}
}
}
export const useManagedArrayItems = () => {
const managedItems = ref([])
const context = ref(false)
const startContext = () => (context.value = true)
const pushItem = (item) => {
const index = managedItems.value.findIndex(it => item.id === it.id)
if (index < 0) {
managedItems.value.push(item)
return item
} else {
return goToItem(index)
}
}
const goToItem = index => {
let result = null
if (index > -1 && (result = managedItems.value[index])) {
context.value = true
managedItems.value = managedItems.value.slice(0, index + 1)
}
return result
}
const clearItems = () => {
if (!context.value) {
managedItems.value = []
}
context.value = false
}
return {
managedItems,
startContext,
pushItem,
goToItem,
clearItems
}
}
export const useSortableParams = (params, selector, moveCls = '.move-indicator') => {
let sortable = null
const sortableRef = ref()
const dragging = ref(false)
const hoverIndex = ref(-1)
const initSortable = () => {
let el = sortableRef.value?.$el || sortableRef.value
if (el && !sortable) {
const tbody = el.querySelector('tbody')
if (tbody) {
el = tbody
}
sortable = new Sortable(el, {
animation: 150,
draggable: selector,
handle: moveCls,
onStart () {
hoverIndex.value = -1
dragging.value = true
},
onEnd (event) {
const { oldIndex, newIndex } = event
params.value.splice(newIndex, 0, params.value.splice(oldIndex, 1)[0]) // 插入到 newIndex 位置
setTimeout(() => {
dragging.value = false
hoverIndex.value = newIndex
})
}
})
}
}
const destroySortable = () => {
if (sortable) {
sortable.destroy()
sortable = null
}
}
onMounted(() => {
initSortable()
})
watch(() => sortableRef.value, (val) => {
if (val) {
initSortable()
} else {
destroySortable()
}
})
onBeforeUnmount(() => {
destroySortable()
})
return {
dragging,
hoverIndex,
sortableRef
}
}
export const useRenderKey = () => {
const renderKeyMap = new WeakMap()
function renderKey (param) {
if (param.id != null) {
return `param-${param.id}`
}
if (!renderKeyMap.has(param)) {
renderKeyMap.set(param, uniqueId())
}
return `param-tmp-${renderKeyMap.get(param)}`
}
return {
renderKey
}
}
export const useProvideDataLoading = (loadingKey = 'dataLoading') => {
const dataLoading = ref(false)
const startLoading = (config = { delay: 100 }) => {
if (!dataLoading.value) {
dataLoading.value = true
$coreShowLoading(config)
}
}
provide(loadingKey, { dataLoading, startLoading })
return {
dataLoading,
startLoading
}
}
export const useInjectDataLoading = (loadingKey = 'dataLoading') => {
const { dataLoading, startLoading } = inject(loadingKey,
{ dataLoading: ref(false), startLoading: () => {} })
const endLoading = () => {
if (dataLoading?.value) {
setTimeout(() => {
$coreHideLoading()
dataLoading.value = false
})
} else {
$coreHideLoading()
}
}
return {
startLoading,
endLoading
}
}
export const useContextMenu = () => {
const showContextMenu = ref(false)
const contextMenuRef = ref(null)
const contextMenuHandlers = ref([])
const contextMenuItem = ref(null)
const contextMenuDropdownRef = ref()
const handleContextMenuVisibleChange = (visible) => {
if (!visible) {
showContextMenu.value = false
}
}
const handleRequestContextMenu = (event, item, buttons) => {
showContextMenu.value = false
contextMenuItem.value = item
contextMenuHandlers.value = buttons || []
contextMenuRef.value = {
getBoundingClientRect () {
return {
width: 0,
height: 0,
top: event.clientY,
bottom: event.clientY,
left: event.clientX,
right: event.clientX
}
}
}
nextTick(() => {
showContextMenu.value = true
nextTick(() => {
contextMenuDropdownRef.value?.handleOpen?.()
})
})
}
return {
showContextMenu,
contextMenuRef,
contextMenuHandlers,
contextMenuItem,
contextMenuDropdownRef,
handleContextMenuVisibleChange,
handleRequestContextMenu
}
}