はじめに
プログラミングというのものを何も分かっていない私は、数年前にPythonのことを「フォトン」と読んで兄に勉強してみたい!と話をしていたことがあります。思いは実現しないまま、月日が過ぎました。
そんな私に、先生が神がかったツールの扱い方を教えてくださいました。
今回、自分が業務で活用するために「商品振分数量起案ツール」のプログラミングに挑みました。
用意するもの
CodePen(コードペン)https://codepen.io/
ChatGPT(その他Gemini、 Copilot、などAI)https://chatgpt.com/ja-JP/
CodePenはブラウザ上で3つのプログラミング言語
(HTML・CSS・JavaScript)を記入すると、結果がすぐに反映され、動作確認をすることができるツールです。
アカウント登録も不可、(あると保存・共有が可能)で使用できるHPです。
今回私は無料アカウント登録で使用をしました。
CodePenの準備
- CodePenのHPを開きます。
- 左上の「StartCoding」を押します。
- 画面のような編集画面になります。
これでCodePenの準備は完了です。
ChatGPTでソースコードの作成
- 各プログラムで作りたいことを決めます。
今回AIを使用するので、AIに何ができるのか聞いてみるのもよいかもしれません。
私は、りんごを10店舗に何個振り分ければ良いか算出してくれるプログラムを作成します。 - AIに自分の希望を記入します。その際、「CodePenで動くwebアプリを教えてください。」で締めくくります。
私の例では「りんごの合計数量を10店舗に均等に分けるwebアプリで動くHTMLコードを教えてください。」と入力。 - AIはそれに応じてソースコードを返してくれます。
ChatGPT排出コード(open属性あり)
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>りんご振分アプリ</title>
<style>
body{
font-family:sans-serif;
max-width:600px;
margin:30px auto;
padding:20px;
}
input, button{
padding:10px;
font-size:16px;
}
button{
cursor:pointer;
}
#result{
margin-top:20px;
padding:15px;
background:#f5f5f5;
border-radius:8px;
}
</style>
</head>
<body>
<h2>りんご振分アプリ</h2>
<label>りんごの合計数量</label><br>
<input type="number" id="appleQty" min="0" placeholder="例:100">
<button onclick="calculate()">計算</button>
<div id="result"></div>
<script>
function calculate() {
const total = parseInt(
document.getElementById("appleQty").value
);
if(isNaN(total) || total < 0){
alert("数量を入力してください");
return;
}
const storeCount = 10;
const baseQty = Math.floor(total / storeCount);
const remainder = total % storeCount;
let html = `
<h3>振分結果</h3>
<p>合計数量:${total}個</p>
<p>店舗数:${storeCount}店舗</p>
<hr>
`;
for(let i=1; i<=storeCount; i++){
const qty =
i <= remainder
? baseQty + 1
: baseQty;
html += `店舗${i} : ${qty}個<br>`;
}
document.getElementById("result").innerHTML = html;
}
</script>
</body>
</html>
-
単純な均等数量なので、実用的にする為、手を加えます。
-
「店舗ごとに指数を入力して、振分数量に反映するように変更してください。」と要望。
-
その他、ChatGPTが提案のされた機能の中に、CSVファイル.エクセルでの調整、ダウンロード機能まで追加できると提案がありましたので、ソースコードを依頼します。
完成版ソースコード(open属性あり)
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>りんご指数別振分アプリ</title>
<style>
body{
font-family:sans-serif;
max-width:1100px;
margin:20px auto;
padding:20px;
}
input, textarea, button{
padding:8px;
font-size:15px;
}
textarea{
width:100%;
height:120px;
}
table{
width:100%;
border-collapse:collapse;
margin-top:15px;
}
th,td{
border:1px solid #ccc;
padding:8px;
text-align:center;
}
th{
background:#eee;
}
.high{
background:#dff5df;
}
.low{
background:#ffe1e1;
}
button{
margin:5px 0;
cursor:pointer;
}
</style>
</head>
<body>
<h2>りんご指数別 振分アプリ</h2>
<p>
りんご合計数量:
<input type="number" id="totalQty" value="1000">
</p>
<p>
店舗数:
<input type="number" id="storeCount" value="10">
<button onclick="makeTable()">店舗表を作成</button>
</p>
<h3>Excel貼付欄</h3>
<p>Excelから「店舗名・指数・PI値」の順でコピーして貼り付けできます。</p>
<textarea id="pasteArea" placeholder="例:
店舗A 1 120
店舗B 2 180
店舗C 1.5 150"></textarea>
<br>
<button onclick="loadFromText()">貼付データを反映</button>
<table>
<thead>
<tr>
<th>店舗名</th>
<th>指数</th>
<th>PI値</th>
<th>振分数量</th>
</tr>
</thead>
<tbody id="storeTable"></tbody>
</table>
<h3 id="summary">配分合計:0個</h3>
<button onclick="calculate()">計算する</button>
<button onclick="downloadCSV()">CSVダウンロード</button>
<script>
let storeData = [];
function makeTable(){
const count = Number(document.getElementById("storeCount").value);
if(count <= 0){
alert("店舗数を入力してください");
return;
}
storeData = [];
for(let i=1; i<=count; i++){
storeData.push({
name:"店舗" + i,
weight:1,
pi:0,
qty:0
});
}
renderTable();
}
function renderTable(){
const table = document.getElementById("storeTable");
table.innerHTML = "";
storeData.forEach((store,index)=>{
table.innerHTML += `
<tr>
<td>
<input type="text" value="${store.name}" onchange="storeData[${index}].name=this.value">
</td>
<td>
<input type="number" value="${store.weight}" step="0.1" onchange="storeData[${index}].weight=Number(this.value)">
</td>
<td>
<input type="number" value="${store.pi}" step="0.1" onchange="storeData[${index}].pi=Number(this.value)">
</td>
<td class="qty">${store.qty}</td>
</tr>
`;
});
}
function loadFromText(){
const text = document.getElementById("pasteArea").value.trim();
if(!text){
alert("貼付データを入力してください");
return;
}
const lines = text.split("\n");
storeData = [];
lines.forEach(line=>{
const cols = line.split(/\t|,/);
storeData.push({
name:cols[0] || "",
weight:Number(cols[1]) || 0,
pi:Number(cols[2]) || 0,
qty:0
});
});
document.getElementById("storeCount").value = storeData.length;
renderTable();
}
function calculate(){
const totalQty = Number(document.getElementById("totalQty").value);
if(totalQty <= 0){
alert("りんご合計数量を入力してください");
return;
}
let totalIndex = 0;
storeData.forEach(store=>{
const index = store.pi > 0 ? store.pi : store.weight;
store.calcIndex = index;
totalIndex += index;
});
if(totalIndex <= 0){
alert("指数またはPI値の合計が0です");
return;
}
let allocated = 0;
storeData.forEach(store=>{
const exact = totalQty * store.calcIndex / totalIndex;
store.qty = Math.floor(exact);
store.decimal = exact - store.qty;
allocated += store.qty;
});
let remainder = totalQty - allocated;
const sorted = [...storeData].sort((a,b)=>b.decimal - a.decimal);
for(let i=0; i<remainder; i++){
sorted[i].qty++;
}
renderTable();
const rows = document.querySelectorAll("#storeTable tr");
const qtyCells = document.querySelectorAll(".qty");
let totalAllocated = 0;
storeData.forEach((store,index)=>{
qtyCells[index].textContent = store.qty;
totalAllocated += store.qty;
});
colorRows();
document.getElementById("summary").textContent =
"配分合計:" + totalAllocated + "個";
}
function colorRows(){
const rows = document.querySelectorAll("#storeTable tr");
const sorted = [...storeData].sort((a,b)=>b.qty-a.qty);
const highNames = sorted.slice(0,3).map(s=>s.name);
const lowNames = sorted.slice(-3).map(s=>s.name);
storeData.forEach((store,index)=>{
rows[index].className = "";
if(highNames.includes(store.name)){
rows[index].classList.add("high");
}
if(lowNames.includes(store.name)){
rows[index].classList.add("low");
}
});
}
function downloadCSV(){
let csv = "店舗名,指数,PI値,振分数量\n";
storeData.forEach(store=>{
csv += `${store.name},${store.weight},${store.pi},${store.qty}\n`;
});
const bom = new Uint8Array([0xEF, 0xBB, 0xBF]);
const blob = new Blob([bom, csv], {type:"text/csv"});
const url = URL.createObjectURL(blob);
const a = document.createElement("a");
a.href = url;
a.download = "りんご振分結果.csv";
a.click();
URL.revokeObjectURL(url);
}
makeTable();
</script>
</body>
</html>
10.CodePen 上で動作確認をすると、どのcsvファイル含む追加機能も問題なく実行されました。今でも業務ではCSVファイル、Excelファイルを多用している為、実用性が高いです。

困ったこと
スムーズにいったことばかりではなく、
以下注意点をまとめます。
-
ChatGPT上でのプレビューは、正常に機能しないことがあります。
動作確認時に、変数入力時、思うように反映されなかったりと不具合が生じました。
CodePen上では問題なく動作確認。 -
当初、「CodePen」で動作可能なプログラムの作成、とChatGPTに依頼したところ、
CSS,JavaScriptのソースコードも出力してくれました。
しかしながら、これらのコードはCodePenにペーストしてもエラーが排出されて実行されませんでした。
私の入力に誤りがあったのかもしれません。
今回はHTMLのみで動作するようにプロンプトを変更しました。
まとめ
AIによって、作成されたHTMLコードをCodePenで使用することで、
私が思っていた以上の機能を利用することができました。
AIだけで完結することでもあるかもしれませんが、
CodePenで動作確認、またシェアをすることによって、他の方にも使用していただくことが可能です。
会社情報の為、特定をさけるように情報を絞って入力、またはマスキングをすることで
安全に留意して活用していきます。


