end0tknr's kipple - web写経開発

太宰府天満宮の狛犬って、妙にカワイイ

javascriptによるcsvダウンロード機能の実装

以下の csv_find_result() の通りです。 client(ブラウザ)のみで、ダウンロード機能を実現できます。

参考url https://samehack.com/javascript-csv-download/

'use strict';

const cgi_base_url  = "./find_hinban.cgi?";
const scan_base_url =
      "http://xcan.sexy.co.jp/xcan.xcanplan?type=viewzumen&XCANCODE=";

class FindHinban {
    constructor() {}

    init_window =()=> {
        document.querySelector("#find_btn").addEventListener('click',()=>{
            this.find_hinban();
        });
        document.querySelector("#find_str").addEventListener('keypress',(e)=>{
            if (e.keyCode == 13) { // ENTER
                this.find_hinban();
            }
        });
        document.querySelector("#csv_btn").addEventListener('click',()=>{
            this.csv_find_result();
        });
    }

    csv_find_result=()=>{
        let tbody_trs = document.querySelectorAll("#find_result tbody tr");
        if( tbody_trs.length==0 ){
            this.toast_msg("検索結果がある状態でご利用ください");
            return;
        }

        let csv_rows = [];
        for(let tr_elm of tbody_trs ){
            let tr_cols = tr_elm.textContent.trim().split("\n");
            csv_rows.push( [ '"'+tr_cols[1].trim()+'"',
                             '"'+tr_cols[2].trim()+'"',
                             '"'+tr_cols[3].trim()+'"',
                             '"'+tr_cols[4].trim()+'"',
                             '"'+tr_cols[5].trim()+'"' ].join(",") );
        }
        let csv_rows_str = csv_rows.join("\r\n");

        // c.f. https://samehack.com/javascript-csv-download/
        const bom  = new Uint8Array([0xef,0xbb,0xbf]);
        const blob = new Blob([bom, csv_rows_str], {type:"text/csv"});
        const objectUrl = URL.createObjectURL(blob);

        const downloadLink = document.createElement("a");
        const fileName = "検索結果.csv";
        downloadLink.download = fileName;
        downloadLink.href = objectUrl;
        downloadLink.click();
        downloadLink.remove();
    }
    
    find_hinban=()=>{
        let find_str = document.querySelector("#find_str").value;

        find_str = this.validate_find_str(find_str);
        if(! find_str ){
            this.toast_msg(
                "検索キーワードは、品番やその一部(英数字 3~7文字)を"+
                "空白区切りで10コまでです");
            return;
        }

        let zumen_type = document.querySelector("#zumen_type").value.trim();
        
        
        let req_params = {"zumen_type":zumen_type, "find_str":find_str };
        let req_params_str = new URLSearchParams(req_params);
        let req_url = cgi_base_url + req_params_str;
        
        let img_container = document.querySelector("#loading_container img");
        img_container.className = img_container.className.replace("hide","");
        
        fetch(req_url,{method:"GET", cache:"no-cache"})
            .then((res)=>{
                if(!res.ok){
                    img_container.className = "hide";
                    throw new Error(`${res.status} ${res.statusText}`);
                }
                return res.text();
            })
            .then((res_tsvs)=>{
                let tmp_container = document.querySelector("#tmp_container");
                this.disp_find_result(res_tsvs);
                img_container.className = "hide";
            })
            .catch((reason)=>{ alert(reason); });
    }

    disp_find_result=(res_tsvs)=>{
        let tbody_elm = document.querySelector("#find_result tbody");
        var clone_tbody = tbody_elm.cloneNode(false);
        tbody_elm.parentNode.replaceChild(clone_tbody, tbody_elm);
        
        tbody_elm = document.querySelector("#find_result tbody");

        let tsvs = res_tsvs.split("\n");
        if ( res_tsvs.length == 0){
            this.toast_msg("検索キーワードに一致するものは見つかりませんでした");
            return;
        }
        
        let tr_tmpl = document.querySelector("#tbody_tr");

        let i = 1;
        for(let tsv of tsvs){
            let disp_cols = tsv.split("\t");
            var tr_elm = tr_tmpl.content.cloneNode(true);
            var td = tr_elm.querySelectorAll("td");
            td[0].textContent = i++;
            td[1].textContent = disp_cols[0];
            td[2].textContent = disp_cols[1];
            td[3].textContent = disp_cols[2];
            td[4].textContent = disp_cols[3];
            td[5].textContent = disp_cols[4].substring(2);

            tbody_elm.appendChild(tr_elm);
        }

        let btn_elms = document.querySelectorAll("#find_result tbody button");
        for(let btn_elm of btn_elms ){
            btn_elm.addEventListener("click",(e)=>{ this.view_scan(e); });
        }
    }

    view_scan=(e)=>{
        let tr_elm = e.target.parentNode.parentNode;
        let td_elms = tr_elm.querySelectorAll("td");
        let zuban = td_elms[1].textContent.trim();
        let req_url = scan_base_url + zuban;
        location.href = req_url;
    }
    
    toast_msg=(msg)=>{
        let msg_container = document.querySelector("#toast_msg");
        msg_container.innerHTML = msg;
        
        msg_container.className = msg_container.className.replace("hide","");
        setTimeout(()=>{ msg_container.className="hide";},4500);
    }

    validate_find_str=(org_find_str)=>{
        org_find_str = org_find_str.trim();
        if ( org_find_str.length == 0 ){
            return undefined;
        }

        org_find_str = this.to_upper_hankaku(org_find_str);
        
        let re_pat = /([\dA-Z]{3,7})/g;
        let match;
        let find_strs = [];
        while ((match = re_pat.exec(org_find_str))!== null) {
            find_strs.push(match[1]);
        }

        if(find_strs.length < 1 || find_strs.length > 10){
            return undefined;
        }
        return find_strs.join(" ");
    }
    
    to_upper_hankaku=(str)=> {
        let tmp_str = str.replace(/[A-Za-z0-9]/g, function(s) {
            return String.fromCharCode(s.charCodeAt(0) - 0xFEE0);
        });
        return tmp_str.toUpperCase();
    }
}

let find_hinban = new FindHinban();
find_hinban.init_window();