@lambo-design/detail-table 1.0.0-beta.1
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/index.js +8 -0
- package/package.json +18 -0
- package/src/components/Col.js +98 -0
- package/src/components/Row.js +69 -0
- package/src/components/props-util.js +335 -0
- package/src/components/vnode.js +147 -0
- package/src/detail-table-item.vue +19 -0
- package/src/detail-table.vue +178 -0
- package/src/styles/css/index.less +145 -0
package/index.js
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@lambo-design/detail-table",
|
|
3
|
+
"version": "1.0.0-beta.1",
|
|
4
|
+
"description": "",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"scripts": {
|
|
7
|
+
|
|
8
|
+
},
|
|
9
|
+
"author": "lambo",
|
|
10
|
+
"license": "ISC",
|
|
11
|
+
"publishConfig": {
|
|
12
|
+
"access": "public"
|
|
13
|
+
},
|
|
14
|
+
"devDependencies": {
|
|
15
|
+
"@lambo-design/core": "workspace:*",
|
|
16
|
+
"@lambo-design/shared": "workspace:*"
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { getOptionProps, getSlots, getComponentFromProp } from "./props-util";
|
|
2
|
+
|
|
3
|
+
const ColProps = {
|
|
4
|
+
child: Object,
|
|
5
|
+
bordered: Boolean,
|
|
6
|
+
colon: Boolean,
|
|
7
|
+
type: {
|
|
8
|
+
type: String,
|
|
9
|
+
validator: function(value) {
|
|
10
|
+
return ["label", "content"].indexOf(value) !== -1;
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
layout: {
|
|
14
|
+
type: String,
|
|
15
|
+
validator: function(value) {
|
|
16
|
+
return ["horizontal", "vertical"].indexOf(value) !== -1;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const Col = {
|
|
22
|
+
functional: true,
|
|
23
|
+
props: ColProps,
|
|
24
|
+
render(createElement, ctx) {
|
|
25
|
+
const { child, bordered, colon, type, layout } = ctx.props;
|
|
26
|
+
const { prefixCls, span = 1 } = getOptionProps(child);
|
|
27
|
+
const { key } = ctx.data;
|
|
28
|
+
const label = getComponentFromProp(child, "label");
|
|
29
|
+
const slots = getSlots(child);
|
|
30
|
+
const labelProps = {
|
|
31
|
+
attrs: {},
|
|
32
|
+
class: [
|
|
33
|
+
`${prefixCls}-item-label`,
|
|
34
|
+
{
|
|
35
|
+
[`${prefixCls}-item-colon`]: colon,
|
|
36
|
+
[`${prefixCls}-item-no-label`]: !label
|
|
37
|
+
}
|
|
38
|
+
],
|
|
39
|
+
key: `${key}-label`
|
|
40
|
+
};
|
|
41
|
+
if (layout === "vertical") {
|
|
42
|
+
labelProps.attrs.colSpan = span * 2 - 1;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (bordered) {
|
|
46
|
+
if (type === "label") {
|
|
47
|
+
return createElement("th", labelProps, label);
|
|
48
|
+
}
|
|
49
|
+
return createElement(
|
|
50
|
+
"td",
|
|
51
|
+
{
|
|
52
|
+
class: `${prefixCls}-item-content`,
|
|
53
|
+
key: `${key}-content`,
|
|
54
|
+
colSpan: span * 2 - 1
|
|
55
|
+
},
|
|
56
|
+
slots.default
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
if (layout === "vertical") {
|
|
60
|
+
if (type === "content") {
|
|
61
|
+
return createElement(
|
|
62
|
+
"td",
|
|
63
|
+
{ colSpan: span, class: `${prefixCls}-item` },
|
|
64
|
+
createElement(
|
|
65
|
+
"span",
|
|
66
|
+
{ class: `${prefixCls}-item-content`, key: `${key}-content` },
|
|
67
|
+
slots.default
|
|
68
|
+
)
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
return createElement(
|
|
72
|
+
"td",
|
|
73
|
+
{ colSpan: span, class: `${prefixCls}-item` },
|
|
74
|
+
createElement(
|
|
75
|
+
"span",
|
|
76
|
+
{
|
|
77
|
+
class: [
|
|
78
|
+
`${prefixCls}-item-label`,
|
|
79
|
+
{ [`${prefixCls}-item-colon`]: colon }
|
|
80
|
+
],
|
|
81
|
+
key: `${key}-label`
|
|
82
|
+
},
|
|
83
|
+
label
|
|
84
|
+
)
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
return createElement("td", { colSpan: span, class: `${prefixCls}-item` }, [
|
|
88
|
+
createElement("span", labelProps, label),
|
|
89
|
+
createElement(
|
|
90
|
+
"span",
|
|
91
|
+
{ class: `${prefixCls}-item-content`, key: `${key}-content` },
|
|
92
|
+
slots.default
|
|
93
|
+
)
|
|
94
|
+
]);
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
export default Col;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import Col from "./Col";
|
|
2
|
+
|
|
3
|
+
function toArray(value) {
|
|
4
|
+
let ret = value;
|
|
5
|
+
if (value === undefined) {
|
|
6
|
+
ret = [];
|
|
7
|
+
} else if (!Array.isArray(value)) {
|
|
8
|
+
ret = [value];
|
|
9
|
+
}
|
|
10
|
+
return ret;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export default {
|
|
14
|
+
functional: true,
|
|
15
|
+
render: function(createElement, context) {
|
|
16
|
+
const { children, index, prefixCls, bordered, layout, colon } = context.props;
|
|
17
|
+
const renderCol = (colItem, type, idx) => {
|
|
18
|
+
const colProps = {
|
|
19
|
+
child: colItem,
|
|
20
|
+
bordered: bordered,
|
|
21
|
+
colon: colon,
|
|
22
|
+
type: type,
|
|
23
|
+
layout: layout
|
|
24
|
+
}
|
|
25
|
+
return createElement(Col, {props:colProps,key: `${type}-${colItem.key || idx}`});
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const cloneChildren = [];
|
|
29
|
+
const cloneContentChildren = [];
|
|
30
|
+
toArray(children).forEach((childrenItem, idx) => {
|
|
31
|
+
cloneChildren.push(renderCol(childrenItem, "label", idx));
|
|
32
|
+
if (layout === "vertical") {
|
|
33
|
+
cloneContentChildren.push(renderCol(childrenItem, "content", idx));
|
|
34
|
+
} else if (bordered) {
|
|
35
|
+
cloneChildren.push(renderCol(childrenItem, "content", idx));
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
if (layout === "vertical") {
|
|
40
|
+
return [
|
|
41
|
+
createElement(
|
|
42
|
+
'tr',
|
|
43
|
+
{
|
|
44
|
+
class: `${prefixCls}-row`,
|
|
45
|
+
key: `label-${index}`
|
|
46
|
+
},
|
|
47
|
+
cloneChildren
|
|
48
|
+
),
|
|
49
|
+
createElement(
|
|
50
|
+
'tr',
|
|
51
|
+
{
|
|
52
|
+
class: `${prefixCls}-row`,
|
|
53
|
+
key: `content-${index}`
|
|
54
|
+
},
|
|
55
|
+
cloneContentChildren
|
|
56
|
+
)
|
|
57
|
+
];
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return createElement(
|
|
61
|
+
'tr',
|
|
62
|
+
{
|
|
63
|
+
class: `${prefixCls}-row`,
|
|
64
|
+
key: index
|
|
65
|
+
},
|
|
66
|
+
cloneChildren
|
|
67
|
+
)
|
|
68
|
+
}
|
|
69
|
+
};
|
|
@@ -0,0 +1,335 @@
|
|
|
1
|
+
import isPlainObject from 'lodash/isPlainObject';
|
|
2
|
+
import classNames from 'classnames';
|
|
3
|
+
function getType(fn) {
|
|
4
|
+
const match = fn && fn.toString().match(/^\s*function (\w+)/);
|
|
5
|
+
return match ? match[1] : '';
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
const camelizeRE = /-(\w)/g;
|
|
9
|
+
const camelize = str => {
|
|
10
|
+
return str.replace(camelizeRE, (_, c) => (c ? c.toUpperCase() : ''));
|
|
11
|
+
};
|
|
12
|
+
const parseStyleText = (cssText = '', camel) => {
|
|
13
|
+
const res = {};
|
|
14
|
+
const listDelimiter = /;(?![^(]*\))/g;
|
|
15
|
+
const propertyDelimiter = /:(.+)/;
|
|
16
|
+
cssText.split(listDelimiter).forEach(function(item) {
|
|
17
|
+
if (item) {
|
|
18
|
+
const tmp = item.split(propertyDelimiter);
|
|
19
|
+
if (tmp.length > 1) {
|
|
20
|
+
const k = camel ? camelize(tmp[0].trim()) : tmp[0].trim();
|
|
21
|
+
res[k] = tmp[1].trim();
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
return res;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const hasProp = (instance, prop) => {
|
|
29
|
+
const $options = instance.$options || {};
|
|
30
|
+
const propsData = $options.propsData || {};
|
|
31
|
+
return prop in propsData;
|
|
32
|
+
};
|
|
33
|
+
const slotHasProp = (slot, prop) => {
|
|
34
|
+
const $options = slot.componentOptions || {};
|
|
35
|
+
const propsData = $options.propsData || {};
|
|
36
|
+
return prop in propsData;
|
|
37
|
+
};
|
|
38
|
+
const filterProps = (props, propsData = {}) => {
|
|
39
|
+
const res = {};
|
|
40
|
+
Object.keys(props).forEach(k => {
|
|
41
|
+
if (k in propsData || props[k] !== undefined) {
|
|
42
|
+
res[k] = props[k];
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
return res;
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
const getScopedSlots = ele => {
|
|
49
|
+
return (ele.data && ele.data.scopedSlots) || {};
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
const getSlots = ele => {
|
|
53
|
+
let componentOptions = ele.componentOptions || {};
|
|
54
|
+
if (ele.$vnode) {
|
|
55
|
+
componentOptions = ele.$vnode.componentOptions || {};
|
|
56
|
+
}
|
|
57
|
+
const children = ele.children || componentOptions.children || [];
|
|
58
|
+
const slots = {};
|
|
59
|
+
children.forEach(child => {
|
|
60
|
+
if (!isEmptyElement(child)) {
|
|
61
|
+
const name = (child.data && child.data.slot) || 'default';
|
|
62
|
+
slots[name] = slots[name] || [];
|
|
63
|
+
slots[name].push(child);
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
return { ...slots, ...getScopedSlots(ele) };
|
|
67
|
+
};
|
|
68
|
+
const getSlot = (self, name = 'default', options = {}) => {
|
|
69
|
+
return (
|
|
70
|
+
(self.$scopedSlots && self.$scopedSlots[name] && self.$scopedSlots[name](options)) ||
|
|
71
|
+
self.$slots[name] ||
|
|
72
|
+
[]
|
|
73
|
+
);
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
const getAllChildren = ele => {
|
|
77
|
+
let componentOptions = ele.componentOptions || {};
|
|
78
|
+
if (ele.$vnode) {
|
|
79
|
+
componentOptions = ele.$vnode.componentOptions || {};
|
|
80
|
+
}
|
|
81
|
+
return ele.children || componentOptions.children || [];
|
|
82
|
+
};
|
|
83
|
+
const getSlotOptions = ele => {
|
|
84
|
+
if (ele.fnOptions) {
|
|
85
|
+
// 函数式组件
|
|
86
|
+
return ele.fnOptions;
|
|
87
|
+
}
|
|
88
|
+
let componentOptions = ele.componentOptions;
|
|
89
|
+
if (ele.$vnode) {
|
|
90
|
+
componentOptions = ele.$vnode.componentOptions;
|
|
91
|
+
}
|
|
92
|
+
return componentOptions ? componentOptions.Ctor.options || {} : {};
|
|
93
|
+
};
|
|
94
|
+
const getOptionProps = instance => {
|
|
95
|
+
if (instance.componentOptions) {
|
|
96
|
+
const componentOptions = instance.componentOptions;
|
|
97
|
+
const { propsData = {}, Ctor = {} } = componentOptions;
|
|
98
|
+
const props = (Ctor.options || {}).props || {};
|
|
99
|
+
const res = {};
|
|
100
|
+
for (const [k, v] of Object.entries(props)) {
|
|
101
|
+
const def = v.default;
|
|
102
|
+
if (def !== undefined) {
|
|
103
|
+
res[k] =
|
|
104
|
+
typeof def === 'function' && getType(v.type) !== 'Function' ? def.call(instance) : def;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return { ...res, ...propsData };
|
|
108
|
+
}
|
|
109
|
+
const { $options = {}, $props = {} } = instance;
|
|
110
|
+
return filterProps($props, $options.propsData);
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
const getComponentFromProp = (instance, prop, options = instance, execute = true) => {
|
|
114
|
+
if (instance.$createElement) {
|
|
115
|
+
const h = instance.$createElement;
|
|
116
|
+
const temp = instance[prop];
|
|
117
|
+
if (temp !== undefined) {
|
|
118
|
+
return typeof temp === 'function' && execute ? temp(h, options) : temp;
|
|
119
|
+
}
|
|
120
|
+
return (
|
|
121
|
+
(instance.$scopedSlots[prop] && execute && instance.$scopedSlots[prop](options)) ||
|
|
122
|
+
instance.$scopedSlots[prop] ||
|
|
123
|
+
instance.$slots[prop] ||
|
|
124
|
+
undefined
|
|
125
|
+
);
|
|
126
|
+
} else {
|
|
127
|
+
const h = instance.context.$createElement;
|
|
128
|
+
const temp = getPropsData(instance)[prop];
|
|
129
|
+
if (temp !== undefined) {
|
|
130
|
+
return typeof temp === 'function' && execute ? temp(h, options) : temp;
|
|
131
|
+
}
|
|
132
|
+
const slotScope = getScopedSlots(instance)[prop];
|
|
133
|
+
if (slotScope !== undefined) {
|
|
134
|
+
return typeof slotScope === 'function' && execute ? slotScope(h, options) : slotScope;
|
|
135
|
+
}
|
|
136
|
+
const slotsProp = [];
|
|
137
|
+
const componentOptions = instance.componentOptions || {};
|
|
138
|
+
(componentOptions.children || []).forEach(child => {
|
|
139
|
+
if (child.data && child.data.slot === prop) {
|
|
140
|
+
if (child.data.attrs) {
|
|
141
|
+
delete child.data.attrs.slot;
|
|
142
|
+
}
|
|
143
|
+
if (child.tag === 'template') {
|
|
144
|
+
slotsProp.push(child.children);
|
|
145
|
+
} else {
|
|
146
|
+
slotsProp.push(child);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
return slotsProp.length ? slotsProp : undefined;
|
|
151
|
+
}
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
const getAllProps = ele => {
|
|
155
|
+
let data = ele.data || {};
|
|
156
|
+
let componentOptions = ele.componentOptions || {};
|
|
157
|
+
if (ele.$vnode) {
|
|
158
|
+
data = ele.$vnode.data || {};
|
|
159
|
+
componentOptions = ele.$vnode.componentOptions || {};
|
|
160
|
+
}
|
|
161
|
+
return { ...data.props, ...data.attrs, ...componentOptions.propsData };
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
const getPropsData = ele => {
|
|
165
|
+
let componentOptions = ele.componentOptions;
|
|
166
|
+
if (ele.$vnode) {
|
|
167
|
+
componentOptions = ele.$vnode.componentOptions;
|
|
168
|
+
}
|
|
169
|
+
return componentOptions ? componentOptions.propsData || {} : {};
|
|
170
|
+
};
|
|
171
|
+
const getValueByProp = (ele, prop) => {
|
|
172
|
+
return getPropsData(ele)[prop];
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
const getAttrs = ele => {
|
|
176
|
+
let data = ele.data;
|
|
177
|
+
if (ele.$vnode) {
|
|
178
|
+
data = ele.$vnode.data;
|
|
179
|
+
}
|
|
180
|
+
return data ? data.attrs || {} : {};
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
const getKey = ele => {
|
|
184
|
+
let key = ele.key;
|
|
185
|
+
if (ele.$vnode) {
|
|
186
|
+
key = ele.$vnode.key;
|
|
187
|
+
}
|
|
188
|
+
return key;
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
export function getEvents(child) {
|
|
192
|
+
let events = {};
|
|
193
|
+
if (child.componentOptions && child.componentOptions.listeners) {
|
|
194
|
+
events = child.componentOptions.listeners;
|
|
195
|
+
} else if (child.data && child.data.on) {
|
|
196
|
+
events = child.data.on;
|
|
197
|
+
}
|
|
198
|
+
return { ...events };
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// 获取 xxx.native 或者 原生标签 事件
|
|
202
|
+
export function getDataEvents(child) {
|
|
203
|
+
let events = {};
|
|
204
|
+
if (child.data && child.data.on) {
|
|
205
|
+
events = child.data.on;
|
|
206
|
+
}
|
|
207
|
+
return { ...events };
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// use getListeners instead this.$listeners
|
|
211
|
+
// https://github.com/vueComponent/ant-design-vue/issues/1705
|
|
212
|
+
export function getListeners(context) {
|
|
213
|
+
return (context.$vnode ? context.$vnode.componentOptions.listeners : context.$listeners) || {};
|
|
214
|
+
}
|
|
215
|
+
export function getClass(ele) {
|
|
216
|
+
let data = {};
|
|
217
|
+
if (ele.data) {
|
|
218
|
+
data = ele.data;
|
|
219
|
+
} else if (ele.$vnode && ele.$vnode.data) {
|
|
220
|
+
data = ele.$vnode.data;
|
|
221
|
+
}
|
|
222
|
+
const tempCls = data.class || {};
|
|
223
|
+
const staticClass = data.staticClass;
|
|
224
|
+
let cls = {};
|
|
225
|
+
staticClass &&
|
|
226
|
+
staticClass.split(' ').forEach(c => {
|
|
227
|
+
cls[c.trim()] = true;
|
|
228
|
+
});
|
|
229
|
+
if (typeof tempCls === 'string') {
|
|
230
|
+
tempCls.split(' ').forEach(c => {
|
|
231
|
+
cls[c.trim()] = true;
|
|
232
|
+
});
|
|
233
|
+
} else if (Array.isArray(tempCls)) {
|
|
234
|
+
classNames(tempCls)
|
|
235
|
+
.split(' ')
|
|
236
|
+
.forEach(c => {
|
|
237
|
+
cls[c.trim()] = true;
|
|
238
|
+
});
|
|
239
|
+
} else {
|
|
240
|
+
cls = { ...cls, ...tempCls };
|
|
241
|
+
}
|
|
242
|
+
return cls;
|
|
243
|
+
}
|
|
244
|
+
export function getStyle(ele, camel) {
|
|
245
|
+
let data = {};
|
|
246
|
+
if (ele.data) {
|
|
247
|
+
data = ele.data;
|
|
248
|
+
} else if (ele.$vnode && ele.$vnode.data) {
|
|
249
|
+
data = ele.$vnode.data;
|
|
250
|
+
}
|
|
251
|
+
let style = data.style || data.staticStyle;
|
|
252
|
+
if (typeof style === 'string') {
|
|
253
|
+
style = parseStyleText(style, camel);
|
|
254
|
+
} else if (camel && style) {
|
|
255
|
+
// 驼峰化
|
|
256
|
+
const res = {};
|
|
257
|
+
Object.keys(style).forEach(k => (res[camelize(k)] = style[k]));
|
|
258
|
+
return res;
|
|
259
|
+
}
|
|
260
|
+
return style;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
export function getComponentName(opts) {
|
|
264
|
+
return opts && (opts.Ctor.options.name || opts.tag);
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
export function isEmptyElement(c) {
|
|
268
|
+
return !(c.tag || (c.text && c.text.trim() !== ''));
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
export function isStringElement(c) {
|
|
272
|
+
return !c.tag;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
export function filterEmpty(children = []) {
|
|
276
|
+
return children.filter(c => !isEmptyElement(c));
|
|
277
|
+
}
|
|
278
|
+
const initDefaultProps = (propTypes, defaultProps) => {
|
|
279
|
+
Object.keys(defaultProps).forEach(k => {
|
|
280
|
+
if (propTypes[k]) {
|
|
281
|
+
propTypes[k].def && (propTypes[k] = propTypes[k].def(defaultProps[k]));
|
|
282
|
+
} else {
|
|
283
|
+
throw new Error(`not have ${k} prop`);
|
|
284
|
+
}
|
|
285
|
+
});
|
|
286
|
+
return propTypes;
|
|
287
|
+
};
|
|
288
|
+
|
|
289
|
+
export function mergeProps() {
|
|
290
|
+
const args = [].slice.call(arguments, 0);
|
|
291
|
+
const props = {};
|
|
292
|
+
args.forEach((p = {}) => {
|
|
293
|
+
for (const [k, v] of Object.entries(p)) {
|
|
294
|
+
props[k] = props[k] || {};
|
|
295
|
+
if (isPlainObject(v)) {
|
|
296
|
+
Object.assign(props[k], v);
|
|
297
|
+
} else {
|
|
298
|
+
props[k] = v;
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
});
|
|
302
|
+
return props;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
function isValidElement(element) {
|
|
306
|
+
return (
|
|
307
|
+
element &&
|
|
308
|
+
typeof element === 'object' &&
|
|
309
|
+
'componentOptions' in element &&
|
|
310
|
+
'context' in element &&
|
|
311
|
+
element.tag !== undefined
|
|
312
|
+
); // remove text node
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
export {
|
|
316
|
+
hasProp,
|
|
317
|
+
filterProps,
|
|
318
|
+
getOptionProps,
|
|
319
|
+
getComponentFromProp,
|
|
320
|
+
getSlotOptions,
|
|
321
|
+
slotHasProp,
|
|
322
|
+
getPropsData,
|
|
323
|
+
getKey,
|
|
324
|
+
getAttrs,
|
|
325
|
+
getValueByProp,
|
|
326
|
+
parseStyleText,
|
|
327
|
+
initDefaultProps,
|
|
328
|
+
isValidElement,
|
|
329
|
+
camelize,
|
|
330
|
+
getSlots,
|
|
331
|
+
getSlot,
|
|
332
|
+
getAllProps,
|
|
333
|
+
getAllChildren,
|
|
334
|
+
};
|
|
335
|
+
export default hasProp;
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import { filterEmpty, parseStyleText } from './props-util';
|
|
2
|
+
import classNames from 'classnames';
|
|
3
|
+
|
|
4
|
+
export function cloneVNode(vnode, deep) {
|
|
5
|
+
const componentOptions = vnode.componentOptions;
|
|
6
|
+
const data = vnode.data;
|
|
7
|
+
|
|
8
|
+
let listeners = {};
|
|
9
|
+
if (componentOptions && componentOptions.listeners) {
|
|
10
|
+
listeners = { ...componentOptions.listeners };
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
let on = {};
|
|
14
|
+
if (data && data.on) {
|
|
15
|
+
on = { ...data.on };
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const cloned = new vnode.constructor(
|
|
19
|
+
vnode.tag,
|
|
20
|
+
data ? { ...data, on } : data,
|
|
21
|
+
vnode.children,
|
|
22
|
+
vnode.text,
|
|
23
|
+
vnode.elm,
|
|
24
|
+
vnode.context,
|
|
25
|
+
componentOptions ? { ...componentOptions, listeners } : componentOptions,
|
|
26
|
+
vnode.asyncFactory,
|
|
27
|
+
);
|
|
28
|
+
cloned.ns = vnode.ns;
|
|
29
|
+
cloned.isStatic = vnode.isStatic;
|
|
30
|
+
cloned.key = vnode.key;
|
|
31
|
+
cloned.isComment = vnode.isComment;
|
|
32
|
+
cloned.fnContext = vnode.fnContext;
|
|
33
|
+
cloned.fnOptions = vnode.fnOptions;
|
|
34
|
+
cloned.fnScopeId = vnode.fnScopeId;
|
|
35
|
+
cloned.isCloned = true;
|
|
36
|
+
if (deep) {
|
|
37
|
+
if (vnode.children) {
|
|
38
|
+
cloned.children = cloneVNodes(vnode.children, true);
|
|
39
|
+
}
|
|
40
|
+
if (componentOptions && componentOptions.children) {
|
|
41
|
+
componentOptions.children = cloneVNodes(componentOptions.children, true);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return cloned;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export function cloneVNodes(vnodes, deep) {
|
|
48
|
+
const len = vnodes.length;
|
|
49
|
+
const res = new Array(len);
|
|
50
|
+
for (let i = 0; i < len; i++) {
|
|
51
|
+
res[i] = cloneVNode(vnodes[i], deep);
|
|
52
|
+
}
|
|
53
|
+
return res;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export function cloneElement(n, nodeProps = {}, deep) {
|
|
57
|
+
let ele = n;
|
|
58
|
+
if (Array.isArray(n)) {
|
|
59
|
+
ele = filterEmpty(n)[0];
|
|
60
|
+
}
|
|
61
|
+
if (!ele) {
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
const node = cloneVNode(ele, deep);
|
|
65
|
+
// // 函数式组件不支持clone https://github.com/vueComponent/ant-design-vue/pull/1947
|
|
66
|
+
// warning(
|
|
67
|
+
// !(node.fnOptions && node.fnOptions.functional),
|
|
68
|
+
// `can not use cloneElement for functional component (${node.fnOptions && node.fnOptions.name})`,
|
|
69
|
+
// );
|
|
70
|
+
const { props = {}, key, on = {}, nativeOn = {}, children, directives = [] } = nodeProps;
|
|
71
|
+
const data = node.data || {};
|
|
72
|
+
let cls = {};
|
|
73
|
+
let style = {};
|
|
74
|
+
const {
|
|
75
|
+
attrs = {},
|
|
76
|
+
ref,
|
|
77
|
+
domProps = {},
|
|
78
|
+
style: tempStyle = {},
|
|
79
|
+
class: tempCls = {},
|
|
80
|
+
scopedSlots = {},
|
|
81
|
+
} = nodeProps;
|
|
82
|
+
|
|
83
|
+
if (typeof data.style === 'string') {
|
|
84
|
+
style = parseStyleText(data.style);
|
|
85
|
+
} else {
|
|
86
|
+
style = { ...data.style, ...style };
|
|
87
|
+
}
|
|
88
|
+
if (typeof tempStyle === 'string') {
|
|
89
|
+
style = { ...style, ...parseStyleText(style) };
|
|
90
|
+
} else {
|
|
91
|
+
style = { ...style, ...tempStyle };
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if (typeof data.class === 'string' && data.class.trim() !== '') {
|
|
95
|
+
data.class.split(' ').forEach(c => {
|
|
96
|
+
cls[c.trim()] = true;
|
|
97
|
+
});
|
|
98
|
+
} else if (Array.isArray(data.class)) {
|
|
99
|
+
classNames(data.class)
|
|
100
|
+
.split(' ')
|
|
101
|
+
.forEach(c => {
|
|
102
|
+
cls[c.trim()] = true;
|
|
103
|
+
});
|
|
104
|
+
} else {
|
|
105
|
+
cls = { ...data.class, ...cls };
|
|
106
|
+
}
|
|
107
|
+
if (typeof tempCls === 'string' && tempCls.trim() !== '') {
|
|
108
|
+
tempCls.split(' ').forEach(c => {
|
|
109
|
+
cls[c.trim()] = true;
|
|
110
|
+
});
|
|
111
|
+
} else {
|
|
112
|
+
cls = { ...cls, ...tempCls };
|
|
113
|
+
}
|
|
114
|
+
node.data = Object.assign({}, data, {
|
|
115
|
+
style,
|
|
116
|
+
attrs: { ...data.attrs, ...attrs },
|
|
117
|
+
class: cls,
|
|
118
|
+
domProps: { ...data.domProps, ...domProps },
|
|
119
|
+
scopedSlots: { ...data.scopedSlots, ...scopedSlots },
|
|
120
|
+
directives: [...(data.directives || []), ...directives],
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
if (node.componentOptions) {
|
|
124
|
+
node.componentOptions.propsData = node.componentOptions.propsData || {};
|
|
125
|
+
node.componentOptions.listeners = node.componentOptions.listeners || {};
|
|
126
|
+
node.componentOptions.propsData = { ...node.componentOptions.propsData, ...props };
|
|
127
|
+
node.componentOptions.listeners = { ...node.componentOptions.listeners, ...on };
|
|
128
|
+
if (children) {
|
|
129
|
+
node.componentOptions.children = children;
|
|
130
|
+
}
|
|
131
|
+
} else {
|
|
132
|
+
if (children) {
|
|
133
|
+
node.children = children;
|
|
134
|
+
}
|
|
135
|
+
node.data.on = { ...(node.data.on || {}), ...on };
|
|
136
|
+
}
|
|
137
|
+
node.data.on = { ...(node.data.on || {}), ...nativeOn };
|
|
138
|
+
|
|
139
|
+
if (key !== undefined) {
|
|
140
|
+
node.key = key;
|
|
141
|
+
node.data.key = key;
|
|
142
|
+
}
|
|
143
|
+
if (typeof ref === 'string') {
|
|
144
|
+
node.data.ref = ref;
|
|
145
|
+
}
|
|
146
|
+
return node;
|
|
147
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
<template></template>
|
|
2
|
+
<script>
|
|
3
|
+
export default {
|
|
4
|
+
name: 'LamboDetailTableItem',
|
|
5
|
+
props: {
|
|
6
|
+
prefixCls: {
|
|
7
|
+
type: String,
|
|
8
|
+
default: "lambo-detail-table",
|
|
9
|
+
},
|
|
10
|
+
label: String,
|
|
11
|
+
span: {
|
|
12
|
+
type: Number,
|
|
13
|
+
default: 1
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
</script>
|
|
18
|
+
<style lang="less" scoped>
|
|
19
|
+
</style>
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div
|
|
3
|
+
:class="[
|
|
4
|
+
prefixCls,
|
|
5
|
+
{
|
|
6
|
+
[`${prefixCls}-${size}`]: size !== 'default',
|
|
7
|
+
[`${prefixCls}-bordered`]: !!bordered,
|
|
8
|
+
},
|
|
9
|
+
]"
|
|
10
|
+
>
|
|
11
|
+
<div v-if="title" :class="[`${prefixCls}-title`]">{{ title }}</div>
|
|
12
|
+
<div :class="[`${prefixCls}-view`]">
|
|
13
|
+
<table>
|
|
14
|
+
<tbody>
|
|
15
|
+
<Row
|
|
16
|
+
v-for="(item, index) in childrenArray"
|
|
17
|
+
:children="item"
|
|
18
|
+
:key="index"
|
|
19
|
+
:index="index"
|
|
20
|
+
:prefixCls="prefixCls"
|
|
21
|
+
:bordered="bordered"
|
|
22
|
+
:layout="layout"
|
|
23
|
+
:colon="colon"
|
|
24
|
+
></Row>
|
|
25
|
+
</tbody>
|
|
26
|
+
</table>
|
|
27
|
+
</div>
|
|
28
|
+
</div>
|
|
29
|
+
</template>
|
|
30
|
+
<script>
|
|
31
|
+
import {
|
|
32
|
+
isValidElement,
|
|
33
|
+
getOptionProps,
|
|
34
|
+
} from "./components/props-util";
|
|
35
|
+
import { cloneElement } from "./components/vnode";
|
|
36
|
+
import Row from "./components/Row";
|
|
37
|
+
const defaultColumnMap = {
|
|
38
|
+
xxl: 3,
|
|
39
|
+
xl: 3,
|
|
40
|
+
lg: 3,
|
|
41
|
+
md: 3,
|
|
42
|
+
sm: 2,
|
|
43
|
+
xs: 1,
|
|
44
|
+
};
|
|
45
|
+
function toArray(value) {
|
|
46
|
+
let ret = value;
|
|
47
|
+
if (value === undefined) {
|
|
48
|
+
ret = [];
|
|
49
|
+
} else if (!Array.isArray(value)) {
|
|
50
|
+
ret = [value];
|
|
51
|
+
}
|
|
52
|
+
return ret;
|
|
53
|
+
}
|
|
54
|
+
export default {
|
|
55
|
+
name: "LamboDetailTable",
|
|
56
|
+
components: { Row },
|
|
57
|
+
props: {
|
|
58
|
+
prefixCls: {
|
|
59
|
+
type: String,
|
|
60
|
+
default: "lambo-detail-table",
|
|
61
|
+
},
|
|
62
|
+
bordered: Boolean,
|
|
63
|
+
size: {
|
|
64
|
+
type: String,
|
|
65
|
+
default: "default",
|
|
66
|
+
validator: function (value) {
|
|
67
|
+
return ["default", "middle", "small"].indexOf(value) !== -1;
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
title: String,
|
|
71
|
+
column: Number,
|
|
72
|
+
layout: {
|
|
73
|
+
type: String,
|
|
74
|
+
default: "horizontal",
|
|
75
|
+
validator: function (value) {
|
|
76
|
+
return ["horizontal", "vertical"].indexOf(value) !== -1;
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
colon: Boolean,
|
|
80
|
+
},
|
|
81
|
+
data() {
|
|
82
|
+
return {
|
|
83
|
+
screens: {},
|
|
84
|
+
token: undefined,
|
|
85
|
+
childrenArray:null
|
|
86
|
+
};
|
|
87
|
+
},
|
|
88
|
+
computed: {
|
|
89
|
+
/*childrenArray: function () {
|
|
90
|
+
return this.refreshTable();
|
|
91
|
+
},*/
|
|
92
|
+
},
|
|
93
|
+
methods: {
|
|
94
|
+
refreshTable(){
|
|
95
|
+
this.childrenArray = null;
|
|
96
|
+
const { prefixCls } = this;
|
|
97
|
+
const children = this.$slots.default;
|
|
98
|
+
const cloneChildren = toArray(children)
|
|
99
|
+
.map((child) => {
|
|
100
|
+
if (isValidElement(child)) {
|
|
101
|
+
return cloneElement(child, {
|
|
102
|
+
props: {
|
|
103
|
+
prefixCls,
|
|
104
|
+
},
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
return null;
|
|
108
|
+
})
|
|
109
|
+
.filter((node) => node);
|
|
110
|
+
const column = this.getColumn();
|
|
111
|
+
this.childrenArray = this.generateChildrenRows(cloneChildren, column);
|
|
112
|
+
},
|
|
113
|
+
getColumn() {
|
|
114
|
+
const { column } = this.$props;
|
|
115
|
+
// if (typeof column === "object") {
|
|
116
|
+
// for (let i = 0; i < responsiveArray.length; i++) {
|
|
117
|
+
// const breakpoint = responsiveArray[i];
|
|
118
|
+
// if (this.screens[breakpoint] && column[breakpoint] !== undefined) {
|
|
119
|
+
// return column[breakpoint] || defaultColumnMap[breakpoint];
|
|
120
|
+
// }
|
|
121
|
+
// }
|
|
122
|
+
// }
|
|
123
|
+
// If the configuration is not an object, it is a number, return number
|
|
124
|
+
if (typeof column === "number") {
|
|
125
|
+
return column;
|
|
126
|
+
}
|
|
127
|
+
// If it is an object, but no response is found, this happens only in the test.
|
|
128
|
+
// Maybe there are some strange environments
|
|
129
|
+
return 3;
|
|
130
|
+
},
|
|
131
|
+
generateChildrenRows(children, column) {
|
|
132
|
+
const rows = [];
|
|
133
|
+
let columns = null;
|
|
134
|
+
let leftSpans;
|
|
135
|
+
|
|
136
|
+
const itemNodes = toArray(children);
|
|
137
|
+
itemNodes.forEach((node, index) => {
|
|
138
|
+
const itemProps = getOptionProps(node);
|
|
139
|
+
let itemNode = node;
|
|
140
|
+
|
|
141
|
+
if (!columns) {
|
|
142
|
+
leftSpans = column;
|
|
143
|
+
columns = [];
|
|
144
|
+
rows.push(columns);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// Always set last span to align the end of Descriptions
|
|
148
|
+
const lastItem = index === itemNodes.length - 1;
|
|
149
|
+
let lastSpanSame = true;
|
|
150
|
+
if (lastItem) {
|
|
151
|
+
lastSpanSame = !itemProps.span || itemProps.span === leftSpans;
|
|
152
|
+
itemNode = cloneElement(itemNode, {
|
|
153
|
+
props: {
|
|
154
|
+
span: leftSpans,
|
|
155
|
+
},
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// Calculate left fill span
|
|
160
|
+
const { span = 1 } = itemProps;
|
|
161
|
+
columns.push(itemNode);
|
|
162
|
+
leftSpans -= span;
|
|
163
|
+
|
|
164
|
+
if (leftSpans <= 0) {
|
|
165
|
+
columns = null;
|
|
166
|
+
}
|
|
167
|
+
});
|
|
168
|
+
return rows;
|
|
169
|
+
},
|
|
170
|
+
},
|
|
171
|
+
mounted() {
|
|
172
|
+
this.refreshTable();
|
|
173
|
+
}
|
|
174
|
+
};
|
|
175
|
+
</script>
|
|
176
|
+
<style lang="less" scoped>
|
|
177
|
+
@import "styles/css/index";
|
|
178
|
+
</style>
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
.lambo-detail-table-style(){
|
|
2
|
+
@descriptions-prefix-cls: lambo-detail-table;
|
|
3
|
+
|
|
4
|
+
@descriptions-default-padding: 16px 24px;
|
|
5
|
+
@descriptions-middle-padding: 12px 24px;
|
|
6
|
+
@descriptions-small-padding: 8px 16px;
|
|
7
|
+
|
|
8
|
+
.@{descriptions-prefix-cls} {
|
|
9
|
+
&-title {
|
|
10
|
+
margin-bottom: 20px;
|
|
11
|
+
color: fade(#000, 85%);
|
|
12
|
+
font-weight: bold;
|
|
13
|
+
font-size: 16px;
|
|
14
|
+
line-height: 1.5;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
&-view {
|
|
18
|
+
width: 100%;
|
|
19
|
+
overflow: hidden;
|
|
20
|
+
border-radius: 4px;
|
|
21
|
+
table {
|
|
22
|
+
width: 100%;
|
|
23
|
+
table-layout: fixed;
|
|
24
|
+
border-collapse: collapse
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
&-row {
|
|
29
|
+
> th,
|
|
30
|
+
> td {
|
|
31
|
+
padding-bottom: 16px;
|
|
32
|
+
}
|
|
33
|
+
&:last-child {
|
|
34
|
+
border-bottom: none;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
&-item-label {
|
|
39
|
+
color: fade(#000, 85%);
|
|
40
|
+
font-weight: normal;
|
|
41
|
+
font-size: 14px;
|
|
42
|
+
line-height: 1.5;
|
|
43
|
+
|
|
44
|
+
&::after {
|
|
45
|
+
position: relative;
|
|
46
|
+
top: -0.5px;
|
|
47
|
+
margin: 0 8px 0 2px;
|
|
48
|
+
content: ' ';
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
&-item-colon {
|
|
53
|
+
&::after {
|
|
54
|
+
content: ':';
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
&-item-no-label {
|
|
59
|
+
&::after {
|
|
60
|
+
margin: 0;
|
|
61
|
+
content: '';
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
&-item-content {
|
|
66
|
+
display: table-cell;
|
|
67
|
+
color: fade(#000, 65%);;
|
|
68
|
+
font-size: 14px;
|
|
69
|
+
line-height: 1.5;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
&-item {
|
|
73
|
+
padding-bottom: 0;
|
|
74
|
+
> span {
|
|
75
|
+
display: inline-block;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
&-middle {
|
|
80
|
+
.@{descriptions-prefix-cls}-row {
|
|
81
|
+
> th,
|
|
82
|
+
> td {
|
|
83
|
+
padding-bottom: 12px;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
&-small {
|
|
89
|
+
.@{descriptions-prefix-cls}-row {
|
|
90
|
+
> th,
|
|
91
|
+
> td {
|
|
92
|
+
padding-bottom: 8px;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
&-bordered {
|
|
98
|
+
.@{descriptions-prefix-cls}-view {
|
|
99
|
+
border: 1px solid hsv(0, 0, 91%);
|
|
100
|
+
> table {
|
|
101
|
+
table-layout: auto;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
.@{descriptions-prefix-cls}-item-label,
|
|
106
|
+
.@{descriptions-prefix-cls}-item-content {
|
|
107
|
+
padding: @descriptions-default-padding;
|
|
108
|
+
border-right: 1px solid hsv(0, 0, 91%); ;
|
|
109
|
+
|
|
110
|
+
&:last-child {
|
|
111
|
+
border-right: none;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
.@{descriptions-prefix-cls}-item-label {
|
|
116
|
+
background-color: #fafafa;
|
|
117
|
+
&::after {
|
|
118
|
+
display: none;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
.@{descriptions-prefix-cls}-row {
|
|
123
|
+
border-bottom: 1px solid hsv(0, 0, 91%);
|
|
124
|
+
&:last-child {
|
|
125
|
+
border-bottom: none;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
&.@{descriptions-prefix-cls}-middle {
|
|
130
|
+
.@{descriptions-prefix-cls}-item-label,
|
|
131
|
+
.@{descriptions-prefix-cls}-item-content {
|
|
132
|
+
padding: @descriptions-middle-padding;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
&.@{descriptions-prefix-cls}-small {
|
|
137
|
+
.@{descriptions-prefix-cls}-item-label,
|
|
138
|
+
.@{descriptions-prefix-cls}-item-content {
|
|
139
|
+
padding: @descriptions-small-padding;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|