@vue-start/pro 0.1.0

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,728 @@
1
+ import { defineComponent, computed, reactive, inject, h, provide } from 'vue';
2
+ import { map, isString, forEach, get, isObject, isEmpty, isArray, isFunction, mergeWith, reduce, keys, omit, filter as filter$1, sortBy, pick, split } from 'lodash';
3
+ import { filter, tap, merge, Subject } from 'rxjs';
4
+ import { useEffect, setReactiveValue } from '@vue-start/hooks';
5
+ import { useRequestProvide, isFailedRequestActor, isPreRequestActor, isDoneRequestActor } from '@vue-start/request';
6
+
7
+ const createUseRequestActor = filterFun => (actors, callback) => {
8
+ const {
9
+ requestSubject$
10
+ } = useRequestProvide();
11
+ const nameSet = new Set(map(actors, actor => isString(actor) ? actor : actor.name));
12
+ useEffect(() => {
13
+ const sub = requestSubject$.pipe(filter(filterFun), tap(actor => {
14
+ if (nameSet.has(actor.name)) {
15
+ callback(actor);
16
+ }
17
+ })).subscribe();
18
+ return () => {
19
+ sub.unsubscribe();
20
+ };
21
+ }, []);
22
+ };
23
+
24
+ const useDoneRequestActor = createUseRequestActor(isDoneRequestActor);
25
+ const useFailedRequestActor = createUseRequestActor(isFailedRequestActor);
26
+ const useComposeRequestActor = (actors, options, cancelWhileUnmount) => {
27
+ const {
28
+ requestSubject$,
29
+ dispatchRequest
30
+ } = useRequestProvide();
31
+ const nameSet = new Set(map(actors, actor => isString(actor) ? actor : actor.name));
32
+ const lastRequestActors = {};
33
+ useEffect(() => {
34
+ const sub = merge(requestSubject$.pipe(filter(isPreRequestActor), tap(actor => {
35
+ if (nameSet.has(actor.name)) {
36
+ var _options$onStart;
37
+
38
+ (_options$onStart = options.onStart) === null || _options$onStart === void 0 ? void 0 : _options$onStart.call(options, actor);
39
+ lastRequestActors[actor.name] = actor;
40
+ }
41
+ })), requestSubject$.pipe(filter(isDoneRequestActor), tap(actor => {
42
+ if (nameSet.has(actor.name)) {
43
+ var _options$onSuccess, _options$onFinish;
44
+
45
+ (_options$onSuccess = options.onSuccess) === null || _options$onSuccess === void 0 ? void 0 : _options$onSuccess.call(options, actor);
46
+ (_options$onFinish = options.onFinish) === null || _options$onFinish === void 0 ? void 0 : _options$onFinish.call(options, actor);
47
+ lastRequestActors[actor.name] = undefined;
48
+ }
49
+ })), requestSubject$.pipe(filter(isFailedRequestActor), tap(actor => {
50
+ if (nameSet.has(actor.name)) {
51
+ var _options$onFailed, _options$onFinish2;
52
+
53
+ (_options$onFailed = options.onFailed) === null || _options$onFailed === void 0 ? void 0 : _options$onFailed.call(options, actor);
54
+ (_options$onFinish2 = options.onFinish) === null || _options$onFinish2 === void 0 ? void 0 : _options$onFinish2.call(options, actor);
55
+ lastRequestActors[actor.name] = undefined;
56
+ }
57
+ }))).subscribe();
58
+ return () => {
59
+ sub.unsubscribe();
60
+
61
+ if (cancelWhileUnmount) {
62
+ //组件销毁的时候cancel请求
63
+ forEach(lastRequestActors, actor => {
64
+ actor && dispatchRequest({ ...actor,
65
+ stage: "CANCEL"
66
+ });
67
+ });
68
+ }
69
+ };
70
+ }, []);
71
+ };
72
+
73
+ /**
74
+ * 获取Column的valueType,默认"text"
75
+ * @param column
76
+ */
77
+
78
+ const getColumnValueType = column => {
79
+ return column.formValueType || column.valueType || "text";
80
+ };
81
+ /**
82
+ *获取Column的FormItem name
83
+ * @param column
84
+ */
85
+
86
+ const getColumnFormItemName = column => {
87
+ var _column$formItemProps;
88
+
89
+ return ((_column$formItemProps = column.formItemProps) === null || _column$formItemProps === void 0 ? void 0 : _column$formItemProps.name) || column.dataIndex;
90
+ };
91
+ /**
92
+ * 根据Column生成FormItem VNode
93
+ * formFieldProps中的slots参数会以v-slots的形式传递到FormItem的录入组件(子组件)中
94
+ * @param formElementMap
95
+ * @param column
96
+ * @param needRules
97
+ */
98
+
99
+ const getFormItemEl = (formElementMap, column, needRules = true) => {
100
+ var _column$formFieldProp;
101
+
102
+ const valueType = getColumnValueType(column);
103
+ const Comp = get(formElementMap, valueType);
104
+
105
+ if (!Comp) {
106
+ return null;
107
+ }
108
+
109
+ const name = getColumnFormItemName(column);
110
+ const itemProps = needRules ? column.formItemProps : omit(column.formItemProps, "rules");
111
+ return h(Comp, {
112
+ key: name,
113
+ name,
114
+ label: column.title,
115
+ ...itemProps,
116
+ fieldProps: omit(column.formFieldProps, "slots"),
117
+ showProps: column.showProps
118
+ }, (_column$formFieldProp = column.formFieldProps) === null || _column$formFieldProp === void 0 ? void 0 : _column$formFieldProp.slots);
119
+ };
120
+ /**
121
+ * 根据Column生成Item VNode
122
+ * @param elementMap
123
+ * @param column
124
+ * @param value
125
+ */
126
+
127
+ const getItemEl = (elementMap, column, value) => {
128
+ var _column$formFieldProp2;
129
+
130
+ const valueType = column.valueType || "text";
131
+ const Comp = get(elementMap, valueType);
132
+
133
+ if (!Comp) {
134
+ return null;
135
+ }
136
+
137
+ return h(Comp, { ...omit(column.formFieldProps, "slots"),
138
+ showProps: column.showProps,
139
+ value
140
+ }, (_column$formFieldProp2 = column.formFieldProps) === null || _column$formFieldProp2 === void 0 ? void 0 : _column$formFieldProp2.slots);
141
+ };
142
+ const ProModuleKey = Symbol("pro-module");
143
+ const useProModule = () => inject(ProModuleKey);
144
+ const provideProModule = ctx => {
145
+ provide(ProModuleKey, ctx);
146
+ };
147
+ const RequestAction = {
148
+ Success: "request-success$",
149
+ Fail: "request-fail$"
150
+ };
151
+
152
+ const proModuleProps = () => ({
153
+ /**
154
+ * module状态
155
+ */
156
+ state: {
157
+ type: Object
158
+ },
159
+
160
+ /**
161
+ * 配置(静态)
162
+ */
163
+ columns: {
164
+ type: Array
165
+ },
166
+
167
+ /**
168
+ * 配置(动态)
169
+ * columns动态属性兼容
170
+ */
171
+ columnState: {
172
+ type: Object
173
+ },
174
+
175
+ /**
176
+ * 展示组件集
177
+ */
178
+ elementMap: {
179
+ type: Object
180
+ },
181
+
182
+ /**
183
+ * 录入组件集
184
+ */
185
+ formElementMap: {
186
+ type: Object
187
+ },
188
+
189
+ /**
190
+ * requests
191
+ */
192
+ requests: {
193
+ type: Array
194
+ }
195
+ });
196
+
197
+ const ProModule = defineComponent({
198
+ props: { ...proModuleProps()
199
+ },
200
+ setup: (props, {
201
+ slots
202
+ }) => {
203
+ /**
204
+ * columns columnState 合并
205
+ */
206
+ const columns = computed(() => {
207
+ return map(props.columns, item => {
208
+ //如果columnState中有值,merge处理
209
+ const mapData = get(props.columnState, getColumnFormItemName(item));
210
+
211
+ if (isObject(mapData) && !isEmpty(mapData) && !isArray(mapData) && !isFunction(mapData)) {
212
+ //合并
213
+ return mergeWith(item, mapData, (objValue, srcValue) => {
214
+ //如果是数组,替换
215
+ if (isArray(objValue) || isArray(srcValue)) {
216
+ return srcValue;
217
+ }
218
+ });
219
+ }
220
+
221
+ return item;
222
+ });
223
+ });
224
+ /*********************************** 渲染组件 ***************************************/
225
+ // 获取FormItem VNode
226
+
227
+ const getFormItemVNode = (column, needRules = true) => {
228
+ return getFormItemEl(props.formElementMap, column, needRules);
229
+ }; // 获取Item VNode
230
+
231
+
232
+ const getItemVNode = (column, value) => {
233
+ return getItemEl(props.elementMap, column, value);
234
+ };
235
+ /*********************************** 事件处理 ***************************************/
236
+
237
+
238
+ const subject$ = new Subject(); //发送Module事件
239
+
240
+ const sendEvent = action => {
241
+ subject$.next(action);
242
+ };
243
+ /*********************************** 页面状态 ***************************************/
244
+
245
+
246
+ const state = props.state || reactive({});
247
+
248
+ const dispatch = action => {
249
+ //如果要更新的属性值是 object ,执行覆盖操作
250
+ if (isObject(state[action.type])) {
251
+ setReactiveValue(state[action.type], action.payload);
252
+ return;
253
+ }
254
+
255
+ state[action.type] = action.payload;
256
+ };
257
+ /*********************************** request ***************************************/
258
+
259
+
260
+ const {
261
+ dispatchRequest
262
+ } = useRequestProvide();
263
+ const requestMap = reduce(props.requests, (pair, item) => ({ ...pair,
264
+ [item.actor.name]: item
265
+ }), {});
266
+ const actionMap = reduce(props.requests, (pair, item) => ({ ...pair,
267
+ [item.action]: item
268
+ }), {}); //发送请求
269
+
270
+ const sendRequest = (requestNameOrAction, ...params) => {
271
+ const requestOpts = get(requestMap, requestNameOrAction) || get(actionMap, requestNameOrAction);
272
+
273
+ if (!requestOpts) {
274
+ return;
275
+ }
276
+
277
+ let nextParams;
278
+
279
+ if (requestOpts.convertParams) {
280
+ nextParams = requestOpts.convertParams(...params);
281
+ } else {
282
+ nextParams = get(params, 0);
283
+ }
284
+
285
+ dispatchRequest(requestOpts.actor, nextParams);
286
+ };
287
+
288
+ useComposeRequestActor(keys(requestMap), {
289
+ onStart: actor => {
290
+ //如果设置了loading,将请求状态维护到state中
291
+ const loadingName = get(requestMap, [actor.name, "loadingName"]);
292
+
293
+ if (loadingName) {
294
+ dispatch({
295
+ type: loadingName,
296
+ payload: true
297
+ });
298
+ }
299
+ },
300
+ onSuccess: actor => {
301
+ var _requestOpts$onSucces;
302
+
303
+ const requestOpts = get(requestMap, actor.name); //如果设置了stateName,将结果维护到state中
304
+
305
+ if (requestOpts !== null && requestOpts !== void 0 && requestOpts.stateName) {
306
+ var _actor$res;
307
+
308
+ const data = requestOpts.convertData ? requestOpts.convertData(actor) : (_actor$res = actor.res) === null || _actor$res === void 0 ? void 0 : _actor$res.data;
309
+ dispatch({
310
+ type: requestOpts.stateName,
311
+ payload: data
312
+ });
313
+ } //发送成功事件
314
+
315
+
316
+ sendEvent({
317
+ type: RequestAction.Success,
318
+ payload: {
319
+ actor
320
+ }
321
+ }); //回调事件
322
+
323
+ (_requestOpts$onSucces = requestOpts.onSuccess) === null || _requestOpts$onSucces === void 0 ? void 0 : _requestOpts$onSucces.call(requestOpts, actor);
324
+ },
325
+ onFailed: actor => {
326
+ var _requestOpts$onFailed;
327
+
328
+ const requestOpts = get(requestMap, actor.name); //发送失败事件
329
+
330
+ sendEvent({
331
+ type: RequestAction.Fail,
332
+ payload: {
333
+ actor
334
+ }
335
+ }); //回调事件
336
+
337
+ (_requestOpts$onFailed = requestOpts.onFailed) === null || _requestOpts$onFailed === void 0 ? void 0 : _requestOpts$onFailed.call(requestOpts, actor);
338
+ },
339
+ onFinish: actor => {
340
+ const loadingName = get(requestMap, [actor.name, "loadingName"]);
341
+
342
+ if (loadingName) {
343
+ dispatch({
344
+ type: loadingName,
345
+ payload: false
346
+ });
347
+ }
348
+ }
349
+ }, true);
350
+ provideProModule({
351
+ columns,
352
+ getFormItemVNode,
353
+ getItemVNode,
354
+ elementMap: props.elementMap,
355
+ formElementMap: props.formElementMap,
356
+ //
357
+ subject$,
358
+ sendEvent,
359
+ //
360
+ state,
361
+ dispatch,
362
+ //
363
+ requests: props.requests,
364
+ sendRequest
365
+ });
366
+ return () => {
367
+ var _slots$default;
368
+
369
+ return (_slots$default = slots.default) === null || _slots$default === void 0 ? void 0 : _slots$default.call(slots);
370
+ };
371
+ }
372
+ });
373
+
374
+ //订阅module事件
375
+ const useModuleEvent = cb => {
376
+ const {
377
+ subject$
378
+ } = useProModule();
379
+ useEffect(() => {
380
+ const sub = subject$.subscribe({
381
+ next: action => {
382
+ cb(action);
383
+ }
384
+ });
385
+ return () => {
386
+ return sub.unsubscribe();
387
+ };
388
+ }, []);
389
+ };
390
+
391
+ const ProCurdKey = Symbol("pro-curd");
392
+ const useProCurd = () => inject(ProCurdKey);
393
+ const provideProCurd = ctx => provide(ProCurdKey, ctx);
394
+ /************************************ 常量 *************************************/
395
+
396
+ /**
397
+ * curd 5种action
398
+ */
399
+
400
+ let CurdAction;
401
+
402
+ (function (CurdAction) {
403
+ CurdAction["LIST"] = "LIST";
404
+ CurdAction["DETAIL"] = "DETAIL";
405
+ CurdAction["ADD"] = "ADD";
406
+ CurdAction["EDIT"] = "EDIT";
407
+ CurdAction["DELETE"] = "DELETE";
408
+ })(CurdAction || (CurdAction = {}));
409
+
410
+ /**
411
+ * curd 操作模式
412
+ */
413
+ let CurdCurrentMode;
414
+
415
+ (function (CurdCurrentMode) {
416
+ CurdCurrentMode["ADD"] = "ADD";
417
+ CurdCurrentMode["EDIT"] = "EDIT";
418
+ CurdCurrentMode["DETAIL"] = "DETAIL";
419
+ })(CurdCurrentMode || (CurdCurrentMode = {}));
420
+
421
+ /**
422
+ * curd add 模式下 标记 "确定" "确定并继续" 触发
423
+ */
424
+ let CurdAddAction;
425
+
426
+ (function (CurdAddAction) {
427
+ CurdAddAction["NORMAL"] = "NORMAL";
428
+ CurdAddAction["CONTINUE"] = "CONTINUE";
429
+ })(CurdAddAction || (CurdAddAction = {}));
430
+
431
+ const proCurdProps = () => ({
432
+ /**
433
+ * 列表 或 详情 的唯一标识
434
+ */
435
+ rowKey: {
436
+ type: String,
437
+ default: "id"
438
+ },
439
+
440
+ /**
441
+ * operates
442
+ */
443
+ operates: {
444
+ type: Array
445
+ },
446
+
447
+ /************************* 子组件props *******************************/
448
+ listProps: {
449
+ type: Object
450
+ },
451
+ formProps: {
452
+ type: Object
453
+ },
454
+ descProps: {
455
+ type: Object
456
+ },
457
+ modalProps: {
458
+ type: Object
459
+ }
460
+ });
461
+
462
+ const Curd = defineComponent({
463
+ props: { ...proCurdProps()
464
+ },
465
+ setup: (props, {
466
+ slots
467
+ }) => {
468
+ const {
469
+ columns,
470
+ state,
471
+ sendEvent,
472
+ sendRequest
473
+ } = useProModule();
474
+ /**
475
+ * 排序
476
+ * @param list
477
+ * @param propName
478
+ */
479
+
480
+ const dealSort = (list, propName) => {
481
+ return sortBy(list, item => get(item, propName));
482
+ };
483
+ /**
484
+ * 非 hideInForm columns
485
+ */
486
+
487
+
488
+ const formColumns = computed(() => {
489
+ return dealSort(filter$1(columns.value, item => !item.hideInForm), "formSort");
490
+ });
491
+ /**
492
+ * 非 hideInDetail columns
493
+ */
494
+
495
+ const descColumns = computed(() => {
496
+ return dealSort(filter$1(columns.value, item => !item.hideInDetail), "descSort");
497
+ });
498
+ /**
499
+ * 非 hideInTable columns
500
+ */
501
+
502
+ const tableColumns = computed(() => {
503
+ return dealSort(filter$1(columns.value, item => !item.hideInTable), "tableSort");
504
+ });
505
+ /**
506
+ * search columns
507
+ */
508
+
509
+ const searchColumns = computed(() => {
510
+ return dealSort(filter$1(columns.value, item => !!item.search), "searchSort");
511
+ });
512
+ /******************************** 逻辑 *************************************/
513
+ //上一次发起列表请求的参数
514
+
515
+ let prevListParams; //刷新列表
516
+
517
+ const handleSearch = extra => {
518
+ sendRequest(CurdAction.LIST, { ...prevListParams,
519
+ ...extra
520
+ });
521
+ }; //发送事件
522
+
523
+
524
+ const sendCurdEvent = event => {
525
+ sendEvent({
526
+ type: event.action,
527
+ payload: omit(event, "action")
528
+ });
529
+ }; //事件订阅
530
+
531
+
532
+ useModuleEvent(event => {
533
+ if (event.type === RequestAction.Success) {
534
+ return;
535
+ } else if (event.type === RequestAction.Fail) {
536
+ return;
537
+ }
538
+
539
+ const action = event.type;
540
+ const {
541
+ type,
542
+ values,
543
+ record
544
+ } = event.payload;
545
+
546
+ switch (action) {
547
+ case CurdAction.LIST:
548
+ if (type === "emit") {
549
+ prevListParams = values;
550
+ handleSearch();
551
+ }
552
+
553
+ return;
554
+
555
+ case CurdAction.ADD:
556
+ if (type === "execute") {
557
+ sendRequest(CurdAction.ADD, values, state.detailData);
558
+ }
559
+
560
+ return;
561
+
562
+ case CurdAction.EDIT:
563
+ if (type === "execute") {
564
+ sendRequest(CurdAction.EDIT, values, state.detailData);
565
+ }
566
+
567
+ return;
568
+
569
+ case CurdAction.DELETE:
570
+ if (type === "emit") {
571
+ sendRequest(CurdAction.DELETE, record, props.rowKey);
572
+ }
573
+
574
+ return;
575
+ }
576
+ });
577
+ const operateMap = reduce(props.operates, (pair, item) => ({ ...pair,
578
+ [item.action]: item
579
+ }), {}); //根据Action获取ICurdOperateOpts
580
+
581
+ const getOperate = action => {
582
+ return get(operateMap, action);
583
+ };
584
+
585
+ provideProCurd({
586
+ rowKey: props.rowKey,
587
+ curdState: state,
588
+ formColumns,
589
+ descColumns,
590
+ tableColumns,
591
+ searchColumns,
592
+ //
593
+ sendCurdEvent,
594
+ //
595
+ getOperate,
596
+ //
597
+ listProps: props.listProps,
598
+ formProps: props.formProps,
599
+ descProps: props.descProps,
600
+ modalProps: props.modalProps
601
+ });
602
+ return () => {
603
+ var _slots$default;
604
+
605
+ return (_slots$default = slots.default) === null || _slots$default === void 0 ? void 0 : _slots$default.call(slots);
606
+ };
607
+ }
608
+ });
609
+ const ProCurd = defineComponent({
610
+ props: { ...ProModule.props,
611
+ ...Curd.props
612
+ },
613
+ setup: (props, {
614
+ slots
615
+ }) => {
616
+ const curdState = props.curdState || reactive({
617
+ detailData: {}
618
+ });
619
+ /****************** 请求处理 **********************/
620
+ //curd默认网络属性
621
+
622
+ const curdOperateOpts = {
623
+ [CurdAction.LIST]: {
624
+ convertParams: values => values,
625
+ convertData: actor => {
626
+ var _actor$res;
627
+
628
+ return (_actor$res = actor.res) === null || _actor$res === void 0 ? void 0 : _actor$res.data;
629
+ },
630
+ loadingName: "listLoading",
631
+ stateName: "listData"
632
+ },
633
+ [CurdAction.DETAIL]: {
634
+ convertParams: (record, rowKey) => pick(record, rowKey),
635
+ convertData: actor => {
636
+ var _actor$res2;
637
+
638
+ return (_actor$res2 = actor.res) === null || _actor$res2 === void 0 ? void 0 : _actor$res2.data;
639
+ },
640
+ loadingName: "detailLoading",
641
+ stateName: "detailData",
642
+ label: "详情"
643
+ },
644
+ [CurdAction.ADD]: {
645
+ convertParams: (values, record) => ({
646
+ body: { ...record,
647
+ ...values
648
+ }
649
+ }),
650
+ loadingName: "operateLoading",
651
+ label: "添加"
652
+ },
653
+ [CurdAction.EDIT]: {
654
+ convertParams: (values, record) => ({
655
+ body: { ...record,
656
+ ...values
657
+ }
658
+ }),
659
+ loadingName: "operateLoading",
660
+ label: "编辑"
661
+ },
662
+ [CurdAction.DELETE]: {
663
+ convertParams: (values, record) => ({
664
+ body: { ...record,
665
+ ...values
666
+ }
667
+ }),
668
+ label: "删除"
669
+ }
670
+ };
671
+ const requests = map(props.operates, item => {
672
+ const curdOpts = get(curdOperateOpts, item.action);
673
+ return { ...curdOpts,
674
+ ...item
675
+ };
676
+ });
677
+ const moduleKeys = keys(ProModule.props);
678
+ return () => {
679
+ return h(ProModule, { ...pick(props, moduleKeys),
680
+ state: curdState,
681
+ requests
682
+ }, h(Curd, { ...omit(props, ...moduleKeys, "curdState")
683
+ }, slots));
684
+ };
685
+ }
686
+ });
687
+
688
+ /**
689
+ * 剔除showState或showStateRules规则为!true的值
690
+ * @param values
691
+ * @param showState
692
+ * @param showStateRules
693
+ */
694
+ const getValidValues = (values, showState, showStateRules) => {
695
+ if (showState) {
696
+ const invalidKeys = filter$1(keys(showState), key => !showState[key]);
697
+ return omit(values, invalidKeys);
698
+ }
699
+
700
+ if (showStateRules) {
701
+ const invalidKeys = filter$1(keys(showStateRules), key => !showStateRules[key](values));
702
+ return omit(values, invalidKeys);
703
+ }
704
+
705
+ return values;
706
+ };
707
+ /**
708
+ * string类型的path转为arr
709
+ * @param path
710
+ */
711
+
712
+ const convertPathToList = path => {
713
+ if (!path) {
714
+ return undefined;
715
+ }
716
+
717
+ if (isArray(path)) {
718
+ return path;
719
+ }
720
+
721
+ if (path && isString(path) && path.indexOf(".") > 0) {
722
+ return split(path, ".");
723
+ }
724
+
725
+ return [path];
726
+ };
727
+
728
+ export { CurdAction, CurdAddAction, CurdCurrentMode, ProCurd, ProModule, RequestAction, convertPathToList, getColumnFormItemName, getColumnValueType, getFormItemEl, getItemEl, getValidValues, provideProCurd, provideProModule, useComposeRequestActor, useDoneRequestActor, useFailedRequestActor, useModuleEvent, useProCurd, useProModule };