4 changed files with 371 additions and 13 deletions
-
307src/components/JsonExcel.vue
-
2src/main.js
-
40src/views/modules/project/projectInfo/projectInfo.vue
-
35src/views/modules/proofing/requestForProofing.vue
@ -0,0 +1,307 @@ |
|||||
|
<template> |
||||
|
<div :id="idName" @click="generate"> |
||||
|
<slot> Download {{ name }} </slot> |
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<script> |
||||
|
import * as XLSXNS from "xlsx"; |
||||
|
|
||||
|
const XLSX = XLSXNS.default || XLSXNS; |
||||
|
|
||||
|
export default { |
||||
|
props: { |
||||
|
type: { |
||||
|
type: String, |
||||
|
default: "xls", |
||||
|
}, |
||||
|
data: { |
||||
|
type: Array, |
||||
|
required: false, |
||||
|
default: null, |
||||
|
}, |
||||
|
fields: { |
||||
|
type: Object, |
||||
|
default: () => null, |
||||
|
}, |
||||
|
exportFields: { |
||||
|
type: Object, |
||||
|
default: () => null, |
||||
|
}, |
||||
|
defaultValue: { |
||||
|
type: String, |
||||
|
required: false, |
||||
|
default: "", |
||||
|
}, |
||||
|
header: { |
||||
|
default: null, |
||||
|
}, |
||||
|
footer: { |
||||
|
default: null, |
||||
|
}, |
||||
|
name: { |
||||
|
type: String, |
||||
|
default: "data.xls", |
||||
|
}, |
||||
|
fetch: { |
||||
|
type: Function, |
||||
|
}, |
||||
|
meta: { |
||||
|
type: Array, |
||||
|
default: () => [], |
||||
|
}, |
||||
|
worksheet: { |
||||
|
type: String, |
||||
|
default: "Sheet1", |
||||
|
}, |
||||
|
beforeGenerate: { |
||||
|
type: Function, |
||||
|
}, |
||||
|
beforeFinish: { |
||||
|
type: Function, |
||||
|
}, |
||||
|
escapeCsv: { |
||||
|
type: Boolean, |
||||
|
default: true, |
||||
|
}, |
||||
|
stringifyLongNum: { |
||||
|
type: Boolean, |
||||
|
default: false, |
||||
|
}, |
||||
|
}, |
||||
|
computed: { |
||||
|
idName() { |
||||
|
var now = new Date().getTime(); |
||||
|
return "export_" + now; |
||||
|
}, |
||||
|
downloadFields() { |
||||
|
if (this.fields) return this.fields; |
||||
|
if (this.exportFields) return this.exportFields; |
||||
|
}, |
||||
|
}, |
||||
|
methods: { |
||||
|
async generate() { |
||||
|
if (typeof this.beforeGenerate === "function") { |
||||
|
await this.beforeGenerate(); |
||||
|
} |
||||
|
let data = this.data; |
||||
|
try { |
||||
|
if (typeof this.fetch === "function" || !data) data = await this.fetch(); |
||||
|
} catch (e) { |
||||
|
if (typeof this.beforeFinish === "function") await this.beforeFinish(); |
||||
|
throw e; |
||||
|
} |
||||
|
|
||||
|
if (!data || !data.length) { |
||||
|
if (typeof this.beforeFinish === "function") await this.beforeFinish(); |
||||
|
if (this.$message) { |
||||
|
this.$message.warning("没有数据可导出"); |
||||
|
} |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
let json = this.getProcessedJson(data, this.downloadFields); |
||||
|
if (this.type === "csv") { |
||||
|
return this.exportText( |
||||
|
this.jsonToCSV(json), |
||||
|
this.buildFileName("csv"), |
||||
|
"text/csv;charset=utf-8" |
||||
|
); |
||||
|
} |
||||
|
return this.exportWorkbook(this.jsonToWorkbook(json), this.buildFileName("xlsx")); |
||||
|
}, |
||||
|
pageTitle() { |
||||
|
const title = this.$route && this.$route.meta && this.$route.meta.title; |
||||
|
const text = title == null ? "" : String(title).trim(); |
||||
|
if (!text || text.indexOf(".") >= 0) return ""; |
||||
|
return text; |
||||
|
}, |
||||
|
buildFileName(ext) { |
||||
|
const now = this.dayjs().format("YYYYMMDDHHmmss"); |
||||
|
const title = this.pageTitle(); |
||||
|
let raw = String(this.name || "").replace(/\.xlsx?$/i, "").replace(/\.csv$/i, "").trim(); |
||||
|
const prefix = raw.replace(/\d{14}$/, "").replace(/[_\-\s]+$/, ""); |
||||
|
const base = (title || prefix || "导出") + now; |
||||
|
return base.replace(/[\\/:*?"<>|]/g, "_") + "." + ext; |
||||
|
}, |
||||
|
safeSheetName(name) { |
||||
|
const text = String(name || "Sheet1").replace(/[:\\/?*\[\]]/g, " ").trim() || "Sheet1"; |
||||
|
return text.slice(0, 31); |
||||
|
}, |
||||
|
titleRows() { |
||||
|
const header = this.header || this.$attrs.title; |
||||
|
if (header == null || (Array.isArray(header) && header.length === 0)) { |
||||
|
return []; |
||||
|
} |
||||
|
const rows = Array.isArray(header) ? header.filter((item) => item) : [header]; |
||||
|
const title = this.pageTitle(); |
||||
|
if (title && rows.length === 1) { |
||||
|
return [title]; |
||||
|
} |
||||
|
return rows; |
||||
|
}, |
||||
|
exportWorkbook(workbook, filename) { |
||||
|
const output = XLSX.write(workbook, { bookType: "xlsx", type: "array" }); |
||||
|
const blob = new Blob([output], { |
||||
|
type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", |
||||
|
}); |
||||
|
this.saveBlob(blob, filename); |
||||
|
}, |
||||
|
exportText(data, filename, mime) { |
||||
|
const blob = new Blob(["\ufeff" + data], { type: mime }); |
||||
|
this.saveBlob(blob, filename); |
||||
|
}, |
||||
|
async saveBlob(blob, filename) { |
||||
|
if (typeof this.beforeFinish === "function") await this.beforeFinish(); |
||||
|
const link = document.createElement("a"); |
||||
|
const url = window.URL.createObjectURL(blob); |
||||
|
link.href = url; |
||||
|
link.download = filename; |
||||
|
link.style.display = "none"; |
||||
|
document.body.appendChild(link); |
||||
|
link.click(); |
||||
|
document.body.removeChild(link); |
||||
|
window.URL.revokeObjectURL(url); |
||||
|
}, |
||||
|
jsonToWorkbook(data) { |
||||
|
const labels = Object.keys(data[0] || {}); |
||||
|
const rows = []; |
||||
|
const titles = this.titleRows(); |
||||
|
titles.forEach((text) => rows.push([text])); |
||||
|
rows.push(labels); |
||||
|
data.forEach((item) => { |
||||
|
rows.push(labels.map((key) => this.cellValue(item[key]))); |
||||
|
}); |
||||
|
if (this.footer != null && !(Array.isArray(this.footer) && this.footer.length === 0)) { |
||||
|
const footerRows = Array.isArray(this.footer) ? this.footer : [this.footer]; |
||||
|
footerRows.forEach((text) => { |
||||
|
if (text) rows.push([text]); |
||||
|
}); |
||||
|
} |
||||
|
const sheet = XLSX.utils.aoa_to_sheet(rows); |
||||
|
if (labels.length > 1 && titles.length) { |
||||
|
sheet["!merges"] = titles.map((_, index) => ({ |
||||
|
s: { r: index, c: 0 }, |
||||
|
e: { r: index, c: labels.length - 1 }, |
||||
|
})); |
||||
|
} |
||||
|
const workbook = XLSX.utils.book_new(); |
||||
|
const sheetName = this.safeSheetName(this.pageTitle() || this.worksheet); |
||||
|
XLSX.utils.book_append_sheet(workbook, sheet, sheetName); |
||||
|
return workbook; |
||||
|
}, |
||||
|
cellValue(value) { |
||||
|
if (typeof value === "string") { |
||||
|
return this.preprocessLongNum(value.replace(/<br\s*\/?>/gi, "\n")); |
||||
|
} |
||||
|
return this.preprocessLongNum(value); |
||||
|
}, |
||||
|
jsonToCSV(data) { |
||||
|
let _self = this; |
||||
|
var csvData = []; |
||||
|
const header = this.titleRows(); |
||||
|
if (header.length) { |
||||
|
csvData.push(this.parseExtraData(header, "${data}\r\n")); |
||||
|
} |
||||
|
for (let key in data[0]) { |
||||
|
csvData.push(key); |
||||
|
csvData.push(","); |
||||
|
} |
||||
|
csvData.pop(); |
||||
|
csvData.push("\r\n"); |
||||
|
data.map(function (item) { |
||||
|
for (let key in item) { |
||||
|
let escapedCSV = item[key] + ""; |
||||
|
if (_self.escapeCsv) { |
||||
|
escapedCSV = '="' + escapedCSV + '"'; |
||||
|
if (escapedCSV.match(/[,"\n]/)) { |
||||
|
escapedCSV = '"' + escapedCSV.replace(/\"/g, '""') + '"'; |
||||
|
} |
||||
|
} |
||||
|
csvData.push(escapedCSV); |
||||
|
csvData.push(","); |
||||
|
} |
||||
|
csvData.pop(); |
||||
|
csvData.push("\r\n"); |
||||
|
}); |
||||
|
if (this.footer != null) { |
||||
|
csvData.push(this.parseExtraData(this.footer, "${data}\r\n")); |
||||
|
} |
||||
|
return csvData.join(""); |
||||
|
}, |
||||
|
getProcessedJson(data, header) { |
||||
|
let keys = this.getKeys(data, header); |
||||
|
let newData = []; |
||||
|
let _self = this; |
||||
|
data.map(function (item) { |
||||
|
let newItem = {}; |
||||
|
for (let label in keys) { |
||||
|
let property = keys[label]; |
||||
|
newItem[label] = _self.getValue(property, item); |
||||
|
} |
||||
|
newData.push(newItem); |
||||
|
}); |
||||
|
return newData; |
||||
|
}, |
||||
|
getKeys(data, header) { |
||||
|
if (header) { |
||||
|
return header; |
||||
|
} |
||||
|
let keys = {}; |
||||
|
for (let key in data[0]) { |
||||
|
keys[key] = key; |
||||
|
} |
||||
|
return keys; |
||||
|
}, |
||||
|
parseExtraData(extraData, format) { |
||||
|
let parseData = ""; |
||||
|
if (Array.isArray(extraData)) { |
||||
|
for (var i = 0; i < extraData.length; i++) { |
||||
|
if (extraData[i]) parseData += format.replace("${data}", extraData[i]); |
||||
|
} |
||||
|
} else { |
||||
|
parseData += format.replace("${data}", extraData); |
||||
|
} |
||||
|
return parseData; |
||||
|
}, |
||||
|
getValue(key, item) { |
||||
|
const field = typeof key !== "object" ? key : key.field; |
||||
|
let indexes = typeof field !== "string" ? [] : field.split("."); |
||||
|
let value = this.defaultValue; |
||||
|
if (!field) value = item; |
||||
|
else if (indexes.length > 1) value = this.getValueFromNestedItem(item, indexes); |
||||
|
else value = this.parseValue(item[field]); |
||||
|
if (key.hasOwnProperty("callback")) value = this.getValueFromCallback(value, key.callback); |
||||
|
return value; |
||||
|
}, |
||||
|
preprocessLongNum(value) { |
||||
|
if (this.stringifyLongNum) { |
||||
|
if (String(value).startsWith("0x")) { |
||||
|
return value; |
||||
|
} |
||||
|
if (!isNaN(value) && value != "") { |
||||
|
if (value > 99999999999 || value < 0.0000000000001) { |
||||
|
return String(value); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
return value; |
||||
|
}, |
||||
|
getValueFromNestedItem(item, indexes) { |
||||
|
let nestedItem = item; |
||||
|
for (let index of indexes) { |
||||
|
if (nestedItem) nestedItem = nestedItem[index]; |
||||
|
} |
||||
|
return this.parseValue(nestedItem); |
||||
|
}, |
||||
|
getValueFromCallback(item, callback) { |
||||
|
if (typeof callback !== "function") return this.defaultValue; |
||||
|
const value = callback(item); |
||||
|
return this.parseValue(value); |
||||
|
}, |
||||
|
parseValue(value) { |
||||
|
return value || value === 0 || typeof value === "boolean" ? value : this.defaultValue; |
||||
|
}, |
||||
|
}, |
||||
|
}; |
||||
|
</script> |
||||
Write
Preview
Loading…
Cancel
Save
Reference in new issue