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/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
  }