uniapp 前端导出excel

需求:app前端导出excel,不需要后台参与

方案1:用付费插件(Android读取excel或导出数据到Excel表 - DCloud 插件市场)实操确实可以用,可以设置各种属性,比较齐全

方案2:免费,缺点是有些属性目前不能适配,后续要研究一下,下面写下方案2的流程和代码

一、在comon创建exportExcel.js

// exportExcel.js 可以直接复制
let imgCount = 1;//图片计数器

/**
 * 导出Excel
 * @param {Object} fileName 文件名 会自动拼接时间戳防止重名
 * @param {Object} data 数据内容 格式说明见下
 * @param {Object} callback 导出成功的回调方法 返回文件保存路径
 * 
 * 二维数组 其中外层数组中的每个元素为数组 对应一行    内层数组中的每个元素为object对象 对应每个单元格 属性如下:
 * type 类型 text为文字 img为图片 默认文字
 * width 单元格宽度 请带单位 默认300px
 * height 单元格高度 请带单位 默认25px
 * color 文字颜色 默认黑色
 * fontSize 字号 请带单位 默认16px
 * textAlign 文字对齐方式 默认left
 * imgWidth 仅type为img时需要 图片宽度 无需带单位 默认25
 * imgHeight 仅type为img时需要 图片高度 无需带单位 默认25
 * content 单元格内容 type为img时为图片路径 仅支持base64
 * colspan 跨列 默认1
 * rowspan 跨行 默认1
 * 
 * 示例:
 * [
	[{
		content: '姓名',
		color: 'blue',
		type: 'text',
		width: '200px',
		height: '25px',
		fontSize: '16px'
	}, {
		content: '性别',
		color: 'blue',
		type: 'text',
		width: '200px',
		height: '25px',
		fontSize: '16px'
	}, {
		content: '头像',
		color: 'blue',
		type: 'text',
		width: '200px',
		height: '25px',
		fontSize: '16px'
	}],
	[{
		content: '张三',
		color: 'blue',
		type: 'text',
		width: '200px',
		height: '25px',
		fontSize: '16px',
		colspan: 2,
		rowspan:2
	}, {
		content: 'base64图片',
		type: 'img',
		width: '200px',
		height: '25px',
		imgWidth: 25,
		imgHeight: 25
	}],
	[{
		content: '123',
		color: 'blue',
		type: 'text',
		width: '200px',
		height: '25px',
		fontSize: '16px'
	}]
]
 */
let doExport = function (fileName,data,callback){
	imgCount = 1;
	let date = new Date();
	let year = date.getFullYear();
	let month = date.getMonth() + 1;
	let day = date.getDate();
	let hour = date.getHours();
	let minute = date.getMinutes();
	let second = date.getSeconds();
	if(month < 10){
		month = '0' + month;
	}
	if(day < 10){
		day = '0' + day;
	}
	if(hour < 10){
		hour = '0' + hour;
	}
	if(minute < 10){
		minute = '0' + minute;
	}
	if(second < 10){
		second = '0' + second;
	}
	let name = fileName || '导出的Excel';
	let reg = /\\|\//g;
	name = name.replace(reg,'|');
	name = '' + year + month + day + hour + minute + second + '_' + name;
	uni.showLoading({
		title: '正在导出',
		mask: true
	});
	formatTable(name,data,callback);
}

async function formatTable(name,data,callback){
	let table = `<table style="line-height:3;">`;
	for (let item of data) {
		table += `<tr>`;
		for (let i of item) {
			let width = i.width || '70px';
			let height = i.height || '25px';
			let color = i.color || 'balck';
			let fontSize = i.fontSize || '16px';
			let textAlign = i.textAlign || 'left';
			let border = i.border || 'none';
			let colspan = i.colspan || 1;
			let rowspan = i.rowspan || 1;
			if(i.type==='img'){
				let imgWidth = i.imgWidth || 25;
				let imgHeight = i.imgHeight || 25;
				let src = await saveImg(name,i.content);
				console.log(src);
				if(src === 'fail'){
					uni.hideLoading();
					uni.showToast({
						title: '导出失败,请确认是否授权文件权限',
						icon: 'none'
					});
					return;
				}
				table += `<td style="width:${width};height:${height};color:${color};font-size:${fontSize};text-align:${textAlign};border:${border}" colspan="${colspan}" rowspan="${rowspan}"><img src="/图片${imgCount}.jpg" width="${imgWidth}" height="${imgHeight}">(图片${imgCount}.jpg)</td>`;
				imgCount ++;
			}else{
				table += `<td style="width:${width};height:${height};color:${color};font-size:${fontSize};text-align:${textAlign};border:${border};word-wrap:break-word;word-break:break-all;font-family:'宋体'" colspan="${colspan}" rowspan="${rowspan}">${i.content}</td>`;
			}
		}
		table += `</tr>`;
	}
	table += `</table>`;
	exportFile(formatTemplate(table),name,callback);
}

function formatTemplate(data) {
	let template = `<html xmlns:o="urn:schemas-microsoft-com:office:office" 
			xmlns:x="urn:schemas-microsoft-com:office:excel" 
			xmlns="http://www.w3.org/TR/REC-html40">
			<head><!--[if gte mso 9]><xml encoding="UTF-8"><x:ExcelWorkbook><x:ExcelWorksheets><x:ExcelWorksheet>
			<x:Name>sheet1</x:Name>
			<x:WorksheetOptions><x:DisplayGridlines/></x:WorksheetOptions></x:ExcelWorksheet>
			</x:ExcelWorksheets></x:ExcelWorkbook></xml><![endif]-->
			</head><body>${data}</body></html>`;
	return template;
}

function exportFile(fileData,documentName,callback) {
	createDir(documentName,(dirEntry,path,name) => {
		dirEntry.getFile(`${documentName}.xlsx`, {
			create: true
		}, (fileEntry) => {
			fileEntry.createWriter((writer) => {
				writer.onwritestart = (e) => {
					console.log('onwritestart');
				}
				writer.onwrite = (e) => {
					// 成功导出数据;
					setTimeout(() => {
						uni.hideLoading();
						uni.showToast({
							title: "成功导出",
							icon: "success"
						});
						console.log(`导出成功,文件位置:${path}/${documentName}.xlsx`);
						callback(`${path}/${documentName}.xlsx`);
					}, 1000);
				};
				// 写入内容;
				writer.write(fileData);
			}, function(e) {
				console.log(e.message);
				uni.hideLoading();
				uni.showToast({
					title: '导出失败,请确认是否授权文件权限',
					icon: 'none'
				});
			});
		},err=>{
			console.log(err);
			uni.hideLoading();
			uni.showToast({
				title: '导出失败,请确认是否授权文件权限',
				icon: 'none'
			});
		});
	});
}

function saveImg(name,base64){
	return new Promise((resolve,reject) => {
		createDir(name,(dirEntry,path,name) => {
			let bitmap = new plus.nativeObj.Bitmap('图片'+imgCount);
			bitmap.loadBase64Data(base64,res => {
				console.log(`图片${imgCount}加载base64成功`);
				let fileName = '_documents/导出的Excel/' + name + '/图片' + imgCount + '.jpg';
				bitmap.save(fileName,{overwrite:true,quality:100,format:'jpg'},res1 => {
					console.log(res1);
					console.log(`图片${imgCount}保存成功,路径:${fileName}`);
					bitmap.clear();
					resolve('success');
				},err1 => {
					console.log(err1);
					reject('fail');
				});
			},err => {
				console.log(err);
				reject('fail');
			});
		});
	});
}

function createDir(name,callback){
	plus.io.requestFileSystem(plus.io.PUBLIC_DOCUMENTS, (fs) => {
		let rootObj = fs.root;
		let fullPath = rootObj.fullPath;
		rootObj.getDirectory('导出的Excel',{create:true},dirEntry => {
			dirEntry.getDirectory(name,{create:true},dirEntry2 => {
				let pathStr = fullPath.replace("/storage/emulated/0", "");
				pathStr += '导出的Excel/'+name;
				console.log(`目录${pathStr}创建成功`);
				callback(dirEntry2,pathStr,name);
			},err2=>{
				console.log(err2);
				uni.hideLoading();
				uni.showToast({
					title: '导出失败,请确认是否授权文件权限',
					icon: 'none'
				});
			});
		},err1=>{
			console.log(err1);
			uni.hideLoading();
			uni.showToast({
				title: '导出失败,请确认是否授权文件权限',
				icon: 'none'
			});
		});
	},err=>{
		console.log(err);
		uni.hideLoading();
		uni.showToast({
			title: '导出失败,请确认是否授权文件权限',
			icon: 'none'
		});
	});
}

module.exports = doExport;

二、组件中使用

let doExport = require('@/common/exportExcel.js')
import { jsons } from './excelJson.js'

async printingOutline(item) { // 离线导出
	//要导出的json数据
	const jsonData = JSON.parse(JSON.stringify(jsons))
	const that = this
	doExport('input', jsonData, function(result){
		that.open(result)
	})
},

open(url) { // 打开excel
	uni.openDocument({
		filePath: '/storage/emulated/0'+url, // 要加上前面/storage/emulated/0,不然打不开
		success:(res3) =>console.log('成功打开文档'),
		fail: (err) => {
			console.log('失败')
			console.log(err)
		}
	})
}

excelJson.js

export const jsons = [
	[
		{
			content: '预防控制中心',	
			type: 'text',
			fontSize: '18px',
			colspan: 18,
			textAlign: 'center',
			height: '50px'
		}
	],
	[
		{
			content: '采(抽)样登记表',
			type: 'text',
			fontSize: '18px',
			colspan: 18,
			textAlign: 'center',
			height: '50px'
		}
	],
	[
		{
			id: 'test_category',
			content: '检验检测类别',
			type: 'text',
			fontSize: '10px',
			colspan: 18,
			border: 'solid 1px #000'
		}
	],
	[
		{
			id: 'index',
			content: '序号',
			type: 'text',
			fontSize: '10px',
			border: 'solid 1px #000'
		},
		{
			id: 'sample_category_text',
			content: '样品类别',
			type: 'text',
			fontSize: '10px',
			border: 'solid 1px #000'
		},
		{
			id: 'sample_number',
			content: '样品编号',
			type: 'text',
			fontSize: '10px',
			border: 'solid 1px #000'
		},
		{
			id: 'sample_name',
			content: '样品名称',
			type: 'text',
			fontSize: '10px',
		},
		{
			id: 'sample_specifications_text',
			content: '样品规格',
			type: 'text',
			fontSize: '10px',
		},
		{
			id: 'quantity',
			content: '数量',
			type: 'text',
			fontSize: '10px',
		},
		{
			id: 'packaging_type_text',
			content: '包装类型',
			type: 'text',
			fontSize: '10px'
		},
		{
			id: 'sample_trademark',
			content: '样品商标',
			type: 'text',
			fontSize: '10px'
		},
		{
			id: 'packaging_form',
			content: '包装形式',
			type: 'text',
			fontSize: '10px'
		},
		{
			id: 'place_of_origin',
			content: '产地',
			type: 'text',
			fontSize: '10px',
		},
		{
			id: 'manufacturer',
			content: '生产厂家(样品来源)',
			type: 'text',
			fontSize: '10px',		    
		},
		{
			id: 'manufacturer_address',
			content: '生产厂家地址',
			type: 'text',
			fontSize: '10px',
		},
		{
			id: 'manufacture_date_number',
			content: '生产日期/批号',
			type: 'text',
			fontSize: '10px',
		},
		{
			id: 'sample_character_text',
			content: '样品性状',
			type: 'text',
			fontSize: '10px',
		},
		{
			id: 'storage_condition_text',
			content: '保存条件',
			type: 'text',
			fontSize: '10px',
		},
		{
			id: 'sample_locations',
			content: '采样地点',
			type: 'text',
			fontSize: '10px',
		},
		{
			id: 'sample_locations_type_text',
			content: '采样地点类型',
			type: 'text',
			fontSize: '10px',
		},
		{
			id: 'remark',
			content: '备注',
			type: 'text',
			fontSize: '10px',
		}
	]
]

三、导出结果

 

  • 2
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值