@bit-sun/business-component 1.0.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.
@@ -0,0 +1,599 @@
1
+ /*
2
+ * @Description:
3
+ * @Author: rodchen
4
+ * @Date: 2021-12-01 10:52:08
5
+ * @LastEditTime: 2021-12-08 00:27:22
6
+ * @LastEditors: rodchen
7
+ */
8
+ // @ts-nocheck
9
+ import React from 'react';
10
+ import {
11
+ Button,
12
+ Card,
13
+ Radio,
14
+ Checkbox,
15
+ Space,
16
+ Dropdown,
17
+ Menu,
18
+ Tooltip,
19
+ } from 'antd';
20
+ import { DragDropContext, Droppable, Draggable } from 'react-beautiful-dnd';
21
+ import 'antd/dist/antd.css';
22
+ import {
23
+ ExclamationCircleOutlined,
24
+ DownOutlined,
25
+ ProfileTwoTone,
26
+ UnorderedListOutlined,
27
+ } from '@ant-design/icons';
28
+ import './index.less';
29
+
30
+ const luckysheet = window.luckysheet;
31
+
32
+ let itemsTemp = [];
33
+
34
+ // for dnd
35
+ // fake data generator
36
+ const getItems = (count) =>
37
+ Array.from({ length: count }, (v, k) => k).map((k) => ({
38
+ id: `item-${k}`,
39
+ content: `item ${k}`,
40
+ }));
41
+
42
+ // a little function to help us with reordering the result
43
+ const reorder = (list, startIndex, endIndex) => {
44
+ const result = Array.from(list);
45
+ const [removed] = result.splice(startIndex, 1);
46
+ result.splice(endIndex, 0, removed);
47
+
48
+ return result;
49
+ };
50
+
51
+ const grid = 8;
52
+
53
+ const getItemStyle = (isDragging, draggableStyle) => ({
54
+ // some basic styles to make the items look a bit nicer
55
+ userSelect: 'none',
56
+ padding: `4px`,
57
+ margin: `4px`,
58
+ // change background colour if dragging
59
+
60
+ // styles we need to apply on draggables
61
+ ...draggableStyle,
62
+ });
63
+
64
+ const getListStyle = (isDraggingOver) => ({
65
+ background: isDraggingOver ? '#fff' : '#fff',
66
+ display: 'flex',
67
+ padding: grid,
68
+ overflow: 'auto',
69
+ });
70
+
71
+ const filterLetters = (i) => {
72
+ if (i >= 0 && i <= 25) {
73
+ return String.fromCharCode(65 + i);
74
+ } else {
75
+ return undefined;
76
+ }
77
+ };
78
+
79
+ class Luckysheet extends React.Component {
80
+ constructor(props) {
81
+ super(props);
82
+
83
+ itemsTemp = props.columns.map((item, index) => {
84
+ return {
85
+ id: `item-0${index}`,
86
+ content: item[0],
87
+ code: item[1],
88
+ };
89
+ });
90
+
91
+ this.state = {
92
+ showErrorData: false,
93
+ data: [],
94
+ items: [...itemsTemp],
95
+ resultData: [],
96
+ errorListCheck: false,
97
+ };
98
+ }
99
+
100
+ onDragEnd(result) {
101
+ // dropped outside the list
102
+ if (!result.destination) {
103
+ return;
104
+ }
105
+
106
+ const items = reorder(
107
+ this.state.items,
108
+ result.source.index,
109
+ result.destination.index,
110
+ );
111
+
112
+ this.setState({
113
+ items,
114
+ });
115
+
116
+ itemsTemp = items;
117
+
118
+ luckysheet.refresh();
119
+ }
120
+
121
+ getCount = () => {
122
+ try {
123
+ const { items } = this.state;
124
+
125
+ let data = luckysheet.getSheetData();
126
+ let validIndex = items.length;
127
+
128
+ if (data[0] && data[0][validIndex]) {
129
+ return {
130
+ total: data.filter((item) => item[validIndex]).length,
131
+ error: data.filter(
132
+ (item) => item[validIndex] && item[validIndex].v !== '通过',
133
+ ).length,
134
+ };
135
+ } else {
136
+ return {
137
+ total: 0,
138
+ error: 0,
139
+ };
140
+ }
141
+ } catch (e) {
142
+ return {
143
+ total: 0,
144
+ error: 0,
145
+ };
146
+ }
147
+ };
148
+
149
+ setConfig = (data) => {
150
+ const { items } = this.state;
151
+ return {
152
+ container: 'luckysheet',
153
+ showtoolbar: false,
154
+ hook: {
155
+ columnTitleCellRenderBefore: function (columnAbc, postion, ctx) {
156
+ if (columnAbc.name) {
157
+ let charCode = columnAbc.name.charCodeAt();
158
+ if (charCode - 65 <= items.length) {
159
+ columnAbc.name = itemsTemp[charCode - 65]
160
+ ? itemsTemp[charCode - 65].content
161
+ : '校验结果';
162
+ } else {
163
+ columnAbc.name = '';
164
+ }
165
+ }
166
+ },
167
+ cellRenderAfter: function (cell, postion, sheetFile, ctx) {
168
+ if (cell) {
169
+ cell.fs = 10;
170
+ }
171
+ // console.log(postion);
172
+ },
173
+ cellAllRenderBefore: function (data, sheetFile, ctx) {
174
+ sheetFile.config.borderInfo = [];
175
+ // console.info(data,sheetFile,ctx)
176
+ },
177
+ },
178
+ // showtoolbarConfig: {
179
+ // undoRedo: true, //撤销重做,注意撤消重做是两个按钮,由这一个配置决定显示还是隐藏
180
+ // paintFormat: false, //格式刷
181
+ // currencyFormat: false, //货币格式
182
+ // percentageFormat: false, //百分比格式
183
+ // numberDecrease: false, // '减少小数位数'
184
+ // numberIncrease: false, // '增加小数位数
185
+ // moreFormats: false, // '更多格式'
186
+ // font: true, // '字体'
187
+ // fontSize: true, // '字号大小'
188
+
189
+ // },
190
+ data: [
191
+ {
192
+ name: 'Cell', //工作表名称
193
+ color: '', //工作表颜色
194
+ index: 0, //工作表索引
195
+ status: 1, //激活状态
196
+ order: 0, //工作表的下标
197
+ hide: 0, //是否隐藏
198
+ row: 36, //行数
199
+ column: 18, //列数
200
+ defaultRowHeight: 20, //自定义行高
201
+ defaultColWidth: 120, //自定义列宽
202
+ config: {},
203
+ celldata: data,
204
+ scrollLeft: 0, //左右滚动条位置
205
+ // "scrollTop": 315, //上下滚动条位置
206
+ luckysheet_select_save: [], //选中的区域
207
+ calcChain: [], //公式链
208
+ isPivotTable: false, //是否数据透视表
209
+ pivotTable: {}, //数据透视表设置
210
+ filter_select: {}, //筛选范围
211
+ filter: null, //筛选配置
212
+ luckysheet_alternateformat_save: [], //交替颜色
213
+ luckysheet_alternateformat_save_modelCustom: [], //自定义交替颜色
214
+ luckysheet_conditionformat_save: {}, //条件格式
215
+ frozen: {}, //冻结行列配置
216
+ chart: [], //图表配置
217
+ zoomRatio: 1, // 缩放比例
218
+ image: [], //图片
219
+ showGridLines: 1, //是否显示网格线
220
+ dataVerification: {}, //数据验证配置
221
+ luckysheet_alternateformat_save: [
222
+ {
223
+ cellrange: {
224
+ //单元格范围
225
+ row: [0, 1000],
226
+ column: [0, 18],
227
+ },
228
+ format: {
229
+ head: {
230
+ //页眉颜色
231
+ fc: '#6aa84f',
232
+ bc: '#ffffff',
233
+ },
234
+ one: {
235
+ //第一种颜色
236
+ bc: '#ffffff',
237
+ },
238
+ two: {
239
+ //第二种颜色
240
+ bc: '#f2f4f5',
241
+ },
242
+ foot: {
243
+ //页脚颜色
244
+ fc: '#000',
245
+ bc: '#a5efcc',
246
+ },
247
+ },
248
+ hasRowHeader: false, //含有页眉
249
+ hasRowFooter: false, //含有页脚
250
+ },
251
+ ], //交替颜色
252
+ luckysheet_alternateformat_save_modelCustom: [
253
+ {
254
+ head: {
255
+ //页眉颜色
256
+ fc: '#6aa84f',
257
+ bc: '#ffffff',
258
+ },
259
+ one: {
260
+ //第一种颜色
261
+ fc: '#000',
262
+ bc: '#ffffff',
263
+ },
264
+ two: {
265
+ //第二种颜色
266
+ fc: '#000',
267
+ bc: '#e5fbee',
268
+ },
269
+ foot: {
270
+ //页脚颜色
271
+ fc: '#000',
272
+ bc: '#a5efcc',
273
+ },
274
+ },
275
+ ], //自定义交替颜色
276
+ },
277
+ ],
278
+ cellRightClickConfig: {
279
+ copy: false, // 复制
280
+ copyAs: false, // 复制为
281
+ paste: false, // 粘贴
282
+ insertRow: false, // 插入行
283
+ insertColumn: false, // 插入列
284
+ // deleteRow: false, // 删除选中行
285
+ // deleteColumn: false, // 删除选中列
286
+ deleteCell: false, // 删除单元格
287
+ hideRow: false, // 隐藏选中行和显示选中行
288
+ hideColumn: false, // 隐藏选中列和显示选中列
289
+ rowHeight: false, // 行高
290
+ columnWidth: false, // 列宽
291
+ clear: false, // 清除内容
292
+ matrix: false, // 矩阵操作选区
293
+ sort: false, // 排序选区
294
+ filter: false, // 筛选选区
295
+ chart: false, // 图表生成
296
+ image: false, // 插入图片
297
+ link: false, // 插入链接
298
+ data: false, // 数据验证
299
+ cellFormat: false, // 设置单元格格式
300
+ },
301
+ showsheetbar: false,
302
+ optionstate: false,
303
+ showstatisticBarConfig: {
304
+ count: false, // 计数栏
305
+ view: false, // 打印视图
306
+ zoom: false, // 缩放
307
+ },
308
+ column: 10, //列数
309
+ columnHeaderHeight: 30,
310
+ lang: 'zh',
311
+ defaultFontSize: '10',
312
+ frozen: {
313
+ type: 'rangeBoth',
314
+ range: { row_focus: 1, column_focus: 1 },
315
+ },
316
+ };
317
+ };
318
+
319
+ componentDidMount() {
320
+ luckysheet.create(this.setConfig([]));
321
+ }
322
+
323
+ componentWillUnmount() {
324
+ // luckysheet.create(this.setConfig([]));
325
+ luckysheet.destroy();
326
+ }
327
+
328
+ getData = () => {
329
+ console.time();
330
+ let sheetData = luckysheet.getSheetData();
331
+ let data = sheetData
332
+ .filter((item) => item[0])
333
+ .map((item) => {
334
+ let obj = {};
335
+ item.slice(0, itemsTemp.length).map((innerItem, index) => {
336
+ obj[this.state.items[index].code] = innerItem && innerItem.v;
337
+ });
338
+ return obj;
339
+ });
340
+
341
+ return data;
342
+ };
343
+
344
+ resetData = () => {
345
+ const { validDataFunction, updateData } = this.props;
346
+ const resultData = this.getData();
347
+ new Promise((resolve, reject) => {
348
+ validDataFunction(resultData, resolve);
349
+ }).then((res) => {
350
+ const { items } = this.state;
351
+ let validIndex = items.length;
352
+
353
+ let sheetData = luckysheet.getSheetData();
354
+
355
+ sheetData.map((item, index) => {
356
+ if (!res[index]) return item;
357
+
358
+ if (res[index].flag) {
359
+ item[validIndex] = {
360
+ ...item[validIndex],
361
+ v: '通过',
362
+ m: '通过',
363
+ fc: 'green', //字体颜色为 "#990000"
364
+ };
365
+ } else {
366
+ item[validIndex] = {
367
+ ...item[validIndex],
368
+ v: res[index].checkResults,
369
+ m: res[index].checkResults,
370
+ fc: 'red', //字体颜色为 "#990000"
371
+ };
372
+ }
373
+
374
+ item[validIndex].ct = { fa: 'General', t: 'g' };
375
+ });
376
+ // sheetData.map((item, index) => {
377
+ // luckysheet.setCellValue(index + 1, 4, 345)
378
+ // })
379
+
380
+ luckysheet.create(this.setConfig(luckysheet.transToCellData(sheetData)));
381
+ this.setState({
382
+ data: luckysheet.transToCellData(sheetData),
383
+ errorListCheck: false,
384
+ });
385
+
386
+ updateData = this.getData();
387
+
388
+ debugger;
389
+ });
390
+ };
391
+
392
+ filterData = (type: string) => {
393
+ const { showErrorData, data } = this.state;
394
+ let sheetData = luckysheet.transToData(data).filter((item, index) => {
395
+ if (type === 'all') {
396
+ return false;
397
+ }
398
+ if (type === 'error') {
399
+ return item[itemsTemp.length] && item[itemsTemp.length].v === '通过';
400
+ }
401
+ });
402
+
403
+ luckysheet.create(this.setConfig(luckysheet.transToCellData(sheetData)));
404
+ exportData = this.getData();
405
+ this.setState({
406
+ data: luckysheet.transToCellData(sheetData),
407
+ errorListCheck: false,
408
+ });
409
+ };
410
+
411
+ toggleData = () => {
412
+ const { showErrorData, data } = this.state;
413
+
414
+ if (showErrorData) {
415
+ luckysheet.create(this.setConfig(data));
416
+ } else {
417
+ let sheetData = luckysheet.getSheetData();
418
+ sheetData = sheetData.filter((item, index) => {
419
+ return !item[itemsTemp.length] || item[itemsTemp.length].v !== '通过';
420
+ });
421
+
422
+ luckysheet.create(this.setConfig(luckysheet.transToCellData(sheetData)));
423
+ }
424
+
425
+ this.setState({
426
+ showErrorData: !showErrorData,
427
+ });
428
+ };
429
+
430
+ onChange = (e) => {
431
+ this.setState({
432
+ radioValue: e.target.value,
433
+ });
434
+ this.toggleData();
435
+ };
436
+
437
+ errorChange = (e: any) => {
438
+ this.toggleData();
439
+ this.setState({
440
+ errorListCheck: e.target.checked,
441
+ });
442
+ };
443
+
444
+ menuList = (
445
+ <Menu>
446
+ <Menu.Item className="sheet_table-menu_item_text">
447
+ <a onClick={() => this.filterData('all')}>清空全部数据</a>
448
+ </Menu.Item>
449
+ <Menu.Divider />
450
+ <Menu.Item className="sheet_table-menu_item_text">
451
+ <a onClick={() => this.filterData('error')}>仅清空错误数据</a>
452
+ </Menu.Item>
453
+ </Menu>
454
+ );
455
+
456
+ leftMenu = (
457
+ <Menu>
458
+ <Menu.Item className="sheet_table-menu_item_text">
459
+ <span className="sheet_table_text">请拖动字段来对应列</span>
460
+ </Menu.Item>
461
+ <Menu.Divider />
462
+ <div>
463
+ <DragDropContext onDragEnd={(e) => this.onDragEnd(e)}>
464
+ <Droppable droppableId="droppable" direction="vertical">
465
+ {(provided, snapshot) => (
466
+ <div
467
+ ref={provided.innerRef}
468
+ style={{
469
+ ...getListStyle(snapshot.isDraggingOver),
470
+ flexDirection: 'column',
471
+ }}
472
+ {...provided.droppableProps}
473
+ >
474
+ {this.state.items.map((item, index) => (
475
+ <Draggable key={item.id} draggableId={item.id} index={index}>
476
+ {(provided, snapshot) => (
477
+ <div
478
+ ref={provided.innerRef}
479
+ {...provided.draggableProps}
480
+ {...provided.dragHandleProps}
481
+ style={getItemStyle(
482
+ snapshot.isDragging,
483
+ provided.draggableProps.style,
484
+ )}
485
+ >
486
+ <Space>
487
+ <span>{filterLetters(index)} 列 </span>
488
+ <Space className="sheet_table_dnd_text">
489
+ <UnorderedListOutlined />
490
+ {item.content}
491
+ </Space>
492
+ </Space>
493
+ </div>
494
+ )}
495
+ </Draggable>
496
+ ))}
497
+ {provided.placeholder}
498
+ </div>
499
+ )}
500
+ </Droppable>
501
+ </DragDropContext>
502
+ </div>
503
+ </Menu>
504
+ );
505
+
506
+ render() {
507
+ const { errorListCheck } = this.state;
508
+ const { title } = this.props;
509
+
510
+ let totalSummary = this.getCount();
511
+
512
+ const luckyCss = {
513
+ margin: '0px',
514
+ padding: '0px',
515
+ position: 'absolute',
516
+ width: '100%',
517
+ height: '100%',
518
+ left: '0px',
519
+ top: '0px',
520
+ };
521
+ return (
522
+ <Card
523
+ title={
524
+ <Space>
525
+ {title}
526
+ <Tooltip
527
+ title={
528
+ <>
529
+ <span>使用指南:</span>
530
+ <br></br>
531
+ <span>
532
+ 1、拖动数据项,以适配源数据的顺序,如您Excel中数据排序依次为编码、价格和数量,则您也可以将数据项的顺序调整为一致
533
+ </span>
534
+ <br></br>
535
+ <span>2、复制文件数据(多列一起),在文本框内进行粘贴</span>
536
+ <br></br>
537
+ <span>
538
+ 3、点击识别按钮进行数据校验,如全部正确,则点击录入按钮可录入数据,如存在错误数据,则需修改后再进行录入
539
+ </span>
540
+ </>
541
+ }
542
+ >
543
+ <ExclamationCircleOutlined />
544
+ </Tooltip>
545
+ </Space>
546
+ }
547
+ >
548
+ <div className="sheet_table_top">
549
+ <Space>
550
+ <span>排序列</span>
551
+ <Dropdown
552
+ trigger={['click']}
553
+ overlay={this.leftMenu}
554
+ placement="bottomLeft"
555
+ >
556
+ <a>
557
+ <ProfileTwoTone />
558
+ </a>
559
+ </Dropdown>
560
+ </Space>
561
+ <Space>
562
+ <Dropdown
563
+ trigger={['click']}
564
+ overlay={this.menuList}
565
+ placement="bottomRight"
566
+ >
567
+ <Button>
568
+ 清空
569
+ <DownOutlined />
570
+ </Button>
571
+ </Dropdown>
572
+
573
+ <Button type="primary" onClick={this.resetData}>
574
+ 识别
575
+ </Button>
576
+ </Space>
577
+ </div>
578
+
579
+ <div style={{ position: 'relative', height: '400px' }}>
580
+ <div id="luckysheet" style={luckyCss}></div>
581
+ </div>
582
+ <div className="sheet_table_footer">
583
+ <span className="sheet_table_footer_l">
584
+ 共 {totalSummary.total} 条数据, 其中错误 {totalSummary.error} 项
585
+ </span>
586
+ <Space className="sheet_table_footer_r">
587
+ <Checkbox
588
+ checked={errorListCheck}
589
+ onClick={this.errorChange}
590
+ ></Checkbox>
591
+ 仅展示错误数据
592
+ </Space>
593
+ </div>
594
+ </Card>
595
+ );
596
+ }
597
+ }
598
+
599
+ export default Luckysheet;
package/src/index.ts ADDED
@@ -0,0 +1,9 @@
1
+ /*
2
+ * @Description:
3
+ * @Author: rodchen
4
+ * @Date: 2021-11-30 22:59:39
5
+ * @LastEditTime: 2021-12-07 17:05:50
6
+ * @LastEditors: rodchen
7
+ */
8
+
9
+ export { default as SheetTable } from './SheetTable';
package/tsconfig.json ADDED
@@ -0,0 +1,29 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "esnext",
4
+ "module": "esnext",
5
+ "moduleResolution": "node",
6
+ "importHelpers": true,
7
+ "jsx": "react",
8
+ "esModuleInterop": true,
9
+ "sourceMap": true,
10
+ "baseUrl": "./",
11
+ "strict": true,
12
+ "paths": {
13
+ "@/*": ["src/*"],
14
+ "@@/*": ["src/.umi/*"]
15
+ },
16
+ "allowSyntheticDefaultImports": true
17
+ },
18
+ "exclude": [
19
+ "node_modules",
20
+ "lib",
21
+ "es",
22
+ "dist",
23
+ "typings",
24
+ "**/__test__",
25
+ "test",
26
+ "docs",
27
+ "tests"
28
+ ]
29
+ }
package/typings.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ declare module '*.css';
2
+ declare module '*.less';