kintone
投稿日:

「検品記録がまだ紙?」─ kintoneで検品チェックシートをデジタル化し不良品率を可視化する

皆さんこんにちは。kintoneアプリエンジニアのtomiokaです。

先日、部品メーカーのお客様から「検品記録を紙からデジタルに移したい」と相談がありました。

従業員100名ほどの工場で、検品結果を紙のチェックシートに手書きし、月末にExcelへ転記して集計するという三重作業をしていました。現場の検査員は毎日チェックシートを書いているのに、品質管理担当が集計結果を見られるのは翌月。「先月の不良率が高かったラインを今月改善する」というサイクルが、どうしても1ヶ月遅れになってしまう状態です。

今回の記事は、従業員100名規模の部品メーカーで品質管理を担当されている方に向けて書いています。紙の検品記録をkintoneでデジタル化し、不良品率をリアルタイムで可視化した事例をお伝えします。

紙の検品記録で起きている問題

お客様の状況を整理すると、以下の問題がありました。

  • 検査員が紙のチェックシートに記入 → 品質管理担当がExcelに転記 → 月末に集計、という三重作業
  • 転記ミスが月に数件発生し、不良率の数字が合わない
  • 不良品が見つかっても写真記録が残らず、「どんな不良だったか」を後から確認できない
  • ロット番号との紐づけが紙の上だけなので、特定ロットの追跡に時間がかかる
  • 「どのラインで不良が多いか」の分析が月次でしかできない

特に「写真が残らない」問題は深刻でした。取引先から品質クレームが入ったとき、過去の検品記録を紙で遡って確認するのに半日かかることもあったそうです。

kintoneでどう解決したか

構成は2つのアプリです。

アプリ名役割主なフィールド
検品記録日々の検品結果の記録ロット番号、製品名、検査ライン、検品項目(サブテーブル)、判定結果、不良写真、検査員
製品マスタ製品ごとの検品基準製品名、検品項目一覧、基準値、許容範囲

検品記録アプリがメインです。検査員がタブレットで直接入力し、不良品があればその場でカメラ撮影して添付します。

検品記録アプリのフィールド構成

フィールド名フィールドタイプフィールドコード
検品日日付inspection_date
ロット番号文字列(1行)lot_number
製品名ドロップダウンproduct_name
検査ラインドロップダウンinspection_line
総検査数数値total_count
不良品数数値defect_count
不良率(%)計算defect_rate
判定結果ドロップダウンjudgment
不良写真添付ファイルdefect_photo
不良内容文字列(複数行)defect_detail
検査員ドロップダウンinspector
備考文字列(複数行)notes

不良率は計算フィールドで defect_count / total_count * 100 を自動計算します。検査員が入力するのは総検査数と不良品数だけなので、計算ミスが起きません。

判定結果は「合格」「条件付合格」「不合格」の3段階です。不良率が基準値を超えた場合に「不合格」とする運用ですが、判定自体は検査員が選択します。自動判定にしなかったのは、不良の内容によっては基準値内でも「条件付合格」にすべきケースがあるためです。

一覧画面に不良率ダッシュボードを表示する

検品記録アプリの一覧画面に、ライン別の不良率をカード表示するカスタマイズです。品質管理担当が朝一で開いたとき、「どのラインで不良が多いか」がすぐにわかります。

(function() {
  'use strict';

  kintone.events.on('app.record.index.show', function(event) {
    var headerSpace = kintone.app.getHeaderMenuSpaceElement();
    if (!headerSpace) return event;
    if (headerSpace.querySelector('#defect-dashboard')) return event;

    var records = event.records;

    // ライン別に集計
    var lineStats = {};
    records.forEach(function(record) {
      var line = record.inspection_line.value;
      var total = Number(record.total_count.value) || 0;
      var defects = Number(record.defect_count.value) || 0;

      if (!line) return;

      if (!lineStats[line]) {
        lineStats[line] = { total: 0, defects: 0 };
      }
      lineStats[line].total += total;
      lineStats[line].defects += defects;
    });

    // ダッシュボードを生成
    var container = document.createElement('div');
    container.id = 'defect-dashboard';
    container.style.cssText = 'display:flex;gap:16px;padding:12px 0;flex-wrap:wrap;';

    var title = document.createElement('div');
    title.textContent = 'ライン別 不良率サマリー';
    title.style.cssText = 'width:100%;font-size:14px;font-weight:bold;color:#333;margin-bottom:4px;';
    container.appendChild(title);

    Object.keys(lineStats).forEach(function(line) {
      var stats = lineStats[line];
      var rate = stats.total > 0
        ? (stats.defects / stats.total * 100).toFixed(2)
        : '0.00';

      // 不良率に応じて色を変える
      var rateNum = parseFloat(rate);
      var bg = '#E8F5E9';
      var border = '#388E3C';
      if (rateNum >= 1.0) {
        bg = '#FFF3E0';
        border = '#F57C00';
      }
      if (rateNum >= 3.0) {
        bg = '#FFEBEE';
        border = '#D32F2F';
      }

      var card = document.createElement('div');
      card.style.cssText =
        'padding:12px 20px;border-radius:8px;min-width:140px;' +
        'background:' + bg + ';border-left:4px solid ' + border + ';';

      var lineLabel = document.createElement('div');
      lineLabel.textContent = line;
      lineLabel.style.cssText = 'font-size:12px;color:#666;margin-bottom:4px;';

      var rateLabel = document.createElement('div');
      rateLabel.textContent = rate + '%';
      rateLabel.style.cssText = 'font-size:24px;font-weight:bold;color:' + border + ';';

      var detail = document.createElement('div');
      detail.textContent = stats.defects + '/' + stats.total + '個';
      detail.style.cssText = 'font-size:11px;color:#888;margin-top:2px;';

      card.appendChild(lineLabel);
      card.appendChild(rateLabel);
      card.appendChild(detail);
      container.appendChild(card);
    });

    headerSpace.appendChild(container);
    return event;
  });
})();

このコードは検品記録アプリの一覧画面で動きます。一覧に表示されているレコードをライン別に集計し、不良率を計算して色付きカードで表示します。不良率1%以上はオレンジ、3%以上は赤になるので、問題のあるラインがひと目でわかります。

注意点として、この集計は一覧に表示されているレコード(event.records)だけが対象です。全期間の正確な集計が必要な場合は、REST APIで全レコードを取得する処理に変える必要があります。一覧のフィルタで「今月分」だけに絞り込んでおけば、今月の不良率サマリーとして使えます。

過去記事との連携:点検→検品→出荷のデータ一貫管理

以前の記事(kintone×QRコードで現場点検をスマート化)では、設備点検の記録をkintoneで管理する方法を紹介しました。今回の検品記録と組み合わせると、「設備点検→検品→出荷」のデータが一貫して管理できるようになります。

たとえば、設備点検で「ラインAの温度が基準値を外れた」という記録があったとき、同じ日のラインAの検品記録を確認すれば、「温度異常が不良品発生に影響したか」を追跡できます。紙の記録では、点検簿と検品簿を別々に引っ張り出して突き合わせる必要がありましたが、kintoneなら関連レコード一覧で紐づけるだけです。

ハマりどころ・注意点

計算フィールドの小数点表示

kintoneの計算フィールドで defect_count / total_count * 100 を設定する際、表示桁数の設定を忘れると、0.3333333…のように長い小数が表示されます。フォーム設定で表示桁数を「2」に設定しておくのが必須です。最初これを忘れて、検査員から「数字が読みにくい」と言われました、、、、

添付ファイルフィールドのタブレット対応

kintoneのモバイルアプリでは、添付ファイルフィールドからカメラを直接起動できます。ただし、写真のファイルサイズが大きいと通信量がかさみます。工場のWi-Fi環境が不安定な場合は、あらかじめ写真の解像度を下げる運用ルールを決めておくのが良いです。

不良率が0のときの除算エラー

総検査数が0のレコード(たとえばライン停止日の記録)がある場合、不良率の計算でゼロ除算エラーが起きます。計算フィールドの式を IF(total_count = 0, 0, defect_count / total_count * 100) にしておくと安全です。

導入結果

お客様に導入していただいたところ、以下の変化がありました。

  • 検品結果の集計:月末にExcel転記で丸1日 → リアルタイムでダッシュボード確認
  • 転記ミス:月3〜5件 → ゼロ(手入力が1回で済むため)
  • 品質クレーム対応:過去記録を紙で探して半日 → kintoneで検索して数分
  • 不良率の傾向把握:月次レポートでしかわからなかった → 日次で確認可能

特に不良率の日次確認ができるようになったことで、「ラインAの不良率が急に上がった」という異変に当日中に気づけるようになりました。以前は月末の集計で初めて「先月のラインAは不良率が高かった」とわかっていたので、対応が1ヶ月早くなったことになります。

まとめ

今回は、部品メーカーの検品記録をkintoneでデジタル化した事例を紹介しました。

  • 検品記録と製品マスタの2アプリ構成で、紙のチェックシートを置き換える
  • 不良品の写真をその場で添付し、後から追跡可能にする
  • 一覧画面のダッシュボードでライン別不良率をリアルタイムに可視化する
  • 過去記事の設備点検アプリと連携させて、「点検→検品→出荷」のデータ一貫管理を実現する

製造業の品質管理は「記録して終わり」ではなく「記録を分析して改善につなげる」ことが重要です。kintoneでデジタル化すれば、記録と分析が同時にできるようになります。

株式会社ファストコーディングでは、kintoneのカスタマイズや業務アプリの構築をお手伝いしています。「製造現場の記録をデジタル化したい」「品質データの分析基盤を作りたい」という方は、お問い合わせフォームからお気軽にご連絡ください。