t20-common-lib 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json ADDED
@@ -0,0 +1,73 @@
1
+ {
2
+ "name": "t20-common-lib",
3
+ "version": "0.1.0",
4
+ "description": "T20",
5
+ "private": false,
6
+ "main": "dist/index.js",
7
+ "module": "src/index.js",
8
+ "style": "dist/styles/index.css",
9
+ "files": [
10
+ "dist",
11
+ "src",
12
+ "packages"
13
+ ],
14
+ "scripts": {
15
+ "serve": "vue-cli-service serve",
16
+ "build": "vue-cli-service build",
17
+ "lint": "vue-cli-service lint",
18
+ "lib": "vue-cli-service build --target lib --name t20-common-lib --dest dist src/index.js",
19
+ "docs:dev": "vuepress dev docs",
20
+ "docs:build": "vuepress build docs",
21
+ "prepublishOnly": "npm run lib",
22
+ "clean": "rimraf dist"
23
+ },
24
+ "keywords": [
25
+ "vue",
26
+ "element-ui",
27
+ "t20-common-lib"
28
+ ],
29
+ "author": "liuzongxi",
30
+ "license": "MIT",
31
+ "dependencies": {
32
+ "core-js": "^2.6.12",
33
+ "element-ui": "^2.15.13",
34
+ "vue": "^2.6.14",
35
+ "vue-server-renderer": "^2.6.14"
36
+ },
37
+ "devDependencies": {
38
+ "@vue/cli-plugin-babel": "~4.5.19",
39
+ "@vue/cli-plugin-eslint": "~4.5.19",
40
+ "@vue/cli-service": "~4.5.19",
41
+ "@vue/component-compiler-utils": "^3.3.0",
42
+ "babel-eslint": "^10.1.0",
43
+ "babel-plugin-component": "^1.1.1",
44
+ "cross-env": "^7.0.3",
45
+ "eslint": "^6.7.2",
46
+ "eslint-plugin-vue": "^6.2.2",
47
+ "node-sass": "^4.14.1",
48
+ "postcss-loader": "^3.0.0",
49
+ "rimraf": "^3.0.2",
50
+ "sass-loader": "^8.0.2",
51
+ "vue-template-compiler": "^2.6.14",
52
+ "vuepress": "^1.9.7"
53
+ },
54
+ "eslintConfig": {
55
+ "root": true,
56
+ "env": {
57
+ "node": true
58
+ },
59
+ "extends": [
60
+ "plugin:vue/essential",
61
+ "eslint:recommended"
62
+ ],
63
+ "parserOptions": {
64
+ "parser": "babel-eslint"
65
+ },
66
+ "rules": {}
67
+ },
68
+ "browserslist": [
69
+ "> 1%",
70
+ "last 2 versions",
71
+ "not dead"
72
+ ]
73
+ }
@@ -0,0 +1,62 @@
1
+ <template>
2
+ <el-button
3
+ :size="size"
4
+ :type="type"
5
+ :icon="icon"
6
+ :loading="loading"
7
+ :disabled="disabled || !hasPermission"
8
+ :round="round"
9
+ :circle="circle"
10
+ @click="handleClick"
11
+ v-bind="$attrs"
12
+ v-on="$listeners"
13
+ >
14
+ <slot></slot>
15
+ </el-button>
16
+ </template>
17
+
18
+ <script>
19
+ export default {
20
+ name: 'MyButton',
21
+ props: {
22
+ size: {
23
+ type: String,
24
+ default: 'medium',
25
+ validator: val => ['mini', 'small', 'medium', 'large'].includes(val)
26
+ },
27
+ type: {
28
+ type: String,
29
+ default: 'default',
30
+ validator: val => ['primary', 'success', 'warning', 'danger', 'info', 'text', 'default'].includes(val)
31
+ },
32
+ icon: String,
33
+ loading: Boolean,
34
+ disabled: Boolean,
35
+ round: Boolean,
36
+ circle: Boolean,
37
+ permission: String
38
+ },
39
+ computed: {
40
+ hasPermission() {
41
+ if (!this.permission) return true
42
+ // 实际项目中替换为真实的权限判断逻辑
43
+ return true
44
+ }
45
+ },
46
+ methods: {
47
+ handleClick(e) {
48
+ this.$emit('click', e)
49
+ }
50
+ }
51
+ }
52
+ </script>
53
+
54
+ <style scoped lang="scss">
55
+ ::v-deep .el-button {
56
+ margin-right: 8px;
57
+
58
+ &:last-child {
59
+ margin-right: 0;
60
+ }
61
+ }
62
+ </style>
File without changes
package/src/index.js ADDED
@@ -0,0 +1,41 @@
1
+ import './styles/index.css'
2
+ /** 全局指令 */
3
+ import fitlers from './filters/index'
4
+ import repairEl from './utils/repairElementUI'
5
+ // 导入组件
6
+ import MyButton from './components/MyButton'
7
+
8
+ // 存储组件列表
9
+ const components = [
10
+ MyButton
11
+ ]
12
+
13
+ // 定义 install 方法,接收 Vue 作为参数
14
+ const install = function (Vue, opts = { prefix: 'T20', i18nConfig: {} }) {
15
+ components.forEach((component) => {
16
+ let name = component.name
17
+ if (!name) return console.error('必须设置组件名称:', component)
18
+
19
+ name = opts.prefix + name.replace(name[0], name[0].toUpperCase())
20
+ Vue.component(name, component)
21
+ })
22
+
23
+ Object.keys(fitlers).forEach((key) => {
24
+ Vue.filter(key + 'Format', fitlers[key])
25
+ })
26
+ }
27
+
28
+ // 判断是否是直接引入文件
29
+ if (typeof window !== 'undefined' && window.Vue) {
30
+ install(window.Vue)
31
+ }
32
+
33
+ export default {
34
+ install
35
+ }
36
+
37
+ export {
38
+ // 以下是具体的组件列表
39
+ MyButton,
40
+ repairEl
41
+ }
File without changes
File without changes
@@ -0,0 +1,107 @@
1
+ // 设置表头最小宽度,保证表头不换行
2
+ const ASCII_W = {
3
+ ' ': 4.125,
4
+ 0: 8.21875,
5
+ 1: 8.21875,
6
+ 2: 8.21875,
7
+ 3: 8.21875,
8
+ 4: 8.21875,
9
+ 5: 8.21875,
10
+ 6: 8.21875,
11
+ 7: 8.21875,
12
+ 8: 8.21875,
13
+ 9: 8.21875,
14
+ '!': 4.375,
15
+ '"': 6.109375,
16
+ '#': 8.9375,
17
+ $: 8.21875,
18
+ '%': 12.46875,
19
+ '&': 12.1875,
20
+ "'": 3.59375,
21
+ '(': 4.6875,
22
+ ')': 4.6875,
23
+ '*': 6.375,
24
+ '+': 10.390625,
25
+ ',': 3.375,
26
+ '-': 6.0625,
27
+ '.': 3.375,
28
+ '/': 5.984375,
29
+ ':': 3.375,
30
+ ';': 3.375,
31
+ '<': 10.390625,
32
+ '=': 10.390625,
33
+ '>': 10.390625,
34
+ '?': 6.765625,
35
+ '@': 14.4375,
36
+ A: 9.859375,
37
+ B: 8.796875,
38
+ C: 9.375,
39
+ D: 10.671875,
40
+ E: 7.703125,
41
+ F: 7.4375,
42
+ G: 10.421875,
43
+ H: 10.828125,
44
+ I: 4.125,
45
+ J: 5.546875,
46
+ K: 8.890625,
47
+ L: 7.1875,
48
+ M: 13.6875,
49
+ N: 11.390625,
50
+ O: 11.421875,
51
+ P: 8.578125,
52
+ Q: 11.421875,
53
+ R: 9.140625,
54
+ S: 8.09375,
55
+ T: 8.03125,
56
+ U: 10.453125,
57
+ V: 9.46875,
58
+ W: 14.25,
59
+ X: 9.03125,
60
+ Y: 8.453125,
61
+ Z: 8.6875,
62
+ '[': 4.6875,
63
+ '\\': 5.828125,
64
+ ']': 4.6875,
65
+ '^': 10.390625,
66
+ _: 6.28125,
67
+ '`': 4.140625,
68
+ a: 7.75,
69
+ b: 8.953125,
70
+ c: 7.03125,
71
+ d: 8.96875,
72
+ e: 7.953125,
73
+ f: 4.859375,
74
+ g: 8.96875,
75
+ h: 8.625,
76
+ i: 3.734375,
77
+ j: 3.75,
78
+ k: 7.625,
79
+ l: 3.734375,
80
+ m: 13.125,
81
+ n: 8.640625,
82
+ o: 8.90625,
83
+ p: 8.953125,
84
+ q: 8.96875,
85
+ r: 5.40625,
86
+ s: 6.546875,
87
+ t: 5.21875,
88
+ u: 8.640625,
89
+ v: 7.359375,
90
+ w: 11.0625,
91
+ x: 7.109375,
92
+ y: 7.421875,
93
+ z: 6.890625,
94
+ '{': 4.6875,
95
+ '|': 3.78125,
96
+ '}': 4.6875,
97
+ '~': 10.390625
98
+ }
99
+
100
+ export default function getWidth(label) {
101
+ label = label || ''
102
+ let labels = label.match(/./gu) || []
103
+ let labelW = 0
104
+ labels.forEach((s) => (labelW += ASCII_W[s] || 14))
105
+
106
+ return labelW
107
+ }
@@ -0,0 +1,141 @@
1
+ import Vue from 'vue'
2
+ import ElementUI from 'element-ui'
3
+
4
+ function setPropsDefault(component, props) {
5
+ let c_props = component.props
6
+ Object.keys(props).forEach((key) => {
7
+ c_props[key] = Object.assign({}, c_props[key], props[key])
8
+ })
9
+ }
10
+ function setMethodsDefault(component, methods) {
11
+ let c_methods = component.methods
12
+ Object.keys(methods).forEach((key) => {
13
+ c_methods[key] = methods[key]
14
+ })
15
+ }
16
+
17
+ setPropsDefault(ElementUI.TableColumn, {
18
+ filterPlacement: {
19
+ default: 'bottom'
20
+ }
21
+ })
22
+
23
+ setPropsDefault(ElementUI.Dropdown, {
24
+ placement: {
25
+ default: 'bottom'
26
+ }
27
+ })
28
+
29
+ setPropsDefault(ElementUI.Dialog, {
30
+ appendToBody: {
31
+ default: true
32
+ }
33
+ })
34
+
35
+ import getWidth from './asciiWidth'
36
+
37
+ setMethodsDefault(ElementUI.TableColumn, {
38
+ setColumnWidth(column) {
39
+ if (this.realWidth) {
40
+ column.width = this.realWidth
41
+ }
42
+ if (this.realMinWidth) {
43
+ column.minWidth = this.realMinWidth
44
+ }
45
+ if (!column.minWidth) {
46
+ if (!column.width) {
47
+ let labelW = getWidth(column.label)
48
+
49
+ let sortable = column.sortable ? 24 : 0
50
+ let filters = column.filters ? 16 : 0
51
+ column.minWidth = Math.max(80, labelW + 22 + sortable + filters)
52
+ } else {
53
+ column.minWidth = 80
54
+ }
55
+ }
56
+ column.realWidth = column.width === undefined ? column.minWidth : column.width
57
+ return column
58
+ }
59
+ })
60
+
61
+ // 美化表头搜索
62
+ import FilterPanel from './tableheaderFilterpanel.vue'
63
+ function hasClass(el, cls) {
64
+ if (!el || !cls) return false
65
+ if (cls.indexOf(' ') !== -1) throw new Error('className should not contain space.')
66
+ if (el.classList) {
67
+ return el.classList.contains(cls)
68
+ } else {
69
+ return (' ' + el.className + ' ').indexOf(' ' + cls + ' ') > -1
70
+ }
71
+ }
72
+ if (ElementUI.Table.components.TableHeader) {
73
+ setMethodsDefault(ElementUI.Table.components.TableHeader, {
74
+ handleFilterClick(event, column) {
75
+ event.stopPropagation()
76
+ const target = event.target
77
+ let cell = target.tagName === 'TH' ? target : target.parentNode
78
+ if (hasClass(cell, 'noclick')) return
79
+ cell = cell.querySelector('.el-table__column-filter-trigger') || cell
80
+ const table = this.$parent
81
+
82
+ let filterPanel = this.filterPanels[column.id]
83
+
84
+ if (filterPanel && column.filterOpened) {
85
+ filterPanel.showPopper = false
86
+ return
87
+ }
88
+
89
+ if (!filterPanel) {
90
+ filterPanel = new Vue(FilterPanel)
91
+ this.filterPanels[column.id] = filterPanel
92
+ if (column.filterPlacement) {
93
+ filterPanel.placement = column.filterPlacement
94
+ }
95
+ filterPanel.table = table
96
+ filterPanel.cell = cell
97
+ filterPanel.column = column
98
+ !this.$isServer && filterPanel.$mount(document.createElement('div'))
99
+ }
100
+
101
+ setTimeout(() => {
102
+ filterPanel.showPopper = true
103
+ }, 16)
104
+ }
105
+ })
106
+ }
107
+
108
+ /* 对ElementUI硬优化 */
109
+ import Popper from 'element-ui/lib/utils/popper.js'
110
+ function repairPopper() {
111
+ if (!Popper.prototype.repairR) {
112
+ Popper.prototype.repairR = true
113
+
114
+ let __getBoundaries = Popper.prototype._getBoundaries
115
+ Popper.prototype._getBoundaries = function (data, padding, boundariesElement) {
116
+ const boundaries = __getBoundaries.call(this, data, padding, boundariesElement)
117
+
118
+ if (this._options.boundariesElement === 'viewport') {
119
+ const root = window
120
+ const body = root.document.body
121
+ const html = root.document.documentElement
122
+ let width = Math.max(body.scrollWidth, body.offsetWidth, html.clientWidth, html.scrollWidth, html.offsetWidth)
123
+ let height = Math.max(
124
+ body.scrollHeight,
125
+ body.offsetHeight,
126
+ html.clientHeight,
127
+ html.scrollHeight,
128
+ html.offsetHeight
129
+ )
130
+
131
+ boundaries.right = boundaries.right - root.document.documentElement.clientWidth + width
132
+ boundaries.bottom = boundaries.bottom - root.document.documentElement.clientHeight + height
133
+ }
134
+ return boundaries
135
+ }
136
+ }
137
+ }
138
+
139
+ export default function () {
140
+ repairPopper()
141
+ }
@@ -0,0 +1,257 @@
1
+ <template>
2
+ <transition name="el-zoom-in-top">
3
+ <div
4
+ v-if="multiple"
5
+ v-show="showPopper"
6
+ v-click-outside:capture="handleOutsideClick"
7
+ class="el-table-filter p-a m-t"
8
+ >
9
+ <el-input
10
+ v-model="searchVal"
11
+ class="input-w m-b"
12
+ :placeholder="'请输入' | $lc"
13
+ clearable
14
+ suffix-icon="el-icon-search"
15
+ />
16
+ <div>
17
+ <el-checkbox v-model="allCheck" :label="true" :indeterminate="indeterminate"
18
+ >{{ '全部' | $lc }}{{ filters | alltextF }}</el-checkbox
19
+ >
20
+ </div>
21
+ <el-checkbox-group v-model="filteredValue" class="input-w p-b-s" style="max-height: 226px; overflow: auto">
22
+ <template v-for="filter in filters">
23
+ <el-checkbox
24
+ v-if="filter.text.includes(searchVal)"
25
+ :key="filter.value"
26
+ class="m-t-s m-r-0"
27
+ :label="filter.value"
28
+ style="display: block"
29
+ >
30
+ <!-- v-title="filter.text" :show-overflow-tooltip="true" -->
31
+ <span class="align-bottom">{{ filter.text }}</span>
32
+ <span>{{ filter | countF }}</span>
33
+ </el-checkbox>
34
+ </template>
35
+ </el-checkbox-group>
36
+ <div class="flex-box flex-c m-t-s">
37
+ <el-button
38
+ type="primary"
39
+ size="mini"
40
+ @click="
41
+ () => {
42
+ filteredValue.length ? handleConfirm() : handleReset()
43
+ }
44
+ "
45
+ >
46
+ {{ '确认' | $lc }}
47
+ </el-button>
48
+ <el-button plain size="mini" @click="handleReset">{{ '清空' | $lc }}</el-button>
49
+ </div>
50
+ </div>
51
+ <div v-else v-show="showPopper" v-click-outside:capture="handleOutsideClick" class="el-table-filter p-a m-t">
52
+ <el-input
53
+ v-model="searchVal"
54
+ class="input-w m-b-ss"
55
+ :placeholder="'请输入' | $lc"
56
+ clearable
57
+ suffix-icon="el-icon-search"
58
+ />
59
+ <ul class="el-table-filter__list">
60
+ <li
61
+ class="el-table-filter__list-item"
62
+ :class="{
63
+ 'is-active': filterValue === undefined || filterValue === null
64
+ }"
65
+ @click="handleSelect(null)"
66
+ >
67
+ {{ '全部' | $lc }}{{ filters | alltextF }}
68
+ </li>
69
+ </ul>
70
+ <ul class="el-table-filter__list" style="max-height: 226px; overflow: auto">
71
+ <template v-for="filter in filters">
72
+ <li
73
+ v-if="filter.text.includes(searchVal)"
74
+ :key="filter.value"
75
+ class="el-table-filter__list-item"
76
+ :label="filter.value"
77
+ :class="{ 'is-active': isActive(filter) }"
78
+ @click="handleSelect(filter.value)"
79
+ >
80
+ <!-- v-title="filter.text" :show-overflow-tooltip="true" -->
81
+ <span class="text-ellipsis align-bottom" style="display: inline-block; max-width: 12em">{{
82
+ filter.text
83
+ }}</span>
84
+ <span>{{ filter | countF }}</span>
85
+ </li>
86
+ </template>
87
+ </ul>
88
+ </div>
89
+ </transition>
90
+ </template>
91
+
92
+ <script>
93
+ // import { $lc } from './i18n/index'
94
+ import Popper from 'element-ui/lib/utils/vue-popper.js'
95
+ export default {
96
+ name: 'ElTableFilterPanelPor',
97
+ filters: {
98
+ countF(item) {
99
+ if (item.count === undefined) {
100
+ return ''
101
+ } else {
102
+ return ' (' + item.count + ')'
103
+ }
104
+ },
105
+ alltextF(list = []) {
106
+ if (list.some((c) => c.count !== undefined)) {
107
+ let total = 0
108
+ list.forEach((c) => {
109
+ if (!isNaN(c.count)) {
110
+ total = total + Number(c.count)
111
+ }
112
+ })
113
+ return ' (' + total + ')'
114
+ } else {
115
+ return ''
116
+ }
117
+ }
118
+ },
119
+ mixins: [Popper],
120
+ props: {
121
+ placement: {
122
+ type: String,
123
+ default: 'bottom-end'
124
+ }
125
+ },
126
+
127
+ data() {
128
+ return {
129
+ table: null,
130
+ cell: null,
131
+ column: null,
132
+ searchVal: ''
133
+ // allCheck: false
134
+ }
135
+ },
136
+
137
+ computed: {
138
+ filters() {
139
+ return this.column && this.column.filters
140
+ },
141
+
142
+ filterValue: {
143
+ get() {
144
+ return (this.column.filteredValue || [])[0]
145
+ },
146
+ set(value) {
147
+ if (this.filteredValue) {
148
+ if (typeof value !== 'undefined' && value !== null) {
149
+ this.filteredValue.splice(0, 1, value)
150
+ } else {
151
+ this.filteredValue.splice(0, 1)
152
+ }
153
+ }
154
+ }
155
+ },
156
+
157
+ filteredValue: {
158
+ get() {
159
+ if (this.column) {
160
+ return this.column.filteredValue || []
161
+ }
162
+ return []
163
+ },
164
+ set(value) {
165
+ if (this.column) {
166
+ this.column.filteredValue = value
167
+ }
168
+ }
169
+ },
170
+
171
+ allCheck: {
172
+ get() {
173
+ return this.filteredValue.length === 0 ? false : this.filteredValue.length === this.filters.length
174
+ },
175
+ set(val) {
176
+ if (val) {
177
+ this.filteredValue = this.filters.map((f) => f.value)
178
+ } else {
179
+ this.filteredValue = []
180
+ }
181
+ }
182
+ },
183
+
184
+ indeterminate() {
185
+ return this.filteredValue.length > 0 && this.filteredValue.length !== this.filters.length
186
+ },
187
+
188
+ multiple() {
189
+ if (this.column) {
190
+ return this.column.filterMultiple
191
+ }
192
+ return true
193
+ }
194
+ },
195
+
196
+ mounted() {
197
+ this.popperElm = this.$el
198
+ this.referenceElm = this.cell
199
+ this.table.bodyWrapper.addEventListener('scroll', () => {
200
+ this.updatePopper()
201
+ })
202
+
203
+ this.$watch('showPopper', (value) => {
204
+ if (this.column) this.column.filterOpened = value
205
+ if (value) this.searchVal = ''
206
+ // if (value) {
207
+ // Dropdown.open(this)
208
+ // } else {
209
+ // Dropdown.close(this)
210
+ // }
211
+ })
212
+ },
213
+
214
+ methods: {
215
+ isActive(filter) {
216
+ return filter.value === this.filterValue
217
+ },
218
+
219
+ handleOutsideClick() {
220
+ setTimeout(() => {
221
+ this.showPopper = false
222
+ }, 16)
223
+ },
224
+
225
+ handleConfirm() {
226
+ this.confirmFilter(this.filteredValue)
227
+ this.handleOutsideClick()
228
+ },
229
+
230
+ handleReset() {
231
+ this.filteredValue = []
232
+ this.confirmFilter(this.filteredValue)
233
+ this.handleOutsideClick()
234
+ },
235
+
236
+ handleSelect(filterValue) {
237
+ this.filterValue = filterValue
238
+
239
+ if (typeof filterValue !== 'undefined' && filterValue !== null) {
240
+ this.confirmFilter(this.filteredValue)
241
+ } else {
242
+ this.confirmFilter([])
243
+ }
244
+
245
+ this.handleOutsideClick()
246
+ },
247
+
248
+ confirmFilter(filteredValue) {
249
+ this.table.store.commit('filterChange', {
250
+ column: this.column,
251
+ values: filteredValue
252
+ })
253
+ this.table.store.updateAllSelected()
254
+ }
255
+ }
256
+ }
257
+ </script>