紹介

カスタムフィールドは高度なカスタマイズ機能を備えており、ユーザー自身のニーズに応じて独自に開発できます。システムは保存すべきデータの保存のみを担当します。そのカスタマイズ性の高さゆえに、ユーザーには一定のフロントエンド開発スキルが求められます!

設定

アプリ設定管理 - オブジェクト管理 - オブジェクト編集 - 新規フィールド作成

パラメータ 必須 説明
値表示 必須 詳細ページで表示される形式
構造 必須 フィールドは構造に基づいてカスタム表示されます
カスタムPC表示 任意 PC端末でカスタムフィールドを表示する際:カスタムHTML、CSS、JSに基づいて表示モーダルページのインタラクションを決定
カスタムPC編集 任意 PC端末でカスタムフィールドを編集する際:カスタムHTML、CSS、JSに基づいて編集モーダルページのインタラクションを決定
カスタムモバイル表示 任意 モバイル端末でカスタムフィールドを表示する際:カスタムHTML、CSS、JSに基づいて表示モーダルページのインタラクションを決定
カスタムモバイル編集 任意 モバイル端末でカスタムフィールドを編集する際:カスタムHTML、CSS、JSに基づいて編集モーダルページのインタラクションを決定
インターフェースカスタムコード-html 任意 ページのHTMLコード
インターフェースカスタムコード-css 任意 ページのCSSコード
インターフェースカスタムコード-js 任意 デフォルトコード内のコメントガイドに従い、適切な位置にカスタムロジックを記述します
インターフェースカスタムコード-リソース 任意 画像、ファイルなどのリソースをアップロードし、カスタムフィールドインターフェース内で参照できるようにします
以上の説明を踏まえて、どのように設定すればよいでしょうか?

デモ

構造:
[{ "id": 1,
    "code":"CN_fruits",
    "name": "fruits1",
    "products": [{
        "id": "1-1",
        "name": "りんご"
    },{
        "id": "1-2",
        "name": "バナナ"
    },{
        "id": "1-3",
        "name": "みかん"
    },{
        "id": "1-4",
        "name": "ココナッツ"
    },{
        "id": "1-5",
        "name": "パイナップル"
    },{
        "id": "1-6",
        "name": "スイカ"
    },{
        "id": "1-7",
        "name": "ぶどう"
    },{
        "id": "1-8",
        "name": "もも"
    }]
}]

カスタムPC表示

/************************* html *****************************/
<div id="udesk-custom-field" class="udesk-custom-field">
    <table class="udesk-custom-field-table">
        <thead>
            <th>
                選択済みか
            </th>
            <th>
                カテゴリ
            </th>
            <th>
                詳細
            </th>
            <th>
                時間1
            </th>
            <th>
                時間2
            </th>
        </thead>
        <tbody id="udesk-custom-field-tbody"></tbody>
    </table>
    <p class="work-time-total-container">
        時間1合計:
        <span id="udesk-work-time-total">0</span>
    </p>
    <p class="on-way-time-total-container">
        時間2合計:
        <span id="udesk-on-way-time-total">0</span>
    </p>
</div>
<script src="https://cdn.staticfile.org/jquery/1.10.2/jquery.min.js"></script>


/************************* css *****************************/
.udesk-custom-field {
    position: relative;
}
.udesk-custom-field-table {
    width: 100%;
    min-height: 25px;
    font-size: 13px;
    line-height: 1.5;
    text-align: center;
    border-collapse: collapse;
}
.udesk-custom-field-table tr th,
.udesk-custom-field-table tr td {
    padding: 8px;
    border: 1px solid #ccc;
}
.product-td {
    text-align: left;
}
.product-td label {
    margin: 0 5px;
}
.product-td label > input {
    vertical-align: bottom;
}


/************************* js *****************************/
/*
* initData : このイベントを必ず登録してください。データ初期化に使用します。
* データ構造 {
* data: このフィールドの構造部分を定義,
* value: インターフェースに保存されたデータ
* }
*
* onSavedValueData: このイベントを必ず登録してください。データ保存に使用します。
*
* */


(function (global) {
    var fullDataList = [];
    global.webApiClient.init();
    global.webApiClient.on("init", function () {
        //このイベントはデータ保存に使用されます
        global.webApiClient.initData();
    });

    global.webApiClient.on("initData", function (message) {
        //このイベントは初期データを受信できます
        if (message) {
            dataSource = message.data;
            value = message.value;
        }
        if (value && typeof value === "string" && value !== "") {
            value = JSON.parse(value);
        }

        try {
            fullDataList = buildTableDataList(dataSource, value);
            renderTable(fullDataList);
            renderTotal(fullDataList);
        } catch (error) {
            //データ形式が正しくありません。
        }
    });

    global.webApiClient.on("onDestroyed", function () {
        //このイベントはメモリを破棄し、メモリリークを防ぐために使用されます
        global.webApiClient.off("init");
        global.webApiClient.off("initData");
        global.webApiClient.off("onDestroyed");
        fullDataList = [];
    });

    function getServerProductsData(list) {
        var newProducs = [];
        for (var index = 0; index < list.length; index++) {
            var listItem = list[index];
            if (listItem.isChecked) {
                newProducs.push(listItem.data.id);
            }
        }
        return newProducs;
    }

    function buildTableDataList(dataList, value) {
        var newDataList = [];
        let values = value.values;
        for (var index = 0; index < dataList.length; index++) {
            var dataItem = dataList[index];
            var targetValue = findTargetValue(values, function (item) {
                return item.id == dataItem.id;
            });

            var newDataItem = {
                data: dataItem,
                isChecked: false,
                products: buildProducts(dataItem.products, targetValue),
                onlineTime: 0,
                onWayTime: 0,
            };

            if (targetValue) {
                newDataItem.isChecked = true;
                newDataItem.onlineTime = targetValue.onlineTime;
                newDataItem.onWayTime = targetValue.onWayTime;
            }
            newDataList.push(newDataItem);
        }

        return newDataList;
    }

    function buildProducts(products, targetValue) {
        var productList = [];
        if (products && products.length > 0) {
            for (var j = 0; j < products.length; j++) {
                var product = products[j];
                var isChecked = false;
                if (targetValue) {
                    var findTarget = findTargetValue(
                        targetValue.products,
                        function (item) {
                            return item == product.id;
                        }
                    );

                    isChecked = findTarget == null ? false : true;
                }
                productList.push({
                    data: product,
                    isChecked: isChecked,
                });
            }
        }
        return productList;
    }

    function renderTotal(fullDataList) {
        var workTimeTotal = 0;
        var onWayTimeTotal = 0;
        for (var index = 0; index < fullDataList.length; index++) {
            let fullData = fullDataList[index];
            workTimeTotal += Number(fullData.onlineTime);
            onWayTimeTotal += Number(fullData.onWayTime);
        }
        global.document.getElementById(
            "udesk-work-time-total"
        ).innerHTML = workTimeTotal;
        global.document.getElementById(
            "udesk-on-way-time-total"
        ).innerHTML = onWayTimeTotal;
    }

    function renderTable(dataList) {
        var tr = "";
        for (var index = 0; index < dataList.length; index++) {
            var dataItem = dataList[index];
            tr +=
                "<tr data-id=" +
                dataItem.data.id +
                "><td><input type='checkbox' value=" +
                dataItem.data.id +
                (dataItem.isChecked ? " checked disabled/>" : " disabled/>") +
                " </td>";

            tr +=
                "<td>" +
                dataItem.data.name +
                "</td><td class='product-td'>";

            $.each(dataItem.products, function (i, product) {
                tr +=
                    "<label><input type='checkbox' value=" +
                    product.data.id +
                    (product.isChecked ? " checked disabled/>" : " disabled/>") +
                    product.data.name +
                    "</label>";
            });

            tr +=
                "</td><td><input type='number' min=0 value=" +
                dataItem.onlineTime +
                " disabled /></td>";

            tr +=
                "</td><td><input type='number' min=0 value=" +
                dataItem.onWayTime +
                " disabled /></td></tr>";
        }

        global.document.getElementById(
            "udesk-custom-field-tbody"
        ).innerHTML = tr;
    }

    function findTargetValue(value, matcherCallback) {
        var findValue = null;
        if (value && value.length > 0) {
            for (var i = 0; i < value.length; i++) {
                var valueItem = value[i];
                if (matcherCallback(valueItem)) {
                    findValue = valueItem;
                    break;
                } else {
                    findValue = null;
                }
            }
        }
        return findValue;
    }
})(window);

カスタムPC編集

/************************* html *****************************/
<div id="udesk-custom-field" class="udesk-custom-field">
    <table class="udesk-custom-field-table">
        <thead>
            <tr>
                <th>
                    選択状態
                </th>
                <th>
                    カテゴリ
                </th>
                <th>
                    詳細
                </th>
                <th>
                    時間1
                </th>
                <th>
                    時間2
                </th>
            </tr>
        </thead>
        <tbody id="udesk-custom-field-tbody"></tbody>
    </table>
    <p class="work-time-total-container">
        時間1合計:
        <span id="udesk-work-time-total">0</span>
    </p>
    <p class="on-way-time-total-container">
        時間2合計:
        <span id="udesk-on-way-time-total">0</span>
    </p>
</div>
<script src="https://cdn.staticfile.org/jquery/1.10.2/jquery.min.js"></script>

/************************* css *****************************/
.udesk-custom-field {
    position: relative;
}
.udesk-custom-field-table {
    width: 100%;
    min-height: 25px;
    font-size: 13px;
    line-height: 1.5;
    text-align: center;
    border-collapse: collapse;
}
.udesk-custom-field-table tr th,
.udesk-custom-field-table tr td {
    padding: 8px;
    border: 1px solid #ccc;
}
.product-td {
    text-align: left;
}
.product-td label {
    margin: 0 5px;
}
.product-td label > input {
    vertical-align: bottom;
}


/************************* js *****************************/
/*
* initData : このイベントは必ず登録してください。データ初期化に使用します。
* データ構造 {
* data: このフィールドの構造部分を定義,
* value: インターフェースに保存されたデータ
* }
*
* onSavedValueData: このイベントは必ず登録してください。データ保存に使用します。
*
* */

(function (global) {
    var fullDataList = [];
    var dataSource = [];
    global.webApiClient.init();
    global.webApiClient.on("init", function () {
        //このイベントはデータ保存に使用します
        global.webApiClient.initData();
    });

    global.webApiClient.on("initData", function (message) {
        //このイベントは初期データを受信できます
        if (message) {
            dataSource = message.data;
            value = message.value;
        }
        if (value && typeof value === "string" && value !== "") {
            value = JSON.parse(value);
        }

        try {
            fullDataList = buildTableDataList(dataSource, value);
            renderTable(fullDataList);
            renderTotal(fullDataList);
        } catch (error) {
            //データ形式が正しくありません。
        }
    });

    global.webApiClient.on("onSavedValueData", function () {
        //このイベントはデータ保存に使用します
        var data = getServerDataValue();
        if (data && data.errorMessage) {
            alert(data.errorMessage);
        } else {
            global.webApiClient.saveValueData(data.value);
        }
    });

    global.webApiClient.on("onDestroyed", function () {
        //このイベントはメモリを破棄し、メモリリークを防ぐために使用します
        global.webApiClient.off("init");
        global.webApiClient.off("initData");
        global.webApiClient.off("onSavedValueData");
        global.webApiClient.off("onDestroyed");

        global.changeCheckBoxValue = null;
        global.changeOnlineTime = null;
        global.changeOnWayTime = null;
        fullDataList = [];
    });

    global.changeCheckBoxValue = function (e, dataItemId, productId) {
        for (var a = 0; a < fullDataList.length; a++) {
            var fullDataItem = fullDataList[a];
            var checkedValue = e.target.checked;

            if (dataItemId == fullDataItem.data.id) {
                if (productId == null) {
                    fullDataItem.isChecked = checkedValue;
                } else {
                    if (checkedValue) {
                        fullDataItem.isChecked = checkedValue;
                    }
                    findTargetValue(fullDataItem.products, function (
                        item
                    ) {
                        if (item.data.id == productId) {
                            item.isChecked = checkedValue;
                            return true;
                        } else {
                            return false;
                        }
                    });
                }
                break;
            }
        }
        renderTable(fullDataList);
    };

    global.changeOnlineTime = function (e, dataItemId) {
        var onlineTimeValue = e.target.value;
        findTargetValue(fullDataList, function (item) {
            if (item.data.id == dataItemId) {
                item.onlineTime = onlineTimeValue;
                return true;
            } else {
                return false;
            }
        });
        renderTotal(fullDataList);
    };

    global.changeOnWayTime = function (e, dataItemId) {
        var onWayTimeValue = e.target.value;
        findTargetValue(fullDataList, function (item) {
            if (item.data.id == dataItemId) {
                item.onWayTime = onWayTimeValue;
                return true;
            } else {
                return false;
            }
        });
        renderTotal(fullDataList);
    };

    function getServerDataValue() {
        var newValues = [];
        var workTimeTotal = 0;
        var onWayTimeTotal = 0;
        var isValid = true;
        var errorMessage = "";
        if (Array.isArray(fullDataList) && fullDataList.length > 0) {
            for (var key = 0; key < fullDataList.length; key++) {
                var dataItem = fullDataList[key];
                if (dataItem.isChecked) {
                    var productsData = getServerProductsData(
                        dataItem.products
                    );

                    var hasProucts =
                        productsData &&
                        Array.isArray(productsData.products) &&
                        productsData.products &&
                        productsData.products.length > 0;

                    if (!hasProucts) {
                        isValid = false;
                        errorMessage =
                            "製品ライン" +
                            dataItem.data.name +
                            "に関連する製品を選択してください";
                        break;
                    }

                    if (dataItem.onlineTime <= 0) {
                        isValid = false;
                        errorMessage =
                            "製品ライン" +
                            dataItem.data.name +
                            "の作業時間を入力してください";
                        break;
                    }

                    newValues.push({
                        id: dataItem.data.id,
                        name: dataItem.data.name,
                        code: dataItem.data.code,
                        onlineTime: dataItem.onlineTime,
                        onWayTime: dataItem.onWayTime,
                        products: productsData.products,
                        productNames: productsData.productNames,
                    });
                    workTimeTotal += Number(dataItem.onlineTime);
                    onWayTimeTotal += Number(dataItem.onWayTime);
                }
            }
        } else {
            return {
                errorMessage: "データが空です",
            };
        }

        if (isValid) {
            if (newValues && newValues.length < 1) {
                return {
                    errorMessage: "保存するデータを空にすることはできません!",
                };
            } else {
                return {
                    errorMessage: errorMessage,
                    value: JSON.stringify({
                        values: newValues,
                        workTimeTotal: workTimeTotal,
                        onWayTimeTotal: onWayTimeTotal,
                    }),
                };
            }
        } else {
            return {
                errorMessage: errorMessage,
            };
        }
    }

    function getServerProductsData(list) {
        var newProducts = [];
        var newProductNames = [];
        for (var index = 0; index < list.length; index++) {
            var listItem = list[index];
            if (listItem.isChecked) {
                newProducts.push(listItem.data.id);
                newProductNames.push(listItem.data.name);
            }
        }
        return {
            products: newProducts,
            productNames: newProductNames.join(","),
        };
    }

    function buildTableDataList(dataList, value) {
        var newDataList = [];
        let values = value.values;
        for (var i = 0; i < dataList.length; i++) {
            var dataItem = dataList[i];
            var targetValue = findTargetValue(values, function (item) {
                return item.id == dataItem.id;
            });

            var newDataItem = {
                data: dataItem,
                isChecked: false,
                products: buildProducts(dataItem.products, targetValue),
                onlineTime: 0,
                onWayTime: 0,
            };

            if (targetValue) {
                newDataItem.isChecked = true;
                newDataItem.onlineTime = targetValue.onlineTime;
                newDataItem.onWayTime = targetValue.onWayTime;
            }
            newDataList.push(newDataItem);
        }

        return newDataList;
    }

    function buildProducts(products, targetValue) {
        var productList = [];
        if (products && products.length > 0) {
            for (var j = 0; j < products.length; j++) {
                var product = products[j];
                var isChecked = false;
                if (targetValue) {
                    var findTarget = findTargetValue(
                        targetValue.products,
                        function (item) {
                            return item == product.id;
                        }
                    );

                    isChecked = findTarget == null ? false : true;
                }
                productList.push({
                    data: product,
                    isChecked: isChecked,
                });
            }
        }
        return productList;
    }

    function renderTotal(fullDataList) {
        var workTimeTotal = 0;
        var onWayTimeTotal = 0;
        for (var index = 0; index < fullDataList.length; index++) {
            let fullData = fullDataList[index];
            if (fullData.onlineTime) {
                workTimeTotal += Number(fullData.onlineTime);
            }
            if (fullData.onWayTime) {
                onWayTimeTotal += Number(fullData.onWayTime);
            }
        }
        workTimeTotal = !!workTimeTotal ? workTimeTotal.toFixed(1) : 0;
        onWayTimeTotal = !!onWayTimeTotal
            ? onWayTimeTotal.toFixed(1)
            : 0;
        global.document.getElementById(
            "h3c-work-time-total"
        ).innerHTML = workTimeTotal;
        global.document.getElementById(
            "h3c-on-way-time-total"
        ).innerHTML = onWayTimeTotal;
    }

    function renderTable(dataList) {
        var tr = "";
        for (var index = 0; index < dataList.length; index++) {
            var dataItem = dataList[index];
            tr +=
                "<tr data-id=" +
                dataItem.data.id +
                "><td><input type='checkbox' onChange='changeCheckBoxValue(event" +
                ',"' +
                dataItem.data.id +
                "\")' value=" +
                dataItem.data.id +
                (dataItem.isChecked ? " checked/>" : " />") +
                " </td>";

            tr +=
                "<td>" +
                dataItem.data.name +
                "</td><td class='product-td'>";

            $.each(dataItem.products, function (i, product) {
                tr +=
                    "<label><input type='checkbox' onChange='changeCheckBoxValue(event" +
                    "," +
                    dataItem.data.id +
                    ',"' +
                    product.data.id +
                    "\")' value=" +
                    product.data.id +
                    (product.isChecked ? " checked/>" : " />") +
                    product.data.name +
                    "</label>";
            });

            tr +=
                "</td><td><input type='number' min=0 oninput='changeOnlineTime(event" +
                "," +
                dataItem.data.id +
                ")' value=" +
                dataItem.onlineTime +
                " /></td>";

            tr +=
                "</td><td><input type='number' min=0 oninput='changeOnWayTime(event" +
                "," +
                dataItem.data.id +
                ")' value=" +
                dataItem.onWayTime +
                " /></td></tr>";
        }

        global.document.getElementById(
            "h3c-custom-field-tbody"
        ).innerHTML = tr;
    }

    function findTargetValue(value, matcherCallback) {
        var findValue = null;
        if (value && value.length > 0) {
            for (var i = 0; i < value.length; i++) {
                var valueItem = value[i];
                if (matcherCallback(valueItem)) {
                    findValue = valueItem;
                    break;
                } else {
                    findValue = null;
                }
            }
        }
        return findValue;
    }
})(window);

カスタムモバイル表示

/************************* html *****************************/
<div id="udesk-custom-field-mobile" class="udesk-custom-field-mobile">
    <ul id="udesk-custom-field-content" class="udesk-custom-field-content"></ul>
    <p class="work-time-total-container">
        時間1合計:
        <span id="udesk-work-time-total">0</span>
    </p>
    <p class="on-way-time-total-container">
        時間2合計:
        <span id="udesk-on-way-time-total">0</span>
    </p>
</div>
<script src="https://cdn.staticfile.org/jquery/1.10.2/jquery.min.js"></script>


/************************* css *****************************/
.udesk-custom-field-mobile {
    position: relative;
    font-size: 13px;
    line-height: 1.5;
}

.udesk-custom-field-mobile ul,
.udesk-custom-field-mobile li,
.udesk-custom-field-mobile label,
.udesk-custom-field-mobile input {
    margin: 0;
    padding: 0;
}

.udesk-custom-field-mobile ul {
    list-style: none;
}

.udesk-custom-field-mobile ul > li {
    list-style: none;
}

.udesk-custom-field-mobile .udesk-custom-field-content > li {
    margin-bottom: 20px;
    padding: 10px;
    border: 1px solid #ccc;
}

.udesk-custom-field-mobile .content-item {
    line-height: 32px;
    border-bottom: 1px solid #ccc;
}

.udesk-custom-field-mobile .content-item.productline-header {
    font-weight: 600;
    font-size: 14px;
}

.udesk-custom-field-mobile .content-item label {
    margin-right: 5px;
}

.udesk-custom-field-mobile .content-item .selecte-product-btn {
    float: right;
    font-size: 18px;
    cursor: pointer;
}


/************************* js *****************************/
/*
* initData : このイベントは必ず登録してください。データ初期化に使用します。
* データ構造 {
* data: このフィールドの構造部分を定義,
* value: インターフェースに保存されたデータ
* }
*
* onSavedValueData: このイベントは必ず登録してください。データ保存に使用します。
*
* */

(function (global) {
    var dataSource = [];
    var showValue = [];
    var selectedProductLine = [];
    var selectedProducts = [];

    global.webApiClient.init();
    global.webApiClient.on("initData", function (message) {
        //このイベントは初期データを受信できます

        if (message) {
            dataSource = message.data;
            showValue = message.value.values || [];
        }

        try {
            renderDomData(showValue);
            renderTotal(showValue);
        } catch (error) {
            //データ形式が正しくありません
        }
    });

    global.webApiClient.on("onDestroyed", function () {
        //このイベントはメモリを破棄し、メモリリークを防ぐために使用します
        global.webApiClient.off("init");
        global.webApiClient.off("initData");
        global.webApiClient.off("onDestroyed");

        fullDataList = [];
        dataSource = [];
        showValue = [];
        selectedProductLine = [];
        selectedProducts = [];
    });

    function renderTotal(showValue) {
        var workTimeTotal = 0;
        var onWayTimeTotal = 0;
        for (var index = 0; index < showValue.length; index++) {
            let fullData = showValue[index];
            workTimeTotal += Number(fullData.onlineTime);
            onWayTimeTotal += Number(fullData.onWayTime);
        }
        global.document.getElementById(
            "udesk-work-time-total"
        ).innerHTML = workTimeTotal;
        global.document.getElementById(
            "udesk-on-way-time-total"
        ).innerHTML = onWayTimeTotal;
    }

    function renderDomData(value) {
        var ulData = "";
        for (var index = 0; index < value.length; index++) {
            var valueItem = value[index];

            ulData +=
                "<li data-product-id=" +
                valueItem.id +
                ">" +
                buildItemRenderData(valueItem) +
                "</li>";
        }

        global.document.getElementById(
            "udesk-custom-field-content"
        ).innerHTML = ulData;
    }

    function buildItemRenderData(value) {
        var content = "";
        var targetProductLine = findTargetValue(dataSource, function (
            item
        ) {
            return item.id == value.id;
        });

        if (targetProductLine) {
            let displayProductName = getDisplayProductName(
                targetProductLine.products,
                value.products
            );

            content +=
                "<div class='content-item productline-header'><span>" +
                targetProductLine.name +
                "</span></div>";

            content +=
                "<div class='content-item'><label>詳細:</label><span class='content-item-content'>" +
                displayProductName +
                "</span><span class='selecte-product-btn' onclick='onAddProduct(" +
                value.id +
                ")'> > </span></div>";

            content +=
                "<div class='content-item'><label>時間1:</label><input class='content-item-content' type='number' min='0' disabled='disabled' value=" +
                value.onlineTime +
                " /></div>";
            content +=
                "<div class='content-item'><label>時間2:</label><input class='content-item-content' type='number' min='0' disabled='disabled' value=" +
                value.onWayTime +
                " /></div>";
        }
        return content;
    }

    function getDisplayProductName(dataSourceProducts, valueProducts) {
        var valueList = [];
        if (valueProducts && valueProducts.length > 0) {
            for (var index = 0; index < valueProducts.length; index++) {
                var targetProductData = findTargetValue(
                    dataSourceProducts,
                    function (item) {
                        return item.id == valueProducts[index];
                    }
                );
                if (targetProductData) {
                    valueList.push(targetProductData.name);
                }
            }
        }

        if (valueList && valueList.length > 0) {
            return valueList.join(",");
        } else {
            return "- -";
        }
    }

    function findTargetValue(value, matcherCallback) {
        var findValue = null;
        if (value && value.length > 0) {
            for (var i = 0; i < value.length; i++) {
                var valueItem = value[i];
                if (matcherCallback(valueItem)) {
                    findValue = valueItem;
                    break;
                } else {
                    findValue = null;
                }
            }
        }
        return findValue;
    }

})(window);

カスタムモバイル編集

``` /**** html ****/

    時間1合計: 0

    時間2合計: 0

      /**** css ****/ .udesk-custom-field-mobile { position: relative; font-size: 13px; line-height: 1.5; }

      .udesk-custom-field-mobile ul, .udesk-custom-field-mobile li, .udesk-custom-field-mobile label, .udesk-custom-field-mobile input { margin: 0; padding: 0; }

      .udesk-custom-field-mobile ul { list-style: none; }

      .udesk-custom-field-mobile ul > li { list-style: none; }

      .udesk-custom-field-mobile .udesk-custom-field-content > li { margin-bottom: 20px; padding: 10px; border: 1px solid #ccc; }

      .udesk-custom-field-mobile .content-item { line-height: 32px; border-bottom: 1px solid #ccc; }

      .udesk-custom-field-mobile .content-item.productline-header { font-weight: 600; font-size: 14px; }

      .udesk-custom-field-mobile .content-item.productline-header .delete-product-line-btn { float: right; color: red; font-weight: normal; cursor: pointer; }

      .udesk-custom-field-mobile .content-item label { margin-right: 5px; }

      .udesk-custom-field-mobile .content-item .selecte-product-btn { float: right; font-size: 18px; cursor: pointer; }

      .add-product-line-btn { width: 100%; margin: 10px 0; padding: 7px 0; text-align: center; border: 1px solid #3c7eff; outline: none; cursor: pointer; background-color: #3c7eff; color: #fff; }

      .add-data-modal-mask { position: fixed; top: 0; left: 0; width: 100%; height: 100%; z-index: 1020; background: rgba(0, 0, 0, 0.1); display: none; }

      .custom-field-modal-wrap { overflow: hidden; overflow-y: auto; width: 60%; height: 70%; max-height: 70%; margin: 50px 20%; padding: 20px; background: #fff; }

      .custom-field-modal-wrap .modal-content-item { display: flex; flex-direction: row; justify-content: space-between; align-items: center; line-height: 28px; border-bottom: 1px solid #ccc; }

      .custom-field-modal-wrap .modal-content-item .modal-content-item-right { width: 20px; line-height: 28px; }

      .actions-content { position: relative; width: 130px; margin: 20px auto; cursor: pointer; }

      .actions-content > .save-btn, .actions-content > .cancel-btn { display: inline-block; height: 32px; font-size: 14px; line-height: 1; margin: 0 8px; padding: 6px 7px; cursor: pointer; border-width: 1px; outline: none; border-radius: 3px; }

      .custom-field-modal-wrap .save-btn { background-color: #3c7eff; color: #fff; border-color: #3c7eff; }

      /**** js ****/ / * initData : このイベントを必ず登録してください。データ初期化に使用します。 * データ構造 { * data: このフィールドの構造部分を定義, * value: インターフェースに保存されたデータ * } * onSavedValueData: このイベントを必ず登録してください。データ保存に使用します。 * /

      (function (global) { var dataSource = []; var showValue = []; var selectedProductLine = []; var selectedProducts = {};

      global.webApiClient.init();
      global.webApiClient.on("initData", function (message) {
          //このイベントは初期データを受信できます
          if (message) {
              dataSource = message.data;
              showValue = message.value.values || [];
          }
      
      
          try {
              renderDomData(showValue);
              renderTotal(showValue);
          } catch (error) {
              //データ形式が正しくありません。
          }
      });
      
      
      global.webApiClient.on("onSavedValueData", function () {
          var workTimeTotal = 0;
          var onWayTimeTotal = 0;
          for (var index = 0; index < showValue.length; index++) {
              var fullDataItem = showValue[index];
              workTimeTotal += Number(fullDataItem.onlineTime);
              onWayTimeTotal += Number(fullDataItem.onWayTime);
          }
      
          //このイベントはデータ保存に使用します
          global.webApiClient.saveValueData(JSON.stringify({
              values: [].concat(showValue || []),
              workTimeTotal: workTimeTotal,
              onWayTimeTotal: onWayTimeTotal
          }));
      });
      
      global.webApiClient.on("onDestroyed", function () {
          //このイベントはメモリを破棄し、メモリリークを防ぐために使用します
          global.webApiClient.off("init");
          global.webApiClient.off("initData");
          global.webApiClient.off("onSavedValueData");
          global.webApiClient.off("onDestroyed");
      
          global.changeOnlineTime = null;
          global.changeOnWayTime = null;
          global.addProductionLine = null;
          global.onAddProduct = null;
          global.deleteProductLine = null;
          fullDataList = [];
      });
      
      function renderTotal(showValue) {
          var workTimeTotal = 0;
          var onWayTimeTotal = 0;
          for (var index = 0; index < showValue.length; index++) {
              let fullData = showValue[index];
              if (fullData.onlineTime) {
                  workTimeTotal += Number(fullData.onlineTime);
              }
              if (fullData.onWayTime) {
                  onWayTimeTotal += Number(fullData.onWayTime);
              }
          }
          workTimeTotal = !!workTimeTotal ? workTimeTotal.toFixed(1) : 0;
          onWayTimeTotal = !!onWayTimeTotal ? onWayTimeTotal.toFixed(1) : 0;
          global.document.getElementById(
              "udesk-work-time-total"
          ).innerHTML = workTimeTotal;
          global.document.getElementById(
              "udesk-on-way-time-total"
          ).innerHTML = onWayTimeTotal;
      }
      
      function renderDomData(value) {
          var ulData = "";
          for (var index = 0; index < value.length; index++) {
              var valueItem = value[index];
      
              ulData +=
                  "<li data-product-id=" +
                  valueItem.id +
                  ">" +
                  buildItemRenderData(valueItem) +
                  "</li>";
          }
      
          global.document.getElementById(
              "udesk-custom-field-content"
          ).innerHTML = ulData;
      }
      
      function buildItemRenderData(value) {
          var content = "";
          var targetProductLine = findTargetValue(dataSource, function (
              item
          ) {
              return item.id == value.id;
          });
      
          if (targetProductLine) {
              let displayProductName = getDisplayProductName(
                  targetProductLine.products,
                  value.products
              );
      
              content +=
                  "<div class='content-item productline-header'><span>" +
                  targetProductLine.name +
                  "</span><span class='delete-product-line-btn' onclick='deleteProductLine(" +
                  value.id +
                  ")'>削除</span></div>";
      
              content +=
                  "<div class='content-item'><label>詳細:</label><span class='content-item-content'>" +
                  displayProductName +
                  "</span><span class='selecte-product-btn' onclick='onAddProduct(" +
                  value.id +
                  ")'> > </span></div>";
              content +=
                  "<div class='content-item'><label>時間1:</label><input class='content-item-content' type='number' min='0' oninput='changeOnlineTime(event" +
                  "," +
                  value.id +
                  ")' value=" +
                  value.onlineTime +
                  " /></div>";
      
              content +=
                  "<div class='content-item'><label>時間2:</label><input class='content-item-content' type='number' min='0' oninput='changeOnWayTime(event" +
                  "," +
                  value.id +
                  ")' value=" +
                  value.onWayTime +
                  " /></div>";
      
          }
          return content;
      }
      
      function getDisplayProductName(dataSourceProducts, valueProducts) {
          var valueList = [];
          if (valueProducts && valueProducts.length > 0) {
              for (var index = 0; index < valueProducts.length; index++) {
                  var targetProductData = findTargetValue(
                      dataSourceProducts,
                      function (item) {
                          return item.id == valueProducts[index];
                      }
                  );
                  if (targetProductData) {
                      valueList.push(targetProductData.name);
                  }
              }
          }
      
          if (valueList && valueList.length > 0) {
              return valueList.join(",");
          } else {
              return "- -";
          }
      }
      
      function findTargetValue(value, matcherCallback) {
          var findValue = null;
          if (value && value.length > 0) {
              for (var i = 0; i < value.length; i++) {
                  var valueItem = value[i];
                  if (matcherCallback(valueItem)) {
                      findValue = valueItem;
                      break;
                  } else {
                      findValue = null;
                  }
              }
          }
          return findValue;
      }
      
      global.changeOnlineTime = function (e, dataItemId) {
          var onlineTimeValue = e.target.value;
          findTargetValue(showValue, function (item) {
              if (item.id == dataItemId) {
                  item.onlineTime = onlineTimeValue;
                  return true;
              } else {
                  return false;
              }
          });
          renderTotal(showValue);
      };
      
      global.changeOnWayTime = function (e, dataItemId) {
          var onWayTimeValue = e.target.value;
          findTargetValue(showValue, function (item) {
              if (item.id == dataItemId) {
                  item.onWayTime = onWayTimeValue;
                  return true;
              } else {
                  return false;
              }
          });
          renderTotal(showValue);
      };
      
      global.addProductionLine = function () {
          var li = "";
          for (var index = 0; index < dataSource.length; index++) {
              var dataItem = dataSource[index];
              var hadProductLine = findTargetValue(showValue, function (
                  value
              ) {
                  return value.id == dataItem.id;
              });
      
              li +=
                  "<li class='modal-content-item'><div>" +
                  dataItem.name +
                  "</div><input class='modal-content-item-right' type='radio' name='product-line' onChange='selectedProductLine(event" +
                  "," +
                  dataItem.id +
                  ',"' +
                  dataItem.name + '","' +
                  dataItem.code +
                  "\")' value='" +
                  dataItem.id +
                  (hadProductLine ? "' disabled/>" : "' />") +
                  "</li>";
          }
      
          global.document.getElementById(
              "add-data-container"
          ).innerHTML = li;
      
          global.document.getElementById(
              "add-data-modal-mask"
          ).style.display = "block";
      };
      
      global.onAddProduct = function (productLineId) {
          var targetProductData = findTargetValue(dataSource, function (
              item
          ) {
              return item.id == productLineId;
          });
      
          if (targetProductData) {
              var showProductLine = findTargetValue(showValue, function (
                  value
              ) {
                  return value.id == productLineId;
              });
      
              var hadProducts = [];
              if (showProductLine) {
                  if (selectedProducts == null) {
                      selectedProducts = {};
                  }
      
                  var productNames = (typeof showProductLine.productNames == "string" && showProductLine.productNames && showProductLine.productNames.split(","));
                  selectedProducts[productLineId] = {
                      products: showProductLine.products || [],
                      productNames: productNames || []
                  };
      
                  hadProducts = [].concat(
                      selectedProducts[productLineId].products
                  );
              }
      
              var li = "";
              var productNames = [];
              for (
                  var index = 0;
                  index < targetProductData.products.length;
                  index++
              ) {
                  var product = targetProductData.products[index];
                  var isChecked =
                      hadProducts.indexOf(product.id) > -1 ? true : false;
                  if (isChecked) {
                      productNames.push(product.name);
                  }
      
                  li +=
                      "<li class='modal-content-item'><div>" +
                      product.name +
                      "</div><input class='modal-content-item-right' type='checkbox' onChange='changeCheckBoxValue(event" +
                      "," +
                      targetProductData.id +
                      ',"' +
                      product.id + '","' +
                      product.name +
                      "\")' value=" +
                      product.id +
                      (isChecked ? " checked/>" : " />") +
                      "</li>";
              }
      
              global.document.getElementById(
                  "add-data-container"
              ).innerHTML = li;
              global.document.getElementById(
                  "add-data-modal-mask"
              ).style.display = "block";
              hadProducts = [];
          }
      };
      
      global.selectedProductLine = function (e, productLineId, productName, productCode) {
          var newValue = {
              id: productLineId,
              code: productCode,
              name: productName,
              products: [],
              productNames: "",
              onlineTime: 0,
              onWayTime: 0,
          };
          if (!Array.isArray(selectedProductLine)) {
              selectedProductLine = [];
          }
          selectedProductLine = [newValue];
      };
      global.changeCheckBoxValue = function (
          e,
          productLineId,
          productId,
          productName
      ) {
          if (selectedProducts == null) {
              selectedProducts = {};
          }
      
          if (selectedProducts[productLineId] == null) {
              selectedProducts[productLineId] = {
                  products: [productId],
                  productNames: [productName]
              };
          } else {
              var targetIndex = selectedProducts[productLineId].products.indexOf(
                  productId
              );
      
              if (targetIndex == -1) {
                  selectedProducts[productLineId].products.push(productId);
                  selectedProducts[productLineId].productNames.push(productName);
              } else {
                  selectedProducts[productLineId].products.splice(targetIndex, 1);
                  selectedProducts[productLineId].productNames.splice(targetIndex, 1);
              }
          }
      };
      
      global.deleteProductLine = function (productLineId) {
          var containerElement = global.document.getElementById(
              "udesk-custom-field-content"
          );
          var removeNode = global.document.querySelector(
              "[data-product-id='" + productLineId + "']"
          );
          containerElement.removeChild(removeNode);
          for (var j = 0; j < showValue.length; j++) {
              var showValueItem = showValue[j];
              if (showValueItem.id == productLineId) {
                  showValue.splice(j, 1);
                  break;
              }
          }
      };
      
      global.saveSelectedData = function () {
          if (selectedProductLine && selectedProductLine.length > 0) {
              var newValue = selectedProductLine[0];
              var li = buildItemRenderData(newValue);
      
              var liDom = global.document.createElement("li");
              liDom.setAttribute("data-product-id", newValue.id);
              liDom.innerHTML = buildItemRenderData(newValue);
      
              global.document
                  .getElementById("udesk-custom-field-content")
                  .appendChild(liDom);
              if (showValue == null) {
                  showValue = [];
              }
              showValue.push(newValue);
      
              clearModalData();
          } else if (selectedProducts) {
              findTargetValue(showValue, function (item) {
                  var targetSelectedProducts = selectedProducts[item.id];
                  if (targetSelectedProducts &&
                      targetSelectedProducts.products
                  ) {
                      item.products = targetSelectedProducts.products;
                      item.productNames = targetSelectedProducts.productNames && targetSelectedProducts.productNames.length > 0 ? targetSelectedProducts.productNames.join(",") : "";
      
                      var li =
                          "<li data-product-id=" +
                          item.id +
                          ">" +
                          buildItemRenderData(item) +
                          "</li>";
      
                      var targetDom = global.document.querySelector(
                          "[data-product-id
      

      デモ展示