@ddwl/ddwl-ui 1.0.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.
Files changed (35) hide show
  1. package/.babelrc +19 -0
  2. package/README.md +92 -0
  3. package/babel.config.js +5 -0
  4. package/package.json +57 -0
  5. package/src/lib/slots/buttonGroup.vue +113 -0
  6. package/src/lib/slots/dict.vue +45 -0
  7. package/src/lib/slots/file.vue +35 -0
  8. package/src/lib/slots/icon.vue +72 -0
  9. package/src/lib/slots/index.js +11 -0
  10. package/src/main.js +59 -0
  11. package/src/packages/button/index.vue +36 -0
  12. package/src/packages/descriptions/index.vue +83 -0
  13. package/src/packages/dialog/index.vue +164 -0
  14. package/src/packages/dialog-confirm/index.vue +99 -0
  15. package/src/packages/drawer/index.vue +127 -0
  16. package/src/packages/file-preview/index.vue +277 -0
  17. package/src/packages/file-preview/static/audio.png +0 -0
  18. package/src/packages/file-preview/static/video.png +0 -0
  19. package/src/packages/filter-tree/index.vue +295 -0
  20. package/src/packages/form/index.vue +149 -0
  21. package/src/packages/form-item/index.vue +215 -0
  22. package/src/packages/import-file/index.vue +166 -0
  23. package/src/packages/menu/index.vue +66 -0
  24. package/src/packages/menu/menuItem.vue +78 -0
  25. package/src/packages/popconfirm/index.vue +39 -0
  26. package/src/packages/render/index.vue +14 -0
  27. package/src/packages/search-form/index.vue +257 -0
  28. package/src/packages/search-input/index.vue +68 -0
  29. package/src/packages/search-table/index.vue +101 -0
  30. package/src/packages/svg-icon/index.vue +43 -0
  31. package/src/packages/table/index.vue +453 -0
  32. package/src/packages/upload/index.vue +355 -0
  33. package/src/utils/index.js +77 -0
  34. package/src/utils/treeLib.js +190 -0
  35. package/vue.config.js +35 -0
@@ -0,0 +1,295 @@
1
+ <!-- eslint-disable vue/no-template-shadow -->
2
+ <!-- 多功能筛选树 -->
3
+ <template>
4
+ <div class="d-filter-tree">
5
+ <slot name="header" />
6
+ <el-input
7
+ v-if="filterable"
8
+ v-model="searchContent"
9
+ type="text"
10
+ :placeholder="placeholder"
11
+ suffix-icon="el-icon-search"
12
+ />
13
+ <el-tree
14
+ ref="tree"
15
+ class="filter-tree mt16"
16
+ :data="data"
17
+ :node-key="nodeKey"
18
+ :expand-on-click-node="false"
19
+ highlight-current
20
+ :props="props"
21
+ :filter-node-method="filterNode"
22
+ :default-expanded-keys="defaultExpandIds"
23
+ v-bind="$attrs"
24
+ @node-click="nodeClick"
25
+ @node-expand="(data)=>handleNodeToggle(data,true)"
26
+ @node-collapse="(data)=>handleNodeToggle(data,false)"
27
+ v-on="$listeners"
28
+ >
29
+ <span
30
+ slot-scope="{ node, data }"
31
+ class="d-filter-tree-node"
32
+ >
33
+ <span class="node-label ellipsis">
34
+ <slot
35
+ name="label"
36
+ :data="data"
37
+ >{{ node.label }}</slot>
38
+ </span>
39
+ <span class="mr8">
40
+ <el-button
41
+ v-if="showNodeButton('append', data)"
42
+ type="text"
43
+ icon="el-icon-plus"
44
+ @click.stop="append(node)"
45
+ />
46
+ <el-button
47
+ v-if="showNodeButton('edit', data)"
48
+ type="text"
49
+ icon="el-icon-edit"
50
+ @click.stop="edit(node)"
51
+ />
52
+ <el-button
53
+ v-if="showNodeButton('remove', data)"
54
+ type="text"
55
+ icon="el-icon-delete"
56
+ @click.stop="remove(node)"
57
+ />
58
+ </span>
59
+ </span>
60
+ </el-tree>
61
+ </div>
62
+ </template>
63
+
64
+ <script>
65
+ import { getNodeByKey, getFirstVaildNode, flatTree } from '@/utils/treeLib'
66
+
67
+ export default {
68
+ name: 'DFilterTree',
69
+ components: {},
70
+ props: {
71
+ data: {
72
+ default: () => [],
73
+ type: Array
74
+ },
75
+ nodeKey: {
76
+ default: 'id',
77
+ type: String
78
+ },
79
+ // 默认选中第一个匹配的节点,如果有指定currentKey,则优先选中该节点
80
+ // eg: { key: 'id', vlaue: true }
81
+ currentDefault: {
82
+ default: null,
83
+ type: Function
84
+ },
85
+ // 选中的节点值
86
+ currentKey: {
87
+ default: '',
88
+ type: [String, Number]
89
+ },
90
+ props: {
91
+ default: () => ({}),
92
+ type: Object
93
+ },
94
+ filterable: {
95
+ default: true,
96
+ type: Boolean
97
+ },
98
+ showButtons: {
99
+ default: false,
100
+ type: Boolean
101
+ },
102
+ templateUrl: {
103
+ default: '',
104
+ type: String
105
+ },
106
+ placeholder: {
107
+ default: '请输入查询内容',
108
+ type: String
109
+ },
110
+ buttonProps: {
111
+ type: Object,
112
+ default: () => ({
113
+ append: false,
114
+ edit: false,
115
+ remove: false
116
+ })
117
+ },
118
+ searchKey: {
119
+ type: String,
120
+ default: 'search'
121
+ }
122
+ },
123
+ data () {
124
+ return {
125
+ searchContent: '',
126
+ defaultExpandIds: [],
127
+ first: true
128
+ }
129
+ },
130
+ computed: {
131
+ showNodeButton () {
132
+ return (type, data) => {
133
+ if (this.buttonProps[type]) {
134
+ if (typeof this.buttonProps[type] === 'function') {
135
+ return this.buttonProps[type](data)
136
+ } else {
137
+ return true
138
+ }
139
+ } else {
140
+ return false
141
+ }
142
+ }
143
+ }
144
+ },
145
+ watch: {
146
+ data: {
147
+ handler () {
148
+ if (this.data && this.data.length) {
149
+ let node
150
+ if (this.currentKey) {
151
+ node = getNodeByKey(this.data, this.currentKey, { key: this.nodeKey })
152
+ } else if (this.currentDefault) {
153
+ // 获取需要默认选中的节点
154
+ const props = {
155
+ key: this.nodeKey
156
+ }
157
+ this.props.label && (props.label = this.props.label)
158
+ this.props.children && (props.children = this.props.children)
159
+ node = getFirstVaildNode(this.data, this.currentDefault, props)
160
+ }
161
+ this.$nextTick(() => {
162
+ if (node) {
163
+ this.$refs.tree.setCurrentKey(node[this.nodeKey])
164
+ this.$emit('node-change', node)
165
+ this.first && this.handleNodeToggle(node, true)
166
+ }
167
+ this.first = false // 只在第一次有数据时执行默认展开
168
+ })
169
+ }
170
+ },
171
+ immediate: true
172
+ },
173
+ searchContent (val) {
174
+ this.$refs.tree.filter(val)
175
+ }
176
+ },
177
+ created () {},
178
+ methods: {
179
+ // 树的过滤methods
180
+ filterNode (value, data) {
181
+ if (!value) return true
182
+ return (data[this.searchKey] || data[(this.props && this.props.label) || 'label']).indexOf(value) !== -1
183
+ },
184
+ // 树节点触发点击
185
+ nodeClick (node) {
186
+ this.$emit('node-change', node)
187
+ },
188
+ append (node) {
189
+ this.$emit('node-append', node)
190
+ },
191
+ edit (node) {
192
+ this.$emit('node-edit', node)
193
+ },
194
+ remove (node) {
195
+ this.$emit('node-remove', node)
196
+ },
197
+ // 树节点展开/关闭
198
+ handleNodeToggle (data, isExpanded) {
199
+ if (isExpanded) {
200
+ // 展开节点
201
+ if (!this.defaultExpandIds.includes(data[this.nodeKey])) {
202
+ this.defaultExpandIds.push(data[this.nodeKey])
203
+ }
204
+ } else {
205
+ // 关闭节点
206
+ const index = this.defaultExpandIds.indexOf(data[this.nodeKey])
207
+ if (index > -1) {
208
+ this.defaultExpandIds.splice(index, 1)
209
+ }
210
+ }
211
+ this.removeExpandChildIds(data)
212
+ },
213
+ removeExpandChildIds (data) {
214
+ const ids = (flatTree(data.children || [], { key: this.nodeKey }) || []).map(node => node[this.nodeKey])
215
+ this.defaultExpandIds = this.defaultExpandIds.filter(id => !ids.includes(id))
216
+ },
217
+ expandNode (id) {
218
+ const node = getNodeByKey(this.data, id, { key: this.nodeKey })
219
+ if (node) this.handleNodeToggle(node, true)
220
+ },
221
+ // el-tree methods
222
+ updateKeyChildren (...args) {
223
+ this.$refs.tree.updateKeyChildren(...args)
224
+ },
225
+ getCheckedNodes (...args) {
226
+ return this.$refs.tree.getCheckedNodes(...args)
227
+ },
228
+ setCheckedNodes (...args) {
229
+ this.$refs.tree.setCheckedNodes(...args)
230
+ },
231
+ getCheckedKeys (...args) {
232
+ return this.$refs.tree.getCheckedKeys(...args)
233
+ },
234
+ setCheckedKeys (...args) {
235
+ this.$refs.tree.setCheckedKeys(...args)
236
+ },
237
+ setChecked (...args) {
238
+ this.$refs.tree.setChecked(...args)
239
+ },
240
+ getHalfCheckedNodes (...args) {
241
+ return this.$refs.tree.getHalfCheckedNodes(...args)
242
+ },
243
+ getHalfCheckedKeys (...args) {
244
+ return this.$refs.tree.getHalfCheckedKeys(...args)
245
+ },
246
+ getCurrentKey (...args) {
247
+ return this.$refs.tree.getCurrentKey(...args)
248
+ },
249
+ getCurrentNode (...args) {
250
+ return this.$refs.tree.getCurrentNode(...args)
251
+ },
252
+ setCurrentKey (...args) {
253
+ this.$refs.tree.setCurrentKey(...args)
254
+ },
255
+ setCurrentNode (...args) {
256
+ this.$refs.tree.setCurrentNode(...args)
257
+ },
258
+ getNode (...args) {
259
+ return this.$refs.tree.getNode(...args)
260
+ }
261
+ }
262
+ }
263
+ </script>
264
+
265
+ <style lang='scss' scoped>
266
+ .d-filter-tree {
267
+ display: flex;
268
+ flex-direction: column;
269
+ height: 100%;
270
+ font-size: 14px;
271
+ .d-filter-tree-buttons {
272
+ display: flex;
273
+ justify-content: space-between;
274
+ & > div {
275
+ cursor: pointer;
276
+ color: #3786FD;
277
+ }
278
+ }
279
+ .d-filter-tree-node {
280
+ display: flex;
281
+ align-items: center;
282
+ flex: 1;
283
+ overflow: hidden;
284
+ width: 100%;
285
+ .node-label {
286
+ flex: 1;
287
+ overflow: hidden;
288
+ }
289
+ }
290
+ .filter-tree {
291
+ flex: 1;
292
+ overflow: auto;
293
+ }
294
+ }
295
+ </style>
@@ -0,0 +1,149 @@
1
+ <!-- 表单 -->
2
+ <template>
3
+ <el-form
4
+ ref="form"
5
+ v-bind="$attrs"
6
+ :model="source"
7
+ >
8
+ <el-row
9
+ style="display: flex;flex-wrap: wrap;"
10
+ :gutter="16"
11
+ :class="!grid && 'flex'"
12
+ >
13
+ <template v-for="item in config">
14
+ <component
15
+ :is="grid ? 'el-col' : 'div'"
16
+ v-if="!item.hide"
17
+ :key="item.key"
18
+ :class="item.className"
19
+ :span="item.span || 24"
20
+ >
21
+ <el-form-item
22
+ class="d-form-item"
23
+ :class="{ 'custom-form-item-top': item.direction === 'vertical' || direction === 'vertical' }"
24
+ :label="item.label"
25
+ :prop="item.key"
26
+ :label-width="item.direction === 'line' ? (item.labelWidth || labelWidth) : '100%'"
27
+ :rules="item.rules || (item.required ? [{ required: true, message: placeholder(item) }] : null)"
28
+ v-bind="item.itemProps"
29
+ >
30
+ <span slot="label">
31
+ <span v-if="!item.labelRender">{{ item.label }}</span>
32
+ <form-label-render v-else :scope="item" :render="item.labelRender" />
33
+ </span>
34
+ <span v-if="item.preText" class="mr8">{{ item.preText }}</span>
35
+ <slot v-if="item.component === 'slot'" :name="item.slotName" />
36
+ <div
37
+ v-else-if="item.component === 'text'"
38
+ :class="item.innerClass"
39
+ :style="item.style"
40
+ >
41
+ {{ item.text || source[item.key] }}
42
+ </div>
43
+ <template v-else>
44
+ <form-item :ref="item.key" v-model="source[item.key]" :config="item" />
45
+ </template>
46
+ <span v-if="item.sufText" class="ml8">{{ item.sufText }}</span>
47
+ </el-form-item>
48
+ </component>
49
+ </template>
50
+ </el-row>
51
+ </el-form>
52
+ </template>
53
+
54
+ <script>
55
+ import FormItem from '../form-item/index'
56
+ import FormLabelRender from '../render'
57
+
58
+ export default {
59
+ name: 'DForm',
60
+ components: {
61
+ FormItem,
62
+ FormLabelRender
63
+ },
64
+ model: {
65
+ prop: 'modelValue',
66
+ event: 'change'
67
+ },
68
+ props: {
69
+ config: {
70
+ type: Array,
71
+ default: () => []
72
+ },
73
+ labelWidth: {
74
+ default: '120px',
75
+ type: String
76
+ },
77
+ modelValue: {
78
+ type: Object,
79
+ default: () => ({})
80
+ },
81
+ grid: {
82
+ type: Boolean,
83
+ default: true
84
+ },
85
+ direction: {
86
+ type: String,
87
+ default: 'vertical'
88
+ }
89
+ },
90
+ data () {
91
+ return {}
92
+ },
93
+ computed: {
94
+ source: {
95
+ get () {
96
+ return this.modelValue
97
+ },
98
+ set (value) {
99
+ this.$emit('change', value)
100
+ }
101
+ },
102
+ placeholder () {
103
+ return ({ component, label }) => {
104
+ // 默认给组件添加placeholder,可自定义
105
+ if (component === 'el-input' || component === 'el-input-number') {
106
+ return `请输入${label}`
107
+ } else {
108
+ return `请选择${label}`
109
+ }
110
+ }
111
+ }
112
+ },
113
+ methods: {
114
+ resetFields () {
115
+ this.$refs.form.resetFields()
116
+ },
117
+ clearValidate () {
118
+ this.$refs.form.clearValidate()
119
+ },
120
+ async validate () {
121
+ const valid = await this.$refs.form.validate()
122
+ return valid
123
+ }
124
+ }
125
+ }
126
+ </script>
127
+
128
+ <style lang="scss" scoped>
129
+ .d-form-item {
130
+ :deep(.el-form-item__content) {
131
+ display: flex;
132
+ .search-item {
133
+ flex: 1;
134
+ overflow: hidden;
135
+ }
136
+ }
137
+ }
138
+ .custom-form-item-top {
139
+ display: flex;
140
+ flex-direction: column;
141
+
142
+ :deep(.el-form-item__label) {
143
+ text-align: left;
144
+ }
145
+ :deep(.el-form-item__content) {
146
+ margin-left: 0 !important;
147
+ }
148
+ }
149
+ </style>
@@ -0,0 +1,215 @@
1
+ <template>
2
+ <div class="search-item">
3
+ <div>
4
+ <span
5
+ v-if="config.prefix"
6
+ class="mr6"
7
+ >{{ config.prefix }}</span>
8
+ <el-radio-group
9
+ v-if="config.component === 'el-radio-group'"
10
+ v-model="value"
11
+ :disabled="!!config.disabled"
12
+ v-bind="config.props"
13
+ v-on="config.listeners"
14
+ @change="change"
15
+ >
16
+ <el-radio
17
+ v-for="radio in config.options"
18
+ :key="radio.value"
19
+ :label="radio.value"
20
+ :disabled="!!radio.disabled"
21
+ >
22
+ {{ radio.label }}
23
+ </el-radio>
24
+ </el-radio-group>
25
+ <el-cascader
26
+ v-if="config.component === 'el-cascader'"
27
+ :ref="config.key"
28
+ v-model="value"
29
+ :style="{
30
+ width: config.width
31
+ }"
32
+ :clearable="clearable(config)"
33
+ :disabled="!!config.disabled"
34
+ :placeholder="config.placeholder || placeholder(config)"
35
+ v-bind="config.props"
36
+ v-on="config.listeners"
37
+ @change="change"
38
+ >
39
+ <!-- 当级联选择项需要弹pop弹窗时 -->
40
+ <template
41
+ v-if="config.hasPopover"
42
+ slot-scope="{ data }"
43
+ >
44
+ <el-popover
45
+ v-if="config.popConfig.isShow(data)"
46
+ :placement="config.popConfig.placement || 'right'"
47
+ trigger="hover"
48
+ >
49
+ <component
50
+ :is="config.popConfig.component"
51
+ :data="data"
52
+ />
53
+ <span slot="reference"> {{ data[config.props.props.label] }}</span>
54
+ </el-popover>
55
+ <span v-else> {{ data[config.props.props.label] }}</span>
56
+ </template>
57
+ </el-cascader>
58
+ <component
59
+ :is="config.component"
60
+ v-else
61
+ :ref="config.key"
62
+ v-model.trim="value"
63
+ :style="{
64
+ width: config.width
65
+ }"
66
+ :clearable="clearable(config)"
67
+ :maxlength="config.maxlength || maxlength(config)"
68
+ :disabled="!!config.disabled"
69
+ :placeholder="config.placeholder || placeholder(config)"
70
+ v-bind="config.props"
71
+ v-on="config.listeners"
72
+ @change="change"
73
+ >
74
+ <template v-if="config.component === 'el-checkbox-group'">
75
+ <el-checkbox
76
+ v-for="(checkbox, checkboxIndex) in config.options"
77
+ :key="checkboxIndex"
78
+ :label="checkbox.value"
79
+ >
80
+ {{ checkbox.label }}
81
+ </el-checkbox>
82
+ </template>
83
+
84
+ <template v-if="config.component === 'el-select'">
85
+ <el-option
86
+ v-for="(option, optionIndex) in config.options"
87
+ :key="optionIndex"
88
+ :label="option.label"
89
+ :value="option.value"
90
+ :disabled="!!option.disabled"
91
+ />
92
+ </template>
93
+ <span
94
+ v-if="config.suffix"
95
+ class="ml6"
96
+ >{{ config.suffix }}</span>
97
+ </component>
98
+ </div>
99
+ </div>
100
+ </template>
101
+
102
+ <script>
103
+ export default {
104
+ name: 'DFormItem',
105
+ components: {},
106
+ model: {
107
+ prop: 'modelValue',
108
+ event: 'change'
109
+ },
110
+ props: {
111
+ config: {
112
+ require: true,
113
+ type: Object,
114
+ default: () => {}
115
+ },
116
+ modelValue: {
117
+ type: [Number, String, Boolean, Object, Array],
118
+ default: ''
119
+ }
120
+ },
121
+ data () {
122
+ return {}
123
+ },
124
+ computed: {
125
+ value: {
126
+ get () {
127
+ return this.modelValue
128
+ },
129
+ set (value) {
130
+ this.$emit('change', value)
131
+ }
132
+ },
133
+ clearable () {
134
+ return (config) => {
135
+ // 优先取配置项clearable
136
+ if (config.clearable !== undefined) {
137
+ return !!config.clearable
138
+ } else {
139
+ return true
140
+ }
141
+ }
142
+ },
143
+ maxlength () {
144
+ return (config) => {
145
+ if (config.component === 'el-input') {
146
+ if (config.props && config.props.type === 'textarea') {
147
+ return 500
148
+ } else {
149
+ return 50
150
+ }
151
+ } else {
152
+ return 99999
153
+ }
154
+ }
155
+ },
156
+ placeholder () {
157
+ return ({ component, label }) => {
158
+ // 默认给组件添加placeholder,可自定义
159
+ if (component === 'el-input' || component === 'el-input-number') {
160
+ return `请输入${label}`
161
+ } else {
162
+ return `请选择${label}`
163
+ }
164
+ }
165
+ }
166
+ },
167
+ methods: {
168
+ /**
169
+ * @description: 普通选择器和级联选择器输出勾选Item节点数据
170
+ * @param {*} value
171
+ * @return {*} data: 输出结构和value数据结构一致,对应value中的节点data
172
+ */
173
+ change (value) {
174
+ if (this.config.onChange) {
175
+ let data = null
176
+
177
+ // 处理级联选择器
178
+ if (this.config.component === 'el-cascader') {
179
+ this.$nextTick(() => {
180
+ // el-cascader搜索勾选bug,需要nextTick后才能正常使用getCheckedNodes
181
+ data = this.$refs[this.config.key].getCheckedNodes()
182
+ const emitPath = (this.config.props && this.config.props.props && this.config.props.props.emitPath !== undefined) ? this.config.props.props.emitPath : true
183
+ const multiple = this.config.props && this.config.props.props && this.config.props.props.multiple
184
+ if (emitPath) {
185
+ if (multiple) {
186
+ data = value.map(arr => data.find(node => arr[arr.length - 1] === node.value).pathNodes)
187
+ } else {
188
+ data = data[data.length - 1].pathNodes
189
+ }
190
+ } else {
191
+ if (multiple) {
192
+ data = value.map(item => data.find(node => item === node.value))
193
+ } else {
194
+ data = data[data.length - 1]
195
+ }
196
+ }
197
+ this.config.onChange(value, data)
198
+ })
199
+ }
200
+
201
+ // 处理下拉选择器
202
+ if (this.config.component === 'el-select') {
203
+ data = this.config.options
204
+ if (Array.isArray(value)) {
205
+ data = data.filter(i => value.includes(i.value)) || []
206
+ } else {
207
+ data = data.find(i => value === i.value) || {}
208
+ }
209
+ }
210
+ this.config.onChange(value, data)
211
+ }
212
+ }
213
+ }
214
+ }
215
+ </script>