plain-design 1.0.0-beta.102 → 1.0.0-beta.104
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/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
|
}
|