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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "plain-design",
3
- "version": "1.0.0-beta.102",
3
+ "version": "1.0.0-beta.104",
4
4
  "description": "",
5
5
  "main": "dist/plain-design.min.js",
6
6
  "module": "dist/plain-design.commonjs.min.js",
@@ -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
- prefix?: string,
9
- process?: (uploadData: iUploadData) => void | iUploadData | Promise<iUploadData | void>
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;}
@@ -0,0 +1,5 @@
1
+ import {CascadeKeys} from "../Cascade/CascadeKeys";
2
+
3
+ export {CascadeKeys};
4
+
5
+ export default CascadeKeys;
@@ -100,6 +100,7 @@ export const Image = designComponent({
100
100
  emit.onSuccess(state.src!);
101
101
  };
102
102
  image.onerror = (e) => {
103
+ console.error(`load image error: ${image.src}`, e, props.urlPrefix);
103
104
  state.status = eImageStatus.error;
104
105
  emit.onError(e);
105
106
  };
@@ -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
- const model = useModel(() => props.modelValue, emit.onUpdateModelValue, { autoWatch: false });
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 = model.value;
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
- return Object.keys(ImagePropsOptions).reduce((prev, key) => {
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 {
@@ -30,6 +30,7 @@
30
30
  &.number-button-type-right {
31
31
  .number-button-container {
32
32
  display: flex;
33
+ color: plv(text-2);
33
34
  flex-direction: column;
34
35
  align-items: stretch;
35
36
  justify-content: center;
@@ -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 (typeof childrenField === "string") {
57
- (data as any)[childrenField] = childrenData;
56
+ if (!!setChildrenData) {
57
+ setChildrenData(data, childrenData);
58
58
  } else {
59
- if (!!setChildrenData) {
60
- setChildrenData(data, childrenData);
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
  }
@@ -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
  }