皆さんこんにちは。kintoneアプリエンジニアのtomiokaです。
先日、運送会社のお客様からこんな相談をいただきました。
「Excelで配車表を作って、LINEグループに投げてるんですけど、もう限界で、、、、」
配車管理は運送業界ではどこの会社でも悩んでいるテーマだと思います。今回はこの相談に対して、kintoneでどう解決したかを書いてみます。
Excelの配車表、こんなことになっていませんか
配車業務は、本質的には「車両」「ドライバー」「案件」の3つを日時で突き合わせるマッチング作業です。案件が10件くらいなら頭の中でも回せますが、30件、50件と増えてくると、、、、
- この車両は今日空いているのか
- このドライバーは何時に戻ってくるのか
- この案件に必要な車種は何か、積載量は足りるのか
これをExcelで管理しようとすると、行と列が膨大になり「見るだけで疲れる」シートになります。さらに、更新したExcelをLINEグループで共有する運用になりがちですが、「どのファイルが最新かわからない。。。」「古いほうを見て出発してしまった」という事故も実際に発生します。
今回相談をくれたお客様(トラック45台の運送会社)がまさにこのパターンでした。配車担当の方が毎朝5時に出社して、前日の運行実績を確認しながらExcelの配車表を更新し、LINEグループにファイルを投げる。ドライバーはスマホで確認するのですが、Excelはスマホだと見づらい。結局「俺の今日どこ?」と電話がかかってくる。急な変更があれば、その都度LINEで流し直すか電話で連絡を回す。「1日の半分はLINEと電話です」とおっしゃっていたのが印象的でした。
kintoneでどう解決したか
構成はシンプルで、3つのアプリを作りました。
| アプリ名 | 役割 | 主なフィールド |
|---|---|---|
| 車両管理 | 車両の基本情報と稼働状態 | 車両番号、車種、積載量(kg)、車検満了日、ステータス |
| ドライバー管理 | ドライバーの情報と勤務状態 | 氏名、免許種類、担当可能車種、勤務状態、連絡先 |
| 配車管理 | 日々の配車と案件情報 | 配車日、荷主、集荷先、配達先、必要車種、割り当て車両、割り当てドライバー、ステータス |
ポイントは、配車管理アプリから車両管理・ドライバー管理をルックアップで参照する構成にしたことです。配車を組むときに「この車両の積載量は何kgか」「このドライバーは大型免許を持っているか」をいちいち別のシートで確認する必要がなくなります。
配車管理アプリのフィールド構成は以下のとおりです。
| フィールド名 | フィールドタイプ | フィールドコード |
|---|---|---|
| 配車日 | 日付 | dispatch_date |
| 荷主名 | 文字列(1行) | shipper_name |
| 集荷先 | 文字列(1行) | pickup_location |
| 配達先 | 文字列(1行) | delivery_location |
| 必要車種 | ドロップダウン | required_vehicle_type |
| 必要積載量(kg) | 数値 | required_capacity |
| 割り当て車両番号 | ルックアップ | assigned_vehicle |
| 割り当てドライバー | ルックアップ | assigned_driver |
| 出発予定時刻 | 時刻 | departure_time |
| 到着予定時刻 | 時刻 | arrival_time |
| ステータス | ドロップダウン | status |
| 備考 | 文字列(複数行) | notes |
ステータスは「未割当」「割当済」「出発済」「完了」「キャンセル」の5段階です。このステータスが配車管理の中心になります。
ただし、アプリを作っただけでは「Excelがkintoneに移動しただけ」です。ここからがカスタマイズの出番です。
一覧画面に「配車ダッシュボード」を追加する
配車担当が一覧画面を開いたとき、今日の配車状況が一目でわかるようにします。「未割当が何件あるか」がすぐわかるだけで、朝の作業効率がまったく変わります。
一覧画面のヘッダーにステータスごとの件数をカード表示するコードです。
(function() {
'use strict';
kintone.events.on('app.record.index.show', function(event) {
var headerSpace = kintone.app.getHeaderMenuSpaceElement();
if (!headerSpace) return event;
// 既にダッシュボードがあれば再描画しない
if (headerSpace.querySelector('#dispatch-dashboard')) return event;
var records = event.records;
// ステータスごとの件数を集計
var counts = { '未割当': 0, '割当済': 0, '出発済': 0, '完了': 0 };
records.forEach(function(record) {
var status = record.status.value;
if (counts.hasOwnProperty(status)) {
counts[status]++;
}
});
// ダッシュボードを生成
var dashboard = document.createElement('div');
dashboard.id = 'dispatch-dashboard';
dashboard.style.cssText = 'display:flex;gap:16px;padding:12px 0;';
var styles = {
'未割当': { bg: '#FFF3CD', border: '#FFC107' },
'割当済': { bg: '#D4EDDA', border: '#28A745' },
'出発済': { bg: '#D1ECF1', border: '#17A2B8' },
'完了': { bg: '#E2E3E5', border: '#6C757D' }
};
Object.keys(styles).forEach(function(key) {
var card = document.createElement('div');
card.style.cssText =
'padding:12px 20px;border-radius:8px;min-width:100px;text-align:center;' +
'background:' + styles[key].bg + ';' +
'border-left:4px solid ' + styles[key].border + ';';
var label = document.createElement('div');
label.style.cssText = 'font-size:12px;color:#555;margin-bottom:4px;';
label.textContent = key;
var count = document.createElement('div');
count.style.cssText = 'font-size:24px;font-weight:bold;color:#333;';
count.textContent = counts[key] + '件';
card.appendChild(label);
card.appendChild(count);
dashboard.appendChild(card);
});
headerSpace.appendChild(dashboard);
return event;
});
})();kintone.app.getHeaderMenuSpaceElement() で一覧画面のヘッダー領域を取得し、ステータスごとの件数をカード形式で並べています。「未割当」が黄色で目立つようにしているので、朝一で開いたときに未割当件数がすぐ確認できます。これだけでもお客様にはかなり喜ばれました。
ただし注意点として、event.records は一覧画面に表示されているレコードのみが対象です。kintoneのデフォルト表示件数は20件なので、案件数が多い場合は一覧の表示件数を「100件」に設定するか、REST APIで当日の全レコードを別途取得して集計する方法を検討してください。
「空きドライバー確認」ボタンをつける
もうひとつ、現場で喜ばれた機能があります。
配車を組むとき、「この日、誰が空いているか」を調べるために、ドライバー管理アプリと配車管理アプリを交互に確認する手間が発生します。配車の登録画面にボタンを1つ置いて、押すだけで空いているドライバーを表示するようにしました。
配車管理アプリのフォームにスペースフィールドを1つ追加して、フィールドコードを driver_check_space に設定してください。
(function() {
'use strict';
// ドライバー管理アプリのIDを設定してください
var DRIVER_APP_ID = 10;
kintone.events.on([
'app.record.create.show',
'app.record.edit.show'
], function(event) {
var spaceEl = kintone.app.record.getSpaceElement('driver_check_space');
if (!spaceEl) return event;
// 既にボタンがあれば再生成しない
if (spaceEl.querySelector('#check-driver-btn')) return event;
var button = document.createElement('button');
button.id = 'check-driver-btn';
button.textContent = '空きドライバーを確認';
button.className = 'kintoneplugin-button-dialog-ok';
button.addEventListener('click', function() {
checkAvailableDrivers();
});
spaceEl.appendChild(button);
return event;
});
function checkAvailableDrivers() {
var record = kintone.app.record.get().record;
var dispatchDate = record.dispatch_date.value;
if (!dispatchDate) {
alert('配車日を先に入力してください。');
return;
}
var DISPATCH_APP_ID = kintone.app.getId();
// 指定日に既に割り当てられているドライバーを取得
var dispatchQuery =
'dispatch_date = "' + dispatchDate + '"' +
' and status not in ("キャンセル")' +
' and assigned_driver != ""';
kintone.api(
kintone.api.url('/k/v1/records', true),
'GET',
{
app: DISPATCH_APP_ID,
query: dispatchQuery,
fields: ['assigned_driver']
}
).then(function(dispatchResp) {
var busyDrivers = dispatchResp.records.map(function(r) {
return r.assigned_driver.value;
});
return kintone.api(
kintone.api.url('/k/v1/records', true),
'GET',
{
app: DRIVER_APP_ID,
query: '勤務状態 in ("出勤可")',
fields: ['氏名', '免許種類', '担当可能車種']
}
).then(function(driverResp) {
var available = driverResp.records.filter(function(driver) {
return busyDrivers.indexOf(driver['氏名'].value) === -1;
});
return available;
});
}).then(function(available) {
if (available.length === 0) {
alert(dispatchDate + ' に空いているドライバーはいません。');
return;
}
var message = '【' + dispatchDate + ' の空きドライバー】\n\n';
available.forEach(function(driver) {
message +=
'・' + driver['氏名'].value +
'(免許: ' + driver['免許種類'].value +
' / 車種: ' + driver['担当可能車種'].value + ')\n';
});
message += '\n合計 ' + available.length + '名';
alert(message);
}).catch(function(error) {
console.error(error);
alert('ドライバー情報の取得に失敗しました。');
});
}
})();処理の流れは以下のとおりです。
- 入力中の「配車日」を取得する
- その日に既に割り当てられているドライバーをREST APIで取得する
- ドライバー管理アプリから勤務可能なドライバーを全員取得する
- 2と3を突き合わせて、空いているドライバーだけを表示する
「この日誰が空いている?」を調べるために毎回電話していた作業がボタン1つになるので、効果は大きいです。
なお、kintone.apiの第4引数(コールバック関数)を省略するとPromiseが返されます。コールバックのネストが深くなりがちなkintoneカスタマイズでは、.then() でチェーンする書き方のほうが可読性が高いのでおすすめです。
通知の話 ─ kintone標準 or Webhook
配車が確定したらドライバーに知らせたい、、、、というのも当然出てくる要望です。
kintoneの標準通知機能を使えば、ステータスが「割当済」に変わったタイミングで通知を飛ばせます。ただし、kintoneの通知はkintoneにログインしているユーザーにしか届きません。ドライバーがkintoneのアカウントを持っていない場合は、Webhookで外部サービス(Slack、LINE WORKSなど)に飛ばす方法もあります。
Webhookの設定は配車管理アプリの設定画面から「Webhook」で行います。なお、Webhookの利用にはcybozu.com共通管理であらかじめ許可設定が必要です。Webhookの詳しい実装はまた別の記事で書こうと思います。
ハマりどころ
このカスタマイズを実装するとき、私も最初はいくつかハマったので共有しておきます。
ルックアップの表示が遅い問題
車両やドライバーの数が数百件を超えると、ルックアップの選択画面が重くなります。ルックアップの「絞り込み初期値」を設定して、勤務状態が「出勤可」のドライバーだけ初期表示するようにすると解消されます。
1日に複数配車のケース
今回の空きドライバー確認は「1日に1件の配車」が前提です。1人のドライバーが午前と午後で別の案件を担当するケースでは、時刻の突き合わせが必要になります。出発予定時刻と到着予定時刻を含めた空き時間帯の判定ロジックを追加する必要がありますが、、、、ここは案件の複雑さに応じて検討してください。
同時編集の競合
配車担当が2人いる場合、同じレコードを同時に編集すると後から保存したほうで上書きされます。kintoneにはレコードのロック機能がないので、担当エリアで担当者を分けるなどの運用ルールが必要です。
氏名での突合と同姓同名
空きドライバー確認のコードでは、ドライバーの一意性を「氏名」で判定しています。同姓同名のケースが気になる場合はドライバー管理アプリに社員番号フィールドを追加して、そちらで照合するようにしてください。
実際に導入してみて
先ほどのトラック45台の運送会社に導入した結果ですが、一番大きかったのは配車担当の方の出社時間が1時間遅くなったことです。朝の配車組み作業が約2時間から40分程度に短縮されて、「朝5時出社がなくなっただけで生活が変わりました」と言っていただけました。
「LINEに流したExcelのどれが最新かわからない」問題も根本的に解消されました。kintoneならドライバーがスマホのブラウザで自分の配車を直接確認できるので、「俺の今日どこ?」という電話がほぼなくなりました。ドライバーへのLINE・電話連絡も1日15〜20回から3〜5回に減っています。
配車ミス(車種・積載量の不一致)も、ルックアップで車両情報が自動表示されるようになったことで、月3〜4件あったものがほぼゼロになりました。
地味に助かっているのが月末の実績集計です。以前はドライバーの日報とExcelの配車表を突き合わせて丸1日かかっていた作業が、kintoneの一覧をCSVエクスポートするだけで済むようになりました。
まとめ
今回は、運送会社の配車管理をkintoneでデジタル化する方法を紹介しました。
ポイントを整理すると、
- 「車両」「ドライバー」「案件」を3つのアプリに分けて、ルックアップで連携する。ExcelをLINEで共有する運用から脱却できる
- 一覧画面にダッシュボードを追加して、配車状況を一目で把握できるようにする
- REST APIで「空きドライバー」を自動抽出する。記憶と電話に頼る配車からデータに基づく配車へ
- 実績データが自動で蓄積されるので、月末の集計がCSVエクスポートだけで済む
配車管理は運送会社の根幹業務ですが、意外とExcel+LINEで回している会社が多い印象です。kintoneなら専用の配車システムを導入するよりもはるかに低コストで、しかも自社の業務に合わせてカスタマイズできます。
株式会社ファストコーディングでは、kintoneアプリの構築やカスタマイズを手がけています。「配車管理をなんとかしたい」「kintoneで業務を効率化したい」といったご相談があれば、お問い合わせフォームからお気軽にご連絡ください。

