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