import { routeName, router } from '@/router' import { Dialog } from '@kankan/components/index' import { ref, Ref, watch } from 'vue' import { useAsyncBus, Handler } from './useAsyncBus' import { useViewStack } from './useViewStack' import { disabledMap } from './custom' import { ui18n } from '@/lang' import { useConfirm } from '@/hook' export const editBus = useAsyncBus<{ save: void; leave: void }>() export type EditHandler = () => void export type EditStatus = { edit: EditHandler desave: EditHandler leaveSave: EditHandler leave: EditHandler } let mark: EditStatus & { isedit: boolean; isdesave: boolean } export type KV = [Ref, T] | [Ref, T, T] export type KVS = Array> export type VS = Array[number][1]> // 进入编辑界面 export const useEdit = (args?: KV | KVS) => { if (!args) return mark.edit() const kvs = (Array.isArray(args[0]) ? args : [args]) as KVS const cacheks = kvs.map(([k, _, d = k.value]) => d) const updateKs = (value: VS) => { for (let i = 0; i < kvs.length; i++) { kvs[i][0].value = value[i] } } mark.edit() updateKs(kvs.map(([_, v]) => v)) editBus.on('leave', () => updateKs(cacheks), { last: true }) } // 保存 export const useEmitSave = () => { editBus.emit('save').then(() => { if (!disabledMap.autoLeave) { useLeaveEdit() } else { useLeaveSave() } }) } // 退出 let sureBackPage = true export const useEmitLeave = async (isBack = true) => { if (mark.isdesave) { const isLeave = await useConfirm(ui18n.t('sys.forceLeaveConfirm')) if (!isLeave) { return false } } sureBackPage = isBack editBus.on('leave', () => (sureBackPage = true), { last: true }) editBus.emit('leave').then(useLeaveEdit) return true } export const useLeaveEditRaw = () => mark.leave() // 退出保存 export const useLeaveSave = () => { editBus.off('save') mark.leaveSave() } // 退出编辑 export const useLeaveEdit = () => { editBus.off('save') editBus.off('leave') mark.leave() mark.leaveSave() } export type DesaveArgs = { save?: Handler leave?: Handler } // 进入未保存模式 export const useDesave = (cbs: DesaveArgs = {}) => { mark.desave() cbs.leave && editBus.on('leave', cbs.leave) cbs.save && editBus.on('save', cbs.save) } export type DesaveArgsAssistArgs = DesaveArgs & { intercept?: (newCurrent: T, oldCurrent: T) => boolean auto?: boolean backup?: () => void recovery?: () => void } export function useDesaveAssist( current: T, setting: DesaveArgsAssistArgs & { auto: false } ): () => () => void export function useDesaveAssist( current: T, setting: DesaveArgsAssistArgs & { auto: true } ): { desave: Ref } export function useDesaveAssist( current: T, setting: DesaveArgsAssistArgs ) { const desave = ref(false) const { recovery, backup, leave } = setting const leaveHandler = () => { isSave = false; if (recovery || backup) { recovery && recovery() backup && backup() desave.value = false leave && (leave as any)() } } let isSave = false const save = async args => { isSave = true try { await setting.save(args) } catch (e) { // recovery && recovery() throw e } isSave = false } const handler = (newv, oldv) => { if (!isSave) { if (!setting.intercept || setting.intercept(newv, oldv)) { desave.value = true mark.isedit || useEdit() useDesave({ save }) backup && editBus.on('save', backup, { last: true }) } leaveHandler && editBus.on('leave', leaveHandler, { last: true }) } } const saveWatch = () => { backup && backup() return watch(current, handler, { deep: true }) } if (setting.auto) { useViewStack(saveWatch) return { desave } } else { return saveWatch } } export const useBack = (type: 'save' | 'leave' = 'leave') => { if (sureBackPage && (type === 'leave' || !disabledMap.autoLeave)) { if (!history.state.back) { router.replace({ name: routeName.value.query }) } else { router.back() } } } type HookArgs = (...args: any) => void | (() => any | void) export const useViewEdit = ( hook?: HookArgs, cb: (type: 'save' | 'leave') => void = useBack ) => useViewStack(() => { useEdit() editBus.on('leave', () => cb('leave'), { last: true }) editBus.on('save', () => cb('save'), { last: true }) const exitFn = hook && hook() return () => { useLeaveEdit() exitFn && exitFn() } }) export const setupEdit = (status: EditStatus) => { mark = { edit: () => { mark.isedit = true status.edit() }, desave: () => { mark.isdesave = true status.desave() }, leave: () => { mark.isdesave = false mark.isedit = false status.leave() }, leaveSave: () => { mark.isdesave = false status.leaveSave() }, isedit: false, isdesave: false } }