afn-basic-components 1.0.0 → 1.1.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/README.md +18 -9
- package/package.json +1 -1
- package/src/components/GlobalDrawer/index.vue +249 -0
- package/src/components/MessagePopUp/index.vue +220 -0
- package/src/components/ProTable/index.vue +352 -0
- package/src/index.js +50 -0
- package/src/styles/sidebar.scss +8 -6
- package/src/styles/variables.scss +5 -0
package/README.md
CHANGED
|
@@ -15,26 +15,26 @@ npm install afn-basic-components
|
|
|
15
15
|
在 main.js 中引入:
|
|
16
16
|
|
|
17
17
|
```javascript
|
|
18
|
-
import Vue from
|
|
19
|
-
import AfnBasicComponents from
|
|
20
|
-
import
|
|
18
|
+
import Vue from "vue";
|
|
19
|
+
import AfnBasicComponents from "afn-basic-components";
|
|
20
|
+
import "afn-basic-components/styles/index.scss";
|
|
21
21
|
|
|
22
|
-
Vue.use(AfnBasicComponents)
|
|
22
|
+
Vue.use(AfnBasicComponents);
|
|
23
23
|
```
|
|
24
24
|
|
|
25
25
|
### 按需引入
|
|
26
26
|
|
|
27
27
|
```javascript
|
|
28
|
-
import { GlobalDrawer, MessagePopUp, ProTable } from
|
|
29
|
-
import
|
|
28
|
+
import { GlobalDrawer, MessagePopUp, ProTable } from "afn-basic-components";
|
|
29
|
+
import "afn-basic-components/styles/index.scss";
|
|
30
30
|
|
|
31
31
|
export default {
|
|
32
32
|
components: {
|
|
33
33
|
GlobalDrawer,
|
|
34
34
|
MessagePopUp,
|
|
35
|
-
ProTable
|
|
36
|
-
}
|
|
37
|
-
}
|
|
35
|
+
ProTable,
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
38
|
```
|
|
39
39
|
|
|
40
40
|
## 📚 组件列表
|
|
@@ -44,6 +44,7 @@ export default {
|
|
|
44
44
|
一个功能强大的抽屉组件,支持标题、内容、宽度、方向等配置。
|
|
45
45
|
|
|
46
46
|
**Props:**
|
|
47
|
+
|
|
47
48
|
- `visible` (Boolean) - 是否显示抽屉,默认 false
|
|
48
49
|
- `title` (String) - 抽屉标题
|
|
49
50
|
- `width` (String) - 抽屉宽度,默认 '50%'
|
|
@@ -51,10 +52,12 @@ export default {
|
|
|
51
52
|
- `beforeClose` (Function) - 关闭前的回调函数
|
|
52
53
|
|
|
53
54
|
**Events:**
|
|
55
|
+
|
|
54
56
|
- `close` - 抽屉关闭时触发
|
|
55
57
|
- `open` - 抽屉打开时触发
|
|
56
58
|
|
|
57
59
|
**示例:**
|
|
60
|
+
|
|
58
61
|
```vue
|
|
59
62
|
<global-drawer
|
|
60
63
|
:visible.sync="drawerVisible"
|
|
@@ -71,6 +74,7 @@ export default {
|
|
|
71
74
|
一个美观的消息提示组件,支持多种类型和配置。
|
|
72
75
|
|
|
73
76
|
**Props:**
|
|
77
|
+
|
|
74
78
|
- `visible` (Boolean) - 是否显示弹窗,默认 false
|
|
75
79
|
- `type` (String) - 消息类型,可选 'success' | 'warning' | 'info' | 'error',默认 'info'
|
|
76
80
|
- `title` (String) - 弹窗标题
|
|
@@ -79,9 +83,11 @@ export default {
|
|
|
79
83
|
- `showClose` (Boolean) - 是否显示关闭按钮,默认 true
|
|
80
84
|
|
|
81
85
|
**Events:**
|
|
86
|
+
|
|
82
87
|
- `close` - 弹窗关闭时触发
|
|
83
88
|
|
|
84
89
|
**示例:**
|
|
90
|
+
|
|
85
91
|
```vue
|
|
86
92
|
<message-pop-up
|
|
87
93
|
:visible.sync="messageVisible"
|
|
@@ -97,6 +103,7 @@ export default {
|
|
|
97
103
|
一个功能强大的表格组件,支持搜索、分页、排序等功能。
|
|
98
104
|
|
|
99
105
|
**Props:**
|
|
106
|
+
|
|
100
107
|
- `tableData` (Array) - 表格数据
|
|
101
108
|
- `columns` (Array) - 表格列配置
|
|
102
109
|
- `loading` (Boolean) - 是否加载中,默认 false
|
|
@@ -105,12 +112,14 @@ export default {
|
|
|
105
112
|
- `showPagination` (Boolean) - 是否显示分页,默认 true
|
|
106
113
|
|
|
107
114
|
**Events:**
|
|
115
|
+
|
|
108
116
|
- `search` - 搜索时触发
|
|
109
117
|
- `reset` - 重置时触发
|
|
110
118
|
- `page-change` - 页码变化时触发
|
|
111
119
|
- `size-change` - 每页条数变化时触发
|
|
112
120
|
|
|
113
121
|
**示例:**
|
|
122
|
+
|
|
114
123
|
```vue
|
|
115
124
|
<pro-table
|
|
116
125
|
:table-data="tableData"
|
package/package.json
CHANGED
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<el-drawer
|
|
3
|
+
:title="title"
|
|
4
|
+
:visible.sync="visible"
|
|
5
|
+
direction="rtl"
|
|
6
|
+
:size="computedWidth"
|
|
7
|
+
class="global-drawer"
|
|
8
|
+
:wrapper-closable="!showCancel"
|
|
9
|
+
:modal-click-close="false"
|
|
10
|
+
>
|
|
11
|
+
<!-- 头部 -->
|
|
12
|
+
<div class="drawer-header" :style="{ width: computedWidth }">
|
|
13
|
+
<span class="title">{{ title }}</span>
|
|
14
|
+
<!-- <i class="el-icon-close close-btn" @click="close" /> -->
|
|
15
|
+
<svg-icon
|
|
16
|
+
icon-class="simulation-close"
|
|
17
|
+
class="el-icon-close close-btn"
|
|
18
|
+
@click="close"
|
|
19
|
+
style="width: 32px; height: 32px; cursor: pointer"
|
|
20
|
+
/>
|
|
21
|
+
</div>
|
|
22
|
+
|
|
23
|
+
<!-- 内容区域 -->
|
|
24
|
+
<div class="drawer-content">
|
|
25
|
+
<slot></slot>
|
|
26
|
+
</div>
|
|
27
|
+
|
|
28
|
+
<!-- 底部 -->
|
|
29
|
+
<div class="drawer-footer" :style="{ width: computedWidth }">
|
|
30
|
+
<el-button
|
|
31
|
+
v-if="showCancel"
|
|
32
|
+
class="cancel-btn"
|
|
33
|
+
style="background-color: #f2f2f2; color: #333; font-weight: medium"
|
|
34
|
+
@click="handleCancel"
|
|
35
|
+
>{{ cancelText }}</el-button
|
|
36
|
+
>
|
|
37
|
+
<el-button type="primary" @click="handleConfirm">{{
|
|
38
|
+
computedConfirmText
|
|
39
|
+
}}</el-button>
|
|
40
|
+
</div>
|
|
41
|
+
</el-drawer>
|
|
42
|
+
</template>
|
|
43
|
+
|
|
44
|
+
<script>
|
|
45
|
+
export default {
|
|
46
|
+
name: 'GlobalDrawer',
|
|
47
|
+
props: {
|
|
48
|
+
title: {
|
|
49
|
+
type: String,
|
|
50
|
+
default: '标题'
|
|
51
|
+
},
|
|
52
|
+
visible: {
|
|
53
|
+
type: Boolean,
|
|
54
|
+
required: true
|
|
55
|
+
},
|
|
56
|
+
size: {
|
|
57
|
+
type: [String, Number], // 支持字符串和数字类型
|
|
58
|
+
default: '600px'
|
|
59
|
+
},
|
|
60
|
+
cancelText: {
|
|
61
|
+
type: String,
|
|
62
|
+
default: '取消'
|
|
63
|
+
},
|
|
64
|
+
confirmText: {
|
|
65
|
+
type: String,
|
|
66
|
+
default: null
|
|
67
|
+
},
|
|
68
|
+
showCancel: {
|
|
69
|
+
type: Boolean,
|
|
70
|
+
default: true
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
data() {
|
|
74
|
+
return {
|
|
75
|
+
// 移除设备类型判断,改为使用媒体查询
|
|
76
|
+
}
|
|
77
|
+
},
|
|
78
|
+
computed: {
|
|
79
|
+
computedWidth() {
|
|
80
|
+
// 直接返回size属性,不再根据设备类型判断
|
|
81
|
+
return typeof this.size === 'number' ? `${this.size}px` : this.size
|
|
82
|
+
},
|
|
83
|
+
computedConfirmText() {
|
|
84
|
+
// 如果传入了confirmText,使用传入的值
|
|
85
|
+
if (this.confirmText) {
|
|
86
|
+
return this.confirmText
|
|
87
|
+
}
|
|
88
|
+
// 否则根据showCancel的值返回默认文本
|
|
89
|
+
return this.showCancel ? '确定' : '关闭'
|
|
90
|
+
}
|
|
91
|
+
},
|
|
92
|
+
methods: {
|
|
93
|
+
close() {
|
|
94
|
+
this.$emit('update:visible', false)
|
|
95
|
+
this.$emit('cancel')
|
|
96
|
+
},
|
|
97
|
+
// 防抖函数 - 支持立即执行模式
|
|
98
|
+
debounce(fn, delay = 300, immediate = true) {
|
|
99
|
+
if (this._debounceTimer) {
|
|
100
|
+
clearTimeout(this._debounceTimer)
|
|
101
|
+
this._debounceTimer = null
|
|
102
|
+
return // 如果在延迟期间再次调用,直接返回不执行
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
if (immediate) {
|
|
106
|
+
// 立即执行模式:第一次调用立即执行
|
|
107
|
+
fn()
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// 设置延迟期间
|
|
111
|
+
this._debounceTimer = setTimeout(() => {
|
|
112
|
+
this._debounceTimer = null
|
|
113
|
+
}, delay)
|
|
114
|
+
},
|
|
115
|
+
// 添加防抖处理的确认方法
|
|
116
|
+
handleConfirm() {
|
|
117
|
+
this.debounce(
|
|
118
|
+
() => {
|
|
119
|
+
this.$emit('confirm')
|
|
120
|
+
},
|
|
121
|
+
300,
|
|
122
|
+
true
|
|
123
|
+
)
|
|
124
|
+
},
|
|
125
|
+
handleCancel() {
|
|
126
|
+
this.$emit('cancel')
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
</script>
|
|
131
|
+
|
|
132
|
+
<style scoped lang="scss">
|
|
133
|
+
.global-drawer {
|
|
134
|
+
--header-height: 70px;
|
|
135
|
+
--footer-height: 70px;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
.drawer-header {
|
|
139
|
+
position: fixed;
|
|
140
|
+
top: 0;
|
|
141
|
+
right: 0;
|
|
142
|
+
height: var(--header-height);
|
|
143
|
+
display: flex;
|
|
144
|
+
align-items: center;
|
|
145
|
+
justify-content: space-between;
|
|
146
|
+
padding: 0 24px;
|
|
147
|
+
border-bottom: 1px solid #f2f2f2;
|
|
148
|
+
background: white;
|
|
149
|
+
z-index: 2000;
|
|
150
|
+
}
|
|
151
|
+
.title {
|
|
152
|
+
text-align: center;
|
|
153
|
+
color: #333;
|
|
154
|
+
margin: 0;
|
|
155
|
+
font-family: PingFangSC, PingFang SC;
|
|
156
|
+
font-weight: 500;
|
|
157
|
+
font-size: 16px;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
.drawer-content {
|
|
161
|
+
height: calc(100vh - var(--header-height) - var(--footer-height));
|
|
162
|
+
overflow-y: auto;
|
|
163
|
+
padding: 30px 24px;
|
|
164
|
+
color: #333;
|
|
165
|
+
font-family: PingFangSC, PingFang SC;
|
|
166
|
+
font-size: 16px;
|
|
167
|
+
/* 换行显示 */
|
|
168
|
+
::v-deep .el-form-item {
|
|
169
|
+
width: 100% !important;
|
|
170
|
+
display: block !important;
|
|
171
|
+
|
|
172
|
+
&__label {
|
|
173
|
+
display: block !important;
|
|
174
|
+
width: 100% !important;
|
|
175
|
+
text-align: left;
|
|
176
|
+
font-size: 14px;
|
|
177
|
+
line-height: 16px;
|
|
178
|
+
margin-bottom: 8px;
|
|
179
|
+
font-family: PingFangSC, PingFang SC;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
&__content {
|
|
183
|
+
margin-left: 0 !important;
|
|
184
|
+
width: 100% !important;
|
|
185
|
+
display: block !important;
|
|
186
|
+
font-family: PingFangSC, PingFang SC;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/* 必填星号换到后面 */
|
|
191
|
+
::v-deep .el-form-item.is-required:not(.is-no-asterisk) {
|
|
192
|
+
.el-form-item__label {
|
|
193
|
+
&::before {
|
|
194
|
+
content: none !important;
|
|
195
|
+
}
|
|
196
|
+
&::after {
|
|
197
|
+
content: '•' !important;
|
|
198
|
+
color: #f56c6c !important;
|
|
199
|
+
margin-left: 4px !important;
|
|
200
|
+
display: inline !important;
|
|
201
|
+
/* vertical-align: middle; */
|
|
202
|
+
line-height: 1;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
.drawer-footer {
|
|
209
|
+
position: fixed;
|
|
210
|
+
bottom: 0;
|
|
211
|
+
right: 0;
|
|
212
|
+
height: var(--footer-height);
|
|
213
|
+
display: flex;
|
|
214
|
+
align-items: center;
|
|
215
|
+
justify-content: flex-end;
|
|
216
|
+
padding: 0 24px;
|
|
217
|
+
border-top: 1px solid #f2f2f2;
|
|
218
|
+
background: white;
|
|
219
|
+
z-index: 2000;
|
|
220
|
+
color: #333;
|
|
221
|
+
font-family: PingFangSC, PingFang SC;
|
|
222
|
+
.el-button {
|
|
223
|
+
font-family: PingFangSC, PingFang SC;
|
|
224
|
+
border: none;
|
|
225
|
+
font-weight: 500;
|
|
226
|
+
font-size: 14px;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
.cancel-btn:hover {
|
|
230
|
+
color: #4a7ff8 !important;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// 使用媒体查询实现移动端适配
|
|
235
|
+
@media (max-width: 768px) {
|
|
236
|
+
::v-deep .el-drawer {
|
|
237
|
+
width: 100% !important;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
.drawer-header,
|
|
241
|
+
.drawer-footer {
|
|
242
|
+
width: 100% !important;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
.drawer-content {
|
|
246
|
+
padding: 20px 16px;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
</style>
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<el-dialog
|
|
3
|
+
:visible.sync="visible"
|
|
4
|
+
:width="width"
|
|
5
|
+
:custom-class="'custom-dialog ' + type"
|
|
6
|
+
:close-on-click-modal="!closeOnModalClick"
|
|
7
|
+
:show-close="!closeOnModalClick"
|
|
8
|
+
@close="handleCancel"
|
|
9
|
+
>
|
|
10
|
+
<!-- 标题区域 -->
|
|
11
|
+
<template #title>
|
|
12
|
+
<div class="dialog-header">
|
|
13
|
+
<svg-icon style="width: 24px; height: 24px" :icon-class="type" />
|
|
14
|
+
<span class="header-title">{{ title }}</span>
|
|
15
|
+
</div>
|
|
16
|
+
<div
|
|
17
|
+
class="custom-close"
|
|
18
|
+
@mouseover="isHover = true"
|
|
19
|
+
@mouseleave="isHover = false"
|
|
20
|
+
@click="handleCancel"
|
|
21
|
+
>
|
|
22
|
+
<svg-icon
|
|
23
|
+
:icon-class="isHover ? 'close-hover' : 'close'"
|
|
24
|
+
class="close-icon"
|
|
25
|
+
/>
|
|
26
|
+
</div>
|
|
27
|
+
</template>
|
|
28
|
+
|
|
29
|
+
<!-- 内容区域 -->
|
|
30
|
+
<div class="dialog-content">
|
|
31
|
+
<slot>{{ content }}</slot>
|
|
32
|
+
</div>
|
|
33
|
+
|
|
34
|
+
<!-- 按钮区域 -->
|
|
35
|
+
<template #footer>
|
|
36
|
+
<el-button
|
|
37
|
+
v-if="type === 'danger'"
|
|
38
|
+
class="custom-btn"
|
|
39
|
+
style="color: #333333; background-color: #f1f1f1; border: none"
|
|
40
|
+
@click="handleCancel"
|
|
41
|
+
>取消</el-button
|
|
42
|
+
>
|
|
43
|
+
<el-button type="primary" @click="handleConfirm">{{
|
|
44
|
+
confirmText
|
|
45
|
+
}}</el-button>
|
|
46
|
+
</template>
|
|
47
|
+
</el-dialog>
|
|
48
|
+
</template>
|
|
49
|
+
|
|
50
|
+
<script>
|
|
51
|
+
export default {
|
|
52
|
+
name: 'MessagePopUp',
|
|
53
|
+
props: {
|
|
54
|
+
type: {
|
|
55
|
+
type: String,
|
|
56
|
+
default: 'info',
|
|
57
|
+
validator: (v) => ['info', 'success', 'error', 'danger'].includes(v)
|
|
58
|
+
},
|
|
59
|
+
title: {
|
|
60
|
+
type: String,
|
|
61
|
+
default: '提示信息'
|
|
62
|
+
},
|
|
63
|
+
width: {
|
|
64
|
+
type: String,
|
|
65
|
+
default: '500px'
|
|
66
|
+
},
|
|
67
|
+
content: {
|
|
68
|
+
type: String,
|
|
69
|
+
default: ''
|
|
70
|
+
},
|
|
71
|
+
//是否禁止取消
|
|
72
|
+
closeOnModalClick: {
|
|
73
|
+
type: Boolean,
|
|
74
|
+
default: false
|
|
75
|
+
},
|
|
76
|
+
conFirmText: {
|
|
77
|
+
type: String,
|
|
78
|
+
default: ''
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
computed: {
|
|
82
|
+
confirmText() {
|
|
83
|
+
// 优先使用传入的confirmText
|
|
84
|
+
return this.conFirmText || (this.type === 'danger' ? '确定' : '我知道了')
|
|
85
|
+
}
|
|
86
|
+
},
|
|
87
|
+
data() {
|
|
88
|
+
return {
|
|
89
|
+
visible: false,
|
|
90
|
+
isHover: false
|
|
91
|
+
}
|
|
92
|
+
},
|
|
93
|
+
methods: {
|
|
94
|
+
open() {
|
|
95
|
+
this.visible = true
|
|
96
|
+
},
|
|
97
|
+
handleConfirm() {
|
|
98
|
+
this.$emit('confirm', 'confirm')
|
|
99
|
+
this.visible = false
|
|
100
|
+
},
|
|
101
|
+
handleCancel() {
|
|
102
|
+
if (this.closeOnModalClick) return
|
|
103
|
+
this.$emit('confirm', 'cancel')
|
|
104
|
+
this.visible = false
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
</script>
|
|
109
|
+
|
|
110
|
+
<style scoped lang="scss">
|
|
111
|
+
::v-deep .el-dialog {
|
|
112
|
+
border-radius: 12px;
|
|
113
|
+
margin: 35% auto;
|
|
114
|
+
}
|
|
115
|
+
::v-deep .el-dialog:not(.is-fullscreen) {
|
|
116
|
+
margin-top: 33vh !important;
|
|
117
|
+
}
|
|
118
|
+
::v-deep .el-dialog__header {
|
|
119
|
+
padding: 24px;
|
|
120
|
+
}
|
|
121
|
+
::v-deep .el-dialog__body {
|
|
122
|
+
padding: 0 24px 24px 60px;
|
|
123
|
+
}
|
|
124
|
+
/* 添加圆角 */
|
|
125
|
+
:deep(.custom-dialog) {
|
|
126
|
+
border-radius: 8px !important;
|
|
127
|
+
margin: 20px !important;
|
|
128
|
+
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1) !important;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/* 移动端适配 */
|
|
132
|
+
@media (max-width: 768px) {
|
|
133
|
+
::v-deep .el-dialog {
|
|
134
|
+
width: 90% !important;
|
|
135
|
+
margin: 20% auto !important;
|
|
136
|
+
}
|
|
137
|
+
::v-deep .el-dialog__header {
|
|
138
|
+
padding: 16px;
|
|
139
|
+
}
|
|
140
|
+
::v-deep .el-dialog__body {
|
|
141
|
+
padding: 0 16px 16px 40px;
|
|
142
|
+
}
|
|
143
|
+
::v-deep .el-dialog__footer {
|
|
144
|
+
padding: 0 16px 16px;
|
|
145
|
+
text-align: end;
|
|
146
|
+
}
|
|
147
|
+
.dialog-header {
|
|
148
|
+
padding-bottom: 8px;
|
|
149
|
+
.header-title {
|
|
150
|
+
font-size: 15px;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
.dialog-content {
|
|
154
|
+
font-size: 13px;
|
|
155
|
+
line-height: 20px;
|
|
156
|
+
}
|
|
157
|
+
.custom-close {
|
|
158
|
+
right: 16px;
|
|
159
|
+
top: 16px;
|
|
160
|
+
}
|
|
161
|
+
.el-button {
|
|
162
|
+
min-width: 80px;
|
|
163
|
+
padding: 8px 15px;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
.dialog-header {
|
|
168
|
+
display: flex;
|
|
169
|
+
align-items: center;
|
|
170
|
+
padding-bottom: 10px;
|
|
171
|
+
font-family: PingFangSC, PingFang SC;
|
|
172
|
+
font-weight: 500;
|
|
173
|
+
font-size: 16px;
|
|
174
|
+
color: #333333;
|
|
175
|
+
line-height: 22px;
|
|
176
|
+
text-align: left;
|
|
177
|
+
font-style: normal;
|
|
178
|
+
.header-title {
|
|
179
|
+
margin-left: 12px;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
.header-icon {
|
|
183
|
+
font-size: 20px;
|
|
184
|
+
margin-right: 8px;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
.dialog-content {
|
|
188
|
+
font-family: PingFangSC, PingFang SC;
|
|
189
|
+
font-weight: 400;
|
|
190
|
+
font-size: 14px;
|
|
191
|
+
color: #333333;
|
|
192
|
+
line-height: 22px;
|
|
193
|
+
text-align: left;
|
|
194
|
+
font-style: normal;
|
|
195
|
+
}
|
|
196
|
+
.el-button {
|
|
197
|
+
min-width: 88px;
|
|
198
|
+
}
|
|
199
|
+
::v-deep .el-dialog__header {
|
|
200
|
+
position: relative; /* 为绝对定位提供参考 */
|
|
201
|
+
}
|
|
202
|
+
::v-deep .el-dialog__headerbtn {
|
|
203
|
+
display: none !important;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
.custom-close {
|
|
207
|
+
position: absolute;
|
|
208
|
+
right: 24px;
|
|
209
|
+
top: 24px;
|
|
210
|
+
cursor: pointer;
|
|
211
|
+
z-index: 2000;
|
|
212
|
+
transition: transform 0.3s;
|
|
213
|
+
|
|
214
|
+
.close-icon {
|
|
215
|
+
width: 18px;
|
|
216
|
+
height: 18px;
|
|
217
|
+
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
</style>
|
|
@@ -0,0 +1,352 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="pro-table">
|
|
3
|
+
<!-- 搜索区域card -->
|
|
4
|
+
<div class="pro-search-card" v-if="showSearch" ref="searchRef">
|
|
5
|
+
<div class="pro-search">
|
|
6
|
+
<div class="title-container">
|
|
7
|
+
<div class="title-text">
|
|
8
|
+
<slot name="title">
|
|
9
|
+
{{ showTitle || $route.name }}
|
|
10
|
+
</slot>
|
|
11
|
+
</div>
|
|
12
|
+
</div>
|
|
13
|
+
<slot name="search"></slot>
|
|
14
|
+
</div>
|
|
15
|
+
</div>
|
|
16
|
+
|
|
17
|
+
<!-- 表格区域card -->
|
|
18
|
+
<div class="pro-content-card">
|
|
19
|
+
<div class="pro-tool" v-if="toolbarConfig" ref="toolbarRef">
|
|
20
|
+
<div class="pro-xTool">
|
|
21
|
+
<div class="toolbar">
|
|
22
|
+
<div class="toolbar-left">
|
|
23
|
+
<slot name="tools"></slot>
|
|
24
|
+
</div>
|
|
25
|
+
<div class="toolbar-right">
|
|
26
|
+
<el-tooltip
|
|
27
|
+
v-if="toolbarConfig.search"
|
|
28
|
+
class="search-tooltip"
|
|
29
|
+
effect="dark"
|
|
30
|
+
:content="showSearch ? '隐藏搜索' : '显示搜索'"
|
|
31
|
+
placement="top"
|
|
32
|
+
>
|
|
33
|
+
<el-button
|
|
34
|
+
size="mini"
|
|
35
|
+
circle
|
|
36
|
+
icon="el-icon-search"
|
|
37
|
+
@click="showSearch = !showSearch"
|
|
38
|
+
/>
|
|
39
|
+
</el-tooltip>
|
|
40
|
+
<slot name="toolButton"></slot>
|
|
41
|
+
</div>
|
|
42
|
+
</div>
|
|
43
|
+
</div>
|
|
44
|
+
</div>
|
|
45
|
+
<div ref="remainingRef" style="flex: 1; overflow: hidden">
|
|
46
|
+
<slot :remainingHeight="remainingHeight"></slot>
|
|
47
|
+
<div ref="footerRef">
|
|
48
|
+
<slot name="footer"></slot>
|
|
49
|
+
</div>
|
|
50
|
+
</div>
|
|
51
|
+
</div>
|
|
52
|
+
</div>
|
|
53
|
+
</template>
|
|
54
|
+
|
|
55
|
+
<script>
|
|
56
|
+
export default {
|
|
57
|
+
name: 'ProTable',
|
|
58
|
+
props: {
|
|
59
|
+
// 显示工具栏相关项
|
|
60
|
+
toolbarConfig: {
|
|
61
|
+
type: [Object, Boolean],
|
|
62
|
+
default: () => {
|
|
63
|
+
return {
|
|
64
|
+
custom: true,
|
|
65
|
+
refresh: true,
|
|
66
|
+
search: true
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
},
|
|
70
|
+
fixedHeightOffset: {
|
|
71
|
+
type: Number,
|
|
72
|
+
default: 93
|
|
73
|
+
}
|
|
74
|
+
},
|
|
75
|
+
data() {
|
|
76
|
+
return {
|
|
77
|
+
showSearch: true,
|
|
78
|
+
searchHeight: 0,
|
|
79
|
+
toolbarHeight: 0,
|
|
80
|
+
footerHeight: 0
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
computed: {
|
|
84
|
+
refresh() {
|
|
85
|
+
if (this.$listeners.refresh) {
|
|
86
|
+
return { query: () => this.$emit('refresh') }
|
|
87
|
+
} else {
|
|
88
|
+
return false
|
|
89
|
+
}
|
|
90
|
+
},
|
|
91
|
+
showTitle() {
|
|
92
|
+
return this.title || this.$route.meta?.title
|
|
93
|
+
},
|
|
94
|
+
remainingHeight() {
|
|
95
|
+
const total = this.searchHeight + this.toolbarHeight + this.footerHeight
|
|
96
|
+
return `calc(100vh - ${93 + total}px)` // 当前总和231 → 100vh-324px
|
|
97
|
+
}
|
|
98
|
+
},
|
|
99
|
+
mounted() {
|
|
100
|
+
this.calcHeights()
|
|
101
|
+
window.addEventListener('resize', this.calcHeights)
|
|
102
|
+
},
|
|
103
|
+
beforeDestroy() {
|
|
104
|
+
window.removeEventListener('resize', this.calcHeights)
|
|
105
|
+
},
|
|
106
|
+
watch: {
|
|
107
|
+
showSearch() {
|
|
108
|
+
this.$nextTick(() => {
|
|
109
|
+
this.calcHeights()
|
|
110
|
+
})
|
|
111
|
+
}
|
|
112
|
+
},
|
|
113
|
+
methods: {
|
|
114
|
+
calcHeights() {
|
|
115
|
+
this.searchHeight = this.showSearch
|
|
116
|
+
? this.$refs.searchRef?.clientHeight || 0
|
|
117
|
+
: 0
|
|
118
|
+
this.toolbarHeight = this.$refs.toolbarRef?.clientHeight || 0
|
|
119
|
+
this.footerHeight = this.$refs.footerRef?.clientHeight || 0
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
</script>
|
|
124
|
+
|
|
125
|
+
<style lang="scss" scoped>
|
|
126
|
+
.pro-table {
|
|
127
|
+
height: 100%;
|
|
128
|
+
display: flex;
|
|
129
|
+
flex-direction: column;
|
|
130
|
+
color: #333;
|
|
131
|
+
font-family: PingFangSC, PingFang SC;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// 搜索区域card
|
|
135
|
+
.pro-search-card {
|
|
136
|
+
width: 100%;
|
|
137
|
+
background-color: #fff;
|
|
138
|
+
border-radius: 12px;
|
|
139
|
+
padding: 24px;
|
|
140
|
+
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.02);
|
|
141
|
+
margin-bottom: 16px;
|
|
142
|
+
display: flex;
|
|
143
|
+
color: #333;
|
|
144
|
+
|
|
145
|
+
.title-container {
|
|
146
|
+
width: 100%;
|
|
147
|
+
height: 44px;
|
|
148
|
+
border-bottom: 1px solid #f2f2f2;
|
|
149
|
+
margin-bottom: 9px;
|
|
150
|
+
|
|
151
|
+
.title-text {
|
|
152
|
+
display: inline-block;
|
|
153
|
+
height: 100%;
|
|
154
|
+
font-size: 16px;
|
|
155
|
+
font-weight: 500;
|
|
156
|
+
color: #333;
|
|
157
|
+
border-bottom: 2px solid #4a7ff8;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
::v-deep .el-select-dropdown.el-popper {
|
|
161
|
+
border: none;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// 表格区域card
|
|
166
|
+
.pro-content-card {
|
|
167
|
+
flex: 1;
|
|
168
|
+
background-color: #fff;
|
|
169
|
+
border-radius: 12px;
|
|
170
|
+
padding: 24px;
|
|
171
|
+
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.02);
|
|
172
|
+
display: flex;
|
|
173
|
+
flex-direction: column;
|
|
174
|
+
overflow: hidden;
|
|
175
|
+
color: #333;
|
|
176
|
+
font-weight: normal;
|
|
177
|
+
::v-deep .el-table__body-wrapper {
|
|
178
|
+
/* max-height: #{v-bind(remainingHeight)};
|
|
179
|
+
height: auto !important;
|
|
180
|
+
overflow-y: auto; */
|
|
181
|
+
&::-webkit-scrollbar {
|
|
182
|
+
width: 6px;
|
|
183
|
+
height: 6px;
|
|
184
|
+
}
|
|
185
|
+
&::-webkit-scrollbar-thumb {
|
|
186
|
+
background: #c1c1c1;
|
|
187
|
+
border-radius: 3px;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
.pro-search {
|
|
193
|
+
width: 100%;
|
|
194
|
+
|
|
195
|
+
::v-deep .el-form-item {
|
|
196
|
+
margin-top: 15px;
|
|
197
|
+
margin-bottom: 0px;
|
|
198
|
+
}
|
|
199
|
+
/* ::v-deep .el-form-item:last-child {
|
|
200
|
+
margin-bottom: 0 !important;
|
|
201
|
+
} */
|
|
202
|
+
::v-deep .el-button {
|
|
203
|
+
font-family: PingFangSC, PingFang SC;
|
|
204
|
+
font-weight: 500;
|
|
205
|
+
font-size: 14px;
|
|
206
|
+
height: 34px;
|
|
207
|
+
min-width: 88px;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
.pro-tool {
|
|
212
|
+
margin-bottom: 24px;
|
|
213
|
+
}
|
|
214
|
+
.toolbar {
|
|
215
|
+
display: flex;
|
|
216
|
+
justify-content: space-between;
|
|
217
|
+
/* align-items: center;
|
|
218
|
+
margin-bottom: 12px; */
|
|
219
|
+
height: 34px;
|
|
220
|
+
/* ::v-deep .el-button {
|
|
221
|
+
font-size: 14px;
|
|
222
|
+
height: 34px;
|
|
223
|
+
} */
|
|
224
|
+
.toolbar-left {
|
|
225
|
+
::v-deep .el-button {
|
|
226
|
+
font-family: PingFangSC, PingFang SC;
|
|
227
|
+
|
|
228
|
+
font-weight: 500;
|
|
229
|
+
font-size: 14px;
|
|
230
|
+
height: 34px;
|
|
231
|
+
min-width: 88px;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
.toolbar-right {
|
|
237
|
+
display: flex;
|
|
238
|
+
gap: 8px;
|
|
239
|
+
align-items: center;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
.search-tooltip {
|
|
243
|
+
margin-right: 8px;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// 移动端适配 (≤768px)
|
|
247
|
+
@media (max-width: 768px) {
|
|
248
|
+
/* .pro-search-card {
|
|
249
|
+
padding: 16px;
|
|
250
|
+
margin-bottom: 12px;
|
|
251
|
+
|
|
252
|
+
.title-container {
|
|
253
|
+
height: 36px;
|
|
254
|
+
margin-bottom: 8px;
|
|
255
|
+
|
|
256
|
+
.title-text {
|
|
257
|
+
font-size: 14px;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
} */
|
|
261
|
+
|
|
262
|
+
.pro-content-card {
|
|
263
|
+
padding: 16px;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
.pro-tool {
|
|
267
|
+
margin-bottom: 16px;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
.toolbar {
|
|
271
|
+
flex-direction: row;
|
|
272
|
+
height: auto;
|
|
273
|
+
gap: 12px;
|
|
274
|
+
|
|
275
|
+
.toolbar-left {
|
|
276
|
+
display: flex;
|
|
277
|
+
flex-wrap: wrap;
|
|
278
|
+
gap: 8px;
|
|
279
|
+
width: 85%;
|
|
280
|
+
justify-content: flex-start;
|
|
281
|
+
|
|
282
|
+
::v-deep .el-button {
|
|
283
|
+
height: 32px;
|
|
284
|
+
min-width: 76px;
|
|
285
|
+
font-size: 13px;
|
|
286
|
+
margin-left: 0px;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
::v-deep .el-button--mini {
|
|
290
|
+
height: 28px;
|
|
291
|
+
min-width: 60px;
|
|
292
|
+
font-size: 12px;
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
.toolbar-right {
|
|
297
|
+
width: 15%;
|
|
298
|
+
justify-content: flex-end;
|
|
299
|
+
align-items: self-start;
|
|
300
|
+
|
|
301
|
+
::v-deep .el-button--mini.is-circle {
|
|
302
|
+
width: 28px;
|
|
303
|
+
height: 28px;
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
.pro-search {
|
|
309
|
+
::v-deep .el-form-item {
|
|
310
|
+
margin-top: 12px !important;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
::v-deep .el-button {
|
|
314
|
+
height: 32px !important;
|
|
315
|
+
min-width: 76px !important;
|
|
316
|
+
font-size: 13px !important;
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
// 平板端适配 (769px-1024px)
|
|
322
|
+
@media (min-width: 769px) and (max-width: 1024px) {
|
|
323
|
+
.pro-search-card {
|
|
324
|
+
padding: 20px !important;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
.pro-content-card {
|
|
328
|
+
padding: 20px !important;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
.toolbar {
|
|
332
|
+
.toolbar-left {
|
|
333
|
+
display: flex !important;
|
|
334
|
+
flex-wrap: wrap !important;
|
|
335
|
+
gap: 8px !important;
|
|
336
|
+
|
|
337
|
+
::v-deep .el-button {
|
|
338
|
+
height: 33px !important;
|
|
339
|
+
min-width: 80px !important;
|
|
340
|
+
font-size: 13px !important;
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
.toolbar-right {
|
|
345
|
+
::v-deep .el-button--mini.is-circle {
|
|
346
|
+
width: 30px !important;
|
|
347
|
+
height: 30px !important;
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
</style>
|
package/src/index.js
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
// 导入组件
|
|
2
|
+
import GlobalDrawer from './components/GlobalDrawer/index.vue'
|
|
3
|
+
import MessagePopUp from './components/MessagePopUp/index.vue'
|
|
4
|
+
import ProTable from './components/ProTable/index.vue'
|
|
5
|
+
|
|
6
|
+
// 导入样式
|
|
7
|
+
import './styles/variables.scss'
|
|
8
|
+
import './styles/btn.scss'
|
|
9
|
+
import './styles/element-ui.scss'
|
|
10
|
+
import './styles/index.scss'
|
|
11
|
+
import './styles/sidebar.scss'
|
|
12
|
+
import './styles/tags-view.scss'
|
|
13
|
+
import './styles/transition.scss'
|
|
14
|
+
import './styles/utils.scss'
|
|
15
|
+
|
|
16
|
+
// 组件列表
|
|
17
|
+
const components = [
|
|
18
|
+
GlobalDrawer,
|
|
19
|
+
MessagePopUp,
|
|
20
|
+
ProTable
|
|
21
|
+
]
|
|
22
|
+
|
|
23
|
+
// 定义 install 方法,接收 Vue 作为参数
|
|
24
|
+
const install = function(Vue) {
|
|
25
|
+
// 判断是否安装
|
|
26
|
+
if (install.installed) return
|
|
27
|
+
install.installed = true
|
|
28
|
+
|
|
29
|
+
// 遍历注册所有组件
|
|
30
|
+
components.forEach(component => {
|
|
31
|
+
Vue.component(component.name, component)
|
|
32
|
+
})
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// 判断是否是直接引入文件,如果是,就不用调用 Vue.use()
|
|
36
|
+
if (typeof window !== 'undefined' && window.Vue) {
|
|
37
|
+
install(window.Vue)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// 导出组件
|
|
41
|
+
export {
|
|
42
|
+
GlobalDrawer,
|
|
43
|
+
MessagePopUp,
|
|
44
|
+
ProTable
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// 导出 install 方法
|
|
48
|
+
export default {
|
|
49
|
+
install
|
|
50
|
+
}
|
package/src/styles/sidebar.scss
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
@import "./variables.scss";
|
|
2
|
+
|
|
1
3
|
#app {
|
|
2
4
|
.main-container {
|
|
3
5
|
min-height: 100%;
|
|
@@ -114,7 +116,7 @@
|
|
|
114
116
|
.el-submenu {
|
|
115
117
|
overflow: hidden;
|
|
116
118
|
|
|
117
|
-
|
|
119
|
+
& > .el-submenu__title {
|
|
118
120
|
padding: 0 !important;
|
|
119
121
|
|
|
120
122
|
.svg-icon {
|
|
@@ -133,8 +135,8 @@
|
|
|
133
135
|
|
|
134
136
|
.el-menu--collapse {
|
|
135
137
|
.el-submenu {
|
|
136
|
-
|
|
137
|
-
|
|
138
|
+
& > .el-submenu__title {
|
|
139
|
+
& > span {
|
|
138
140
|
height: 0;
|
|
139
141
|
width: 0;
|
|
140
142
|
overflow: hidden;
|
|
@@ -151,7 +153,7 @@
|
|
|
151
153
|
|
|
152
154
|
.el-menu-item,
|
|
153
155
|
.el-submenu__title {
|
|
154
|
-
|
|
156
|
+
& > span {
|
|
155
157
|
height: 0;
|
|
156
158
|
width: 0;
|
|
157
159
|
overflow: hidden;
|
|
@@ -171,7 +173,7 @@
|
|
|
171
173
|
|
|
172
174
|
// when menu collapsed
|
|
173
175
|
.el-menu--vertical {
|
|
174
|
-
|
|
176
|
+
& > .el-menu {
|
|
175
177
|
.svg-icon {
|
|
176
178
|
margin-right: 16px;
|
|
177
179
|
}
|
|
@@ -182,7 +184,7 @@
|
|
|
182
184
|
}
|
|
183
185
|
}
|
|
184
186
|
|
|
185
|
-
.nest-menu .el-submenu
|
|
187
|
+
.nest-menu .el-submenu > .el-submenu__title,
|
|
186
188
|
.el-menu-item {
|
|
187
189
|
&:hover {
|
|
188
190
|
// you can use $subMenuHover
|
|
@@ -20,6 +20,11 @@ $base-logo-light-title-color: #001529; // 🌅 浅色主题Logo标题颜色 -
|
|
|
20
20
|
|
|
21
21
|
$base-sub-menu-background: transparent; // 🎨 子菜单背景色
|
|
22
22
|
$base-sub-menu-hover: rgba(202, 210, 228, 0.3); // 🖱️ 子菜单悬停背景色
|
|
23
|
+
$base-menu-hover: rgba(202, 210, 228, 0.3); // 🖱️ 菜单悬停背景色
|
|
24
|
+
$base-sub-menu-active: rgba(202, 210, 228, 0.5); // ✨ 子菜单激活背景色
|
|
25
|
+
$base-sub-menu-active-text: rgb(74, 127, 248); // 💫 子菜单激活文字颜色
|
|
26
|
+
$base-menu-active: rgba(202, 210, 228, 0.5); // ✨ 菜单激活背景色
|
|
27
|
+
$base-menu-active-color: rgb(74, 127, 248); // 💫 菜单激活文字颜色
|
|
23
28
|
|
|
24
29
|
//自定义新增
|
|
25
30
|
$base-menu-active-background: #fff; // 🌟 新增:菜单选中背景色 -
|