皆さんこんにちは。この記事はIIT(Iwate Industrial Tecnology) Advent Calendar 2025の17日目の記事です。
今回、私はサイゼリヤの注文システムを再現してみました。ここでは、どのようなシステムを再現したのか、どのようなコードを使ったか、どこが難しかったなどを説明していきます。
サイゼリヤ注文システムとは
サイゼリヤといったらなんといってもあの番号ですよね。料理一つ一つに番号が付けられてあってその番号を使って注文していきます。私も料理番号全部覚えようとした時があったんですけれど、種類が多すぎて覚えることができませんでした。
サイゼリヤの注文は前までは番号を紙に書いて個数を書いて店員さんに渡すやり方が主流でした。私は字が汚いのでちゃんと料理が届くか不安でした。
しかし最近になって注文のやり方が大きく変わりました。紙がなくなって、自分のスマートフォンを使って注文するようになりました。
これですね。これはお食事中のQRコードなので読み込んでも無駄ですよ。
このQRコードを読み込むと注文フォームへ自動で飛ばされます。
ここでは割愛しますが、最初の画面の注文を始めるボタンを押した後、人数選択画面に飛ぶので人数を選択すると番号入力画面に進みます。
そして今回私が再現したのはこの番号入力画面です。
番号入力画面
まず本家と私が作ったのを比較しましょう。
左の画像が本家の番号入力画面で、右の画像が私のつくった番号入力画面です。
ちょっとだけ違いますね。
このロゴはchatgptを使って作りました。画像を添付して、「これに似たロゴ作ってみて」と言っただけでこの仕上がりです。すごいですね。
つぎにプログラム画面を見てみましょう
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>番号入力</title>
<link rel="stylesheet" href="https://unpkg.com/ress/dist/ress.min.css">
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<body>
<header class="header">メニューブックから番号を入力してください</header>
<img src="image/seriberi.png" alt="セリベリロゴ">
<button>次へ進む</button>
<div class="display" id="display"></div>
<div id="itemName"></div>
<!-- 数字ボタン -->
<div class="keypad">
<button data-num="1">1</button>
<button data-num="2">2</button>
<button data-num="3">3</button>
<button data-num="4">4</button>
<button data-num="5">5</button>
<button data-num="6">6</button>
<button data-num="7">7</button>
<button data-num="8">8</button>
<button data-num="9">9</button>
<button data-num=""></button>
<button data-num="0">0</button>
<button class="delete" id="deleteBtn">削除</button>
</div>
<footer class="menu">
<button class="active">注文追加</button>
<button>注文かご</button>
<button>注文履歴</button>
<button>店員呼出</button>
<button>会計する</button>
</footer>
<script src="script/main.js"></script>
<div id="itemName" class="item-name"></div>
</body>
</html>
/* ヘッダー */
.number-header {
background: #4b9d45;
color: #ffffff;
font-size: 1.6rem;
padding: 15px 0;
margin: 0;
}
/* ロゴ部分 */
img[alt="セリベリロゴ"] {
display: block;
margin: 100px auto 40px;
width: 45%;
}
/* 番号表示欄 */
.number-display {
width: 70%;
margin: 20px auto;
padding: 20px;
border: 3px solid #4b9d45;
border-radius: 8px;
font-size: 2rem;
min-height: 40px;
}
/* テンキー配置 */
.keypad {
width: 80%;
max-width: 400px;
margin: 20px auto 120px;
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 15px;
}
/* テンキーボタン */
.keypad button {
padding: 15px;
font-size: 1.8rem;
border: 2px solid #ccc;
border-radius: 12px;
background: #f6f6f6;
color: #4b9d45;
box-shadow: inset 0px -3px 3px rgba(0,0,0,0.15);
cursor: pointer;
transition: 0.1s;
}
.keypad button:hover {
filter: brightness(0.95);
}
/* 削除キー */
.keypad .delete-btn {
background: #4b9d45;
color: #ffffff;
}
/* 下部メニュー */
.menu-number {
display: flex;
justify-content: space-around;
align-items: center;
background: #4b9d45;
padding: 14px 0;
position: fixed;
bottom: 0;
width: 100%;
}
.menu-number button {
background: linear-gradient(#ffffff,#e6e6e6);
border: 2px solid #c8c8c8;
border-radius: 10px;
padding: 10px 8px;
font-weight: bold;
width: 16%;
transition: 0.2s;
font-size: 1rem;
}
.menu-number button:hover {
filter: brightness(0.92);
}
/* 商品名表示 */
#itemName {
background: #e7f7dd;
width: 80%;
margin: 20px auto 10px;
padding: 15px;
border-radius: 6px;
font-size: 1.8rem;
color: #2f7d33;
text-align: left;
font-weight: bold;
box-sizing: border-box;
}
/* 「次へ進む」ボタン */
.next-btn {
background: linear-gradient(#d64545, #b03030);
border: 1px solid #8c1f1f;
color: white;
padding: 15px 35px;
font-size: 1.6rem;
border-radius: 10px;
font-weight: bold;
margin: 10px auto 15px;
display: block;
}
/* 番号表示欄 */
#display {
width: 80%;
margin: 15px auto;
padding: 20px;
font-size: 2.4rem;
border: 3px solid #2f7d33;
border-radius: 10px;
background: #ffffff;
color: #222;
min-height: 40px;
box-sizing: border-box;
}
/* テンキー */
.keypad {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 14px;
width: 80%;
margin: 20px auto 130px;
}
/* テンキーの個々のボタン */
.keypad button {
padding: 18px 0;
font-size: 2rem;
background: linear-gradient(#ffffff, #f0f0f0);
border-radius: 12px;
border: 2px solid #c8c8c8;
color: #2f7d33;
box-shadow: 0 2px 0 #bdbdbd;
cursor: pointer;
}
/* 削除キー */
.keypad .delete,
#deleteBtn {
background: #2f7d33 !important;
color: white !important;
border: none;
box-shadow: 0 2px 0 #1f5521;
}
document.addEventListener("DOMContentLoaded", () => {
const display = document.getElementById("display");
const itemName = document.getElementById("itemName"); // 商品名表示欄
const numButtons = document.querySelectorAll(".keypad button[data-num]");
const deleteBtn = document.getElementById("deleteBtn");
// 商品一覧
const items = {
// 前菜系
"1401": "辛味チキン",
"1402": "アロスティチーニ",
"1452": "Wサイズアロスティチーニ",
"1407": "チョリソー",
"1416": "ポテトのグリル",
"1405": "エスカルゴのオーブン焼き",
"1410": "ムール貝のガーリック焼き",
"1404": "ポップコーンシュリンプ",
"1408": "蒸し鶏の香味ソース",
"1423": "生ハムとバッファローモッツァアレラの盛り合わせ",
"1422": "ハモン・セラーノ",
"1417": "バッファローモッツァアレラのカプレーゼ",
"1406": "小エビのカクテル",
"1403": "ほうれん草のソテー",
"1425": "柔らか青豆の温サラダ",
"1413": "キャロットラペ",
// サラダ系
"1202": "小エビのサラダ",
"1209": "チキンのサラダ",
"1205": "わかめのサラダ",
"5305": "サイゼリヤドレッシング",
// スープ系
"1307": "玉ねぎのズッパ",
"1301": "コーンクリームスープ",
"1305": "田舎風ミネストローネ",
// フォッカチオ系
"3110": "フォッカチオ",
"3111": "ガーリックフォッカチオ",
"3112": "シナモンフォッカチオ",
"3113": "チーズフォッカチオ",
"3114": "たらこフォッカチオ",
// ピザ系
"2203": "バッファローモッツァレラのマルゲリータピザ",
"2204": "野菜とキノコのピザ",
"2206": "たっぷりコーンのピザ",
"2208": "ソーセージピザ",
// ドリア系
"2101": "ミラノ風ドリア",
"2103": "半熟卵のミラノ風ドリア",
"2108": "焼きチーズミラノ風ドリア",
"2110": "タラコとポップコーンシュリンプのドリア",
"2115": "ポップコーンシュリンプとタラコのクリームグラタン",
// パスタ系
"2305": "カルボナーラ",
"2301": "タラコソースシシリー風",
"2320": "小エビのタラコソース",
"2304": "パルマ風スパゲッティ",
"2321": "きのことほうれん草のクリームスパゲッティ",
"2328": "イカの墨入りセピアソース",
"2306": "ミートソースボロニア風",
"2316": "半熟卵のミートソースボロニア風",
"2303": "ペペロンチーノ",
"2317": "半熟卵のペペロンチーノ",
"2310": "スープ入り塩味ボンゴレ",
"2325": "ペンネアラビアータ",
// 肉系
"2418": "ミックスグリル",
"2406": "ハンバーグステーキ",
"2403": "イタリアンハンバーグ",
"2407": "ディアボラ風ハンバーグ",
"2402": "若鳥のディアボラ風",
"2404": "柔らかチキンのチーズ焼き",
"2419": "ビーフステーキ",
"2418": "ミックスグリル",
"2417": "ラム(仔羊)のランプステーキ",
// デザート系
"3206": "イタリアンプリン",
"3906": "イタリアンプリン(あとで)",
"3201": "ティラミスクラシコ",
"3901": "ティラミスクラシコ(あとで)",
"3212": "プリンとティラミスクラシコの盛り合わせ",
"3912": "プリンとティラミスクラシコの盛り合わせ(あとで)",
"3205": "ミルクジェラート",
"3205": "ミルクジェラート(あとで)",
"3207": "チョコレートケーキ",
"3207": "チョコレートケーキ(あとで)",
"3216": "チョコレートケーキ&ミルクジェラート",
"3216": "チョコレートケーキ&ミルクジェラート(あとで)",
"3213": "トリフアイスクリーム",
"3213": "トリフアイスクリーム(あとで)",
"3215": "コーヒーゼリー&ミルクジェラート",
"3215": "コーヒーゼリー&ミルクジェラート(あとで)",
"3214": "ジェラート&シナモンフォッカチオ",
"3214": "ジェラート&シナモンフォッカチオ(あとで)",
// ドリンクバー
"5101": "セット ドリンクバー",
"5102": "キッズ",
"5103": "単品",
// お酒
"3301": "ジョッキ",
"3302": "グラスビール",
"3303": "アサヒドライゼロ",
"3304": "氷結レモン",
// ワイン
"3401": "グラスワイン 赤",
"3402": "グラスワイン 白",
"3403": "デカンタ小 赤",
"3404": "デカンタ小 白",
"3405": "デカンタ大 赤",
"3408": "デカンタ大 白",
"3407": "マグナム 赤",
"3408": "マグナム 白",
"3413": "ドンファフェロ",
"3412": "ランブルスコロゼ",
"3414": "ランブルスコセッコ",
"3415": "ベルデッキオ",
"3416": "キャンティ",
"3419": "キャンティカステッリデルグレヴェペーザ"
};
// 数字ボタン処理
numButtons.forEach(btn => {
btn.addEventListener("click", () => {
display.textContent += btn.dataset.num;
const code = display.textContent;
// 商品名表示
if (items[code]) {
itemName.textContent = items[code];
} else {
itemName.textContent = "";
}
});
});
// 削除ボタン
deleteBtn.addEventListener("click", () => {
display.textContent = display.textContent.slice(0, -1);
const code = display.textContent;
if (items[code]) {
itemName.textContent = items[code];
} else {
itemName.textContent = "";
}
});
});
この番号入力画面のなかで
- 次に進む
- 注文かご
- 注文履歴
- 店員呼出
- 会計する
はただの飾りのボタンになっています。
数字表示欄にid="display"、商品名を表示する欄にはid="itemName"を設定しています。js側でdocument.getElementById()を使ってそれぞれの表示内容を直接書き換えれます。
コードを書いている中で一番大変だったのは、やっぱりメニューを書くことでした。パスタの中でも半熟卵があったり、デザートに「あとで」があったりでその分書く量も増えてます。
最後に
サイゼリヤの注文システムを初めて見たときに、シンプルながら見やすく、使いやすいと思い今回再現することになりました。簡単に見えてもコードの中は複雑で書く量もものすごく多くこの業界は奥が深いと改めて感じました。
これからもIT技術者になるものとして、サイゼリヤのバイトとして、頑張っていきたいと思います。
参考サイト
[UX小話]サイゼリヤの新オーダーシステムの話
https://note.com/corobutika/n/na0cd59b99c4b
大人の自由研究(Python):サイゼリヤのスマホ注文アプリを真夜中テンションで再現してみた
https://note.com/ojojo919/n/n7a39bb4d171a


