kintoneって全文検索という便利な機能があるんですよ。
エクセル業務のkintone乗り換えも多いんですよ。
乗り換え時に、全文検索もあるし、とりあえず手元にあるエクセルを全部登録しとくか!
という話もあると思うんですよ・・・多分・・・きっとどこかに・・・
ということで(?)、昔のデータを探す時にエクセルをダウンロードすることなく、kintone上でエクセル内の画像だけでも見られたら便利だなと思い立ち・・・思い立ったが吉日!
まずはdeveloper networkなどで似た記事がないか確認 φ(・ω・ )
なかったのでエクセルファイル内の画像をkintoneに登録するサンプルプログラムを作ってみました。
できること
kintoneに添付されたエクセル内の画像を添付ファイルとして登録する。
文字データは未対応ですが、もう少し頑張ればできると思います。
出来上がりのイメージ
今回は結果から!
↓のように2シートに計5枚の画像が挿入されているエクセルで試してみると・・・
上手く行きました!(画面が灰色になっているのはリロードのため)
エクセル5ファイル、計40個の画像でも正常に動作することを確認しています。
前提
- エクセルの形式はxlsx
- 画像の種類はJPG、GIF、PNG
- kintoneのフォーム設定は以下の通り
フィールド名 | フィールドタイプ | フィールドコード |
---|---|---|
エクセルファイル | 添付ファイル | excelFile |
画像ファイル | 添付ファイル | imageFile |
スペース | button |
- JS/CSS設定は以下
- https://js.cybozu.com/jquery/2.2.0/jquery.min.js
- https://js.cybozu.com/jszip/v2.5.0/jszip.min.js
- ↓のJSファイル(ボタンを少し綺麗にする場合はCSSファイルも)
sample.js
(function() {
'use strict';
kintone.events.on('app.record.detail.show', parseExcel);
function parseExcel(event) {
var button = kintone.app.record.getSpaceElement('button');
$(button).append('<button id="parseExcelButton">エクセルファイル内の画像をkintoneに登録!</button>');
$(button).append('<div id="parseExcelMessage"></div>');
var record = event.record;
$('#parseExcelButton').on('click', function(e) {
$(this).prop('disabled', true);
e.preventDefault();
var files = record.excelFile.value;
var excelFileKeys = [];
for (var i = 0; i < files.length; i++) {
if (files[i].contentType !== 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet') {
continue;
}
excelFileKeys.push(files[i].fileKey);
}
if (excelFileKeys.length === 0) {
$('#parseExcelMessage').text('エクセルファイルが登録されていません。');
return false;
}
Promise.all(excelFileKeys.map(function(excelFileKey) {
$('#parseExcelMessage').text('エクセルファイル取得中...');
return getFile(excelFileKey);
})).then(function(blobList) {
console.log('[SUCCESS] get excel files.');
$('#parseExcelMessage').text('エクセルファイル内の画像取得中...');
// 2次元配列を1次元配列に
var blobs = Array.prototype.concat.apply([], blobList);
return Promise.all(blobs.map(function(blob) {
return pickupImages(blob);
}));
}).then(function(imageList) {
console.log('[SUCCESS] get image files.');
$('#parseExcelMessage').text('画像登録中...');
var images = Array.prototype.concat.apply([], imageList);
return Promise.all(images.map(function(image) {
return uploadImage(image);
}));
}).then(function(fileKeyList) {
console.log('[SUCCESS] upload image files.');
$('#parseExcelMessage').text('レコード更新中...');
var fileKeys = Array.prototype.concat.apply([], fileKeyList);
return updateRecord(fileKeys);
}).then(function() {
location.reload();
}).catch(function(error) {
console.log('[ERROR]', error);
});
});
}
// kintoneに添付されたファイルをダウンロード
function getFile(fileKey) {
var url = '/k/v1/file.json?fileKey=' + fileKey;
var df = new $.Deferred();
var xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
xhr.responseType = 'blob';
xhr.onload = function(e) {
if (this.status === 200) {
df.resolve(this.response);
}
};
xhr.send();
return df.promise();
}
// エクセルファイル内の画像を取得
function pickupImages(blob) {
var df = new $.Deferred();
var reader = new FileReader();
reader.readAsDataURL(blob);
// .xlsxファイルの読み込み
reader.onload = function(e) {
var xlsxBase64 = e.target.result.split(',')[1];
var zip = new JSZip();
zip = zip.load(xlsxBase64, {base64: true});
var mediaFiles = zip.folder('xl/media').file(/^image/);
var images = [];
for (var i = 0; i < mediaFiles.length; i++) {
var filePath = mediaFiles[i].name;
var fileName = filePath.replace(/.*\//, '');
var fileMime = toMimeType(filePath);
var arrayBuffer = zip.file(filePath).asArrayBuffer();
var imageBlob = new Blob([arrayBuffer], {type: fileMime});
images[i] = {'name': fileName, 'blob': imageBlob};
}
df.resolve(images);
};
return df.promise();
}
// 画像をkintoneに登録し、fileKeyを返す
function uploadImage(image) {
return new Promise(function(resolve, reject) {
var formData = new FormData();
formData.append('__REQUEST_TOKEN__', kintone.getRequestToken());
formData.append('file', image.blob, image.name);
var xhr = new XMLHttpRequest();
xhr.open('POST', '/k/v1/file.json', true);
xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
xhr.onload = function(e) {
if (this.status === 200) {
var res = JSON.parse(this.responseText);
resolve(res.fileKey);
} else {
reject(JSON.parse(this.responseText));
}
};
xhr.send(formData);
});
}
// レコード更新
function updateRecord(fileKeys) {
var appId = kintone.app.getId();
var recId = kintone.app.record.getId();
var putData = {
'app': appId,
'id': recId,
'record': {
'imageFile': {
'value': []
}
}
};
for (var i = 0; i < fileKeys.length; i++) {
putData.record['imageFile'].value.push({'fileKey': fileKeys[i]});
}
return kintone.api('/k/v1/record', 'PUT', putData);
}
// MimeTypeを返す
function toMimeType(filePath) {
var reg = /(.*)(?:\.([^.]+$))/;
var fileExt = filePath.match(reg)[2];
var mimeType = '';
switch (fileExt.toLowerCase()) {
case 'jpg':
mimeType = 'image/jpeg';
break;
case 'jpeg':
mimeType = 'image/jpeg';
break;
case 'png':
mimeType = 'image/png';
break;
case 'gif':
mimeType = 'image/gif';
break;
}
return mimeType;
}
})();
sample.css
button#parseExcelButton{
display: block;
padding: 10px;
margin: 20px;
text-align: center;
border: 3px solid;
border-color: #ccc #999 #999 #ccc;
color: #666
}
button#parseExcelButton:hover{
background: #aaa;
color: #fff;
}
div#parseExcelMessage{
display: block;
padding: 10px;
margin: 20px;
text-align: center;
}
kintone開発者ライセンス
kintone面白そうだな~と思った方は5ユーザー、1年間無償の開発者ライセンスを使ってみてください!