掲示板

AIで買い物電卓を作った話

買い物をするときに、ピッタリ1,000円とか、それを少し超える金額にしたい時とかがあるので、AI(Copilot)で買い物電卓を作ってみました。

今までは、スマホの電卓でやっていたので、足したり引いたり大変でした。きっと、アプリストアには、それに適した電卓アプリもあるだろうなぁと思いましたが、見つけられず。あの検索キーワードだけで、アプリを探すのってムリゲーですよね。

というわけで、なければ自分で作ろう、なんですけど、スマホのアプリ、特にiPhoneは、作ったことがないので無理!(Androidもかなり昔で浦島太郎状態)、というわけで、Javascript で作ることにしました。

昔なら、テキストエディタで、<HTML…とか書いて作っていましたが、今はAIに頼めば、コードを書いてくれるので楽ですね。

電卓の仕様としては、商品名、金額を入力して、追加ボタンを押すと、表に追加されて、デフォルトでチェックボックスが1つチェックされます。各行にチェックボックスは5つあって、同じものを5個まで加算できます。

IMG_4037.jpeg

表にある項目のチェックボックスが付いている商品の合計金額が常に表示されるようになっていて、合計から外したい商品があれば、チェックボックスを外せば、即合計に反映される、というものです。

これであれば、あれを買ったり、やっぱりやめたりみたいなときに、チェックボックスをポチポチやればいいだけなので楽です。

まぁ、そのあと、割引を設定したり、税別、税込で入力できるようにしたりと、色々仕様追加していきました。


出力は1つのHTMLファイルにしてもらって、ブラウザで開けば、実行できるようにしました。(ソースは、body、script合わせて167行でした。一応、下の方に載せましたが、ちょっとテキストエディタで加工する必要があります。半角スペースは、マイネ王では消えてしまうので、全角スペースにしてありますが、それを戻す必要があります)

iPhoneの場合、PCのWebブラウザで自分のiCloud Driveを開き、そこに作成したHTMLファイルをドロップして、iPhoneのファイルアプリからHTMLファイルを共有→Edgeで開く、で実行できます。Safariでは、ローカルファイルの実行は出来ないみたいです。

もっと簡単に実行する方法があれば、知りたいですが。
(→今のところ、iPhoneのHTML Viewer Q がいい感じです。HTMLソースを見ようとすると、爆音の全画面広告が出るので注意!😅)


途中、チェックボックスを押しても、合計が反映しないというバグに見舞われましたが、「ちょっとこの辺がおかしいんじゃない?」と指摘してあげると、AIは、「するどい。まさにその通りで、○○が✕✕なので、…」とか言って、直し始めます。分かっていたら、最初からやれよと突っ込みたくなりますが😅、ちゃんと直してくるので逆に感心します。(わざとやっている?)

それでも結局、直らんのかwというのも何回かありましたが、ちょっと前に動いていたソースを、「前は、こんな感じで動いていたよ」とか教えると、そこを直して、結果的にちゃんと動くものを出してきたりするので、やっぱりすごいですね。

おまけに、「CSVで出力する機能や、カテゴリーごとに分ける機能も付けましょうか?」とか言ってきましたが、(いや、そんなことしたら、またバグるんで😅)ということで、そこまではしませんでした。

AIは、言葉の次のフレーズを1つずつ、次に続く言葉はこれが一番適切、というような感じで決めていくと聞いたことがありますが、そんなので、よくプログラミングができるなぁと思います。

ちなみに、一通り望む仕様のものが完成してから、そのソースから、色々な機能を削ぎ落した簡易版を作ってと依頼したところ、意外とバグだらけの物を出してきて、機能を追加していくのは得意だけれど、削除していくのは下手だなぁと思いました。

でも、半年くらい前に、別のものを書いてもらったときに比べると、なんか進化しているような気もします。まぁ定量的な評価ではないので、本当のところはどうかは分かりませんが😅

AIが書いたソースを見て、こうやって書けばいいんだ、と色々書き方を知ることができるので、一人で悩んでいるのに比べると、時間も掛からずに、新たなテクニックも学べていいですね。


■ 一応ソースを貼ってみました。
・以下ソースをまるっとコピーして、テキストエディタにペースト
・テキストエディタで全角スペース1個を半角スペース2個に一括置換
・shopping_cal.html みたいな名前を付けて保存
・ブラウザで開く

これでいけると思いますけど。

■ 仕様、使い方の詳細ですが、
・金額を入力して追加ボタンを押す。商品名は空欄なら --- になる
・デフォルトで1個分チェックされる
・デフォルトで税別価格の入力となる。合計は、これに税率が掛け合わされて合計される
・税込で入力したいなら、あとで税別のチェックを外す
・割引率は、デフォルトで20%、デフォルトで割引のチェックはオフ。見切り品なんかは、ここをチェック
・削除ボタンで行を削除できる
・金額の入力は、数字のみなので、スマホではテンキー入力に切り替わる
・拡大できないようにしてある。スマホでは、テキストボックスにフォーカスを当てると、拡大されてしまい使いづらいので(上の方にviewportとか設定がありますので適当に倍率を変えてください)
・全体の税率を変えたい時は、ラジオボタンで選択(食料品とそれ以外を混在して買うことは想定していないです)

<!DOCTYPE html>
<html lang="ja">
<head>
 <meta charset="UTF-8">
 <meta name="viewport" content="width=device-width, initial-scale=0.8, maximum-scale=0.8" />
 <title>商品別割引・税込み計算機</title>
 <link href="https://fonts.googleapis.com/css2?family=Roboto Mono&display=swap" rel="stylesheet">
 <style>
  body { font-family: sans-serif; margin: 20px; }
  input, button { margin: 5px; padding: 8px; }
  table { border-collapse: collapse; width: 100%; margin-top: 20px; }
  th, td { border: 1px solid #ccc; padding: 2px; text-align: center; }
  th:nth-child(n+3):nth-child(-n+7),
  td:nth-child(n+3):nth-child(-n+7) {
   width: 30px;
  }
  #total {
   font-family: 'Roboto Mono', monospace;
   font-size: 28px;
   font-weight: 600;
   letter-spacing: 1px;
  }
  #itemName, #itemPrice {
   font-size: 16px;
   width: 100px;
  }
  input[type="number"].discount-input {
   width: 30px;
  }
  button {
   padding: 8px 12px;
   font-size: 14px;
  }
 </style>
</head>
<body>
 <input type="text" id="itemName" placeholder="商品名">
 <input type="number" id="itemPrice" placeholder="金額" inputmode="numeric" pattern="\d*">
 <button onclick="addItem()">追加</button>

 <h4>
  税率:
  <label><input type="radio" name="taxRate" value="8" checked onchange="updateTotal()"> 8%</label>
  <label><input type="radio" name="taxRate" value="10" onchange="updateTotal()"> 10%</label><br>
 </h4>
 <h3>
  税込み合計金額: ¥<span id="total">0.00</span>
 </h3>

 <table id="itemTable">
  <thead>
   <tr>
    <th>商品名</th>
    <th>金額</th>
    <th>1</th>
    <th>2</th>
    <th>3</th>
    <th>4</th>
    <th>5</th>
    <th>割引率(%)</th>
    <th>割引</th>
    <th>税別</th>
    <th>削除</th>
   </tr>
  </thead>
  <tbody></tbody>
 </table>

 <script>
  function addItem() {
   const nameInput = document.getElementById("itemName").value.trim();
   const name = nameInput === "" ? "---" : nameInput;
   const price = parseInt(document.getElementById("itemPrice").value, 10);
   if (isNaN(price)) {
    alert("金額を正しく入力してください");
    return;
   }

   const table = document.getElementById("itemTable").getElementsByTagName("tbody")[0];
   const row = table.insertRow();
   row.insertCell().textContent = name;
   row.insertCell().textContent = "¥" + price;

   for (let i = 0; i < 5; i++) {
    const cell = row.insertCell();
    const checkbox = document.createElement("input");
    checkbox.type = "checkbox";
    checkbox.checked = (i === 0);
    checkbox.classList.add("main-check");
    checkbox.addEventListener("change", updateTotal);
    cell.appendChild(checkbox);
   }

   const discountRateCell = row.insertCell();
   const discountInput = document.createElement("input");
   discountInput.type = "number";
   discountInput.value = 20;
   discountInput.min = 0;
   discountInput.max = 100;
   discountInput.classList.add("discount-input");
   discountInput.setAttribute("inputmode", "numeric");
   discountInput.setAttribute("pattern", "\\d*");
   discountInput.addEventListener("change", updateTotal);
   discountRateCell.appendChild(discountInput);

   const discountCheckCell = row.insertCell();
   const discountCheckbox = document.createElement("input");
   discountCheckbox.type = "checkbox";
   discountCheckbox.classList.add("discount-check");
   discountCheckbox.addEventListener("change", updateTotal);
   discountCheckCell.appendChild(discountCheckbox);

   const taxCheckCell = row.insertCell();
   const taxCheckbox = document.createElement("input");
   taxCheckbox.type = "checkbox";
   taxCheckbox.classList.add("tax-check");
   taxCheckbox.checked = true;
   taxCheckbox.addEventListener("change", updateTotal);
   taxCheckCell.appendChild(taxCheckbox);

   const deleteCell = row.insertCell();
   const deleteButton = document.createElement("button");
   deleteButton.textContent = "削除";
   deleteButton.onclick = function () {
    row.remove();
    updateTotal();
   };
   deleteCell.appendChild(deleteButton);

   updateTotal();
   document.getElementById("itemName").value = "";
   document.getElementById("itemPrice").value = "";
  }

  function updateTotal() {
   let sum = 0;
   const selectedTaxRate = parseFloat(document.querySelector('input[name="taxRate"]:checked').value) || 0;

   const rows = document.querySelectorAll("#itemTable tbody tr");
   rows.forEach(row => {
    const priceText = row.cells[1].textContent;
    const price = parseFloat(priceText.replace("¥", ""));

    const itemChecks = row.querySelectorAll(".main-check");
    const checkedCount = Array.from(itemChecks).filter(cb => cb.checked).length;

    if (checkedCount > 0) {
     const discountInput = row.querySelector(".discount-input");
     const discountRate = parseFloat(discountInput.value) || 0;
     const discountCheck = row.querySelector(".discount-check");
     const isDiscounted = discountCheck && discountCheck.checked;
     const taxCheck = row.querySelector(".tax-check");
     const isTaxed = taxCheck && taxCheck.checked;

     let unitPrice = isDiscounted
      ? price * (1 - discountRate / 100)
      : price;

     if (isTaxed) {
      unitPrice *= (1 + selectedTaxRate / 100);
     }

     sum += unitPrice * checkedCount;
    }
   });

   document.getElementById("total").textContent = sum.toFixed(2);
  }
 </script>
</body>
</html>


26 件のコメント
1 - 26 / 26
素晴らしい!ソースコード(というか計算webサイト)をどこかに公開して貰えるなら見たい所。(無理は言いません)

2025-10-07_13h04_37.jpg

アッカリ〜ン@_@….,….,…😅さん
こんにちは~♪

この電卓、スバラシ~!
(*^ー゚)b グッジョブ!!
ちょうど、いろいろ買いたいものがあったとこなので、パクらせていただきました~
ありがとうございます!
┏○ペコッ


アッカリ〜ンさんの画像を貼り付けて 「これと似た感じの買い物電卓をjavascriptで作って!」 って指示して作ってもらいました。
ChatGPTは無料枠お仕置き中で画像読み込んでくれないんで、WindowsのEdgeでCopilotでお願いしました。
ExcelやNumbers、デザインアプリなんかで希望の仕上がり具合の見た目だけ作って「Javascriptで作って」 だけでも作ってくれそうですね。

ところで、合計金額ですが、アッカリ〜ンさんのだと割引が適用されてなくないですか?


このあと、iPhoneでの使用法、検討してみます。

>> さと さん

一応、ソースを貼ってみました。
割引とか税率とかが無い、単に足すだけののほうが、意外と汎用性はあるかも。
まぁ自分専用にいくらでも変更できるところがいいですね。

マイネ王にhtmlファイルを置ければいいけど、さすがにセキュリティがね😅
ありがとうごさいます

>> Piroschka@٩(ˊᗜˋ*)و さん

画像を読み込んで、コードを作ってもらうって、荒業ですね😅
そんなこともできてしまうんですね。私は、1つ1つ仕様を説明していきました。
以下のような感じで原型ができました。

「htmlとjavascriptで計算機を作りたいです」
「名前と金額を入力すると、ページに行が追加されて、チェックボックスが3つ表示されます。そのチェックボックスにチェックを入れるとその金額の合計が表示されます。あとから、別の商品の名前と金額を追加することができて、それを入力すると、あらたに行が追加されて、チェックボックス3つが表示され、それのチェックを入れると、それも合計に自動的に足されます」
「すばらしい!チェックボックス5個でお願いします。あと、合計は、小数点以下は要りません。」
「追加したときには、デフォルトでチェックは1つだけ入れておいて欲しいです」
「行の削除ボタンも欲しいですね」

>> Piroschka@٩(ˊᗜˋ*)و さん

>割引が適用されてなくないですか?

割引は、割引率はデフォルトで20%になっていて、割引のチェックボックスはOFFになっています。割引対象のものだけチェックを入れる感じです。
iPhoneアプリで、
HTML View Q というのが、ファイルアプリのhtmlファイルを実行するのにいい感じです。

コードも見れますが、全画面広告が出ます😱
編集はできないようです。

8D0B6F08-254C-434A-B953-D5475AD70E97.jpeg

5個まで開いて切り替えられるし、ズームしないようにしたら、もう普通のアプリみたい。
ブラウザみたいに、下に引っ張って更新掛かって消えてしまうってこともないし。

398A7BD8-3005-4629-B5EE-367D2363FB03.jpeg

そういえば、前にAIで作ってもらったこれも、マナーモードオフにするとちゃんと音が鳴りました😅
見やすいフォントがいい、と言ったので、何か外部からフォントを持ってきているようですが、あの辺は、ふつうのフォントに戻してもいいかもですね。

細かいところは、自分で修正というのが一番早いようです。

>> アッカリ〜ン@_@….,….,…😅 さん

そもそも、割引のチェックが入ってなかったんですね。
早とちり、スミマセン💦


ソースありがとうございます!
アッカリ〜ンさんのを参考に、自分のをもうちょっと洗練させてみたいと思います。
AIでまず最初に無くなる職業はプログラマーですね。
子供が理系か文系か選ぶ時期で、AIの時代だからIT業界に就職したいとか言ってるんだけど、AIで最も不要になる職業かも

>> アッカリ〜ン@_@….,….,…😅 さん

「HTML View Q」 というのは見つからず、「HTML Viewer Q」 といのはあったんですが……
見た目も似ているんで、これかなって思うのですが。

■HTML Viewer Q
https://apps.apple.com/jp/app/html-viewer-q/id81004297

>> さと さん

まだ無くなりはしないと思いますけどね。

今回、作っていく途中で、合計を全然反映してくれない状態が続きました。指摘して、分かりましたと言っても、動作させてみると、反映されていない。それが何度も繰り返されました。

仕方ないので、自分でソースを見て、怪しそうなところを指摘していったのですが、本来なら、こういうデバッグや設計評価なんかをAIにやって欲しいところですが、現状では、AIが出力したものを、AIが本当に正しいかを色々な観点から評価して、自ら修正する、ということは簡単にはできないようです。

これが出来ない限り、AIにすべてを任せることはできず、AIがたくさん出力した生成物をひたすら人間がチェックする、という逆に大変なことになります。

現時点でAIは、作業を効率化するための道具で、これに丸投げして、「AIが作ったコードが間違っていたので大事故になりました」では済まされない気がします。

>> Piroschka@٩(ˊᗜˋ*)و さん

すみません、それです。
ちょっと間違ってました。
オレンジ色のアイコンのやつです😅

>> アッカリ〜ン@_@….,….,…😅 さん

GoogleサイトにHTML貼って公開しちゃうのはどう?
そしたら、公開アドレスをSafariとかで開くだけで、ブラウザで動くWebアプリみたいに使える気がします。
多分これが一番シンプルだと思いますけど、後はGemを作ってGeminiアプリから起動して使う様にしちゃうとかは今っぽいかも?

>> fio@帰ってきた自宅警備員 さん

Googleサイト、そういえば前に少し触ろうとしてたなぁ🤔
新しいアカウント作ろうとして止まってた😅

Geminiアプリ、まだ使ったことないです😅
htmlコピペして使ってみました。
なるほどーこれを作ろうと思ったのが素晴らしい。
私は何でもexcelで計算しちゃうので、javascriptで作るとか思い付きませんでした。

私も今度何かプログラムが欲しいと思ったらコパイロットに頼んでみます。

それから、Googleサイトというホームページ作成機能があるのですねー知りませんでした。なんと2008年からあるとは!随分歴史あるんですね。

>> アッカリ〜ン@_@….,….,…😅 さん

なんとソースを見て指摘ですか(笑)
今は、ちょっとしたコードのサンプルやヒントを貰う感じでしか使えないですかね。初めてその言語で組む時とか。
デバッグやテストに向いていそうな気がするのだけど、、、近い内にはできるようになるかなーまだまだ無理かなー

>> さと さん

グラフとか複雑な計算だとExcelに行っちゃいますよね。
ただ、スマホでExcelを使おうとすると、ページを拡大縮小させたり、数字の入力とかがちょっと面倒です。
あとマクロも使えないですし。

今回は、保存する必要もないのでちょうどよかったです。

>> さと さん

>ちょっとしたコードのサンプルやヒントを貰う感じでしか使えないですかね。

いや、今回、仕様を言葉で説明しただけで、ほぼ何もコードを書いていないので、サンプルというレベルではないですね。追加していった仕様も、途中、バグはありながらも、最終的には完全に動く形で出来上がってますから。

ただ、大体こんな構造で作りたい、というのをあらかじめイメージしておかないと難しいかもしれません。
DOMやJavascriptを少し理解しているとやり易いかもしれません。私も少しかじったくらいですが😅

>> fio@帰ってきた自宅警備員 さん

Googleサイトで、HTMLコードの埋め込みができるみたいですね。
それでやってみると、確かにそのアドレスを開いてやれば、普通のブラウザで動くので、自分だけの限定公開にしておいて、ブラウザで開けば、すぐにでも使えますね。(公開でもいいですけど)

ただ、元々のGooleサイトのページの中に埋め込む感じになるので、周りに余分な空白とかがありますね。
色々工夫すれば、極限までそれを少なくできるかもしれません。

HTML Viewer Q の存在を知ってしまうと、htmlファイルを放り込んで開くとほぼ専用アプリみたいに動くのでかなり快適で、こっちかなぁと思ってしまいます。

Googleサイトで、自分用のページを作って、色々なものを並べておくっていうのも、ログインさえしていれば、違う環境ですぐ使えるので、それはそれでいいですね。
あと、単純ですが、こんな電卓を作りたいです。

「数字が入っている文章を貼り付けると、数字だけをリストにして全部足してくれる。
リストにはチェックボックスが付いていて不要なものは、外せる。」

まぁ正規表現で検索結果をループ回してリスト作る、だけですが、1からコード書こうとすると、ちょっと億劫。あと全角はどうするとか。

メモ帳なんかに、金額が羅列してあって、全部足したい、なんてときに有効です。ほんとうは、買い物電卓みたいにwebページみたいなところに書き足してってもいいのですが、1日とか経つと、次に表示したときにリロードされて消えてしまうんですよね。

Javascriptでローカルにデータを保存するようにするか、リロードを行わないみたいな指定ができるのかな?

まぁ保管物は、Excel使えって話ですが、数字入力面倒なんですよね😅
Excelファイルがやたら増えちゃうのもアレだし。

>> アッカリ〜ン@_@….,….,…😅 さん

確かに、スマホでEXCELは使いにくいので、ブラウザで計算してくれるのは助かりそうですね。
Googleサイトの埋め込みよりは、GitHub Pagesのほうが扱いやすい?
色々ムズイけど。
プログラム経験があって、GitHub使ったことないって🤣
Git完全に忘れたよ~。1からやるか…。


PWA + GitHub でアプリ化
https://qiita.com/sochan2424/items/fac2232a8217c3a611b7

PWAで自分用Webアプリを作ってみた
https://note.com/nomura5550/n/n10af506090dc

GitHub Pagesを使って無料でWebページを公開してみよう
https://qiita.com/anapausis/items/e95b4f0e99ae892bc3c7
コメントするには、ログインまたはメンバー登録(無料)が必要です。