@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,166 @@
1
+ <template>
2
+ <d-dialog
3
+ v-model="visible"
4
+ form-refs="importForm"
5
+ :width="width"
6
+ :title="title"
7
+ submit-btn-text="导入"
8
+ submit-btn-icon="el-icon-upload2"
9
+ @submit="submit"
10
+ >
11
+ <el-form
12
+ ref="importForm"
13
+ :model="form"
14
+ :inline="true"
15
+ >
16
+ <el-form-item
17
+ class="import-form-item"
18
+ prop="file"
19
+ label="选择文件"
20
+ :rules="[
21
+ { required: true, message: '请选择文件' }
22
+ ]"
23
+ >
24
+ <div class="custom-file-input">
25
+ <div class="custom-file-content">
26
+ {{ form.file ? form.file.name : '请选择' }}
27
+ </div>
28
+ <el-upload
29
+ :file-list="fileList"
30
+ :show-file-list="false"
31
+ :auto-upload="false"
32
+ action=""
33
+ :on-change="uploadChange"
34
+ >
35
+ <el-button
36
+ type="primary"
37
+ icon="el-icon-folder"
38
+ />
39
+ </el-upload>
40
+ </div>
41
+ </el-form-item>
42
+ <el-button
43
+ icon="el-icon-paperclip"
44
+ type="text"
45
+ @click="downloadFile"
46
+ >
47
+ 模板下载
48
+ </el-button>
49
+ </el-form>
50
+ <slot>
51
+ <p>1. 支持导入格式为xlsx、xls的文件,且文件大小不可超过5M</p>
52
+ <p>2. 模板的表头不可更改,不可删除</p>
53
+ <p>3. 若导入数据存在编码一致的情况则会更新原有数据</p>
54
+ <p>4. 若导入过程中有问题,需调整模板内容后再重新导入</p>
55
+ </slot>
56
+ </d-dialog>
57
+ </template>
58
+
59
+ <script>
60
+ import DDialog from '../dialog'
61
+
62
+ export default {
63
+ name: 'DImportFile',
64
+ components: { DDialog },
65
+ model: {
66
+ prop: 'modelValue',
67
+ event: 'change'
68
+ },
69
+ props: {
70
+ modelValue: {
71
+ default: false,
72
+ type: Boolean
73
+ },
74
+ width: {
75
+ default: '520px',
76
+ type: String
77
+ },
78
+ title: {
79
+ default: '',
80
+ type: String
81
+ },
82
+ templateUrl: {
83
+ default: '',
84
+ type: String
85
+ },
86
+ fileType: {
87
+ default: () => ['xlsx', 'xls'],
88
+ type: Array
89
+ },
90
+ fileSize: {
91
+ default: 5,
92
+ type: Number
93
+ }
94
+ },
95
+ data () {
96
+ return {
97
+ fileList: [],
98
+ form: {
99
+ file: ''
100
+ }
101
+ }
102
+ },
103
+ computed: {
104
+ visible: {
105
+ get () {
106
+ return this.modelValue
107
+ },
108
+ set (value) {
109
+ this.form.file = ''
110
+ this.fileList = []
111
+ this.$refs.importForm.clearValidate()
112
+ this.$emit('change', value)
113
+ }
114
+ }
115
+ },
116
+ methods: {
117
+ downloadFile () {
118
+ window.location.href = `${process.env.NODE_ENV === 'development' ? 'http://121.40.125.185:19999' : ''}${this.templateUrl}?authToken=${this.$store.getters.token}`
119
+ },
120
+ uploadChange (file, fileList) {
121
+ const isLimit = file.size / 1024 / 1024 < this.fileSize
122
+ const isType = this.fileType.includes(file.name.substr(file.name.lastIndexOf('.') + 1).toLocaleLowerCase())
123
+ if (!isType) {
124
+ this.$message.error(`请上传正确的文件格式(${this.fileType.join('、')})`)
125
+ return false
126
+ }
127
+ if (!isLimit) {
128
+ this.$message.error(`上传文件大小不能超过${this.fileSize}MB`)
129
+ return false
130
+ }
131
+ this.fileList = fileList
132
+ this.form.file = file.raw
133
+ },
134
+ async submit (callback) {
135
+ if (!this.form.file) {
136
+ this.$message.error('请选择导入文件')
137
+ callback(new Error(false))
138
+ return
139
+ }
140
+ try {
141
+ this.$emit('submit', this.form.file, callback)
142
+ } catch (e) {
143
+ callback(new Error(false))
144
+ }
145
+ }
146
+ }
147
+ }
148
+ </script>
149
+
150
+ <style lang="scss" scoped>
151
+ .custom-file-input {
152
+ display: flex;
153
+ width: 230px;
154
+ .custom-file-content {
155
+ width: 100%;
156
+ height: 32px;
157
+ border: 1px solid #dcdfe6;
158
+ border-right: none;
159
+ border-radius: 2px 0 0 2px;
160
+ padding: 0 8px;
161
+ white-space: nowrap;
162
+ overflow: hidden;
163
+ text-overflow: ellipsis;
164
+ }
165
+ }
166
+ </style>
@@ -0,0 +1,66 @@
1
+ <!-- 菜单 -->
2
+ <template>
3
+ <el-menu
4
+ class="d-menu"
5
+ :default-active="isVertical ? $route.path : activeMenu"
6
+ :router="isVertical"
7
+ unique-opened
8
+ :mode="mode"
9
+ @select="menuSelect">
10
+ <menu-item v-for="item in data" :key="item.name" :data="item" :mode="mode"></menu-item>
11
+ </el-menu>
12
+ </template>
13
+
14
+ <script>
15
+ import MenuItem from './menuItem.vue'
16
+ export default {
17
+ name: 'DMenu',
18
+ components: { MenuItem },
19
+ props: {
20
+ data: {
21
+ type: Array,
22
+ default: () => []
23
+ },
24
+ mode: {
25
+ type: String,
26
+ default: 'vertical'
27
+ }
28
+ },
29
+ data () {
30
+ return {
31
+ activeMenu: ''
32
+ }
33
+ },
34
+ computed: {
35
+ isVertical () {
36
+ return this.mode === 'vertical'
37
+ }
38
+ },
39
+ watch: {
40
+ '$route.path': {
41
+ handler (path) {
42
+ if (!this.isVertical) {
43
+ if (this.activeMenu && path.substring(0, this.activeMenu.length) === this.activeMenu) return
44
+ const data = this.data.find(item => path.substring(0, item.path.length) === item.path)
45
+ this.activeMenu = data?.path
46
+ this.$emit('select', data, false)
47
+ }
48
+ },
49
+ immediate: true
50
+ }
51
+ },
52
+ methods: {
53
+ menuSelect (index) {
54
+ if (this.isVertical) return
55
+ const data = this.data.find(item => item.path === index)
56
+ this.$emit('select', data, true)
57
+ }
58
+ }
59
+ }
60
+ </script>
61
+
62
+ <style lang='scss' scoped>
63
+ .d-menu {
64
+ height: 100%;
65
+ }
66
+ </style>
@@ -0,0 +1,78 @@
1
+ <!-- 菜单子项 -->
2
+ <template>
3
+ <el-submenu
4
+ v-if="mode === 'vertical' && data.children && data.children.length"
5
+ :index="data.path"
6
+ >
7
+ <template slot="title">
8
+ <img
9
+ v-if="data.meta.icon"
10
+ class="mr8 menu-icon"
11
+ :src="data.meta.icon"
12
+ >
13
+ <span>{{ data.meta.title }}</span>
14
+ </template>
15
+ <menu-item
16
+ v-for="item in data.children"
17
+ :key="item.name"
18
+ :data="item"
19
+ />
20
+ </el-submenu>
21
+ <el-menu-item
22
+ v-else
23
+ :index="data.path"
24
+ >
25
+ <template slot="title">
26
+ <div
27
+ v-if="data.meta.icon"
28
+ class="menu-icon-box"
29
+ >
30
+ <img
31
+ class="menu-icon"
32
+ :src="data.meta.icon"
33
+ >
34
+ </div>
35
+ <span class="ml6 ellipsis flex-1">{{ data.meta.title }}</span>
36
+ </template>
37
+ </el-menu-item>
38
+ </template>
39
+
40
+ <script>
41
+ export default {
42
+ name: 'MenuItem',
43
+ components: {},
44
+ props: {
45
+ data: {
46
+ type: Object,
47
+ default: () => ({})
48
+ },
49
+ mode: {
50
+ type: String,
51
+ default: 'vertical'
52
+ }
53
+ },
54
+ data () {
55
+ return {
56
+ }
57
+ },
58
+ computed: {},
59
+ created () {},
60
+ methods: {}
61
+ }
62
+ </script>
63
+
64
+ <style lang='scss' scoped>
65
+ .menu-icon-box {
66
+ width: 26px;
67
+ height: 26px;
68
+ border-radius: 50%;
69
+ background-color: #fff;
70
+ display: flex;
71
+ align-items: center;
72
+ justify-content: center;
73
+ }
74
+ .menu-icon {
75
+ width: 16px;
76
+ height: 16px;
77
+ }
78
+ </style>
@@ -0,0 +1,39 @@
1
+ <!-- 二次确认气泡 -->
2
+ <template>
3
+ <el-popconfirm
4
+ :title="title"
5
+ cancel-button-type=""
6
+ icon="el-icon-warning"
7
+ @confirm="confirm"
8
+ >
9
+ <span slot="reference" :class="`${type}-text-btn`">{{ buttonName }}</span>
10
+ </el-popconfirm>
11
+ </template>
12
+
13
+ <script>
14
+ export default {
15
+ name: 'DPopconfirm',
16
+ props: {
17
+ title: {
18
+ default: '您确定删除该信息?',
19
+ type: String
20
+ },
21
+ buttonName: {
22
+ default: '删除',
23
+ type: String
24
+ },
25
+ type: {
26
+ default: 'primary',
27
+ type: String
28
+ }
29
+ },
30
+ data () {
31
+ return {}
32
+ },
33
+ methods: {
34
+ confirm () {
35
+ this.$emit('confirm')
36
+ }
37
+ }
38
+ }
39
+ </script>
@@ -0,0 +1,14 @@
1
+ <!-- eslint-disable vue/require-default-prop -->
2
+ <script>
3
+ export default {
4
+ name: 'DRender',
5
+ functional: true,
6
+ props: {
7
+ scope: Object,
8
+ render: Function
9
+ },
10
+ render: (h, ctx) => {
11
+ return ctx.props.render ? ctx.props.render(ctx.props.scope, h) : ''
12
+ }
13
+ }
14
+ </script>
@@ -0,0 +1,257 @@
1
+ <!-- 搜索组件 -->
2
+ <template>
3
+ <div class="d-search-form">
4
+ <el-row class="flex-wrap" :gutter="gutter">
5
+ <el-col
6
+ v-for="(item, index) in list"
7
+ v-show="showCol(index)"
8
+ :key="item.key"
9
+ :span="item.span || Math.floor(24 / cell)"
10
+ class="col-item"
11
+ >
12
+ <div class="search-item">
13
+ <div class="search-item-label">
14
+ {{ item.label }}
15
+ </div>
16
+ <form-item v-model="form[item.key]" :config="item" />
17
+ </div>
18
+ </el-col>
19
+ <el-col :span="hiddenIndex === list.length || expend ? emptySpan : 0" style="height: 68px;">
20
+ <span />
21
+ </el-col>
22
+ <el-col v-if="hasSlot && expend && !suffixSlot" :span="24 - submitSpan" class="mb16">
23
+ <slot />
24
+ </el-col>
25
+ <el-col :span="submitSpan">
26
+ <div
27
+ :style="{
28
+ 'margin-top': hasSlot && expend && !suffixSlot ? '0px' : '20px'
29
+ }"
30
+ class="d-search-form-btn"
31
+ >
32
+ <el-button type="primary" :disabled="searchLoading" @click="search">
33
+ 查询
34
+ </el-button>
35
+ <el-button :disabled="searchLoading" @click="reset">
36
+ 重置
37
+ </el-button>
38
+ <el-button
39
+ v-if="list.length > hiddenIndex"
40
+ class="expend-btn"
41
+ :class="`el-icon-arrow-${expend ? 'up' : 'down'}`"
42
+ @click="changeStatus"
43
+ />
44
+ </div>
45
+ </el-col>
46
+ <el-col v-if="hasSlot && (!expend || suffixSlot)" :span="20" class="mb16">
47
+ <slot />
48
+ </el-col>
49
+ </el-row>
50
+ </div>
51
+ </template>
52
+
53
+ <script>
54
+ import FormItem from '../form-item'
55
+ import { cloneDeep } from 'lodash'
56
+
57
+ // 初始化表单
58
+ let initForm = {}
59
+
60
+ export default {
61
+ name: 'DSearchForm',
62
+ components: {
63
+ FormItem
64
+ },
65
+ model: {
66
+ prop: 'value',
67
+ event: 'change'
68
+ },
69
+ props: {
70
+ config: {
71
+ require: true,
72
+ default: () => [],
73
+ type: Array
74
+ },
75
+ cell: {
76
+ default: 6,
77
+ type: Number
78
+ },
79
+ gutter: {
80
+ default: 16,
81
+ type: Number
82
+ },
83
+ value: {
84
+ default: () => {},
85
+ type: Object
86
+ },
87
+ searchData: {
88
+ default: null,
89
+ type: Function
90
+ },
91
+ buttonSpan: {
92
+ default: 0,
93
+ type: Number
94
+ }
95
+ },
96
+ data () {
97
+ return {
98
+ list: [],
99
+ hiddenIndex: 0,
100
+ emptySpan: 0,
101
+ expend: false,
102
+ searchLoading: false,
103
+ // 判断是否有插槽节点,目前只在组件初始化完成时判断
104
+ hasSlot: false,
105
+ suffixSlot: true
106
+ }
107
+ },
108
+ computed: {
109
+ form: {
110
+ get () {
111
+ return this.value
112
+ },
113
+ set (value) {
114
+ this.$emit('change', value)
115
+ }
116
+ },
117
+ submitSpan () {
118
+ return this.buttonSpan || 24 / this.cell
119
+ },
120
+ spanList () {
121
+ return this.list.map(item => item.span || Math.floor(24 / this.cell)) || []
122
+ },
123
+ showCol () {
124
+ return (index) => {
125
+ return this.expend || index < this.hiddenIndex
126
+ }
127
+ }
128
+ },
129
+ watch: {
130
+ config: {
131
+ handler () {
132
+ this.list = this.config.filter(item => !item.hidden)
133
+ },
134
+ deep: true,
135
+ immediate: true
136
+ },
137
+ spanList: {
138
+ handler (val, oldVal) {
139
+ if (!val.length || JSON.stringify(val) === JSON.stringify(oldVal)) {
140
+ return
141
+ }
142
+ this.calcSpan()
143
+ },
144
+ deep: true,
145
+ immediate: true
146
+ }
147
+ },
148
+ created () {
149
+ initForm = cloneDeep(this.value)
150
+ this.$nextTick(() => {
151
+ this.hasSlot = !!(this.$slots.default && this.$slots.default.length)
152
+ this.calcSpan()
153
+ })
154
+ },
155
+ methods: {
156
+ /**
157
+ * @description: 查询
158
+ */
159
+ async search () {
160
+ this.$emit('search')
161
+ if (this.searchData) {
162
+ try {
163
+ this.searchLoading = true
164
+ await this.searchData({ pageNum: 1 }, this.form)
165
+ this.searchLoading = false
166
+ } catch (e) {
167
+ this.searchLoading = false
168
+ }
169
+ }
170
+ },
171
+ /**
172
+ * @description: 重置
173
+ */
174
+ async reset () {
175
+ this.form = cloneDeep(initForm)
176
+ this.$emit('search')
177
+ if (this.searchData) {
178
+ this.resetLoading = true
179
+ await this.searchData({ pageNum: 1 }, this.form)
180
+ this.resetLoading = false
181
+ }
182
+ },
183
+ /**
184
+ * @description: 展开/收起
185
+ */
186
+ changeStatus () {
187
+ this.expend = !this.expend
188
+ this.$emit('expand-change', this.expend)
189
+ },
190
+ calcSpan () {
191
+ let hiddenIndex = 1
192
+ const total = this.spanList.length ? this.spanList.reduce((a, b, index) => {
193
+ const sum = a + b
194
+ if (hiddenIndex < 2) {
195
+ if (24 - sum < this.submitSpan) {
196
+ hiddenIndex = index
197
+ }
198
+ if (24 - sum >= this.submitSpan && index === this.spanList.length - 1) {
199
+ hiddenIndex = index + 1
200
+ }
201
+ }
202
+ return sum
203
+ }) : 0
204
+ this.hiddenIndex = hiddenIndex
205
+
206
+ const offsetSpan = 24 - total % 24
207
+ if (this.hasSlot) {
208
+ if (offsetSpan < this.submitSpan || offsetSpan === 24) {
209
+ this.suffixSlot = false
210
+ this.emptySpan = 0
211
+ } else {
212
+ this.suffixSlot = true
213
+ this.emptySpan = offsetSpan >= this.submitSpan ? offsetSpan - this.submitSpan : 24 - this.submitSpan
214
+ }
215
+ } else {
216
+ this.emptySpan = offsetSpan >= this.submitSpan ? offsetSpan - this.submitSpan : 24 - this.submitSpan
217
+ }
218
+ }
219
+ }
220
+ }
221
+ </script>
222
+
223
+ <style lang="scss" scoped>
224
+ .d-search-form {
225
+ margin-bottom: 4px;
226
+ .col-item {
227
+ align-items: end;
228
+ }
229
+ .el-select {
230
+ width: 100%;
231
+ .el-input_inner {
232
+ height: 32px;
233
+ }
234
+ }
235
+ &-btn {
236
+ text-align: right;
237
+ margin-bottom: 16px;
238
+ }
239
+ &-overflow {
240
+ margin-top: 24px;
241
+ }
242
+ .expend-btn {
243
+ padding: 8px 8px;
244
+ }
245
+ }
246
+ .search-item {
247
+ margin-bottom: 12px;
248
+ &-label {
249
+ margin-bottom: 4px;
250
+ font-weight: 400;
251
+ color: #333333;
252
+ }
253
+ :deep(.el-input__inner) {
254
+ height: 32px !important;
255
+ }
256
+ }
257
+ </style>
@@ -0,0 +1,68 @@
1
+ <!-- 查询输入框组件 -->
2
+ <template>
3
+ <div class="d-search-input">
4
+ <slot><div /></slot>
5
+ <div>
6
+ <el-input
7
+ v-model="value"
8
+ class="search-input-container"
9
+ :placeholder="placeholder"
10
+ :clearable="clearable"
11
+ @keyup.enter.native="$emit('search', value)"
12
+ >
13
+ <i slot="suffix" class="el-input__icon el-icon-search pointer" @click="$emit('search', value)" />
14
+ </el-input>
15
+ </div>
16
+ </div>
17
+ </template>
18
+
19
+ <script>
20
+ export default {
21
+ name: 'DSearchInput',
22
+ components: {},
23
+ model: {
24
+ prop: 'modelValue',
25
+ event: 'change'
26
+ },
27
+ props: {
28
+ modelValue: {
29
+ type: String,
30
+ default: ''
31
+ },
32
+ placeholder: {
33
+ type: String,
34
+ default: '请输入查询内容'
35
+ },
36
+ clearable: {
37
+ type: Boolean,
38
+ default: true
39
+ }
40
+ },
41
+ data () {
42
+ return {}
43
+ },
44
+ computed: {
45
+ value: {
46
+ get () {
47
+ return this.modelValue
48
+ },
49
+ set (value) {
50
+ this.$emit('change', value)
51
+ }
52
+ }
53
+ },
54
+ watch: {},
55
+ created () {},
56
+ methods: {}
57
+ }
58
+ </script>
59
+
60
+ <style lang='scss' scoped>
61
+ .d-search-input {
62
+ display: flex;
63
+ justify-content: space-between;
64
+ .search-input-container {
65
+ width: 320px;
66
+ }
67
+ }
68
+ </style>