web-component-gallery 2.2.33 → 2.2.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.
- package/dist/index.umd.js +1 -1
- package/dist/js.umd.js +1 -1
- package/dist/styles.css +21 -0
- package/dist/styles.umd.js +1 -0
- package/lib/descriptions-list/index.jsx +2 -1
- package/lib/index.js +5 -2
- package/lib/table/index.vue +148 -111
- package/lib/table-examples/index.js +19 -0
- package/lib/table-examples/styles/index.js +1 -0
- package/lib/table-examples/styles/index.less +0 -0
- package/lib/transfer-table/index.js +7 -0
- package/lib/transfer-table/index.vue +278 -0
- package/lib/transfer-table/styles/index.js +1 -0
- package/lib/transfer-table/styles/index.less +20 -0
- package/package.json +1 -1
- package/utils/Utils.js +19 -3
- package/utils/ColorPalette.js +0 -57
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<!-- 列表形式穿梭框 -->
|
|
3
|
+
<div class="TransferTable">
|
|
4
|
+
<div class="TransferTable__Search" v-if="searchSetting && searchSetting.length">
|
|
5
|
+
<Search
|
|
6
|
+
v-model="searchForm"
|
|
7
|
+
:formSetting="searchSetting"
|
|
8
|
+
@handleSearch="handleSearch"
|
|
9
|
+
@handleReset="handleReset"
|
|
10
|
+
/>
|
|
11
|
+
</div>
|
|
12
|
+
<div class="TransferTable__Content">
|
|
13
|
+
<div class="TransferTable__Left">
|
|
14
|
+
<Table
|
|
15
|
+
v-bind="{
|
|
16
|
+
datas: listDatasA,
|
|
17
|
+
columns,
|
|
18
|
+
paginationParams: listPaginationA,
|
|
19
|
+
rowSelection: {
|
|
20
|
+
selectedRowKeys: selectedKeys,
|
|
21
|
+
onChange: selectedRecords,
|
|
22
|
+
getCheckboxProps: record => ({
|
|
23
|
+
props: {
|
|
24
|
+
disabled: isRecordDisabled(record)
|
|
25
|
+
}
|
|
26
|
+
})
|
|
27
|
+
}
|
|
28
|
+
}"
|
|
29
|
+
@pageSizeChange="(pagination) => (listPaginationA = pagination, onListPageAHandler())"
|
|
30
|
+
>
|
|
31
|
+
<span class="Table__Name" slot="ATableTitle">{{title}}列表</span>
|
|
32
|
+
<template #action="{customProps, index}">
|
|
33
|
+
<Button
|
|
34
|
+
v-for="(op, i) in operateSetting"
|
|
35
|
+
:key="i"
|
|
36
|
+
type="link"
|
|
37
|
+
:disabled="shouldDisableButton(op, customProps)"
|
|
38
|
+
@click="handleTableAction(op.code, customProps)"
|
|
39
|
+
>
|
|
40
|
+
{{ op.title }}
|
|
41
|
+
</Button>
|
|
42
|
+
</template>
|
|
43
|
+
</Table>
|
|
44
|
+
</div>
|
|
45
|
+
|
|
46
|
+
<div class="TransferTable__Right">
|
|
47
|
+
<Table
|
|
48
|
+
v-bind="{
|
|
49
|
+
datas: listDatasB,
|
|
50
|
+
columns,
|
|
51
|
+
paginationParams: listPaginationB,
|
|
52
|
+
rowSelection: {
|
|
53
|
+
selectedRowKeys: selectedKeys,
|
|
54
|
+
onChange: selectedRecords,
|
|
55
|
+
getCheckboxProps: record => ({
|
|
56
|
+
props: {
|
|
57
|
+
disabled: isRecordDisabled(record)
|
|
58
|
+
}
|
|
59
|
+
})
|
|
60
|
+
}
|
|
61
|
+
}"
|
|
62
|
+
@pageSizeChange="(pagination) => (listPaginationB = pagination, onListPageBHandler())"
|
|
63
|
+
>
|
|
64
|
+
<span class="Table__Name" slot="ATableTitle">已选{{title}}列表</span>
|
|
65
|
+
<template #action="{customProps, index}">
|
|
66
|
+
<Button
|
|
67
|
+
v-for="(op, i) in operateSetting"
|
|
68
|
+
:key="i"
|
|
69
|
+
type="link"
|
|
70
|
+
:disabled="shouldDisableButton(op, customProps)"
|
|
71
|
+
@click="handleTableAction(op.code, customProps)"
|
|
72
|
+
>
|
|
73
|
+
{{ op.title }}
|
|
74
|
+
</Button>
|
|
75
|
+
</template>
|
|
76
|
+
</Table>
|
|
77
|
+
</div>
|
|
78
|
+
|
|
79
|
+
</div>
|
|
80
|
+
</div>
|
|
81
|
+
</template>
|
|
82
|
+
|
|
83
|
+
<script>
|
|
84
|
+
|
|
85
|
+
import { Button } from 'ant-design-vue'
|
|
86
|
+
import { Search, Table } from '../index'
|
|
87
|
+
import { chunkArray } from '../../utils/Utils'
|
|
88
|
+
|
|
89
|
+
export default {
|
|
90
|
+
name: 'TransferTable',
|
|
91
|
+
components: {
|
|
92
|
+
Search,
|
|
93
|
+
Table,
|
|
94
|
+
Button
|
|
95
|
+
},
|
|
96
|
+
props: {
|
|
97
|
+
// 列表名称
|
|
98
|
+
title: {
|
|
99
|
+
type: String,
|
|
100
|
+
default: '人员'
|
|
101
|
+
},
|
|
102
|
+
// 双向绑定的已选记录
|
|
103
|
+
value: {
|
|
104
|
+
type: Array,
|
|
105
|
+
default: () => ([])
|
|
106
|
+
},
|
|
107
|
+
// 列表项
|
|
108
|
+
columns: Array,
|
|
109
|
+
// 支持传递额外参数
|
|
110
|
+
extraParams: {
|
|
111
|
+
type: Object,
|
|
112
|
+
default: () => ({})
|
|
113
|
+
},
|
|
114
|
+
// 搜索项
|
|
115
|
+
searchSetting: Array,
|
|
116
|
+
// 操作配置
|
|
117
|
+
operateSetting: Array,
|
|
118
|
+
// 分页接口(A表数据获取)
|
|
119
|
+
onListPageHandler: {
|
|
120
|
+
type: Function,
|
|
121
|
+
required: true
|
|
122
|
+
},
|
|
123
|
+
// 已经保存到数据库的记录ID列表
|
|
124
|
+
savedRecordIds: {
|
|
125
|
+
type: Array,
|
|
126
|
+
default: () => ([])
|
|
127
|
+
}
|
|
128
|
+
},
|
|
129
|
+
data() {
|
|
130
|
+
return {
|
|
131
|
+
// 搜索条件
|
|
132
|
+
searchForm: {},
|
|
133
|
+
selectedKeys: [],
|
|
134
|
+
|
|
135
|
+
// A表格(待选区)
|
|
136
|
+
listDatasA: [],
|
|
137
|
+
listPaginationA: {
|
|
138
|
+
current: 1,
|
|
139
|
+
size: 10,
|
|
140
|
+
total: 0
|
|
141
|
+
},
|
|
142
|
+
|
|
143
|
+
// B表格(已选区)
|
|
144
|
+
listDatasB: [],
|
|
145
|
+
listPaginationB: {
|
|
146
|
+
current: 1,
|
|
147
|
+
size: 10,
|
|
148
|
+
total: 0
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
},
|
|
152
|
+
computed: {
|
|
153
|
+
// 使用计算属性实现双向绑定
|
|
154
|
+
selectedRecordsB: {
|
|
155
|
+
get() {
|
|
156
|
+
return this.value
|
|
157
|
+
},
|
|
158
|
+
set(val) {
|
|
159
|
+
this.$emit('input', val)
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
},
|
|
163
|
+
watch: {
|
|
164
|
+
// 当搜索条件变化时重置左表
|
|
165
|
+
searchForm: {
|
|
166
|
+
handler() {
|
|
167
|
+
this.resetLeftTable()
|
|
168
|
+
},
|
|
169
|
+
deep: true
|
|
170
|
+
},
|
|
171
|
+
selectedRecordsB: {
|
|
172
|
+
handler() {
|
|
173
|
+
this.onListPageBHandler()
|
|
174
|
+
},
|
|
175
|
+
deep: true
|
|
176
|
+
}
|
|
177
|
+
},
|
|
178
|
+
mounted() {
|
|
179
|
+
this.onListPageAHandler()
|
|
180
|
+
},
|
|
181
|
+
methods: {
|
|
182
|
+
// 列表操作处理
|
|
183
|
+
handleTableAction(name, record) {
|
|
184
|
+
this.$postM({
|
|
185
|
+
name,
|
|
186
|
+
method: 'modalOpen',
|
|
187
|
+
params: record
|
|
188
|
+
})
|
|
189
|
+
},
|
|
190
|
+
handleReset() {
|
|
191
|
+
this.searchForm = {}
|
|
192
|
+
this.handleSearch()
|
|
193
|
+
},
|
|
194
|
+
handleSearch() {
|
|
195
|
+
this.listPagination = {
|
|
196
|
+
current: 1,
|
|
197
|
+
size: 10,
|
|
198
|
+
total: 0
|
|
199
|
+
}
|
|
200
|
+
this.onListPageHandler()
|
|
201
|
+
},
|
|
202
|
+
// 获取左侧表格数据
|
|
203
|
+
async onListPageAHandler() {
|
|
204
|
+
const params = {
|
|
205
|
+
...this.listPaginationA,
|
|
206
|
+
...this.extraParams,
|
|
207
|
+
...this.searchForm
|
|
208
|
+
}
|
|
209
|
+
try {
|
|
210
|
+
const { total, records } = await this.onListPageHandler(params)
|
|
211
|
+
this.listDatasA = records
|
|
212
|
+
this.listPaginationA = {
|
|
213
|
+
...this.listPaginationA,
|
|
214
|
+
total
|
|
215
|
+
}
|
|
216
|
+
} catch(err) {
|
|
217
|
+
console.error('获取待选人员失败:', err)
|
|
218
|
+
}
|
|
219
|
+
},
|
|
220
|
+
|
|
221
|
+
// 获取右侧表格数据(从已选记录中分页)
|
|
222
|
+
onListPageBHandler() {
|
|
223
|
+
try {
|
|
224
|
+
const chunks = chunkArray(this.selectedRecordsB, this.listPaginationB.size)
|
|
225
|
+
this.listDatasB = chunks[this.listPaginationB.current - 1] || []
|
|
226
|
+
this.listPaginationB = {
|
|
227
|
+
...this.listPaginationB,
|
|
228
|
+
total: this.selectedRecordsB.length
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// 同步选中状态
|
|
232
|
+
this.selectedKeys = this.selectedRecordsB.map(r => r.id)
|
|
233
|
+
} catch(err) {
|
|
234
|
+
console.error('更新已选列表失败:', err)
|
|
235
|
+
}
|
|
236
|
+
},
|
|
237
|
+
|
|
238
|
+
// 取消 / 选择当前行
|
|
239
|
+
selectedRecords(selectedKey, selectedRecord) {
|
|
240
|
+
const currentIds = new Set(this.selectedRecordsB.map(r => r.id))
|
|
241
|
+
const newIds = new Set(selectedKey)
|
|
242
|
+
|
|
243
|
+
this.selectedRecordsB = newIds.size > currentIds.size
|
|
244
|
+
? [...this.selectedRecordsB, ...selectedRecord.filter(r =>
|
|
245
|
+
newIds.has(r.id) && !currentIds.has(r.id)
|
|
246
|
+
)]
|
|
247
|
+
: this.selectedRecordsB.filter(r => newIds.has(r.id))
|
|
248
|
+
},
|
|
249
|
+
|
|
250
|
+
// 重置左表到第一页
|
|
251
|
+
async resetLeftTable() {
|
|
252
|
+
this.listPaginationA.current = 1
|
|
253
|
+
await this.onListPageAHandler()
|
|
254
|
+
},
|
|
255
|
+
|
|
256
|
+
// 检查记录是否已被保存(需要禁用)
|
|
257
|
+
isRecordDisabled(record) {
|
|
258
|
+
return this.savedRecordIds.includes(record.id)
|
|
259
|
+
},
|
|
260
|
+
|
|
261
|
+
// 判断按钮是否应该禁用
|
|
262
|
+
shouldDisableButton(operation, record) {
|
|
263
|
+
// 如果没有设置 savedRecordIds,则不禁用任何按钮
|
|
264
|
+
if (!this.savedRecordIds || this.savedRecordIds.length === 0) {
|
|
265
|
+
return false
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
// 如果该操作明确设置为不禁用已保存记录,则返回 false
|
|
269
|
+
if (operation.disableSaved === false) {
|
|
270
|
+
return false
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
// 默认情况下,已保存的记录相关操作按钮会被禁用
|
|
274
|
+
return this.isRecordDisabled(record)
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
</script>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
require('./index.less');
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
@import '~ant-design-vue/lib/style/themes/default.less';
|
|
2
|
+
@import '../../style/mixins.less';
|
|
3
|
+
|
|
4
|
+
.TransferTable {
|
|
5
|
+
flex: 1;
|
|
6
|
+
.flex-layout(column, @padding-xs 0);
|
|
7
|
+
|
|
8
|
+
&__Search {
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
&__Content {
|
|
12
|
+
flex: 1;
|
|
13
|
+
.flex-layout(@flexGap: 0 @padding-xs);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
&__Left,
|
|
17
|
+
&__Right {
|
|
18
|
+
height: 100%;
|
|
19
|
+
}
|
|
20
|
+
}
|
package/package.json
CHANGED
package/utils/Utils.js
CHANGED
|
@@ -2,12 +2,28 @@ import message from 'ant-design-vue/es/message'
|
|
|
2
2
|
import { verifyIPStr } from './Validate'
|
|
3
3
|
import { findNthOccurrence } from './Filter'
|
|
4
4
|
|
|
5
|
+
|
|
5
6
|
/**
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
7
|
+
* 数据分块工具函数
|
|
8
|
+
* @param {Array} arr - 源数组
|
|
9
|
+
* @param {number} size - 分块大小
|
|
10
|
+
* @returns {Array} 分块后的数组
|
|
9
11
|
*/
|
|
12
|
+
export function chunkArray(arr, size) {
|
|
13
|
+
const result = []
|
|
14
|
+
for (let i = 0; i < arr.length; i += size) {
|
|
15
|
+
result.push(arr.slice(i, i + size))
|
|
16
|
+
}
|
|
17
|
+
return result
|
|
18
|
+
}
|
|
10
19
|
|
|
20
|
+
/**
|
|
21
|
+
* 下载文件
|
|
22
|
+
* @param {Blob} response - 文档流
|
|
23
|
+
* @param {string} name - 文件名称
|
|
24
|
+
* @param {string} type - 文件类型
|
|
25
|
+
* @returns {void}
|
|
26
|
+
*/
|
|
11
27
|
export function downLoadFn( response, name, type = "application/vnd.ms-excel" ) {
|
|
12
28
|
|
|
13
29
|
let reader = new FileReader()
|
package/utils/ColorPalette.js
DELETED
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
const tinycolor = require('tinycolor2')
|
|
2
|
-
|
|
3
|
-
const hueStep = 2
|
|
4
|
-
const saturationStep = 16
|
|
5
|
-
const saturationStep2 = 5
|
|
6
|
-
const brightnessStep1 = 5
|
|
7
|
-
const brightnessStep2 = 15
|
|
8
|
-
const lightColorCount = 5
|
|
9
|
-
const darkColorCount = 4
|
|
10
|
-
|
|
11
|
-
const getHue = (hsv, i, isLight) => {
|
|
12
|
-
let hue = hsv.h >= 60 && hsv.h <= 240
|
|
13
|
-
? isLight ? hsv.h - hueStep * i : hsv.h + hueStep * i
|
|
14
|
-
: isLight ? hsv.h + hueStep * i : hsv.h - hueStep * i
|
|
15
|
-
|
|
16
|
-
hue < 0
|
|
17
|
-
? hue += 360
|
|
18
|
-
: hue >= 360 && (hue -= 360)
|
|
19
|
-
|
|
20
|
-
return Math.round(hue)
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
const getSaturation = (hsv, i, isLight) => {
|
|
24
|
-
let saturation = isLight
|
|
25
|
-
? Math.round(hsv.s * 100) - saturationStep * i
|
|
26
|
-
: (
|
|
27
|
-
i === darkColorCount
|
|
28
|
-
? Math.round(hsv.s * 100) + saturationStep
|
|
29
|
-
: Math.round(hsv.s * 100) + saturationStep2 * i
|
|
30
|
-
)
|
|
31
|
-
|
|
32
|
-
if (saturation > 100) saturation = 100
|
|
33
|
-
if (isLight && i === lightColorCount && saturation > 10) saturation = 10
|
|
34
|
-
if (saturation < 6) saturation = 6
|
|
35
|
-
|
|
36
|
-
return Math.round(saturation)
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
const getValue = (hsv, i, isLight) => {
|
|
40
|
-
if (isLight) return Math.round(hsv.v * 100) + brightnessStep1 * i
|
|
41
|
-
return Math.round(hsv.v * 100) - brightnessStep2 * i
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
// 颜色调色板生成器
|
|
45
|
-
module.exports = (color, index) => {
|
|
46
|
-
const isLight = index <= 6
|
|
47
|
-
const hsv = tinycolor(color).toHsv()
|
|
48
|
-
const i = isLight
|
|
49
|
-
? lightColorCount + 1 - index
|
|
50
|
-
: index - lightColorCount - 1
|
|
51
|
-
|
|
52
|
-
return tinycolor({
|
|
53
|
-
h: getHue(hsv, i, isLight),
|
|
54
|
-
s: getSaturation(hsv, i, isLight),
|
|
55
|
-
v: getValue(hsv, i, isLight)
|
|
56
|
-
}).toHexString()
|
|
57
|
-
}
|