Shoeisha Technology Media

CodeZine(コードジン)

記事種別から探す

Spread.ViewsとPayPalを連携して商品発送管理システムを作る

IoT時代の救世主! SpreadJSで作るデータ可視化アプリ 第4回

  • LINEで送る
  • このエントリーをはてなブックマークに追加

目次

3. トレリスで商品管理UIを作る

 ここから、実際に利用できる商品管理の画面にしていきます。

 まずは実際のデータを利用するため、サンプルデータの読み込み箇所である<script src="data/timelineBoard.js" type="text/javascript"></script>を削除します。

 また、DEMOではトレリスレイアウトとノーマルレイアウトの切り替えができる機能がありましたが、トレリスのみを利用するので削除します。

 以下の箇所を削除しましょう。

index.html
省略
        <div class="button-container">
            <button id="normal" type="button" class="btn btn-default" onclick="changeToNormalLayout()">Default</button>
            <button id="trellis" type="button" class="btn btn-default active" onclick="changeToTrellisLayout()">Trellis
        </button>
        </div>
省略

 次に画像を設置します。public/imagesフォルダを作成し、その中に商品となる画像と、background.pngを設置します。background.pngはデモリソースからコピーしてきましょう。

商品管理の状態定義を行う

 ここから、scriptタグ内を編集します。

 まずは商品管理の状態定義をします。'未発送','ラベル申込/決済_済','ラベル印字_済','パッケージング_済','発送完了','配送完了'の6つ状態を定義しました。

index.html
省略
      <script>
        //状態定義
        const workGroups = ['未発送','ラベル申込/決済_済','ラベル印字_済','パッケージング_済','発送完了','配送完了']; //ヘッダー情報


省略

 もともとのデモだと、存在するデータをもとに状態定義が行われ、データが空の状態だと扱いづらさがありました。

 ここの設定は「カードレイアウトによるトレリス」のデモソースが参考になりました。

描画用のテンプレートの用意

 次に、実際にデータが描画されるカード部分のテンプレートを用意します。こちらも住所用のdata-column="address"や郵便番号用のdata-column="address_zip"などの項目を追加しています。

index.html
省略
      <script>
      	 省略

      	 //カードのテンプレート
        const rowTemplate = `
        <div class="group-item-container">
            <div class="group-item-container-inner {{? it.progress==100}}finish{{?? it.progress>=80}}eighty-per{{?? it.progress>=50}}fifty-per{{?? it.progress>=30}}thirty-per{{??}}start{{?}}">
                <div data-column="title" class="group-item-title  {{? it.progress==100}}finish-head{{?? it.progress>=80}}eighty-per-head{{?? it.progress>=50}}fifty-per-head{{?? it.progress>=30}}thirty-per-head{{??}}start-head{{?}}"></div>
                <div data-column="photo" class="group-photo-container"></div>
                <div data-column="description" class="group-item-description"></div>
                <div data-column="address_zip" class="group-item-description">〒</div>
                <div data-column="address" class="group-item-description"></div>
            </div>
        </div>`;
        const photoPresenter = '<img class="employee-photo" src={{=it.photo}} />';

省略

購入者情報用のデータ定義とテンプレートとの紐付け

 次に、データ定義をします。titleやdescriptionなどのフィールドはデモのままで良いですが、購入者の住所や郵便番号のフィールドを追加しました。

 また、dataFieldの箇所がテンプレート側との紐付けになります。

index.html
省略
      <script>
      	 省略

        //データ定義
        const columns = [
            {
                id: 'title',
                name: 'title',
                dataField: 'title'
            }, {
                id: 'description',
                name: 'description',
                dataField: 'description'
            }, {
                id: 'photo',
                dataField: 'photo',
                presenter: photoPresenter
            }, {
                id: 'progress',
                dataField: 'progress'
            }, {
                id: 'address',
                name: 'address',
                dataField: 'address'
            }, {
                id: 'address_zip',
                name: 'address_zip',
                dataField: 'address_zip'
            }
        ];

省略

仮データの用意

 データの定義やテンプレートを用意しましたが、実データがまだなかったので仮データを用意します。

index.html
省略
      <script>
      	 省略

      	 //仮データ
        let data = [
            {"work": "未発送", "description": "Nefry BT x 1", "title": "菅原のびすけ", "photo": "./images/ds.png", "progress": 0, "address": "東京都千代田区外神田2-9-3\nユニオンビル工新 8F", "address_zip":"101-0021"},
            {"work": "未発送", "description": "Nefry BT x 1", "title": "菅原のびすけ", "photo": "./images/ds.png", "progress": 0, "address": "東京都千代田区外神田2-9-3\nユニオンビル工新 8F", "address_zip":"101-0021"},
            {"work": "ラベル申込/決済_済", "description": "Nefry BT x 1", "title": "菅原のびすけ", "photo": "./images/ds.png", "progress": 20, "address": "東京都千代田区外神田2-9-3\nユニオンビル工新 8F", "address_zip":"101-0021"},
            {"work": "ラベル印字_済", "description": "Nefry BT x 1", "title": "菅原のびすけ", "photo": "./images/ds.png", "progress": 40, "address": "東京都千代田区外神田2-9-3\nユニオンビル工新 8F", "address_zip":"101-0021"},
            {"work": "パッケージング_済", "description": "Nefry BT x 1", "title": "菅原のびすけ", "photo": "./images/ds.png", "progress": 60, "address": "東京都千代田区外神田2-9-3\nユニオンビル工新 8F", "address_zip":"101-0021"},
            {"work": "発送完了", "description": "Nefry BT x 1", "title": "菅原のびすけ", "photo": "./images/ds.png", "progress": 80, "address": "東京都千代田区外神田2-9-3\nユニオンビル工新 8F", "address_zip":"101-0021"},
            {"work": "配送完了", "description": "Nefry BT x 1", "title": "菅原のびすけ", "photo": "./images/ds.png", "progress": 100, "address": "東京都千代田区外神田2-9-3\nユニオンビル工新 8F", "address_zip":"101-0021"},
        ];

省略

描画する

 最後に、描画部分です。ここまでに用意した、定義情報、テンプレート、データをもとにトレリスの描画をします。

index.html
省略
      <script>
      	 省略

      	 //描画
        const TrellisGrouping = new GC.Spread.Views.Plugins.TrellisGrouping({panelUnitWidth: 190});

        const dataView = new GC.Spread.Views.DataView(document.getElementById('grid1'), data, columns, new GC.Spread.Views.Plugins.GridLayout({
            grouping: [{
                field: 'work',
                preDefinedGroups: workGroups,
                header: {height: 24}
            }],
            rowTemplate: rowTemplate,
            rowHeight: 150,
            groupStrategy: TrellisGrouping
        }));

	</script>
</body>
</html>

CSS調整

 画像の表示箇所調整でCSSも編集します。細かい調整はCSSを直接編集しましょう。

index.html
省略
	<style>
	省略

        .group-photo-container {
            position: absolute;
            top: 3.5em;
            right: 0.4em;
        }

    省略
	</style>
省略

ソースのまとめとここまでの完成画面

 ここまでできると、このようなUIが完成します。

 また、ここまでのindex.htmlが以下になります。

index.html
<!doctype html>
<html style="height:100%;font-size:14px;">

<head>
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link rel="stylesheet" type="text/css" href="css/gc.spread.views.dataview.10.3.0.css">
    <link rel="stylesheet" type="text/css" href="css/bootstrap-snippet.min.css">
    <script src="js/gc.spread.common.10.3.0.min.js" type="text/javascript"></script>
    <script src="js/gc.spread.views.dataview.10.3.0.min.js" type="text/javascript"></script>
    <script src="js/locale/gc.spread.views.dataview.locale.ja-JP.10.3.0.min.js" type="text/javascript"></script>
    <script src="js/plugins/gc.spread.views.gridlayout.10.3.0.min.js" type="text/javascript"></script>
    <script src="js/plugins/gc.spread.views.trellisgrouping.10.3.0.min.js" type="text/javascript"></script>
    <script src="js/zepto.min.js" type="text/javascript"></script>
    <script src="js/license.js" type="text/javascript"></script>
    <style>
        * {
            -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
        }

        html {
            position: fixed;
            width: 100%;
        }

        ::-webkit-scrollbar {
            width: 5px;
            height: 5px;
            border-radius: 5px;
        }

        ::-webkit-scrollbar-thumb {
            background: #d6dadc;
        }

        ::-webkit-scrollbar-corner {
            display: none;
        }

        .gc-grid {
            border: none;
            background: #fff url(images/background.png);
            color: #4d4d4d;
            padding: 0.4em;
        }

        .button-container {
            margin-bottom: 1em;
        }

        .employee-photo {
            width: 32px;
            height: 32px;
            border-radius: 50%;
        }

        .group-item-title {
            border: none;
            color: #f1f1f1;
            background: #C48C43;
            white-space: nowrap;
            text-overflow: ellipsis;
            padding: 0.4em;
            font-size: 16px;
        }

        .group-photo-container,
        .group-item-description {
            border: none;
        }

        .group-photo-container {
            position: absolute;
            top: 3.5em;
            right: 0.4em;
        }

        .group-item-description {
            padding: 8px;
        }

        .gc-trellis-group-header-inner {
            padding: 0 0.4em;
            font-size: 16px;
        }

        .group-item-container {
            height: 100%;
            font-size: 12px;
            overflow: hidden;
            position: relative;
        }

        .group-item-container-inner {
            height: 95%;
            border-radius: 4px;
            overflow: hidden;
            color: #f1f1f1;
            box-shadow: 0 3px 5px rgba(0, 0, 0, 0.10);
        }

        .finish {
            background: #603E50;
        }

        .eighty-per {
            background: #695877;
        }

        .fifty-per {
            background: #73738E;
        }

        .thirty-per {
            background: #7C9EAA;
        }

        .start {
            background: #8FC8C9;
        }

        .finish-head {
            background: #533747;
        }

        .eighty-per-head {
            background: #5F506B;
        }

        .fifty-per-head {
            background: #6A6B83;
        }

        .thirty-per-head {
            background: #76949F;
        }

        .start-head {
            background: #86BBBD;
        }

        .trellis-grouping .gc-trellis-group-header {
            line-height: 24px;
        }
    </style>
</head>

<body style="margin:0;position:absolute;top:0;bottom:0;left:0;right:0;font-size:14px;user-select:none;-webkit-user-select: none;overflow:hidden;">
    <div style="height: 100%; position: relative">
        <div style="height:90%;">
            <div id="grid1" style="height:100%;"></div>
        </div>
    </div>

    <script>
        //状態定義
        const workGroups = ['未発送','ラベル申込/決済_済','ラベル印字_済','パッケージング_済','発送完了','配送完了']; //ヘッダー情報

        //カードのテンプレート
        const rowTemplate = `
        <div class="group-item-container">
            <div class="group-item-container-inner {{? it.progress==100}}finish{{?? it.progress>=80}}eighty-per{{?? it.progress>=50}}fifty-per{{?? it.progress>=30}}thirty-per{{??}}start{{?}}">
                <div data-column="title" class="group-item-title  {{? it.progress==100}}finish-head{{?? it.progress>=80}}eighty-per-head{{?? it.progress>=50}}fifty-per-head{{?? it.progress>=30}}thirty-per-head{{??}}start-head{{?}}"></div>
                <div data-column="photo" class="group-photo-container"></div>
                <div data-column="description" class="group-item-description"></div>
                <div data-column="address_zip" class="group-item-description">〒</div>
                <div data-column="address" class="group-item-description"></div>
            </div>
        </div>`;
        const photoPresenter = '<img class="employee-photo" src={{=it.photo}} />';

        //データ定義
        const columns = [
            {
                id: 'title',
                name: 'title',
                dataField: 'title'
            }, {
                id: 'description',
                name: 'description',
                dataField: 'description'
            }, {
                id: 'photo',
                dataField: 'photo',
                presenter: photoPresenter
            }, {
                id: 'progress',
                dataField: 'progress'
            }, {
                id: 'address',
                name: 'address',
                dataField: 'address'
            }, {
                id: 'address_zip',
                name: 'address_zip',
                dataField: 'address_zip'
            }
        ];

        //仮データ
        let data = [
            {"work": "未発送", "description": "Nefry BT x 1", "title": "菅原のびすけ", "photo": "./images/ds.png", "progress": 0, "address": "東京都千代田区外神田2-9-3\nユニオンビル工新 8F", "address_zip":"101-0021"},
            {"work": "未発送", "description": "Nefry BT x 1", "title": "菅原のびすけ", "photo": "./images/ds.png", "progress": 0, "address": "東京都千代田区外神田2-9-3\nユニオンビル工新 8F", "address_zip":"101-0021"},
            {"work": "ラベル申込/決済_済", "description": "Nefry BT x 1", "title": "菅原のびすけ", "photo": "./images/ds.png", "progress": 20, "address": "東京都千代田区外神田2-9-3\nユニオンビル工新 8F", "address_zip":"101-0021"},
            {"work": "ラベル印字_済", "description": "Nefry BT x 1", "title": "菅原のびすけ", "photo": "./images/ds.png", "progress": 40, "address": "東京都千代田区外神田2-9-3\nユニオンビル工新 8F", "address_zip":"101-0021"},
            {"work": "パッケージング_済", "description": "Nefry BT x 1", "title": "菅原のびすけ", "photo": "./images/ds.png", "progress": 60, "address": "東京都千代田区外神田2-9-3\nユニオンビル工新 8F", "address_zip":"101-0021"},
            {"work": "発送完了", "description": "Nefry BT x 1", "title": "菅原のびすけ", "photo": "./images/ds.png", "progress": 80, "address": "東京都千代田区外神田2-9-3\nユニオンビル工新 8F", "address_zip":"101-0021"},
            {"work": "配送完了", "description": "Nefry BT x 1", "title": "菅原のびすけ", "photo": "./images/ds.png", "progress": 100, "address": "東京都千代田区外神田2-9-3\nユニオンビル工新 8F", "address_zip":"101-0021"},
        ];

        //描画
        const TrellisGrouping = new GC.Spread.Views.Plugins.TrellisGrouping({panelUnitWidth: 190});
        const dataView = new GC.Spread.Views.DataView(document.getElementById('grid1'), data, columns, new GC.Spread.Views.Plugins.GridLayout({
            grouping: [{
                field: 'work',
                preDefinedGroups: workGroups,
                header: {height: 24}
            }],
            rowTemplate: rowTemplate,
            rowHeight: 150,
            groupStrategy: TrellisGrouping
        }));
    </script>
</body>

</html>

  • LINEで送る
  • このエントリーをはてなブックマークに追加

著者プロフィール

  • 菅原のびすけ(dotstudio株式会社)(スガワラ ノビスケ)

     日本最大規模のIoTコミュニティ「IoTLT」主催。岩手県立大学大学院ソフトウェア情報学研究科を卒業後、株式会社LIGでWebエンジニアとして入社し、Web開発に携わる。2016年にdotstudio株式会社を立ち上げ、今はIoT領域を中心に活動している。JavaScript Roboticsコミ...

バックナンバー

連載:IoT時代の救世主! SpreadJSで作るデータ可視化アプリ
All contents copyright © 2005-2018 Shoeisha Co., Ltd. All rights reserved. ver.1.5