@leevan/jtui 2.0.33 → 2.0.35

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.
@@ -0,0 +1,47 @@
1
+ {
2
+ "name": "el-cascader-multi",
3
+ "version": "1.1.8",
4
+ "description": "基于element-ui的级联多选",
5
+ "main": "src/index.js",
6
+ "scripts": {
7
+ "test": "echo \"Error: no test specified\" && exit 1",
8
+ "build": "cross-env NODE_ENV=production webpack --progress "
9
+ },
10
+ "repository": {
11
+ "type": "git",
12
+ "url": "git+https://github.com/Charming2015/el-cascader-multi.git"
13
+ },
14
+ "keywords": [
15
+ "element",
16
+ "multi",
17
+ "cascader"
18
+ ],
19
+ "author": "charming <2019.02>",
20
+ "license": "ISC",
21
+ "bugs": {
22
+ "url": "https://github.com/Charming2015/el-cascader-multi/issues"
23
+ },
24
+ "homepage": "https://github.com/Charming2015/el-cascader-multi#readme",
25
+ "devDependencies": {
26
+ "babel-core": "^6.26.3",
27
+ "babel-loader": "^7.1.5",
28
+ "css-loader": "^1.0.0",
29
+ "express": "^4.16.3",
30
+ "mini-css-extract-plugin": "^0.5.0",
31
+ "node-sass": "^4.9.2",
32
+ "sass-loader": "^7.0.3",
33
+ "vue-loader": "^15.2.6",
34
+ "vue-style-loader": "^4.1.1",
35
+ "vue-template-compiler": "^2.5.16",
36
+ "webpack": "^4.16.3",
37
+ "webpack-cli": "^3.2.3",
38
+ "webpack-command": "^0.4.1",
39
+ "webpack-dev-server": "^3.1.5",
40
+ "webpack-hot-middleware": "^2.22.3"
41
+ },
42
+ "dependencies": {
43
+ "cross-env": "^5.2.0",
44
+ "element-ui": "^2.4.11",
45
+ "vue": "^2.5.16"
46
+ }
47
+ }
@@ -0,0 +1,9 @@
1
+ import multiCascader from './multi-cascader/multi-cascader.vue'
2
+
3
+ const install = (Vue) => {
4
+ Vue.component(multiCascader.name, multiCascader)
5
+ }
6
+ if (typeof window !== 'undefined' && window.Vue) {
7
+ install(window.Vue)
8
+ }
9
+ export default { install }
@@ -0,0 +1,331 @@
1
+ <template>
2
+ <div class="">
3
+ <el-select
4
+ style="width:100%;height:100%;"
5
+ v-model="selectedLabels"
6
+ multiple
7
+ :popper-class="innerPopperClass"
8
+ @remove-tag="removeOne"
9
+ :filterable="filterable"
10
+ :filter-method="innerFilterMethod"
11
+ :reserve-keyword="reserveKeyword"
12
+ @change="changeLabel"
13
+ v-bind="$attrs"
14
+ @blur="handleBlur"
15
+ @visible-change="visibleChange"
16
+ @focus="handleFocus"
17
+ @clear="handleClear"
18
+ :allow-create="false"
19
+ >
20
+ <span slot="prefix" v-if="$slots.prefix">
21
+ <slot name="prefix"></slot>
22
+ </span>
23
+ <template v-if="!isSearching">
24
+ <el-option value="__root">
25
+ <div class="ground" @click.stop>
26
+ <render-list
27
+ :only-last="onlyLast"
28
+ :list="root.childNodes"
29
+ :level="1"
30
+ :active-list="activeList"
31
+ @handle-click="handleClick"
32
+ @handle-check="handleCheck"
33
+ :label-key="labelKey"
34
+ :expand-trigger="expandTrigger"
35
+ ></render-list>
36
+ <template v-for="item in maxLevellist">
37
+ <div
38
+ :class="`floor-item floor-position-left-${item.id + 1}`"
39
+ :key="item.id"
40
+ v-if="item.rendered"
41
+ v-show="activeList.length >= item.id"
42
+ >
43
+ <render-list
44
+ :only-last="onlyLast"
45
+ :list="showData[item.id]"
46
+ :level="item.id + 1"
47
+ :active-list="activeList"
48
+ @handle-click="handleClick"
49
+ @handle-check="handleCheck"
50
+ :label-key="labelKey"
51
+ :expand-trigger="expandTrigger"
52
+ ></render-list>
53
+ </div>
54
+ </template>
55
+ </div>
56
+ </el-option>
57
+ </template>
58
+ <template v-if="isSearching">
59
+ <el-option
60
+ v-for="item in searchResult"
61
+ :value="item.showLabel"
62
+ :key="getKey(item)"
63
+ >
64
+ <div style="width:100%;height:100%" @click.stop="selectOne(item)">
65
+ {{item.totalLabel}}
66
+ </div>
67
+ </el-option>
68
+ </template>
69
+ </el-select>
70
+ </div>
71
+ </template>
72
+
73
+ <script>
74
+ import TreeStore from './lib/Tree.js'
75
+ import renderList from './render-list.vue'
76
+ import _ from 'lodash'
77
+ import { _findByObj } from './tool/unit'
78
+ export default {
79
+ name: 'el-cascader-multi',
80
+ components: {
81
+ renderList
82
+ },
83
+ props: {
84
+ data: {
85
+ type: Array,
86
+ default: () => [],
87
+ required: true
88
+ },
89
+ value: {
90
+ type: Array,
91
+ default: () => [],
92
+ required: true
93
+ },
94
+ separator: {
95
+ type: String,
96
+ default: '-'
97
+ },
98
+ filterable: {
99
+ type: Boolean,
100
+ default: false
101
+ },
102
+ filterMethod: {
103
+ type: Function
104
+ },
105
+ popperClass: {
106
+ type: String,
107
+ default: ''
108
+ },
109
+ reserveKeyword: {
110
+ type: Boolean,
111
+ default: true
112
+ },
113
+ valueKey: {
114
+ type: String,
115
+ default: 'value'
116
+ },
117
+ labelKey: {
118
+ type: String,
119
+ default: 'label'
120
+ },
121
+ childrenKey: {
122
+ type: String,
123
+ default: 'children'
124
+ },
125
+ expandTrigger: {
126
+ type: String,
127
+ default: 'click'
128
+ },
129
+ onlyLast: {
130
+ type: Boolean,
131
+ default: false
132
+ },
133
+ isTwoDimensionValue: {
134
+ type: Boolean,
135
+ default: true
136
+ },
137
+ showLeafLabel: {
138
+ type: Boolean,
139
+ default: false
140
+ }
141
+ },
142
+ data () {
143
+ return {
144
+ selectedLabels: [],
145
+ selectedIds: [],
146
+ selectedNodes: [],
147
+ activeClass: 'floor-width-1',
148
+ store: {},
149
+ root: [],
150
+ maxLevellist: [],
151
+ showData: {},
152
+ activeList: [],
153
+ searchText: '',
154
+ searchResult: []
155
+ }
156
+ },
157
+ computed: {
158
+ isSearching () {
159
+ return !(this.searchText.trim() === '')
160
+ },
161
+ innerPopperClass () {
162
+ return `${this.popperClass} multi-cascader ${this.isSearching ? '' : 'multi-cascader-style'} ${this.activeClass}`
163
+ }
164
+ },
165
+ watch: {
166
+ data: {
167
+ deep: true,
168
+ handler () {
169
+ this.init()
170
+ }
171
+ },
172
+ value: {
173
+ deep: true,
174
+ handler () {
175
+ // this.init()
176
+ this.updateSelect(this.value, true, true)
177
+ }
178
+ },
179
+ selectedNodes () {
180
+ this.$emit('change', this.selectedNodes.map(o => o[this.isTwoDimensionValue ? '_idArr' : this.valueKey]))
181
+ }
182
+ },
183
+ methods: {
184
+ visibleChange (v) {
185
+ this.activeList = []
186
+ this.activeClass = 'floor-width-1'
187
+ if (!v) {
188
+ this.searchText = ''
189
+ }
190
+ this.$emit('visible-change', v)
191
+ },
192
+ handleBlur (e) {
193
+ this.searchText = ''
194
+ this.$emit('blur', e)
195
+ },
196
+ handleFocus (e) {
197
+ this.$emit('focus', e)
198
+ },
199
+ handleClear () {
200
+ this.selectedNodes.forEach(node => {
201
+ node.check(false)
202
+ })
203
+ this.$emit('input', [])
204
+ this.$emit('clear')
205
+ },
206
+ selectOne (item) {
207
+ item.checked = !item.checked
208
+ this.handleCheck(item)
209
+ },
210
+ changeLabel (v) {
211
+ this.store.nodeList.forEach(node => {
212
+ node.check(v.includes(node.showLabel))
213
+ })
214
+ },
215
+ innerFilterMethod (v) {
216
+ this.searchText = v
217
+ let tempResult = this.store.nodeList
218
+ if (v.trim() !== '') {
219
+ this.activeClass = ''
220
+ if (typeof this.filterMethod === 'function') {
221
+ this.searchResult = this.filterMethod(tempResult, v)
222
+ } else {
223
+ tempResult = tempResult.filter(o => o.isLeaf)
224
+ tempResult = tempResult.filter(o => o.showLabel.includes(v))
225
+ this.searchResult = tempResult
226
+ }
227
+ } else {
228
+ this.activeClass = 'floor-width-1'
229
+ }
230
+ },
231
+ getKey () {
232
+ return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => {
233
+ let r = Math.random() * 16 | 0
234
+ let v = c === 'x' ? r : (r & 0x3 | 0x8)
235
+ return v.toString(16)
236
+ })
237
+ },
238
+ handleClick (node, levelIndex, level) {
239
+ if (this.maxLevellist[level - 1]) {
240
+ this.maxLevellist[level - 1].rendered = true
241
+ }
242
+ this.activeClass = `floor-width-${node.isLeaf ? level : level + 1}`
243
+ let tempList = [...this.activeList]
244
+ if (level < tempList.length) {
245
+ tempList.splice(level)
246
+ }
247
+ tempList[level - 1] = node.id
248
+ this.showData[level] = node.childNodes
249
+ this.activeList = tempList
250
+ },
251
+ handleCheck (node) {
252
+ node.check(node.checked)
253
+ this.selectedIds = this.store.selectedIds
254
+ this.updateSelect(this.store.selectedIds)
255
+ this.$emit('input', this.selectedNodes.map(o => o[this.isTwoDimensionValue ? '_idArr' : this.valueKey]))
256
+ },
257
+ removeOne (v) {
258
+ let targetNode = this.selectedNodes.find(o => o.showLabel === v) || {}
259
+ targetNode.checked = false
260
+ this.handleCheck(targetNode)
261
+ this.$emit('remove-tag', v)
262
+ },
263
+ updateSelect (data = [], needCheckNode = false, setValue = false) {
264
+ let tempSelectedNodes = []
265
+ let tempSelectedLabels = []
266
+ let tempSelectedIds = []
267
+ this.store.nodeList.forEach(node => {
268
+ node.checked && node.check(false)
269
+ })
270
+ data.forEach(o => {
271
+ let targetNode
272
+ if (setValue) {
273
+ targetNode = _findByObj(this.store.nodeList, { [this.isTwoDimensionValue ? '_idArr' : this.valueKey]: o }) || {}
274
+ // targetNode = _.find(this.store.nodeList, { [this.isTwoDimensionValue ? '_idArr' : this.valueKey]: o }) || {}
275
+ tempSelectedIds.push(targetNode.id)
276
+ } else {
277
+ targetNode = this.store.nodesMap[o]
278
+ tempSelectedIds.push(o)
279
+ }
280
+ if (targetNode) {
281
+ needCheckNode && targetNode.check(true)
282
+ tempSelectedNodes.push(targetNode)
283
+ tempSelectedLabels.push(targetNode.showLabel)
284
+ }
285
+ })
286
+ this.selectedNodes = tempSelectedNodes
287
+ this.selectedLabels = tempSelectedLabels
288
+ this.selectedIds = tempSelectedIds
289
+ },
290
+ init () {
291
+ this.store = new TreeStore({
292
+ data: this.data,
293
+ separator: this.separator,
294
+ valueKey: this.valueKey,
295
+ labelKey: this.labelKey,
296
+ childrenKey: this.childrenKey,
297
+ showLeafLabel: this.showLeafLabel
298
+ })
299
+ this.root = this.store.root
300
+ this.maxLevellist = Array.from({ length: this.store.maxLevel - 1 }, (v, i) => {
301
+ this.showData[i + 1] = []
302
+ return {
303
+ id: i + 1,
304
+ rendered: false
305
+ }
306
+ })
307
+ this.updateSelect(this.value, true, true)
308
+ }
309
+ },
310
+ mounted () {
311
+ this.init()
312
+ }
313
+ }
314
+ </script>
315
+
316
+ <style lang="scss">
317
+ .multi-cascader{
318
+ min-width:auto !important;
319
+ }
320
+ .multi-cascader .el-select-dropdown__item{
321
+ height:100%;
322
+ padding:0;
323
+ }
324
+ .multi-cascader .el-select-dropdown__wrap{
325
+ max-height: 540px;
326
+ }
327
+
328
+ .ground{
329
+ display:flex;
330
+ }
331
+ </style>
@@ -0,0 +1,177 @@
1
+ <template>
2
+ <ul class="ul-style">
3
+ <li class="li-style"
4
+ v-for="(node, nodeIndex) in list"
5
+ :key="guid(node)"
6
+ @click="handleClick(node, nodeIndex, level)"
7
+ :class="{'active-li': activeList[level - 1] === node.id}"
8
+ @mousemove="handleMouseMove(node, nodeIndex, level)"
9
+ @mouseout="handleMouseOut"
10
+ >
11
+ <p class="li-label-style" v-toolTip>
12
+ <span @click.stop v-show="!onlyLast || (onlyLast && node.isLeaf)">
13
+ <el-checkbox
14
+ @change="handleCheck($event, node)"
15
+ v-model="node.checked"
16
+ :disabled="node.disabled"
17
+ ></el-checkbox>
18
+ </span>
19
+ <span style="margin-left:5px">{{node[labelKey]}}</span>
20
+ <i v-if="node.childNodes && node.childNodes.length > 0" class="li-label-icon el-icon-arrow-right"></i>
21
+ </p>
22
+ </li>
23
+ </ul>
24
+ </template>
25
+
26
+ <script>
27
+ export default {
28
+ directives: {
29
+ toolTip: {
30
+ inserted: function (el) {
31
+ el.title = el.scrollWidth > el.offsetWidth ? el.innerText : ''
32
+ }
33
+ }
34
+ },
35
+ props: {
36
+ activeList: {
37
+ type: Array,
38
+ default: () => []
39
+ },
40
+ list: {
41
+ type: Array,
42
+ default: () => []
43
+ },
44
+ level: {
45
+ type: [Number, String]
46
+ },
47
+ labelKey: {
48
+ type: String,
49
+ default: 'label'
50
+ },
51
+ expandTrigger: {
52
+ type: String,
53
+ default: 'click'
54
+ },
55
+ onlyLast: {
56
+ type: Boolean,
57
+ default: false
58
+ }
59
+ },
60
+ data () {
61
+ return {
62
+ oldValue: {
63
+ oldNode: null,
64
+ oldLevelIndex: null,
65
+ oldLevel: null
66
+ }
67
+ }
68
+ },
69
+ methods: {
70
+ handleMouseOut () {
71
+ this.oldValue = {
72
+ oldNode: null,
73
+ oldLevelIndex: null,
74
+ oldLevel: null
75
+ }
76
+ },
77
+ // mouseEnter会一直触发,然后阻止了click事件,改为mouseMove事件
78
+ handleMouseMove (node, levelIndex, level) {
79
+ if (this.expandTrigger !== 'hover') {
80
+ return false
81
+ }
82
+ let { oldNode, oldLevelIndex, oldLevel } = this.oldValue
83
+ if (
84
+ (node === oldNode) &&
85
+ (oldLevelIndex === levelIndex) &&
86
+ (oldLevel === level)
87
+ ) {
88
+ return false
89
+ } else {
90
+ this.oldValue = {
91
+ oldNode: node,
92
+ oldLevelIndex: levelIndex,
93
+ oldLevel: level
94
+ }
95
+ }
96
+ this.$emit('handle-click', node, levelIndex, level)
97
+ },
98
+ handleClick (node, levelIndex, level) {
99
+ if (this.expandTrigger === 'click') {
100
+ this.$emit('handle-click', node, levelIndex, level)
101
+ }
102
+ },
103
+ handleCheck (v, node) {
104
+ node.checked = v
105
+ this.$emit('handle-check', node)
106
+ },
107
+ guid () {
108
+ return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
109
+ let r = Math.random() * 16 | 0
110
+ let v = c === 'x' ? r : (r & 0x3 | 0x8)
111
+ return v.toString(16)
112
+ })
113
+ }
114
+ }
115
+ }
116
+ </script>
117
+
118
+ <style lang="scss">
119
+ .ul-style{
120
+ list-style: none;
121
+ max-height:500px;
122
+ overflow-y: auto;
123
+ &::-webkit-scrollbar {
124
+ width: 8px;
125
+ height: 8px;
126
+ display: none;
127
+ }
128
+ &:hover::-webkit-scrollbar{
129
+ display: block;
130
+ }
131
+ &::-webkit-scrollbar-thumb {
132
+ border-radius: 10px;
133
+ background:#d4d3d3;
134
+ }
135
+ }
136
+ .li-style {
137
+ height: 34px;
138
+ padding-right:20px;
139
+ box-sizing: border-box;
140
+ list-style: none;
141
+ max-width: 240px;
142
+ cursor: pointer;
143
+ white-space: nowrap;
144
+ overflow: hidden;
145
+ text-overflow: ellipsis;
146
+ line-height: 34px;
147
+ &:hover{
148
+ background-color: #c8e3fe;
149
+ }
150
+ &.selected {
151
+ color: #46a0fc;
152
+ }
153
+ &.active-li {
154
+ background-color: #c8e3fe;
155
+ color: #46a0fc;
156
+ }
157
+ .li-label-style{
158
+ text-align: left;
159
+ width: 100%;
160
+ box-sizing: border-box;
161
+ padding:0 15px;
162
+ position: relative;
163
+ text-overflow: ellipsis;
164
+ white-space: nowrap;
165
+ overflow: hidden;
166
+ .li-label-icon {
167
+ position: absolute;
168
+ right: 0px;
169
+ top: 50%;
170
+ transform: translate(0, -50%);
171
+ }
172
+ .el-checkbox {
173
+ margin-right: 10px;
174
+ }
175
+ }
176
+ }
177
+ </style>
@@ -0,0 +1,14 @@
1
+ export function _uniq (arr) {
2
+ let result = []
3
+ arr.forEach(item => {
4
+ if (!result.includes(item)) {
5
+ result.push(item)
6
+ }
7
+ })
8
+ return result
9
+ }
10
+
11
+ export function _findByObj (arr, obj) {
12
+ let keys = Object.keys(obj)
13
+ return arr.find(item => keys.every(key => JSON.stringify(item[key]) === JSON.stringify(obj[key])))
14
+ }
@@ -0,0 +1,88 @@
1
+ const path = require('path')
2
+ // 插件
3
+ const MiniCssExtractPlugin = require("mini-css-extract-plugin");
4
+ const VueLoaderPlugin = require('vue-loader/lib/plugin')
5
+ // 路径
6
+ const ENTRY_PATH = resolve('./src/index.js')
7
+ const DIST_DIR = resolve('./dist')
8
+
9
+ module.exports = (env, argv) => {
10
+ return {
11
+ // 入口
12
+ entry: [
13
+ resolve('src/index.js')
14
+ ],
15
+ // 出口
16
+ output: {
17
+ path: resolve('dist'),
18
+ filename: 'index.js',
19
+ },
20
+ resolve: {
21
+ // 定义模块查找的后缀,方便在代码引用时可省略后缀
22
+ extensions: ['.js', '.vue', '.json'],
23
+ // 定义路径简写
24
+ alias: {
25
+ 'vue$': 'vue/dist/vue.esm.js',
26
+ 'src' : resolve('src'),
27
+ '@' : resolve('src'),
28
+ }
29
+ },
30
+ module: {
31
+ // 文件的loader
32
+ rules: [
33
+ {
34
+ test: /\.js$/,
35
+ loader:"babel-loader",
36
+ exclude: /node_modules/
37
+ },
38
+ {
39
+ test: /\.vue$/,
40
+ loader: 'vue-loader'
41
+ },
42
+ {
43
+ test: /\.css$/,
44
+ use: [
45
+ 'vue-style-loader',
46
+ 'css-loader'
47
+ ]
48
+ },
49
+ {
50
+ test: /\.scss$/,
51
+ use: [
52
+ 'vue-style-loader',
53
+ 'css-loader',
54
+ 'sass-loader'
55
+ ]
56
+ },
57
+ {
58
+ test: /\.sass$/,
59
+ use: [
60
+ 'vue-style-loader',
61
+ 'css-loader',
62
+ {
63
+ loader: 'sass-loader',
64
+ options: {
65
+ indentedSyntax: true
66
+ }
67
+ }
68
+ ]
69
+ }
70
+ ]
71
+ },
72
+ plugins: [
73
+ // 处理css,可以把vue中提取css为单独文件
74
+ new MiniCssExtractPlugin({
75
+ filename: "css/[name].[hash].css"
76
+ }),
77
+ // webpack4下,vue-loader需要这样引入
78
+ new VueLoaderPlugin()
79
+ ],
80
+
81
+ devtool: 'source-map'
82
+ }
83
+ }
84
+
85
+ function resolve(dir) {
86
+ return path.join(__dirname, './', dir);
87
+ }
88
+
@@ -0,0 +1,17 @@
1
+ /*
2
+ * @Author: leevan
3
+ * @Date: 2024-04-20 17:28:33
4
+ * @LastEditTime: 2024-04-20 17:28:36
5
+ * @LastEditors: leevan
6
+ * @FilePath: /jtui-pc/packages/Search-Type/index.js
7
+ */
8
+ // 导入组件,组件必须声明 name
9
+ import SearchType from './index.vue';
10
+
11
+ // 为组件提供 install 安装方法,供按需引入
12
+ SearchType.install = function (Vue) {
13
+ Vue.component(SearchType.name, SearchType)
14
+ }
15
+
16
+ // 导出组件
17
+ export default SearchType