yuang-framework-ui-common 1.0.114 → 1.0.115
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.
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import { ref, watch, computed } from 'vue';
|
|
2
|
+
|
|
3
|
+
interface InfoProps {
|
|
4
|
+
value: string;
|
|
5
|
+
label: string;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* 通用弹窗选择器基类 Hooks
|
|
10
|
+
* 解决:
|
|
11
|
+
* - v-model 两次赋值
|
|
12
|
+
* - 输入框缓存
|
|
13
|
+
* - 防抖刷新
|
|
14
|
+
* - 加载状态
|
|
15
|
+
* - 弹窗开关
|
|
16
|
+
*/
|
|
17
|
+
export function useBaseDialog(
|
|
18
|
+
props: any,
|
|
19
|
+
emit: any,
|
|
20
|
+
options: {
|
|
21
|
+
/** 单选获取详情接口 */
|
|
22
|
+
selectInfo: (id: string) => Promise<any>;
|
|
23
|
+
/** 批量获取列表接口 */
|
|
24
|
+
selectInfoList: (ids: string[]) => Promise<any[]>;
|
|
25
|
+
/** 配置映射字段 */
|
|
26
|
+
infoProps?: InfoProps;
|
|
27
|
+
}
|
|
28
|
+
) {
|
|
29
|
+
const { selectInfo, selectInfoList, infoProps = { value: 'id', label: 'name' } } = options;
|
|
30
|
+
|
|
31
|
+
// v-model的值
|
|
32
|
+
// const modelValue = defineModel<string>();
|
|
33
|
+
// defineModel 只能在vue文件中使用
|
|
34
|
+
// ✅ 修复:不在 hook 里用 defineModel,改为外部传入
|
|
35
|
+
const modelValue = computed({
|
|
36
|
+
get() {
|
|
37
|
+
if (typeof props.modelValue == 'undefined') {
|
|
38
|
+
throw new Error('需要在props中定义modelValue');
|
|
39
|
+
}
|
|
40
|
+
return props.modelValue;
|
|
41
|
+
},
|
|
42
|
+
set(v) {
|
|
43
|
+
emit('update:modelValue', v);
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
// 输入框的值
|
|
47
|
+
const inputValue = ref<string>('');
|
|
48
|
+
// 初始化列表
|
|
49
|
+
const initList = ref<string[]>([]);
|
|
50
|
+
// 是否显示弹出框
|
|
51
|
+
const isShowDialog = ref<boolean>(false);
|
|
52
|
+
// 是否初始化成功
|
|
53
|
+
const isInitSuccess = ref<boolean>(false);
|
|
54
|
+
|
|
55
|
+
// 是否锁定的
|
|
56
|
+
let isLocked = true;
|
|
57
|
+
|
|
58
|
+
// 使用 computed 创建一个只读的、组合了 props 的本地配置,这样更简洁,且具有响应式
|
|
59
|
+
const componentParam = computed(() => ({
|
|
60
|
+
isMultiple: true,
|
|
61
|
+
isShowInput: true,
|
|
62
|
+
isDisabled: false,
|
|
63
|
+
isReadonly: false,
|
|
64
|
+
profileId: 'dev',
|
|
65
|
+
...props.param,
|
|
66
|
+
initList: initList.value
|
|
67
|
+
}));
|
|
68
|
+
|
|
69
|
+
// ========== 初始化(防抖版) ==========
|
|
70
|
+
const init = async () => {
|
|
71
|
+
inputValue.value = '';
|
|
72
|
+
initList.value = [];
|
|
73
|
+
isInitSuccess.value = false;
|
|
74
|
+
|
|
75
|
+
if (!modelValue.value) {
|
|
76
|
+
isInitSuccess.value = true;
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
try {
|
|
81
|
+
// 单选
|
|
82
|
+
if (!componentParam.value?.isMultiple) {
|
|
83
|
+
if (modelValue.value !== '0') {
|
|
84
|
+
const infoData = await selectInfo(modelValue.value);
|
|
85
|
+
inputValue.value = infoData[infoProps.label];
|
|
86
|
+
|
|
87
|
+
initList.value = [infoData];
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
// 多选
|
|
91
|
+
else {
|
|
92
|
+
const idList = modelValue.value.split('|').filter(Boolean);
|
|
93
|
+
if (idList.length) {
|
|
94
|
+
const listData = await selectInfoList(idList);
|
|
95
|
+
inputValue.value = listData.map((item) => item[infoProps.label]).join('、');
|
|
96
|
+
initList.value = listData;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
} catch (err) {
|
|
100
|
+
console.error(err);
|
|
101
|
+
} finally {
|
|
102
|
+
isInitSuccess.value = true;
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
// 监听组件值变化(解决弹窗/重复赋值/缓存问题)
|
|
107
|
+
watch(
|
|
108
|
+
modelValue,
|
|
109
|
+
() => {
|
|
110
|
+
isLocked = true;
|
|
111
|
+
setTimeout(() => {
|
|
112
|
+
if (isLocked) {
|
|
113
|
+
init();
|
|
114
|
+
isLocked = false;
|
|
115
|
+
}
|
|
116
|
+
}, 50);
|
|
117
|
+
},
|
|
118
|
+
{ immediate: true }
|
|
119
|
+
);
|
|
120
|
+
|
|
121
|
+
// ========== 弹窗 ==========
|
|
122
|
+
const showDialog = () => {
|
|
123
|
+
isShowDialog.value = true;
|
|
124
|
+
};
|
|
125
|
+
const hideDialog = () => {
|
|
126
|
+
if (!isInitSuccess.value) {
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
isShowDialog.value = false;
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
// ========== 选择完成 ==========
|
|
133
|
+
const handleChange = (selections) => {
|
|
134
|
+
modelValue.value = '';
|
|
135
|
+
inputValue.value = '';
|
|
136
|
+
|
|
137
|
+
if (selections.length) {
|
|
138
|
+
if (!componentParam.value?.isMultiple) {
|
|
139
|
+
modelValue.value = selections[0][infoProps.value];
|
|
140
|
+
inputValue.value = selections[0][infoProps.label];
|
|
141
|
+
} else {
|
|
142
|
+
modelValue.value = '|' + selections.map((s) => s[infoProps.value]).join('|');
|
|
143
|
+
inputValue.value = selections.map((s) => s[infoProps.label]).join('、');
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
emit('change', selections);
|
|
148
|
+
hideDialog();
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
return {
|
|
152
|
+
modelValue,
|
|
153
|
+
inputValue,
|
|
154
|
+
initList,
|
|
155
|
+
isShowDialog,
|
|
156
|
+
isInitSuccess,
|
|
157
|
+
componentParam,
|
|
158
|
+
showDialog,
|
|
159
|
+
hideDialog,
|
|
160
|
+
handleChange
|
|
161
|
+
};
|
|
162
|
+
}
|