前提
SpreadShhetのwebアプリを利用して、QRコードを読み込むPOSシステムのようなものを考えています。
ここでは、読み取り後の購入情報等をgas側に送信しSpreadSheetへ書き込みを行うと同時にhtml側に領収書ページを表示させたいと考えています。
doPost関数へ値を渡し、SpreadSheetへの書き込み。htmlServiceにてファイルを作成するところまではできていると思います。
ですが、html側のfetchにて返信されたデータを確認するとobjectは受け取れるのですが、html側でページの遷移を起こすことができず、どのように実装してよいか悩んでおります。
実現したいこと
ここに実現したいことを箇条書きで書いてください。
- html側から商品情報等をgasのdopost等へ送り、SpreadSheetにlogを残したい。
- gas側で作成してある"領収書"htmlファイルに値をセットし、jsへ送り返したい。
- doPostで返信されたhtmlをjs側で受け取り、ページ遷移をしたい。
発生している問題・エラーメッセージ
doPostでhtmlService.createHtmlOutputFromFile("result");を返却して、jsで確認すると以下のオブジェクトが確認できるが、doGetのようにページが表示されることはない。
Response {type: 'opaque', url: '', redirected: false, status: 0, ok: false, …}
該当のソースコード
gas
1doPost(e){ 2 const json_data = JSON.parse(e.postData.getDataAsString()); 3 const result = HtmlService.createHtmlOutpustFromFile("result"); 4 result.data = "付随したいデータ"; 5 6 return result.evaluate(); 7} 8 9function get_url(){ 10 // gasのURL取得関数(jsで呼び出す) 11 return ScriptApp.getService().getUrl(); 12}
js(index.html)
1function send_data() { 2 google.script.run.withSuccessHandler(e => { 3 const URL = e; 4 const postparam = { 5 "method" : "POST", 6 "mode" : "no-cors", 7 "Content-Type" : "application/x-www-form-urlencoded", 8 "body" : JSON.stringify(item_dict) 9 }; 10 11 const res = fetch(URL, postparam).then(response => response).then(data => { 12 // 読み取るタイミングやfetchの使い方が曖昧なため、これで合っているかすら疑問 13 // オブジェクトは取得できているが処理の方法を理解できていない、、? 14 console.log(data); 15 }); 16 }).get_url(); 17}
試したこと
doGetでresult.htmlを返却する事は考えたのですが、購入商品情報等のjsonを渡す方法をどう繋げればいよのか、また余計な考えかもしれませんがスマートに処理ができるのでは、、と考えdoPostでの画面遷移の方法を模索しています。
質問の中で、至らない所などあるとは思いますが
どうぞご教授のほどよろしくお願いいたします。
補足情報(FW/ツールのバージョンなど)
html, gas, google chromeなどは最新だと思います
// 以下gas ----------------------------------------------------------------------- function doGet(e) { // 最初に商品読み取り用のページを表示させる。(ここは表示できる) return HtmlService.createHtmlOutputFromFile("index"); } function doPost(e) { // 各種データの取得 const json_data = JSON.parse(e.postData.getDataAsString()); const sheet_id = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; // 管理表で商品の売上数を計上 const sheet_name1 = "管理表"; // logに現在時刻とindexから返却された商品購入情報のjsonを記録 const sheet_name2 = "log"; // 領収書情報に記載されている情報(会社名や電話番号等)を取得 const sheet_name3 = "領収証情報"; const sheet1 = SpreadsheetApp.openById(sheet_id).getSheetByName(sheet_name1); const sheet2 = SpreadsheetApp.openById(sheet_id).getSheetByName(sheet_name2); const sheet3 = SpreadsheetApp.openById(sheet_id).getSheetByName(sheet_name3); const r_last1 = sheet1.getLastRow() + 1; const r_last2 = sheet2.getLastRow() + 1; const range_all1 = sheet1.getRange(1, 1, r_last1, 9); const range_all2 = sheet2.getRange(1, 1, r_last2, 2); const data_all1 = range_all1.getValues(); const data_all2 = range_all2.getValues(); const data_id = data_all1.map(elm => elm[0]); // 購入商品の合計金額 let amount = 0; // 商品の税率情報より求める内税額 let tax = 0; // 商品情報json処理 Object.keys(json_data).forEach(key => { const keyword = key.split(",")[0]; const r_hit1 = data_id.indexOf(keyword); const num = data_all1[r_hit1][5]; range_all1.offset(r_hit1, 5, 1, 1).setValue(num + json_data[key]); amount += key.split(",")[4] * json_data[key]; tax += key.split(",")[5] * json_data[key]; }); // シートへ書き込み const r_hit2 = data_all2.map(elm => elm[0]).indexOf(""); const date = Utilities.formatDate(new Date(), 'JST', "yyyy/MM/dd (E) HH:mm:ss Z"); range_all2.offset(r_hit2,0,1,2).setValues([[date, json_data]]); const info = sheet3.getRange(2, 1, 1, 5).getValues().flat(); // htmlデータ作成 const result = HtmlService.createHtmlOutputFromFile("result"); result.date = info[0]; result.zip = info[1]; result.address = info[2]; result.corp = info[3]; result.phone = info[4]; result.amount = amount; result.tax = tax; result.without = amount - tax; // 返却するが、表示できない return result.evaluate; } function get_url(){ // js側でrun関数で呼び出すデプロイurl取得用の関数 return ScriptApp.getService().getUrl(); } // 以下index.html ----------------------------------------------------------------------- <!DOCTYPE html> <html> <head> <base target="_top"> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width,initial-scale=1"/> <title>QRコードリーダ</title> <script src="https://cdn.jsdelivr.net/npm/jsqr@1.4.0/dist/jsQR.min.js"></script> </head> <!-- html --> <body> <div id="wrapper"> <canvas id="canvas"></canvas> <ul id="results"></ul> <span id="confirm">確定</span> <p id="subtotal">0円</p> </div> <script> // DOM取得とQRコード用のビデオ設定 const video = document.createElement("video"); const canvasElement = document.getElementById("canvas"); const canvas = canvasElement.getContext("2d"); const results = document.getElementById("results"); const subtotal = document.getElementById("subtotal"); const confirm = document.getElementById("confirm"); let item_dict = {}; // カウンターで商品の連続読み取りを阻止 let next_counter = 0; // ここでjsにデータを送る関数を設定 confirm.addEventListener("click", send_data); // Use facingMode: environment to attemt to get the front camera on phones navigator.mediaDevices.getUserMedia({ video: { facingMode: "environment" } }).then(function(stream) { video.srcObject = stream; video.setAttribute("playsinline", true); // required to tell iOS safari we don't want fullscreen video.play(); requestAnimationFrame(tick); }); function tick() { // キャンバスにビデオ画像を反映 if (video.readyState === video.HAVE_ENOUGH_DATA) { canvasElement.height = video.videoHeight; canvasElement.width = video.videoWidth; canvas.drawImage(video, 0, 0, canvasElement.width, canvasElement.height); const imageData = canvas.getImageData(0, 0, canvasElement.width, canvasElement.height); const code = jsQR(imageData.data, imageData.width, imageData.height, { inversionAttempts: "dontInvert", }); if (code) { if (Object.keys(item_dict).includes(code.data)){ // アイテムを読み取っていたら購入個数をプラスしていく if(next_counter > 50){ item_dict[code.data] += 1; results.children[Object.keys(item_dict).indexOf(code.data)].children[1].innerText = item_dict[code.data]; next_counter = 0; change_subtotal(); } } else if (code.data != "") { // 初めて読み込む商品(QRコード)なら画面に表示+内部でdictに追加 const child = document.createElement("li"); const name = document.createElement("p"); const num = document.createElement("p"); const price = document.createElement("p"); const btn_minus = document.createElement("span"); const btn_plus = document.createElement("span"); const btn_delete = document.createElement("span"); btn_minus.addEventListener("click", {num: -1, data: code.data, handleEvent: change_num}); btn_plus.addEventListener("click", {num: 1, data: code.data, handleEvent: change_num}); btn_delete.addEventListener("click", {data: code.data, handleEvent: delete_elm}); name.innerText = code.data.split(",")[1]; num.innerText = 1; price.innerText = code.data.split(",")[4]; btn_minus.innerText = "-"; btn_plus.innerText = "+"; btn_delete.innerText = "x"; child.append(name); child.append(num); child.append(btn_minus); child.append(btn_plus); child.append(btn_delete); results.append(child); item_dict[code.data] = 1; next_counter = 0; change_subtotal(); } } else { next_counter++; } } requestAnimationFrame(tick); } function change_num(e) { item_dict[this.data] += this.num; e.target.parentNode.children[1].innerText = item_dict[this.data]; change_subtotal(); } function delete_elm(e) { delete item_dict[this.data]; e.target.parentNode.remove(); change_subtotal(); } function change_subtotal() { let sum = 0; Object.keys(item_dict).forEach(elm => { sum += item_dict[elm] * elm.split(",")[4]; }); subtotal.innerText = sum.toLocaleString() + "円"; } function send_data() { // ここが一番の疑問点 // データの送信はできていてdoPost側でも読み取れる(こちらから送信はできているため通信は可能) google.script.run.withSuccessHandler(e => { const URL = e; const postparam = { "method" : "POST", "mode" : "no-cors", "Content-Type" : "application/x-www-form-urlencoded", "body" : JSON.stringify(item_dict) }; const res = fetch(URL, postparam).then(response => response).then(data => { // 読み取るタイミングやfetchの使い方が曖昧なため、これで合っているかすら疑問 // オブジェクトは取得できているが処理の方法を理解できていない、、? console.log(data); }); }).get_url(); } </script> </body> </html>
回答1件
あなたの回答
tips
プレビュー