mirror of https://github.com/nocodb/nocodb
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
95 lines
2.9 KiB
95 lines
2.9 KiB
3 years ago
|
import XLSX from 'xlsx'
|
||
|
import { UITypes } from '~/components/project/spreadsheet/helpers/uiTypes'
|
||
3 years ago
|
import TemplateGenerator from '~/components/import/templateParsers/TemplateGenerator'
|
||
3 years ago
|
|
||
|
const excelTypeToUidt = {
|
||
|
d: UITypes.DateTime,
|
||
|
b: UITypes.Checkbox,
|
||
|
n: UITypes.Number,
|
||
|
s: UITypes.SingleLineText
|
||
|
}
|
||
|
|
||
|
export default class ExcelTemplateAdapter extends TemplateGenerator {
|
||
|
constructor(name, ab) {
|
||
|
super()
|
||
|
this.name = name
|
||
3 years ago
|
this.excelData = ab
|
||
3 years ago
|
this.project = {
|
||
|
title: this.name,
|
||
|
tables: []
|
||
|
}
|
||
|
this.data = {}
|
||
|
}
|
||
|
|
||
3 years ago
|
async init() {
|
||
|
this.wb = XLSX.read(new Uint8Array(this.excelData), { type: 'array' })
|
||
|
}
|
||
|
|
||
3 years ago
|
parse() {
|
||
|
for (let i = 0; i < this.wb.SheetNames.length; i++) {
|
||
|
const sheet = this.wb.SheetNames[i]
|
||
|
const table = { tn: sheet, columns: [] }
|
||
|
this.data[sheet] = []
|
||
|
const ws = this.wb.Sheets[sheet]
|
||
|
const rows = XLSX.utils.sheet_to_json(ws, { header: 1 })
|
||
|
|
||
|
for (let col = 0; col < rows[0].length; col++) {
|
||
|
const column = {
|
||
3 years ago
|
cn: (rows[0][col] || `field${col + 1}`).replace(/\./, '_')
|
||
3 years ago
|
}
|
||
|
|
||
3 years ago
|
const cellProps = ws[`${col.toString(26).split('').map(s => (parseInt(s, 26) + 10).toString(36).toUpperCase())}2`] || {}
|
||
3 years ago
|
|
||
|
column.uidt = excelTypeToUidt[cellProps.t] || UITypes.SingleLineText
|
||
|
|
||
|
// todo: optimize
|
||
|
if (column.uidt === UITypes.SingleLineText) {
|
||
|
// check for long text
|
||
|
if (rows.some(r => (r[col] || '').toString().length > 255)) {
|
||
|
column.uidt = UITypes.LongText
|
||
|
} else {
|
||
|
const vals = rows.slice(1).map(r => r[col]).filter(v => v !== null && v !== undefined)
|
||
|
|
||
|
// check column is multi or single select by comparing unique values
|
||
3 years ago
|
if (vals.some(v => v && v.toString().includes(','))) {
|
||
|
const flattenedVals = vals.flatMap(v => v ? v.toString().split(',') : [])
|
||
3 years ago
|
const uniqueVals = new Set(flattenedVals)
|
||
|
if (flattenedVals.length > uniqueVals.size && uniqueVals.size <= flattenedVals.length / 10) {
|
||
|
column.uidt = UITypes.MultiSelect
|
||
|
column.dtxp = [...uniqueVals].join(',')
|
||
|
}
|
||
|
} else {
|
||
|
const uniqueVals = new Set(vals)
|
||
|
if (vals.length > uniqueVals.size && uniqueVals.size <= vals.length / 10) {
|
||
|
column.uidt = UITypes.SingleSelect
|
||
|
column.dtxp = [...uniqueVals].join(',')
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
table.columns.push(column)
|
||
|
}
|
||
|
|
||
|
for (const row of rows.slice(1)) {
|
||
|
const rowData = {}
|
||
|
for (let i = 0; i < table.columns.length; i++) {
|
||
|
// toto: do parsing if necessary based on type
|
||
|
rowData[table.columns[i].cn] = row[i]
|
||
|
}
|
||
|
this.data[sheet].push(rowData)
|
||
|
}
|
||
|
|
||
|
this.project.tables.push(table)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
getTemplate() {
|
||
|
return this.project
|
||
|
}
|
||
|
|
||
|
getData() {
|
||
|
return this.data
|
||
|
}
|
||
|
}
|