plain-design 1.0.0-beta.102 → 1.0.0-beta.104
Sign up to get free protection for your applications and to get access to all the features.
- package/dist/plain-design.commonjs.min.js +2 -2
- package/dist/plain-design.min.css +1 -1
- package/dist/plain-design.min.js +2 -2
- package/dist/report.html +2 -2
- package/package.json +1 -1
- package/src/packages/components/$upload/upload.utils.ts +6 -5
- package/src/packages/components/Cascade/CascadeKeys.tsx +158 -0
- package/src/packages/components/CascadeKeys/index.tsx +5 -0
- package/src/packages/components/Image/index.tsx +1 -0
- package/src/packages/components/ImageUploader/index.tsx +23 -7
- package/src/packages/components/InputNumber/number.scss +1 -0
- package/src/packages/components/TreeCore/createTreeNode.tsx +4 -4
- package/src/packages/entry.tsx +1 -0
- package/src/packages/utils/inheritSlots.ts +2 -0
package/package.json
CHANGED
@@ -2,11 +2,12 @@ import {iHttp} from "../createHttp";
|
|
2
2
|
import {PlainObject} from "plain-utils/utils/event";
|
3
3
|
|
4
4
|
export interface iUploadServiceConfig {
|
5
|
-
http: iHttp,
|
6
|
-
action: string,
|
7
|
-
filename: string,
|
8
|
-
|
9
|
-
|
5
|
+
http: iHttp, // 上传的http请求服务对象
|
6
|
+
action: string, // 默认上传路径
|
7
|
+
filename: string, // 上传文件名
|
8
|
+
getFilePathFromResponse: (resp: any) => string, // 从返回值中获取上传返回的图片路径
|
9
|
+
prefix?: string, // 默认图片路径前缀
|
10
|
+
process?: (uploadData: iUploadData) => void | iUploadData | Promise<iUploadData | void> // 处理请求参数uploadData拦截器
|
10
11
|
}
|
11
12
|
|
12
13
|
export interface iUploadData {
|
@@ -0,0 +1,158 @@
|
|
1
|
+
import {computed, designComponent, PropType, reactive, useModel} from "plain-design-composition";
|
2
|
+
import {CascadeEmitOptions, CascadePropsOptions} from "./cascade.utils";
|
3
|
+
import {TreeScopeSlotsOption} from "../TreeCore/TreeCore.type";
|
4
|
+
import Cascade from "./index";
|
5
|
+
import {omit} from "plain-utils/object/omit";
|
6
|
+
import {inheritSlots} from "../../utils/inheritSlots";
|
7
|
+
import {PlainObject} from "plain-utils/utils/event";
|
8
|
+
|
9
|
+
/**
|
10
|
+
* 用来编辑key可能冲突的级联数据,仅支持单选不支持多选
|
11
|
+
* @author 韦胜健
|
12
|
+
* @date 2024.8.7 18:43
|
13
|
+
*/
|
14
|
+
export const CascadeKeys = designComponent({
|
15
|
+
name: 'conflict-cascade',
|
16
|
+
inheritPropsType: Cascade,
|
17
|
+
props: {
|
18
|
+
/*key有冲突的情况下,不支持多选,多选必须保证key为唯一标识不能有冲突,并且singleValueType必须是all*/
|
19
|
+
...omit(CascadePropsOptions, ['keyField', 'multiple', 'singleValueType', "modelValue"]),
|
20
|
+
/*绑定值一定是数组,可能是nodeData对象数组,也可能是key字符串数组*/
|
21
|
+
modelValue: { type: Array as PropType<(string | PlainObject)[]> },
|
22
|
+
/*keyField一定要存在*/
|
23
|
+
keyField: { type: [String, Function] as PropType<string | ((nodeData: any) => string)>, required: true },
|
24
|
+
/*值类型设置,为true则表明绑定值modelValue为字符串数组,否则为object对象数组*/
|
25
|
+
useKeysValue: { type: Boolean },
|
26
|
+
},
|
27
|
+
emits: CascadeEmitOptions,
|
28
|
+
scopeSlots: {
|
29
|
+
...TreeScopeSlotsOption,
|
30
|
+
},
|
31
|
+
setup({ props, scopeSlots, event: { emit } }) {
|
32
|
+
|
33
|
+
const dataModel = useModel(() => props.data, emit.onUpdateData);
|
34
|
+
|
35
|
+
const model = useModel(() => props.modelValue, emit.onUpdateModelValue);
|
36
|
+
|
37
|
+
const utils = reactive({
|
38
|
+
getDataLabel: computed((): iUseCascadeDataPropsLabelFunction => {
|
39
|
+
const { labelField } = props;
|
40
|
+
return typeof labelField === "function" ? labelField : ((nodeData) => (nodeData as any)[labelField]);
|
41
|
+
}),
|
42
|
+
getDataKey: computed((): iUseCascadeDataPropsValFunction => {
|
43
|
+
const { keyField } = props;
|
44
|
+
return typeof keyField === "function" ? keyField : ((nodeData) => (nodeData as any)[keyField]);
|
45
|
+
}),
|
46
|
+
getDataChildren: computed((): iUseCascadeDataPropsChildrenFunction => {
|
47
|
+
const { childrenField } = props;
|
48
|
+
return typeof childrenField === "function" ? childrenField : ((nodeData) => (nodeData as any)[childrenField]);
|
49
|
+
}),
|
50
|
+
formatData2CascadeData: (nodeData: any, getParent: iCascadeWrapData['getParent'] = (() => undefined)): iCascadeWrapData => {
|
51
|
+
const label = utils.getDataLabel(nodeData);
|
52
|
+
const key = utils.getDataKey(nodeData);
|
53
|
+
const children = utils.getDataChildren(nodeData);
|
54
|
+
const keys: string[] = [...getParent()?.keys || [], key];
|
55
|
+
const ret: iCascadeWrapData = { label, key, nodeData, getParent, keys, keyString: keys.join('.') };
|
56
|
+
if (!!children) {
|
57
|
+
const formatChildren = children.map(child => utils.formatData2CascadeData(child, () => ret));
|
58
|
+
ret.children = formatChildren;
|
59
|
+
}
|
60
|
+
return ret;
|
61
|
+
},
|
62
|
+
});
|
63
|
+
|
64
|
+
const cascadeData = computed((): iCascadeWrapData[] | undefined => props.data?.map(item => utils.formatData2CascadeData(item)));
|
65
|
+
|
66
|
+
const cascadeModelValue = computed((): iCascadeWrapData[] | undefined => {
|
67
|
+
if (!model.value?.length) {return undefined;}
|
68
|
+
const modelValueList = [...model.value];
|
69
|
+
const ret: iCascadeWrapData[] = [];
|
70
|
+
|
71
|
+
let list = cascadeData.value;
|
72
|
+
let itemModelValue = modelValueList.shift();
|
73
|
+
while (itemModelValue && !!list?.length) {
|
74
|
+
const itemModelValueKey = props.useKeysValue ? itemModelValue : utils.getDataKey(itemModelValue);
|
75
|
+
const matchItem = list.find(i => i.key == itemModelValueKey);
|
76
|
+
if (!!matchItem) {
|
77
|
+
ret.push(matchItem);
|
78
|
+
list = matchItem.children || [];
|
79
|
+
itemModelValue = modelValueList.shift();
|
80
|
+
} else {
|
81
|
+
break;
|
82
|
+
}
|
83
|
+
}
|
84
|
+
|
85
|
+
return ret;
|
86
|
+
});
|
87
|
+
|
88
|
+
const handler = {
|
89
|
+
onUpdateData: (newData: iCascadeWrapData[] | undefined | null) => {
|
90
|
+
if (!newData) {dataModel.value = newData;}
|
91
|
+
dataModel.value = cascadeData.value?.map(itemData => itemData.nodeData);
|
92
|
+
},
|
93
|
+
onUpdateModelValue: (val: iCascadeWrapData[] | null | undefined) => {
|
94
|
+
model.value = props.useKeysValue ?
|
95
|
+
val?.map(i => i.key) :
|
96
|
+
val?.map(i => i.nodeData);
|
97
|
+
},
|
98
|
+
setChildrenData: (cascadeWrapData: iCascadeWrapData, childrenData: any[] | null | undefined) => {
|
99
|
+
const { childrenField, setChildrenData } = props;
|
100
|
+
if (typeof childrenField === "string") {
|
101
|
+
(cascadeWrapData.nodeData as any)[childrenField] = childrenData;
|
102
|
+
} else {
|
103
|
+
if (!!setChildrenData) {
|
104
|
+
setChildrenData(cascadeWrapData.nodeData, childrenData);
|
105
|
+
} else {
|
106
|
+
throw new Error('tree: props.setChildrenData is required when childrenField is function');
|
107
|
+
}
|
108
|
+
}
|
109
|
+
},
|
110
|
+
isCheckAble: (cascadeWrapData: iCascadeWrapData) => {return props.isCheckAble!(cascadeWrapData.nodeData);},
|
111
|
+
isLeaf: (cascadeWrapData: iCascadeWrapData) => {return props.isLeaf!(cascadeWrapData.nodeData);},
|
112
|
+
filterMethod: (cascadeWrapData: iCascadeWrapData, filterText: string) => {return props.filterMethod!(cascadeWrapData.nodeData, filterText);},
|
113
|
+
};
|
114
|
+
|
115
|
+
const cascadeAttrs = computed(() => {
|
116
|
+
const { useKeysValue, ..._props } = props;
|
117
|
+
return {
|
118
|
+
..._props,
|
119
|
+
data: cascadeData.value,
|
120
|
+
onUpdateData: handler.onUpdateData,
|
121
|
+
modelValue: cascadeModelValue.value,
|
122
|
+
onUpdateModelValue: handler.onUpdateModelValue,
|
123
|
+
|
124
|
+
setChildrenData: !props.setChildrenData ? undefined : handler.setChildrenData,
|
125
|
+
isCheckAble: !props.isCheckAble ? undefined : handler.isCheckAble,
|
126
|
+
isLeaf: !props.isLeaf ? undefined : handler.isLeaf,
|
127
|
+
filterMethod: !props.filterMethod ? undefined : handler.filterMethod,
|
128
|
+
|
129
|
+
labelField: "label",
|
130
|
+
keyField: "keyString",
|
131
|
+
childrenField: "children",
|
132
|
+
singleValueType: "all" as const,
|
133
|
+
};
|
134
|
+
});
|
135
|
+
|
136
|
+
return () => (
|
137
|
+
<Cascade{...cascadeAttrs.value} v-slots={inheritSlots({ scopeSlots })}/>
|
138
|
+
);
|
139
|
+
},
|
140
|
+
});
|
141
|
+
|
142
|
+
|
143
|
+
interface iCascadeWrapData {
|
144
|
+
label: string,
|
145
|
+
key: string,
|
146
|
+
children?: iCascadeWrapData[],
|
147
|
+
|
148
|
+
keys: string[],
|
149
|
+
keyString: string,
|
150
|
+
nodeData: any,
|
151
|
+
getParent: () => iCascadeWrapData | undefined,
|
152
|
+
}
|
153
|
+
|
154
|
+
interface iUseCascadeDataPropsLabelFunction {(nodeData: any): string;}
|
155
|
+
|
156
|
+
interface iUseCascadeDataPropsValFunction {(nodeData: any): string;}
|
157
|
+
|
158
|
+
interface iUseCascadeDataPropsChildrenFunction {(nodeData: any): any[] | undefined | null;}
|
@@ -12,6 +12,7 @@ import {$file, FileServiceDefaultAccept, FileServiceUploadConfig} from "../$file
|
|
12
12
|
import $configuration from "../$configuration";
|
13
13
|
import {iUploadService} from "../$upload/createUploadService";
|
14
14
|
import i18n from "../i18n";
|
15
|
+
import {iUploadServiceConfig} from "../$upload/upload.utils";
|
15
16
|
|
16
17
|
/**
|
17
18
|
* ImageUploader的状态
|
@@ -40,17 +41,21 @@ export const ImageUploader = designComponent({
|
|
40
41
|
handleDelete: { type: Function as PropType<() => void | Promise<void>> }, // 自定义删除图片逻辑
|
41
42
|
handleUpload: { type: Function as PropType<(file: File) => void | Promise<void>> }, // 自定义上传图片逻辑
|
42
43
|
handlePreview: { type: Function as PropType<(url?: string) => void> }, // 自定义预览逻辑
|
43
|
-
urlPrefix: { type: String },
|
44
|
-
service: { type: Object as PropType<iUploadService> },
|
44
|
+
urlPrefix: { type: String }, // 图片路径前缀
|
45
|
+
service: { type: Object as PropType<iUploadService> }, // 文件上传服务
|
46
|
+
emitBase64: { type: Boolean }, // 当选择文件之后,是否将 base64 值更新到绑定值
|
47
|
+
getFilePathFromResponse: { type: Function as PropType<iUploadServiceConfig['getFilePathFromResponse']> },// 从上传结果中获取图片访问地址
|
45
48
|
},
|
46
49
|
inheritPropsType: HTMLDivElement,
|
47
50
|
emits: {
|
48
51
|
onUpdateModelValue: (val?: string) => true,
|
49
52
|
onLoadSuccess: (url: string) => true,
|
50
53
|
onLoadError: (e: string | Event) => true,
|
54
|
+
onLoadComplete: () => true,
|
51
55
|
onUploadSuccess: (resp: PlainObject | string) => true,
|
52
56
|
onUploadProgress: (percent: number, e: ProgressEvent) => true,
|
53
57
|
onUploadFail: (e: any) => true,
|
58
|
+
onUploadComplete: () => true,
|
54
59
|
},
|
55
60
|
setup({ props, event: { emit } }) {
|
56
61
|
|
@@ -59,7 +64,8 @@ export const ImageUploader = designComponent({
|
|
59
64
|
const urlPrefix = computed(() => props.urlPrefix || upload?.config.prefix);
|
60
65
|
|
61
66
|
const { refs, onRef } = useRefs({ el: HTMLDivElement });
|
62
|
-
|
67
|
+
|
68
|
+
const model = useModel(() => props.modelValue, emit.onUpdateModelValue);
|
63
69
|
|
64
70
|
const { editComputed } = useEdit();
|
65
71
|
|
@@ -70,7 +76,6 @@ export const ImageUploader = designComponent({
|
|
70
76
|
});
|
71
77
|
|
72
78
|
watch(() => props.modelValue, val => {
|
73
|
-
model.value = Image.formatImagePath(val, urlPrefix.value);
|
74
79
|
state.chooseBase64 = undefined;
|
75
80
|
if (!model.value) {
|
76
81
|
return state.status = eImageUploaderStatus.empty;
|
@@ -80,12 +85,14 @@ export const ImageUploader = designComponent({
|
|
80
85
|
image.onload = () => {
|
81
86
|
state.status = eImageUploaderStatus.success;
|
82
87
|
emit.onLoadSuccess(model.value!);
|
88
|
+
emit.onLoadComplete();
|
83
89
|
};
|
84
90
|
image.onerror = (e) => {
|
85
91
|
state.status = eImageUploaderStatus.error;
|
86
92
|
emit.onLoadError(e);
|
93
|
+
emit.onLoadComplete();
|
87
94
|
};
|
88
|
-
image.src =
|
95
|
+
image.src = Image.formatImagePath(val, urlPrefix.value);
|
89
96
|
}, { immediate: true });
|
90
97
|
|
91
98
|
const classes = useClasses(() => [
|
@@ -125,10 +132,16 @@ export const ImageUploader = designComponent({
|
|
125
132
|
onSuccess: (resp) => {
|
126
133
|
if (!!config?.onSuccess) config.onSuccess(resp);
|
127
134
|
console.log('upload success, resp:', resp);
|
128
|
-
model.value = String(state.chooseBase64);
|
135
|
+
// model.value = String(state.chooseBase64);
|
136
|
+
const getFilePathFromResponse: iUploadServiceConfig['getFilePathFromResponse'] | undefined =
|
137
|
+
props.getFilePathFromResponse ||
|
138
|
+
upload?.config.getFilePathFromResponse;
|
139
|
+
|
140
|
+
model.value = getFilePathFromResponse?.(resp);
|
129
141
|
state.chooseBase64 = undefined;
|
130
142
|
state.status = eImageUploaderStatus.success;
|
131
143
|
emit.onUploadSuccess(resp);
|
144
|
+
emit.onUploadComplete();
|
132
145
|
dfd.resolve(resp);
|
133
146
|
},
|
134
147
|
onError: (e) => {
|
@@ -136,6 +149,7 @@ export const ImageUploader = designComponent({
|
|
136
149
|
console.log('upload fail, e:', e);
|
137
150
|
state.status = eImageUploaderStatus.fail;
|
138
151
|
emit.onUploadFail(e);
|
152
|
+
emit.onUploadComplete();
|
139
153
|
dfd.reject(e);
|
140
154
|
},
|
141
155
|
};
|
@@ -181,10 +195,12 @@ export const ImageUploader = designComponent({
|
|
181
195
|
};
|
182
196
|
|
183
197
|
const imageAttrs = computed(() => {
|
184
|
-
|
198
|
+
const ret = Object.keys(ImagePropsOptions).reduce((prev, key) => {
|
185
199
|
prev[key] = (props as any)[key];
|
186
200
|
return prev;
|
187
201
|
}, {} as any);
|
202
|
+
ret.urlPrefix = urlPrefix.value;
|
203
|
+
return ret;
|
188
204
|
});
|
189
205
|
|
190
206
|
return {
|
@@ -53,11 +53,11 @@ export function createTreeNode(
|
|
53
53
|
/*设置子节点数据*/
|
54
54
|
const setChildrenData = (childrenData: any[] | null | undefined) => {
|
55
55
|
const { childrenField, setChildrenData } = props;
|
56
|
-
if (
|
57
|
-
(data
|
56
|
+
if (!!setChildrenData) {
|
57
|
+
setChildrenData(data, childrenData);
|
58
58
|
} else {
|
59
|
-
if (
|
60
|
-
|
59
|
+
if (typeof childrenField === "string") {
|
60
|
+
(data as any)[childrenField] = childrenData;
|
61
61
|
} else {
|
62
62
|
throw new Error('tree: props.setChildrenData is required when childrenField is function');
|
63
63
|
}
|
package/src/packages/entry.tsx
CHANGED
@@ -66,6 +66,7 @@ export {SelectGroup} from './components/SelectGroup';
|
|
66
66
|
export {Form} from './components/Form';
|
67
67
|
export {FormItem} from './components/FormItem';
|
68
68
|
export {Cascade} from './components/Cascade';
|
69
|
+
export {CascadeKeys} from './components/CascadeKeys';
|
69
70
|
export {Image} from './components/Image';
|
70
71
|
export {Tooltip} from './components/Tooltip';
|
71
72
|
export {useImage} from './components/useImage';
|
@@ -24,5 +24,7 @@ export function inheritSlots<
|
|
24
24
|
!!slots && Object.keys(slots).forEach((k: keyof Slots) => {if (slots[k].isExist()) {ret[k] = () => slots[k]();}});
|
25
25
|
!!scopeSlots && Object.keys(scopeSlots).forEach((k: keyof ScopeSlots) => {if (scopeSlots[k].isExist()) {ret[k] = (...args: any[]) => scopeSlots[k](...args);}});
|
26
26
|
|
27
|
+
if (!Object.keys(ret).length) {return undefined;}
|
28
|
+
|
27
29
|
return ret;
|
28
30
|
}
|