@kine-design/core 0.0.1-beta.1 → 0.0.1-beta.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/style/global.css +1 -0
- package/assets/style/var/Wuxing.css +71 -0
- package/assets/style/var.css +23 -0
- package/components/base/affix/api.ts +16 -0
- package/components/base/affix/index.ts +17 -0
- package/components/base/affix/props.d.ts +34 -0
- package/components/base/affix/useAffix.ts +123 -0
- package/components/base/alert/api.ts +18 -0
- package/components/base/alert/index.ts +15 -0
- package/components/base/alert/props.d.ts +50 -0
- package/components/base/anchor/api.ts +20 -0
- package/components/base/anchor/index.ts +18 -0
- package/components/base/anchor/props.d.ts +46 -0
- package/components/base/anchor/useAnchor.ts +83 -0
- package/components/base/autoComplete/api.ts +24 -0
- package/components/base/autoComplete/index.ts +17 -0
- package/components/base/autoComplete/props.d.ts +75 -0
- package/components/base/autoComplete/useAutoComplete.ts +149 -0
- package/components/base/avatar/api.ts +17 -0
- package/components/base/avatar/avatar.css +61 -0
- package/components/base/avatar/index.ts +15 -0
- package/components/base/avatar/props.d.ts +37 -0
- package/components/base/backTop/api.ts +17 -0
- package/components/base/backTop/index.ts +17 -0
- package/components/base/backTop/props.d.ts +38 -0
- package/components/base/backTop/useBackTop.ts +62 -0
- package/components/base/badge/api.ts +22 -0
- package/components/base/badge/index.ts +15 -0
- package/components/base/badge/props.d.ts +50 -0
- package/components/base/button/api.ts +28 -0
- package/components/base/button/button.css +34 -0
- package/components/base/button/index.ts +17 -0
- package/components/base/button/props.d.ts +64 -0
- package/components/base/button/useButton.ts +37 -0
- package/components/base/card/api.ts +17 -0
- package/components/base/card/index.ts +15 -0
- package/components/base/card/props.d.ts +37 -0
- package/components/base/carousel/api.ts +28 -0
- package/components/base/carousel/index.ts +17 -0
- package/components/base/carousel/props.d.ts +72 -0
- package/components/base/carousel/useCarousel.ts +149 -0
- package/components/base/cascader/api.ts +23 -0
- package/components/base/cascader/index.ts +18 -0
- package/components/base/cascader/props.d.ts +103 -0
- package/components/base/cascader/useCascader.ts +334 -0
- package/components/base/checkbox/api.ts +24 -0
- package/components/base/checkbox/checkbox.css +0 -0
- package/components/base/checkbox/index.ts +17 -0
- package/components/base/checkbox/props.d.ts +77 -0
- package/components/base/checkbox/useCheckbox.ts +42 -0
- package/components/base/collapse/api.ts +21 -0
- package/components/base/collapse/index.ts +18 -0
- package/components/base/collapse/props.d.ts +45 -0
- package/components/base/collapse/useCollapse.ts +80 -0
- package/components/base/datePicker/api.ts +18 -0
- package/components/base/datePicker/index.ts +19 -0
- package/components/base/datePicker/props.d.ts +60 -0
- package/components/base/datePicker/useDatePicker.ts +392 -0
- package/components/base/divider/api.ts +15 -0
- package/components/base/divider/divider.css +11 -0
- package/components/base/divider/index.ts +15 -0
- package/components/base/divider/props.d.ts +30 -0
- package/components/base/dropdown/api.ts +33 -0
- package/components/base/dropdown/index.ts +18 -0
- package/components/base/dropdown/props.d.ts +60 -0
- package/components/base/dropdown/useDropdown.ts +123 -0
- package/components/base/empty/api.ts +15 -0
- package/components/base/empty/index.ts +15 -0
- package/components/base/empty/props.d.ts +26 -0
- package/components/base/image/api.ts +25 -0
- package/components/base/image/index.ts +18 -0
- package/components/base/image/props.d.ts +67 -0
- package/components/base/image/useImage.ts +119 -0
- package/components/base/input/api.ts +19 -0
- package/components/base/input/index.ts +17 -0
- package/components/base/input/input.css +19 -0
- package/components/base/input/props.d.ts +60 -0
- package/components/base/input/useInput.ts +53 -0
- package/components/base/inputNumber/api.ts +21 -0
- package/components/base/inputNumber/index.ts +17 -0
- package/components/base/inputNumber/props.d.ts +64 -0
- package/components/base/inputNumber/useInputNumber.ts +140 -0
- package/components/base/li/api.ts +15 -0
- package/components/base/li/index.ts +15 -0
- package/components/base/li/props.d.ts +30 -0
- package/components/base/list/api.ts +16 -0
- package/components/base/list/index.ts +17 -0
- package/components/base/list/props.d.ts +33 -0
- package/components/base/list/useList.ts +36 -0
- package/components/base/loading/api.ts +17 -0
- package/components/base/loading/index.ts +15 -0
- package/components/base/loading/props.d.ts +38 -0
- package/components/base/popover/api.ts +28 -0
- package/components/base/popover/index.ts +17 -0
- package/components/base/popover/props.d.ts +73 -0
- package/components/base/popover/usePopover.ts +192 -0
- package/components/base/progress/api.ts +18 -0
- package/components/base/progress/index.ts +17 -0
- package/components/base/progress/props.d.ts +53 -0
- package/components/base/progress/useProgress.ts +28 -0
- package/components/base/radio/api.ts +19 -0
- package/components/base/radio/index.ts +19 -0
- package/components/base/radio/props.d.ts +59 -0
- package/components/base/radio/useRadio.ts +11 -0
- package/components/base/rate/api.ts +18 -0
- package/components/base/rate/index.ts +17 -0
- package/components/base/rate/props.d.ts +49 -0
- package/components/base/rate/useRate.ts +75 -0
- package/components/base/result/api.ts +20 -0
- package/components/base/result/index.ts +15 -0
- package/components/base/result/props.d.ts +36 -0
- package/components/base/select/api.ts +31 -0
- package/components/base/select/index.ts +18 -0
- package/components/base/select/props.d.ts +132 -0
- package/components/base/select/select.css +7 -0
- package/components/base/select/useSelect.ts +280 -0
- package/components/base/select/useSelectTools.ts +60 -0
- package/components/base/skeleton/api.ts +18 -0
- package/components/base/skeleton/index.ts +15 -0
- package/components/base/skeleton/props.d.ts +41 -0
- package/components/base/slider/api.ts +20 -0
- package/components/base/slider/index.ts +17 -0
- package/components/base/slider/props.d.ts +65 -0
- package/components/base/slider/useSlider.ts +83 -0
- package/components/base/space/api.ts +17 -0
- package/components/base/space/index.ts +15 -0
- package/components/base/space/props.d.ts +39 -0
- package/components/base/steps/api.ts +30 -0
- package/components/base/steps/index.ts +22 -0
- package/components/base/steps/props.d.ts +88 -0
- package/components/base/steps/useSteps.ts +101 -0
- package/components/base/switch/api.ts +22 -0
- package/components/base/switch/index.ts +19 -0
- package/components/base/switch/props.d.ts +66 -0
- package/components/base/switch/useSwitch.tsx +79 -0
- package/components/base/tabs/api.ts +23 -0
- package/components/base/tabs/index.ts +18 -0
- package/components/base/tabs/props.d.ts +41 -0
- package/components/base/tabs/useTabs.ts +66 -0
- package/components/base/tag/api.ts +17 -0
- package/components/base/tag/index.ts +15 -0
- package/components/base/tag/props.d.ts +49 -0
- package/components/base/timePicker/api.ts +21 -0
- package/components/base/timePicker/index.ts +18 -0
- package/components/base/timePicker/props.d.ts +66 -0
- package/components/base/timePicker/useTimePicker.ts +161 -0
- package/components/base/timeline/api.ts +24 -0
- package/components/base/timeline/index.ts +16 -0
- package/components/base/timeline/props.d.ts +60 -0
- package/components/base/tooltip/api.ts +19 -0
- package/components/base/tooltip/index.ts +17 -0
- package/components/base/tooltip/props.d.ts +34 -0
- package/components/base/tooltip/useTooltip.ts +89 -0
- package/components/base/transfer/api.ts +18 -0
- package/components/base/transfer/index.ts +17 -0
- package/components/base/transfer/props.d.ts +63 -0
- package/components/base/transfer/useTransfer.ts +207 -0
- package/components/base/tree/api.ts +47 -0
- package/components/base/tree/index.ts +29 -0
- package/components/base/tree/props.d.ts +108 -0
- package/components/base/tree/tree.ts +263 -0
- package/components/base/tree/useTree.ts +114 -0
- package/components/message/confirm/api.ts +21 -0
- package/components/message/confirm/index.ts +15 -0
- package/components/message/confirm/props.d.ts +69 -0
- package/components/message/dialog/api.ts +19 -0
- package/components/message/dialog/index.ts +15 -0
- package/components/message/dialog/props.d.ts +55 -0
- package/components/message/drawer/api.ts +32 -0
- package/components/message/drawer/index.ts +15 -0
- package/components/message/drawer/props.d.ts +73 -0
- package/components/message/message/api.ts +27 -0
- package/components/message/message/index.ts +20 -0
- package/components/message/message/props.d.ts +54 -0
- package/components/message/message/useMessage.ts +61 -0
- package/components/message/notification/api.ts +23 -0
- package/components/message/notification/index.ts +19 -0
- package/components/message/notification/props.d.ts +64 -0
- package/components/message/notification/useNotification.ts +79 -0
- package/components/message/popover/MPopover.tsx +94 -0
- package/components/message/popover/api.ts +54 -0
- package/components/message/popover/index.ts +17 -0
- package/components/message/popover/popover.css +21 -0
- package/components/message/popover/props.d.ts +76 -0
- package/components/message/popover/usePopover.ts +234 -0
- package/components/other/darkMode/api.ts +17 -0
- package/components/other/darkMode/index.ts +17 -0
- package/components/other/darkMode/props.d.ts +37 -0
- package/components/other/darkMode/useDarkMode.ts +129 -0
- package/components/template/border/api.ts +18 -0
- package/components/template/border/index.ts +15 -0
- package/components/template/border/props.d.ts +41 -0
- package/components/template/breadcrumb/api.ts +15 -0
- package/components/template/breadcrumb/index.ts +15 -0
- package/components/template/breadcrumb/props.d.ts +45 -0
- package/components/template/descriptions/api.ts +23 -0
- package/components/template/descriptions/index.ts +16 -0
- package/components/template/descriptions/props.d.ts +54 -0
- package/components/template/form/api.ts +23 -0
- package/components/template/form/index.ts +20 -0
- package/components/template/form/props.d.ts +60 -0
- package/components/template/grid/api.ts +20 -0
- package/components/template/grid/index.ts +15 -0
- package/components/template/grid/props.d.ts +48 -0
- package/components/template/menu/api.ts +26 -0
- package/components/template/menu/index.ts +18 -0
- package/components/template/menu/props.d.ts +93 -0
- package/components/template/menu/useMenu.ts +155 -0
- package/components/template/pagination/api.ts +22 -0
- package/components/template/pagination/index.ts +19 -0
- package/components/template/pagination/props.d.ts +65 -0
- package/components/template/pagination/usePagination.ts +186 -0
- package/components/template/table/api.ts +18 -0
- package/components/template/table/index.ts +18 -0
- package/components/template/table/props.d.ts +36 -0
- package/components/template/table/useTable.ts +138 -0
- package/components/template/tableColumn/api.ts +17 -0
- package/components/template/tableColumn/index.ts +15 -0
- package/components/template/tableColumn/props.d.ts +32 -0
- package/components/template/virtualList/api.ts +16 -0
- package/components/template/virtualList/index.ts +17 -0
- package/components/template/virtualList/props.d.ts +25 -0
- package/components/template/virtualList/useVirtualList.ts +237 -0
- package/components/types/hook.d.ts +13 -0
- package/components/types/props.d.ts +52 -0
- package/components/types/template.d.ts +59 -0
- package/compositions/common/defineCore.ts +55 -0
- package/compositions/common/useDebounceFn.ts +27 -0
- package/compositions/common/useDrag.ts +65 -0
- package/compositions/common/useElementSize.ts +37 -0
- package/compositions/common/useEventListener.ts +48 -0
- package/compositions/common/usePopover.ts +45 -0
- package/compositions/common/useResizeObserver.ts +43 -0
- package/compositions/common/useTeleport.ts +24 -0
- package/compositions/input/useBooleanInput.ts +52 -0
- package/compositions/modal/useModal.ts +72 -0
- package/compositions/popper/useClickAway.ts +41 -0
- package/compositions/popper/usePopper.ts +63 -0
- package/compositions/utils/filters.ts +135 -0
- package/compositions/virtualList/enums.ts +52 -0
- package/compositions/virtualList/useContainerObserver.ts +89 -0
- package/compositions/virtualList/useEntries.ts +248 -0
- package/compositions/virtualList/useHeightCache.ts +83 -0
- package/compositions/virtualList/useSentinelObserver.ts +81 -0
- package/dist/components/base/affix/index.d.ts +2 -1
- package/dist/components/base/affix/useAffix.d.ts +6 -5
- package/dist/components/base/anchor/index.d.ts +2 -1
- package/dist/components/base/anchor/useAnchor.d.ts +2 -2
- package/dist/components/base/autoComplete/useAutoComplete.d.ts +12 -4
- package/dist/components/base/avatar/index.d.ts +1 -0
- package/dist/components/base/backTop/index.d.ts +2 -1
- package/dist/components/base/backTop/useBackTop.d.ts +2 -2
- package/dist/components/base/button/index.d.ts +3 -21
- package/dist/components/base/button/useButton.d.ts +5 -2
- package/dist/components/base/carousel/useCarousel.d.ts +6 -3
- package/dist/components/base/cascader/useCascader.d.ts +23 -11
- package/dist/components/base/checkbox/index.d.ts +2 -1
- package/dist/components/base/checkbox/useCheckbox.d.ts +4 -3
- package/dist/components/base/collapse/index.d.ts +2 -1
- package/dist/components/base/collapse/useCollapse.d.ts +3 -3
- package/dist/components/base/datePicker/useDatePicker.d.ts +140 -8
- package/dist/components/base/dropdown/index.d.ts +2 -1
- package/dist/components/base/dropdown/useDropdown.d.ts +12 -6
- package/dist/components/base/image/useImage.d.ts +5 -5
- package/dist/components/base/input/index.d.ts +2 -1
- package/dist/components/base/input/useInput.d.ts +1 -2
- package/dist/components/base/inputNumber/index.d.ts +2 -1
- package/dist/components/base/inputNumber/useInputNumber.d.ts +3 -3
- package/dist/components/base/li/index.d.ts +1 -0
- package/dist/components/base/list/index.d.ts +2 -1
- package/dist/components/base/list/useList.d.ts +1 -1
- package/dist/components/base/popover/index.d.ts +2 -1
- package/dist/components/base/popover/usePopover.d.ts +9 -9
- package/dist/components/base/progress/index.d.ts +2 -1
- package/dist/components/base/progress/useProgress.d.ts +2 -2
- package/dist/components/base/rate/index.d.ts +2 -1
- package/dist/components/base/rate/useRate.d.ts +2 -2
- package/dist/components/base/select/useSelect.d.ts +8 -8
- package/dist/components/base/slider/index.d.ts +2 -1
- package/dist/components/base/slider/useSlider.d.ts +4 -4
- package/dist/components/base/steps/index.d.ts +1 -1
- package/dist/components/base/steps/useSteps.d.ts +5 -5
- package/dist/components/base/switch/index.d.ts +2 -1
- package/dist/components/base/switch/useSwitch.d.ts +8 -3
- package/dist/components/base/tabs/index.d.ts +1 -1
- package/dist/components/base/tabs/useTabs.d.ts +3 -3
- package/dist/components/base/tag/index.d.ts +1 -0
- package/dist/components/base/timePicker/useTimePicker.d.ts +14 -6
- package/dist/components/base/tooltip/index.d.ts +1 -1
- package/dist/components/base/tooltip/useTooltip.d.ts +15 -5
- package/dist/components/base/transfer/useTransfer.d.ts +15 -15
- package/dist/components/base/tree/index.d.ts +1 -1
- package/dist/components/base/tree/useTree.d.ts +2 -1
- package/dist/components/message/drawer/index.d.ts +2 -2
- package/dist/components/message/message/useMessage.d.ts +11 -1
- package/dist/components/message/notification/useNotification.d.ts +17 -1
- package/dist/components/message/popover/MPopover.d.ts +6 -1
- package/dist/components/message/popover/index.d.ts +1 -1
- package/dist/components/message/popover/usePopover.d.ts +6 -6
- package/dist/components/other/darkMode/useDarkMode.d.ts +1 -1
- package/dist/components/template/menu/index.d.ts +0 -1
- package/dist/components/template/menu/useMenu.d.ts +2 -1
- package/dist/components/template/pagination/index.d.ts +2 -1
- package/dist/components/template/virtualList/index.d.ts +0 -1
- package/dist/components/template/virtualList/useVirtualList.d.ts +10 -7
- package/dist/compositions/common/useDrag.d.ts +1 -1
- package/dist/compositions/common/useElementSize.d.ts +2 -2
- package/dist/compositions/common/useTeleport.d.ts +4 -2
- package/dist/compositions/modal/useModal.d.ts +1 -1
- package/dist/core.js +6147 -4186
- package/dist/runtime/defineHook.d.ts +1 -1
- package/index.css +1 -0
- package/index.ts +71 -0
- package/package.json +19 -16
- package/runtime/defineHook.ts +21 -0
- package/tools/empty.ts +81 -0
- package/tools/index.ts +15 -0
- package/tools/types.ts +11 -0
- package/tsconfig.json +8 -0
- package/types/common/common.d.ts +25 -0
- package/types/common/model.d.ts +25 -0
- package/types/index.d.ts +11 -0
- package/types/props.d.ts +13 -0
- package/vite.config.build.ts +41 -0
- package/dist/vite.config.build.d.ts +0 -2
|
@@ -0,0 +1,334 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @description Cascader 组件核心 composable
|
|
3
|
+
* @author 阿怪
|
|
4
|
+
* @date 2026/2/26
|
|
5
|
+
* @version v1.0.0
|
|
6
|
+
*
|
|
7
|
+
* 江湖的业务千篇一律,复杂的代码好几百行。
|
|
8
|
+
*
|
|
9
|
+
* 核心逻辑:
|
|
10
|
+
* - 面板展开:按层级维护 activePath(当前激活的选项路径)
|
|
11
|
+
* - 路径追踪:selectedPath 记录已选中的完整路径节点
|
|
12
|
+
* - 搜索过滤:filterable 模式下递归扁平化所有叶子路径进行匹配
|
|
13
|
+
* - 多选:selectedPaths 记录多条已选路径
|
|
14
|
+
*/
|
|
15
|
+
import { computed, ref, toRef, watch } from 'vue';
|
|
16
|
+
import { CascaderOption, CascaderProps } from './props';
|
|
17
|
+
|
|
18
|
+
/** 扁平化后的叶子路径,用于搜索 */
|
|
19
|
+
export interface FlatCascaderOption {
|
|
20
|
+
/** 从根到当前节点的完整路径节点列表 */
|
|
21
|
+
path: CascaderOption[];
|
|
22
|
+
/** 路径标签拼接(用于搜索匹配) */
|
|
23
|
+
pathLabel: string;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* 递归扁平化选项树,收集所有叶子节点路径
|
|
28
|
+
*/
|
|
29
|
+
const flattenOptions = (
|
|
30
|
+
options: CascaderOption[],
|
|
31
|
+
path: CascaderOption[] = [],
|
|
32
|
+
): FlatCascaderOption[] => {
|
|
33
|
+
const result: FlatCascaderOption[] = [];
|
|
34
|
+
for (const option of options) {
|
|
35
|
+
const currentPath = [...path, option];
|
|
36
|
+
if (!option.children || option.children.length === 0 || option.leaf) {
|
|
37
|
+
// 叶子节点
|
|
38
|
+
result.push({
|
|
39
|
+
path: currentPath,
|
|
40
|
+
pathLabel: currentPath.map(o => o.label).join(' '),
|
|
41
|
+
});
|
|
42
|
+
} else {
|
|
43
|
+
// 非叶子节点,继续递归
|
|
44
|
+
result.push(...flattenOptions(option.children, currentPath));
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return result;
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* 根据值路径从选项树中找到对应节点路径
|
|
52
|
+
*/
|
|
53
|
+
const findPathByValues = (
|
|
54
|
+
options: CascaderOption[],
|
|
55
|
+
values: (string | number)[],
|
|
56
|
+
): CascaderOption[] | null => {
|
|
57
|
+
if (!values.length) return null;
|
|
58
|
+
const [head, ...rest] = values;
|
|
59
|
+
const found = options.find(o => o.value === head);
|
|
60
|
+
if (!found) return null;
|
|
61
|
+
if (!rest.length) return [found];
|
|
62
|
+
if (!found.children?.length) return null;
|
|
63
|
+
const subPath = findPathByValues(found.children, rest);
|
|
64
|
+
return subPath ? [found, ...subPath] : null;
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
export function useCascader(props: CascaderProps, ctx: any) {
|
|
68
|
+
const optionsRef = toRef(() => props.options ?? []);
|
|
69
|
+
const modelValueRef = toRef(() => props.modelValue ?? []);
|
|
70
|
+
const multipleRef = toRef(() => props.multiple ?? false);
|
|
71
|
+
|
|
72
|
+
// --- 状态 ---
|
|
73
|
+
/** 下拉面板是否展开 */
|
|
74
|
+
const isOpen = ref(false);
|
|
75
|
+
/** 搜索关键词 */
|
|
76
|
+
const searchQuery = ref('');
|
|
77
|
+
/** 当前各列激活的选项(hover/click 展开下一列用) */
|
|
78
|
+
const activePath = ref<CascaderOption[]>([]);
|
|
79
|
+
|
|
80
|
+
// --- 计算属性 ---
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* 各列可见的选项列表
|
|
84
|
+
* 第 0 列 = 根选项,第 N 列 = activePath[N-1].children
|
|
85
|
+
*/
|
|
86
|
+
const columns = computed<CascaderOption[][]>(() => {
|
|
87
|
+
const cols: CascaderOption[][] = [optionsRef.value];
|
|
88
|
+
for (const node of activePath.value) {
|
|
89
|
+
if (node.children?.length) {
|
|
90
|
+
cols.push(node.children);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return cols;
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
/** 扁平化叶子路径(filterable 模式下使用) */
|
|
97
|
+
const flatOptions = computed<FlatCascaderOption[]>(() => {
|
|
98
|
+
if (!props.filterable) return [];
|
|
99
|
+
return flattenOptions(optionsRef.value);
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
/** 过滤后的扁平选项(搜索模式下显示) */
|
|
103
|
+
const filteredOptions = computed<FlatCascaderOption[]>(() => {
|
|
104
|
+
if (!searchQuery.value) return flatOptions.value;
|
|
105
|
+
const q = searchQuery.value.toLowerCase();
|
|
106
|
+
return flatOptions.value.filter(item =>
|
|
107
|
+
item.pathLabel.toLowerCase().includes(q),
|
|
108
|
+
);
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
/** 是否处于搜索模式 */
|
|
112
|
+
const isSearching = computed(() => props.filterable && searchQuery.value.length > 0);
|
|
113
|
+
|
|
114
|
+
/** 单选:当前已选路径的节点列表 */
|
|
115
|
+
const selectedPath = computed<CascaderOption[]>(() => {
|
|
116
|
+
if (multipleRef.value) return [];
|
|
117
|
+
const mv = modelValueRef.value as (string | number)[];
|
|
118
|
+
if (!mv.length) return [];
|
|
119
|
+
return findPathByValues(optionsRef.value, mv) ?? [];
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
/** 多选:当前已选的路径列表 */
|
|
123
|
+
const selectedPaths = computed<CascaderOption[][]>(() => {
|
|
124
|
+
if (!multipleRef.value) return [];
|
|
125
|
+
const mv = modelValueRef.value as (string | number)[][];
|
|
126
|
+
return mv
|
|
127
|
+
.map(vals => findPathByValues(optionsRef.value, vals))
|
|
128
|
+
.filter((p): p is CascaderOption[] => p !== null);
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
/** 触发器展示文字 */
|
|
132
|
+
const displayLabel = computed<string>(() => {
|
|
133
|
+
if (multipleRef.value) return '';
|
|
134
|
+
if (!selectedPath.value.length) return '';
|
|
135
|
+
if (props.showAllLevels) {
|
|
136
|
+
return selectedPath.value.map(o => o.label).join(` ${props.separator ?? '/'} `);
|
|
137
|
+
}
|
|
138
|
+
return selectedPath.value[selectedPath.value.length - 1]?.label ?? '';
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
/** 多选标签列表 */
|
|
142
|
+
const selectedTags = computed<string[]>(() => {
|
|
143
|
+
if (!multipleRef.value) return [];
|
|
144
|
+
return selectedPaths.value.map(path => {
|
|
145
|
+
if (props.showAllLevels) {
|
|
146
|
+
return path.map(o => o.label).join(` ${props.separator ?? '/'} `);
|
|
147
|
+
}
|
|
148
|
+
return path[path.length - 1]?.label ?? '';
|
|
149
|
+
});
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
// --- 事件处理 ---
|
|
153
|
+
|
|
154
|
+
/** 打开面板时,用已选路径初始化 activePath */
|
|
155
|
+
const initActivePath = () => {
|
|
156
|
+
if (multipleRef.value || !selectedPath.value.length) {
|
|
157
|
+
activePath.value = [];
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
// 已选路径去掉最后一个叶子节点(只保留展开路径)
|
|
161
|
+
activePath.value = selectedPath.value.slice(0, -1);
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
/** 打开下拉面板 */
|
|
165
|
+
const open = () => {
|
|
166
|
+
if (props.disabled) return;
|
|
167
|
+
initActivePath();
|
|
168
|
+
isOpen.value = true;
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
/** 关闭下拉面板 */
|
|
172
|
+
const close = () => {
|
|
173
|
+
isOpen.value = false;
|
|
174
|
+
searchQuery.value = '';
|
|
175
|
+
};
|
|
176
|
+
|
|
177
|
+
/** 点击触发器 */
|
|
178
|
+
const onTriggerClick = () => {
|
|
179
|
+
if (isOpen.value) {
|
|
180
|
+
close();
|
|
181
|
+
} else {
|
|
182
|
+
open();
|
|
183
|
+
}
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* 悬停/点击某列的某个选项,展开下一列
|
|
188
|
+
* @param option 被激活的选项
|
|
189
|
+
* @param colIndex 所在列的索引
|
|
190
|
+
*/
|
|
191
|
+
const onOptionEnter = (option: CascaderOption, colIndex: number) => {
|
|
192
|
+
if (option.disabled) return;
|
|
193
|
+
// 截断 activePath 到当前列
|
|
194
|
+
activePath.value = [...activePath.value.slice(0, colIndex), option];
|
|
195
|
+
};
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* 点击选项(单选叶子节点 → 选中并关闭;多选叶子节点 → 切换选中)
|
|
199
|
+
*/
|
|
200
|
+
const onOptionClick = (option: CascaderOption, colIndex: number) => {
|
|
201
|
+
if (option.disabled) return;
|
|
202
|
+
|
|
203
|
+
// 先更新展开路径
|
|
204
|
+
onOptionEnter(option, colIndex);
|
|
205
|
+
|
|
206
|
+
const isLeaf = !option.children?.length || option.leaf;
|
|
207
|
+
if (!isLeaf) return; // 非叶子节点只展开,不选中
|
|
208
|
+
|
|
209
|
+
// 构造完整的值路径
|
|
210
|
+
const fullPath = [...activePath.value.slice(0, colIndex), option];
|
|
211
|
+
const valuePath = fullPath.map(o => o.value);
|
|
212
|
+
|
|
213
|
+
if (multipleRef.value) {
|
|
214
|
+
// 多选:切换
|
|
215
|
+
const currentMv = (modelValueRef.value as (string | number)[][]) ?? [];
|
|
216
|
+
const existIndex = currentMv.findIndex(
|
|
217
|
+
p => p.length === valuePath.length && p.every((v, i) => v === valuePath[i]),
|
|
218
|
+
);
|
|
219
|
+
let newMv: (string | number)[][];
|
|
220
|
+
if (existIndex >= 0) {
|
|
221
|
+
newMv = currentMv.filter((_, i) => i !== existIndex);
|
|
222
|
+
} else {
|
|
223
|
+
newMv = [...currentMv, valuePath];
|
|
224
|
+
}
|
|
225
|
+
ctx.emit('update:modelValue', newMv);
|
|
226
|
+
ctx.emit('change', newMv);
|
|
227
|
+
} else {
|
|
228
|
+
// 单选:选中并关闭
|
|
229
|
+
ctx.emit('update:modelValue', valuePath);
|
|
230
|
+
ctx.emit('change', valuePath);
|
|
231
|
+
close();
|
|
232
|
+
}
|
|
233
|
+
};
|
|
234
|
+
|
|
235
|
+
/** 搜索模式下点击扁平选项 */
|
|
236
|
+
const onFlatOptionClick = (item: FlatCascaderOption) => {
|
|
237
|
+
const valuePath = item.path.map(o => o.value);
|
|
238
|
+
|
|
239
|
+
if (multipleRef.value) {
|
|
240
|
+
const currentMv = (modelValueRef.value as (string | number)[][]) ?? [];
|
|
241
|
+
const existIndex = currentMv.findIndex(
|
|
242
|
+
p => p.length === valuePath.length && p.every((v, i) => v === valuePath[i]),
|
|
243
|
+
);
|
|
244
|
+
let newMv: (string | number)[][];
|
|
245
|
+
if (existIndex >= 0) {
|
|
246
|
+
newMv = currentMv.filter((_, i) => i !== existIndex);
|
|
247
|
+
} else {
|
|
248
|
+
newMv = [...currentMv, valuePath];
|
|
249
|
+
}
|
|
250
|
+
ctx.emit('update:modelValue', newMv);
|
|
251
|
+
ctx.emit('change', newMv);
|
|
252
|
+
} else {
|
|
253
|
+
ctx.emit('update:modelValue', valuePath);
|
|
254
|
+
ctx.emit('change', valuePath);
|
|
255
|
+
close();
|
|
256
|
+
}
|
|
257
|
+
};
|
|
258
|
+
|
|
259
|
+
/** 删除多选标签 */
|
|
260
|
+
const onDeleteTag = (tagIndex: number) => {
|
|
261
|
+
const currentMv = (modelValueRef.value as (string | number)[][]) ?? [];
|
|
262
|
+
const newMv = currentMv.filter((_, i) => i !== tagIndex);
|
|
263
|
+
ctx.emit('update:modelValue', newMv);
|
|
264
|
+
ctx.emit('change', newMv);
|
|
265
|
+
};
|
|
266
|
+
|
|
267
|
+
/** 清空选中值 */
|
|
268
|
+
const onClear = (e: MouseEvent) => {
|
|
269
|
+
e.stopPropagation();
|
|
270
|
+
const emptyValue = multipleRef.value ? [] : [];
|
|
271
|
+
ctx.emit('update:modelValue', emptyValue);
|
|
272
|
+
ctx.emit('change', emptyValue);
|
|
273
|
+
close();
|
|
274
|
+
};
|
|
275
|
+
|
|
276
|
+
/** 判断某个选项是否在当前激活路径中 */
|
|
277
|
+
const isActiveOption = (option: CascaderOption, colIndex: number) => {
|
|
278
|
+
return activePath.value[colIndex]?.value === option.value;
|
|
279
|
+
};
|
|
280
|
+
|
|
281
|
+
/** 判断某个选项是否为已选路径的一部分(高亮) */
|
|
282
|
+
const isSelectedOption = (option: CascaderOption, colIndex: number) => {
|
|
283
|
+
if (multipleRef.value) {
|
|
284
|
+
return selectedPaths.value.some(path => path[colIndex]?.value === option.value);
|
|
285
|
+
}
|
|
286
|
+
return selectedPath.value[colIndex]?.value === option.value;
|
|
287
|
+
};
|
|
288
|
+
|
|
289
|
+
/** 判断扁平选项是否被选中(多选) */
|
|
290
|
+
const isFlatOptionSelected = (item: FlatCascaderOption) => {
|
|
291
|
+
const valuePath = item.path.map(o => o.value);
|
|
292
|
+
if (multipleRef.value) {
|
|
293
|
+
const currentMv = (modelValueRef.value as (string | number)[][]) ?? [];
|
|
294
|
+
return currentMv.some(
|
|
295
|
+
p => p.length === valuePath.length && p.every((v, i) => v === valuePath[i]),
|
|
296
|
+
);
|
|
297
|
+
}
|
|
298
|
+
const mv = modelValueRef.value as (string | number)[];
|
|
299
|
+
return mv.length === valuePath.length && valuePath.every((v, i) => v === mv[i]);
|
|
300
|
+
};
|
|
301
|
+
|
|
302
|
+
// options 变化时触发 expandChange
|
|
303
|
+
watch(activePath, (newPath) => {
|
|
304
|
+
ctx.emit('expandChange', newPath.map(o => o.value));
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
return {
|
|
308
|
+
// 状态
|
|
309
|
+
isOpen,
|
|
310
|
+
searchQuery,
|
|
311
|
+
activePath,
|
|
312
|
+
// 计算
|
|
313
|
+
columns,
|
|
314
|
+
filteredOptions,
|
|
315
|
+
isSearching,
|
|
316
|
+
selectedPath,
|
|
317
|
+
selectedPaths,
|
|
318
|
+
displayLabel,
|
|
319
|
+
selectedTags,
|
|
320
|
+
// 事件
|
|
321
|
+
open,
|
|
322
|
+
close,
|
|
323
|
+
onTriggerClick,
|
|
324
|
+
onOptionEnter,
|
|
325
|
+
onOptionClick,
|
|
326
|
+
onFlatOptionClick,
|
|
327
|
+
onDeleteTag,
|
|
328
|
+
onClear,
|
|
329
|
+
// 工具
|
|
330
|
+
isActiveOption,
|
|
331
|
+
isSelectedOption,
|
|
332
|
+
isFlatOptionSelected,
|
|
333
|
+
};
|
|
334
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @description checkbox api
|
|
3
|
+
* @author 阿怪
|
|
4
|
+
* @date 2023/4/20 21:55
|
|
5
|
+
* @version v1.0.0
|
|
6
|
+
*
|
|
7
|
+
* 江湖的业务千篇一律,复杂的代码好几百行。
|
|
8
|
+
*/
|
|
9
|
+
import { MCOPO, MPropType } from '../../types/props';
|
|
10
|
+
import { CheckboxGroupProps, CheckboxProps } from './props';
|
|
11
|
+
|
|
12
|
+
export const props: MCOPO<CheckboxProps> = {
|
|
13
|
+
label: { type: String, default: '' },
|
|
14
|
+
checked: { type: Boolean, default: undefined },
|
|
15
|
+
value: { type: null, default: undefined },
|
|
16
|
+
modelValue: { type: null, default: undefined },
|
|
17
|
+
indeterminate: { type: Boolean, default: false },
|
|
18
|
+
disabled: { type: Boolean, default: false },
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export const checkboxGroupProps: MCOPO<CheckboxGroupProps> = {
|
|
22
|
+
value: { type: Array, default: () => [] },
|
|
23
|
+
type: { type: String as MPropType<'single' | 'multiple'>, default: 'single' },
|
|
24
|
+
};
|
|
File without changes
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @description
|
|
3
|
+
* @author 阿怪
|
|
4
|
+
* @date 2024/12/24 10:59
|
|
5
|
+
* @version v1.0.0
|
|
6
|
+
*
|
|
7
|
+
* 江湖的业务千篇一律,复杂的代码好几百行。
|
|
8
|
+
*/
|
|
9
|
+
import { props } from './api';
|
|
10
|
+
import { useCheckbox } from './useCheckbox';
|
|
11
|
+
|
|
12
|
+
export const CheckboxCore = {
|
|
13
|
+
props,
|
|
14
|
+
useCheckbox,
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export type { CheckboxProps } from './props';
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @description checkbox api type
|
|
3
|
+
* @author youus
|
|
4
|
+
* @date 2022/4/7 00:02
|
|
5
|
+
* @version v1.0.0
|
|
6
|
+
*
|
|
7
|
+
* @name m-checkbox
|
|
8
|
+
* @docDescription Checkbox component with shuimo-ui style.
|
|
9
|
+
* 水墨组件的复选框组件。
|
|
10
|
+
* @docUrl https://shuimo.design/checkbox
|
|
11
|
+
*
|
|
12
|
+
* Hello, humor
|
|
13
|
+
*/
|
|
14
|
+
import { HTMLElementEvent } from '../../../types/common/common';
|
|
15
|
+
|
|
16
|
+
export declare type CheckboxProps = {
|
|
17
|
+
/**
|
|
18
|
+
* @description checkbox label text, will replace slot
|
|
19
|
+
* 文本 会覆盖slot
|
|
20
|
+
* @type string
|
|
21
|
+
* @default ''
|
|
22
|
+
*/
|
|
23
|
+
label?: string,
|
|
24
|
+
/**
|
|
25
|
+
* @description checkbox checked
|
|
26
|
+
* 是否选中
|
|
27
|
+
* @default undefined
|
|
28
|
+
*/
|
|
29
|
+
checked?: boolean | undefined | null,
|
|
30
|
+
/**
|
|
31
|
+
* @description checkbox value
|
|
32
|
+
* @default undefined
|
|
33
|
+
*/
|
|
34
|
+
value?: any,
|
|
35
|
+
/**
|
|
36
|
+
* @description value
|
|
37
|
+
* 绑定值
|
|
38
|
+
* @type any
|
|
39
|
+
* @default ''
|
|
40
|
+
*/
|
|
41
|
+
modelValue?: any,
|
|
42
|
+
/**
|
|
43
|
+
* @description checkbox indeterminate
|
|
44
|
+
* 是否为不确定状态
|
|
45
|
+
* @default undefined
|
|
46
|
+
*/
|
|
47
|
+
indeterminate?: boolean,
|
|
48
|
+
/**
|
|
49
|
+
* @description checkbox disabled
|
|
50
|
+
* 是否禁用 todo 暂未支持
|
|
51
|
+
* @type boolean
|
|
52
|
+
* @default false
|
|
53
|
+
*/
|
|
54
|
+
disabled?: boolean
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
export declare type CheckboxEvents = {
|
|
59
|
+
onChange?: (e: HTMLElementEvent<HTMLInputElement>) => void,
|
|
60
|
+
onInput?: (value: any) => void
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
export declare type CheckboxGroupProps = {
|
|
64
|
+
/**
|
|
65
|
+
* @description checkbox value group
|
|
66
|
+
* @type array
|
|
67
|
+
* @default []
|
|
68
|
+
*/
|
|
69
|
+
value?: any[],
|
|
70
|
+
/**
|
|
71
|
+
* @description type
|
|
72
|
+
* @type string
|
|
73
|
+
* @default single
|
|
74
|
+
* @enum 'single' | 'multiple'
|
|
75
|
+
*/
|
|
76
|
+
type?: 'single' | 'multiple'
|
|
77
|
+
};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @description
|
|
3
|
+
* @author 阿怪
|
|
4
|
+
* @date 2024/12/24 10:58
|
|
5
|
+
* @version v1.0.0
|
|
6
|
+
*
|
|
7
|
+
* 江湖的业务千篇一律,复杂的代码好几百行。
|
|
8
|
+
*/
|
|
9
|
+
import { ref, watch } from 'vue';
|
|
10
|
+
import { getNewModelValue, initChecked } from '../../../compositions/input/useBooleanInput.ts';
|
|
11
|
+
import { CheckboxProps } from './props';
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
export function useCheckbox<
|
|
15
|
+
Props extends Required<CheckboxProps>,
|
|
16
|
+
>(props: Props, ctx: any) {
|
|
17
|
+
const checkboxClass = ['m-checkbox', { 'm-disabled': props.disabled, 'm-indeterminate': props.indeterminate }];
|
|
18
|
+
|
|
19
|
+
const checked = ref(initChecked(props));
|
|
20
|
+
|
|
21
|
+
watch(() => props.modelValue, () => {
|
|
22
|
+
checked.value = initChecked(props);
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
const onClick = (e: MouseEvent) => {
|
|
26
|
+
e.stopPropagation();
|
|
27
|
+
if (props.disabled) {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
checked.value = !checked.value;
|
|
31
|
+
const newVal = getNewModelValue(props, checked.value);
|
|
32
|
+
ctx.emit('change', newVal);
|
|
33
|
+
ctx.emit('update:modelValue', newVal);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return {
|
|
37
|
+
checkboxClass,
|
|
38
|
+
checked,
|
|
39
|
+
indeterminate: props.indeterminate,
|
|
40
|
+
onClick
|
|
41
|
+
};
|
|
42
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @description collapse 运行时 props
|
|
3
|
+
* @author 阿怪
|
|
4
|
+
* @date 2026/2/26
|
|
5
|
+
* @version v1.0.0
|
|
6
|
+
*
|
|
7
|
+
* 江湖的业务千篇一律,复杂的代码好几百行。
|
|
8
|
+
*/
|
|
9
|
+
import { MCOPO } from '../../types/props';
|
|
10
|
+
import { CollapseItemProps, CollapseProps } from './props';
|
|
11
|
+
|
|
12
|
+
export const props: MCOPO<CollapseProps> = {
|
|
13
|
+
modelValue: { type: [Array, String, Number], required: true },
|
|
14
|
+
accordion: { type: Boolean, default: false },
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export const itemProps: MCOPO<CollapseItemProps> = {
|
|
18
|
+
name: { type: [String, Number], required: true },
|
|
19
|
+
title: { type: String, default: '' },
|
|
20
|
+
disabled: { type: Boolean, default: false },
|
|
21
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @description collapse core 导出
|
|
3
|
+
* @author 阿怪
|
|
4
|
+
* @date 2026/2/26
|
|
5
|
+
* @version v1.0.0
|
|
6
|
+
*
|
|
7
|
+
* 江湖的业务千篇一律,复杂的代码好几百行。
|
|
8
|
+
*/
|
|
9
|
+
import { props, itemProps } from './api';
|
|
10
|
+
import { useCollapse } from './useCollapse';
|
|
11
|
+
|
|
12
|
+
export const CollapseCore = {
|
|
13
|
+
props,
|
|
14
|
+
itemProps,
|
|
15
|
+
useCollapse,
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export type { CollapseProps, CollapseItemProps } from './props';
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @description collapse api type
|
|
3
|
+
* @author 阿怪
|
|
4
|
+
* @date 2026/2/26
|
|
5
|
+
* @version v1.0.0
|
|
6
|
+
*
|
|
7
|
+
* 江湖的业务千篇一律,复杂的代码好几百行。
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
export declare type CollapseProps = {
|
|
11
|
+
/**
|
|
12
|
+
* @description 当前展开的面板名,手风琴模式为单值,普通模式为数组
|
|
13
|
+
* @type (string | number)[] | string | number
|
|
14
|
+
*/
|
|
15
|
+
modelValue: (string | number)[] | string | number;
|
|
16
|
+
/**
|
|
17
|
+
* @description 是否开启手风琴模式(同时只允许一个面板展开)
|
|
18
|
+
* @type boolean
|
|
19
|
+
* @default false
|
|
20
|
+
*/
|
|
21
|
+
accordion?: boolean;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export declare type CollapseItemProps = {
|
|
25
|
+
/**
|
|
26
|
+
* @description 面板唯一标识
|
|
27
|
+
* @type string | number
|
|
28
|
+
*/
|
|
29
|
+
name: string | number;
|
|
30
|
+
/**
|
|
31
|
+
* @description 面板标题
|
|
32
|
+
* @type string
|
|
33
|
+
*/
|
|
34
|
+
title?: string;
|
|
35
|
+
/**
|
|
36
|
+
* @description 是否禁用该面板
|
|
37
|
+
* @type boolean
|
|
38
|
+
* @default false
|
|
39
|
+
*/
|
|
40
|
+
disabled?: boolean;
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
export declare type CollapseEvents = {
|
|
44
|
+
onChange?: (activeNames: (string | number)[]) => void;
|
|
45
|
+
};
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @description collapse composable
|
|
3
|
+
* @author 阿怪
|
|
4
|
+
* @date 2026/2/26
|
|
5
|
+
* @version v1.0.0
|
|
6
|
+
*
|
|
7
|
+
* 江湖的业务千篇一律,复杂的代码好几百行。
|
|
8
|
+
*/
|
|
9
|
+
import { computed } from 'vue';
|
|
10
|
+
import { CollapseProps } from './props';
|
|
11
|
+
|
|
12
|
+
export function useCollapse(props: Required<CollapseProps>, ctx: any) {
|
|
13
|
+
const { emit } = ctx;
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* 将 modelValue 规范化为数组,统一内部处理
|
|
17
|
+
*/
|
|
18
|
+
const activeNames = computed<(string | number)[]>(() => {
|
|
19
|
+
const val = props.modelValue;
|
|
20
|
+
if (Array.isArray(val)) { return val; }
|
|
21
|
+
if (val === undefined || val === null || val === '') { return []; }
|
|
22
|
+
return [val];
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* 判断指定面板是否处于展开状态
|
|
27
|
+
*/
|
|
28
|
+
const isActive = (name: string | number): boolean => {
|
|
29
|
+
return activeNames.value.includes(name);
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* 切换面板展开/收起
|
|
34
|
+
* - 手风琴模式:同时只允许一个展开
|
|
35
|
+
* - 普通模式:在数组中添加/移除
|
|
36
|
+
*/
|
|
37
|
+
const toggle = (name: string | number, disabled: boolean) => {
|
|
38
|
+
if (disabled) { return; }
|
|
39
|
+
|
|
40
|
+
let next: (string | number)[];
|
|
41
|
+
|
|
42
|
+
if (props.accordion) {
|
|
43
|
+
// 手风琴:已展开则收起,否则切换为仅展开当前
|
|
44
|
+
next = isActive(name) ? [] : [name];
|
|
45
|
+
} else {
|
|
46
|
+
if (isActive(name)) {
|
|
47
|
+
next = activeNames.value.filter(n => n !== name);
|
|
48
|
+
} else {
|
|
49
|
+
next = [...activeNames.value, name];
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// 向父组件同步值
|
|
54
|
+
emit('update:modelValue', props.accordion ? (next[0] ?? '') : next);
|
|
55
|
+
emit('change', next);
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
// ---- class 计算 ----
|
|
59
|
+
|
|
60
|
+
const collapseClass = computed(() => ['m-collapse']);
|
|
61
|
+
|
|
62
|
+
const getItemClass = (name: string | number, disabled: boolean) => [
|
|
63
|
+
'm-collapse-item',
|
|
64
|
+
{ 'm-collapse-item-active': isActive(name) },
|
|
65
|
+
{ 'm-collapse-item-disabled': disabled },
|
|
66
|
+
];
|
|
67
|
+
|
|
68
|
+
const headerClass = ['m-collapse-header'];
|
|
69
|
+
const contentClass = ['m-collapse-content'];
|
|
70
|
+
|
|
71
|
+
return {
|
|
72
|
+
activeNames,
|
|
73
|
+
isActive,
|
|
74
|
+
toggle,
|
|
75
|
+
collapseClass,
|
|
76
|
+
getItemClass,
|
|
77
|
+
headerClass,
|
|
78
|
+
contentClass,
|
|
79
|
+
};
|
|
80
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @description datePicker api
|
|
3
|
+
* @author 阿怪
|
|
4
|
+
* @date 2026/2/25
|
|
5
|
+
* @version v1.0.0
|
|
6
|
+
*
|
|
7
|
+
* 江湖的业务千篇一律,复杂的代码好几百行。
|
|
8
|
+
*/
|
|
9
|
+
import { MCOPO, MPropType } from '../../types/props';
|
|
10
|
+
import { DatePickerProps } from './props';
|
|
11
|
+
|
|
12
|
+
export const props: MCOPO<DatePickerProps> = {
|
|
13
|
+
modelValue: { type: [String, Date], default: '' },
|
|
14
|
+
placeholder: { type: String, default: '请选择日期...' },
|
|
15
|
+
format: { type: String, default: undefined },
|
|
16
|
+
type: { type: String as MPropType<'date' | 'month' | 'datetime'>, default: 'date' },
|
|
17
|
+
disabled: { type: Boolean, default: false },
|
|
18
|
+
};
|