@ithinkdt/naive
Version:
iThinkDT Naive UI
173 lines (151 loc) • 4.89 kB
JSX
import { ref, isRef, computed, watch, nextTick } from 'vue'
import { NFlex, NButton } from 'ithinkdt-ui'
import { walkTree } from '@ithinkdt/common'
import { useModal } from '@ithinkdt/core'
import { DtModuleTree } from './Tree'
export function useModuleSelect(
modules,
{ title, onRefresh, treeProps = {}, modalProps = {}, loading = ref(false), includeParents },
) {
const _selection = ref([])
const outIdSets = []
const modulePathsMap = new Map()
const moduleIdSet = new Set()
let init
const $init = new Promise((resolve) => (init = resolve))
watch(
modules,
(tree) => {
modulePathsMap.clear()
moduleIdSet.clear()
if (!Array.isArray(tree)) return
if (tree.length > 0) {
nextTick(init)
walkTree(
tree,
(it, _i, parents) => {
moduleIdSet.add(it.id)
if (!it.children?.length) {
modulePathsMap.set(it.id, [...parents.map((it) => it.id), it.id])
}
},
{ parentPaths: true },
)
}
},
{ immediate: true },
)
const renderModuleSelect = (showSubmitBtn = false, submiting, onSubmit) => {
return (
<DtModuleTree
data={modules.value}
treeProps={treeProps}
loading={loading.value}
selectable
showSubmitBtn={showSubmitBtn}
submiting={submiting}
v-model:selection={_selection.value}
onSubmit={() => onSubmit(getIds())}
onRefresh={onRefresh}
/>
)
}
const saving = ref(false)
let resolve, reject
const ret = useModal({
type: 'drawer',
width: 520,
...modalProps,
title,
closable: computed(() => !saving.value),
onClose: () => reject(),
content: {
default: () => <div style="padding-left: 16px">{renderModuleSelect(false)}</div>,
footer: () => (
<NFlex>
<NButton onClick={() => reject()} disabled={saving.value || loading.value}>
取 消
</NButton>
<NButton type="primary" onClick={() => resolve()} loading={saving.value || loading.value}>
保 存
</NButton>
</NFlex>
),
},
})
const setSelection = async (selection) => {
outIdSets.length = 0
_selection.value = []
if (selection.length === 0) {
return
}
await $init
const data = []
for (const it of selection) {
if (modulePathsMap.has(it)) data.push(it)
if (!moduleIdSet.has(it)) {
outIdSets.push(it)
}
}
_selection.value = data
}
let last
const handleSelection = async (selection) => {
last?.()
if (isRef(selection)) {
last = watch(
selection,
(data) => {
setSelection(Array.isArray(data) ? [...data] : [])
},
{ immediate: true },
)
} else {
if (selection instanceof Promise) {
selection = await selection
}
setSelection(Array.isArray(selection) ? [...selection] : [])
}
}
const getIds = () => {
let ids = [..._selection.value]
if (includeParents) {
ids = [
...new Set(
ids.flatMap((key) => {
return modulePathsMap.get(key) ?? []
}),
),
].filter((it) => !it.startsWith('app-'))
}
return [...ids, ...outIdSets]
}
return {
open: async (selection, then) => {
ret.show()
await handleSelection(selection)
return new Promise((_resolve, _reject) => {
resolve = _resolve
reject = _reject
})
.then(() => {
saving.value = true
Promise.resolve(then(getIds()))
.then((v) => {
if (false !== v) ret.close()
})
.finally(() => {
saving.value = false
})
})
.catch(() => {
ret.close()
})
},
close: ret.close,
modulePathsMap,
renderModuleSelect,
setSelection: handleSelection,
getSelection: getIds,
}
}