diff --git a/src/ProcessBatchApprovalHandler.js b/src/ProcessBatchApprovalHandler.js
new file mode 100644
index 0000000..961b39e
--- /dev/null
+++ b/src/ProcessBatchApprovalHandler.js
@@ -0,0 +1,283 @@
+(function () {
+ "use strict";
+
+ /**
+ * 一括承認処理を管理するクラス
+ * 特定のビューでレコードの一括承認機能を提供する
+ */
+ class BatchApprovalHandler {
+ /**
+ * コンストラクタ
+ * @param {number} mineView - マイビューのID
+ * @param {string} classifyField - 分類フィールドのプレースホルダー
+ * @param {Object} btnClassifyMap - 年齢分類マッピングオブジェクト
+ * @param {Object} actionMap - アクション名マッピングオブジェクト
+ * @param {Function} getStatusPrefix - ステータス接頭辞を取得する関数
+ * @param {Object} statusFieldMap
+ * @param {string} classifyFormField
+ */
+ constructor(mineView, classifyField, btnClassifyMap, actionMap, getStatusPrefix, statusFieldMap, classifyFormField = "学年") {
+ this.mineView = mineView;
+ this.classifyField = classifyField;
+ this.btnClassifyMap = btnClassifyMap;
+ this.actionMap = actionMap;
+ this.getStatusPrefix = getStatusPrefix;
+ this.statusFieldMap = statusFieldMap;
+ this.classifyFormField = classifyFormField;
+ this.stopFlag = false;
+ }
+
+ stopProcess() {
+ this.stopFlag = true;
+ }
+
+ /**
+ * 一括承認ボタンを作成する
+ * @method
+ */
+ createApproveBtn() {
+ const headerSpace = getHeaderSpace('single-label-line');
+ const elements = createBtnGroupArea('batch-approve-area', '一括承認', this.handleApproveData.bind(this), {
+ btnElId: 'batch-btn'
+ });
+
+ if (elements && headerSpace) {
+ headerSpace.appendChild(elements['batch-approve-area']);
+ }
+ }
+
+ /**
+ * 一括承認処理を実行する
+ * @method
+ * @param {Event} e - イベントオブジェクト
+ */
+ async handleApproveData(e) {
+ this.stopFlag = false;
+ const appId = kintone.app.getId();
+ const loginUser = kintone.getLoginUser();
+
+ loading(true, '一括承認処理中...');
+ showError(false);
+
+ const api = new KintoneRestAPIClient();
+
+ // レコードを取得
+ const records = await this.getRecords(api, appId, loginUser.code);
+ if (!records || records.length === 0) {
+ loading(false);
+ return e;
+ }
+
+ // ステータスを更新
+ const result = await this.updateRecordsStatus(api, appId, records);
+
+ if (result && result.success > 0) {
+ // 承認者情報を更新
+ await this.updateRecords(api, appId, records, result.successIds, loginUser);
+ await this.showSuccessDialog(result);
+ }
+ loading(false);
+ }
+
+ /**
+ * 成功ダイアログを表示する
+ * @method
+ * @param {Object} result - 処理結果
+ */
+ async showSuccessDialog(result) {
+ const contentEl = document.createElement('div');
+ contentEl.style.fontSize = '16px';
+
+ if (result.success === result.total) {
+ contentEl.innerHTML = `✅ 全${result.total}件のレコードを承認しました`;
+ } else {
+ const successText = `✅ ${result.success}件のレコードを承認済み`;
+ const failedText = `⚠️ ${result.total - result.success}件の承認に失敗`;
+ contentEl.innerHTML = `${successText}
${failedText}
合計: ${result.total}件`;
+ }
+
+ showDialog({
+ title: '一括承認完了',
+ content: contentEl,
+ ok: '更新して確認',
+ cancel: false,
+ onClose: () => { location.reload(); }
+ });
+ }
+
+ /**
+ * アクションプロセスマップを読み込む
+ * @method
+ * @param {Object} api - Kintone REST API クライアント
+ * @param {number} appId - アプリID
+ */
+ async loadActionProcessMap(api, appId) {
+ try {
+ const result = await api.app.getProcessManagement({
+ app: appId,
+ preview: false
+ });
+
+ const actionProcessMap = {};
+ result.actions.forEach(action => {
+ actionProcessMap[action.from + ":" + action.name] = action;
+ });
+
+ return actionProcessMap;
+ } catch (error) {
+ showError(true, 'プロセス管理情報の読み取りに失敗しました\n - ' + error.message);
+ }
+ }
+
+ /**
+ * レコードを取得する
+ * @method
+ * @param {Object} api - Kintone REST API クライアント
+ * @param {number} appId - アプリID
+ * @param {string} loginUserCd - ログインユーザーコード
+ */
+ async getRecords(api, appId, loginUserCd) {
+ try {
+ return await api.record.getAllRecordsWithId({
+ app: appId,
+ condition: `作業者 in ("${loginUserCd}")`
+ });
+ } catch (error) {
+ showError(true, 'レコードの読み取りに失敗しました\n - ' + error.message);
+ return null;
+ }
+ }
+
+ /**
+ * レコードを更新する
+ * @method
+ * @param {Object} api - Kintone REST API クライアント
+ * @param {number} appId - アプリID
+ * @param {Array} oldRecords - 更新前レコード
+ * @param {Set} successIds - 成功したレコードID
+ * @param {Object} loginUser - ログインユーザー情報
+ */
+ async updateRecords(api, appId, oldRecords, successIds, loginUser) {
+ const actionProcessMap = await this.loadActionProcessMap(api, appId);
+ if (!actionProcessMap) {
+ return;
+ }
+ const updateFieldRecords = [];
+
+ for (const record of oldRecords) {
+ const updateKey = this.getRecordAutoUpdateField(record, actionProcessMap, successIds);
+ if (updateKey) {
+ updateFieldRecords.push({
+ 'id': record.$id.value,
+ 'record': {
+ [updateKey]: {
+ 'value': loginUser.name
+ }
+ }
+ });
+ }
+ }
+
+ if (updateFieldRecords.length > 0) {
+ try {
+ await api.record.updateAllRecords({
+ app: appId,
+ records: updateFieldRecords
+ });
+ } catch (error) {
+ showError(true, 'レコード更新に失敗しました\n - ' + error.message);
+ }
+ }
+ }
+
+ /**
+ * 自動更新フィールド名を取得する
+ * @method
+ * @param {Object} record - レコードオブジェクト
+ * @param {Object} actionProcessMap - アクションプロセスマップ
+ * @param {Set} successIds - 成功したレコードID
+ */
+ getRecordAutoUpdateField(record, actionProcessMap, successIds) {
+ const id = record.$id.value;
+ if (!successIds.has(id)) {
+ return null;
+ }
+
+ const oldStatus = record.ステータス.value;
+ const actionName = record.action;
+
+ const action = actionProcessMap[oldStatus + ":" + actionName];
+ return action ? this.statusFieldMap[action.to] : null;
+ }
+
+ /**
+ * レコードステータスを更新する
+ * @method
+ * @param {Object} api - Kintone REST API クライアント
+ * @param {number} appId - アプリID
+ * @param {Array} records - 更新対象レコード
+ */
+ async updateRecordsStatus(api, appId, records) {
+ const updateRecords = []
+ for (const record of records) {
+ const actionToPerform = this.getActionName(record);
+ if (this.stopFlag) {
+ return
+ }
+ if (!!actionToPerform) {
+ record.action = actionToPerform;
+ updateRecords.push({
+ id: record.$id.value,
+ action: actionToPerform,
+ revision: record.$revision.value
+ });
+ }
+ }
+
+ const result = {
+ success: 0,
+ total: records.length,
+ successIds: new Set(),
+ };
+
+ const batchSize = 100; // Kintone APIの制限
+ for (let i = 0; i < updateRecords.length; i += batchSize) {
+ const batch = updateRecords.slice(i, i + batchSize);
+
+ try {
+ const response = await api.record.updateRecordsStatus({
+ app: appId,
+ records: batch
+ });
+
+ result.success += response.records.length;
+ response.records.forEach(record => {
+ result.successIds.add(record.id);
+ });
+ } catch (error) {
+ showError(true, `レコードステータス更新エラー\n - ${error.message}`);
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * アクション名を取得する
+ * @method
+ * @param {string} record - レコードオブジェクト
+ */
+ getActionName(record) {
+ const yearStr = record[this.classifyFormField]?.value || '';
+ const status = record.ステータス.value;
+ const actionTemplate = this.actionMap[this.getStatusPrefix(status)] || '';
+ const btnClassify = this.btnClassifyMap[yearStr] || '';
+ return actionTemplate.replaceAll(this.classifyField, btnClassify);
+ }
+
+ }
+
+ // グローバルにクラスを公開
+ window.BatchApprovalHandler = BatchApprovalHandler;
+
+})();
\ No newline at end of file
diff --git a/src/1.園児別出欠簿入力/processStateHandler.js b/src/1.園児別出欠簿入力/processStateHandler.js
index 1d36c1e..ced813b 100644
--- a/src/1.園児別出欠簿入力/processStateHandler.js
+++ b/src/1.園児別出欠簿入力/processStateHandler.js
@@ -8,6 +8,8 @@
'完了': '園長'
}
+ window._StatusFieldMap = statusFieldMap
+
kintone.events.on("app.record.detail.process.proceed", (event) => {
const field = statusFieldMap[event.nextStatus.value];
if (field) {
diff --git a/src/10.個別支援計画/KintoneRestAPIClient.min.js b/src/10.個別支援計画/KintoneRestAPIClient.min.js
new file mode 100644
index 0000000..dc9c93d
--- /dev/null
+++ b/src/10.個別支援計画/KintoneRestAPIClient.min.js
@@ -0,0 +1 @@
+!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.KintoneRestAPIClient=t():e.KintoneRestAPIClient=t()}(window,(function(){return function(e){var t={};function r(n){if(t[n])return t[n].exports;var o=t[n]={i:n,l:!1,exports:{}};return e[n].call(o.exports,o,o.exports,r),o.l=!0,o.exports}return r.m=e,r.c=t,r.d=function(e,t,n){r.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:n})},r.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r.t=function(e,t){if(1&t&&(e=r(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var n=Object.create(null);if(r.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)r.d(n,o,function(t){return e[t]}.bind(null,o));return n},r.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return r.d(t,"a",t),t},r.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},r.p="",r(r.s=74)}([function(e,t,r){(function(t){var r=function(e){return e&&e.Math==Math&&e};e.exports=r("object"==typeof globalThis&&globalThis)||r("object"==typeof window&&window)||r("object"==typeof self&&self)||r("object"==typeof t&&t)||Function("return this")()}).call(this,r(40))},function(e,t,r){var n=r(0),o=r(41),i=r(4),u=r(45),s=r(46),a=r(78),c=o("wks"),f=n.Symbol,l=a?f:f&&f.withoutSetter||u;e.exports=function(e){return i(c,e)||(s&&i(f,e)?c[e]=f[e]:c[e]=l("Symbol."+e)),c[e]}},function(e,t,r){"use strict";var n=r(65),o=Object.prototype.toString;function i(e){return"[object Array]"===o.call(e)}function u(e){return void 0===e}function s(e){return null!==e&&"object"==typeof e}function a(e){return"[object Function]"===o.call(e)}function c(e,t){if(null!=e)if("object"!=typeof e&&(e=[e]),i(e))for(var r=0,n=e.length;rh;h++)if((y=f?g(n(b=e[h])[0],b[1]):g(e[h]))&&y instanceof c)return y;return new c(!1)}p=d.call(e)}for(m=p.next;!(b=m.call(p)).done;)if("object"==typeof(y=a(p,g,b.value,f))&&y&&y instanceof c)return y;return new c(!1)}).stop=function(e){return new c(!0,e)}},function(e,t){e.exports=function(e){try{return{error:!1,value:e()}}catch(e){return{error:!0,value:e}}}},function(e,t,r){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.injectPlatformDeps=t.platformDeps=void 0,t.platformDeps={readFileFromPath:function(){throw new Error("not implemented")},getRequestToken:function(){throw new Error("not implemented")},buildPlatformDependentConfig:function(){throw new Error("not implemented")},buildHeaders:function(){throw new Error("not implemented")}},t.injectPlatformDeps=function(e){t.platformDeps.readFileFromPath=e.readFileFromPath,t.platformDeps.getRequestToken=e.getRequestToken,t.platformDeps.buildPlatformDependentConfig=e.buildPlatformDependentConfig,t.platformDeps.buildHeaders=e.buildHeaders}},function(e,t,r){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.buildPath=void 0,t.buildPath=function(e){var t=e.endpointName,r=e.guestSpaceId;return"/k"+(void 0!==r?"/guest/"+r:"")+"/v1"+(e.preview?"/preview":"")+"/"+t+".json"}},function(e,t,r){var n={};n[r(1)("toStringTag")]="z",e.exports="[object z]"===String(n)},function(e,t,r){var n=r(0),o=r(5);e.exports=function(e,t){try{o(n,e,t)}catch(r){n[e]=t}return t}},function(e,t,r){var n=r(0),o=r(9),i=n.document,u=o(i)&&o(i.createElement);e.exports=function(e){return u?i.createElement(e):{}}},function(e,t,r){var n=r(42),o=Function.toString;"function"!=typeof n.inspectSource&&(n.inspectSource=function(e){return o.call(e)}),e.exports=n.inspectSource},function(e,t,r){var n=r(41),o=r(45),i=n("keys");e.exports=function(e){return i[e]||(i[e]=o(e))}},function(e,t){e.exports={}},function(e,t){var r=Math.ceil,n=Math.floor;e.exports=function(e){return isNaN(e=+e)?0:(e>0?n:r)(e)}},function(e,t){e.exports=function(e){if(null==e)throw TypeError("Can't call method on "+e);return e}},function(e,t,r){var n=r(7),o=r(83),i=r(19),u=r(20),s=r(44),a=r(4),c=r(43),f=Object.getOwnPropertyDescriptor;t.f=n?f:function(e,t){if(e=u(e),t=s(t,!0),c)try{return f(e,t)}catch(e){}if(a(e,t))return i(!o.f.call(e,t),e[t])}},function(e,t){e.exports=["constructor","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","toLocaleString","toString","valueOf"]},function(e,t,r){var n=r(4),o=r(92),i=r(29),u=r(93),s=i("IE_PROTO"),a=Object.prototype;e.exports=u?Object.getPrototypeOf:function(e){return e=o(e),n(e,s)?e[s]:"function"==typeof e.constructor&&e instanceof e.constructor?e.constructor.prototype:e instanceof Object?a:null}},function(e,t,r){var n,o=r(3),i=r(94),u=r(34),s=r(30),a=r(54),c=r(27),f=r(29),l=f("IE_PROTO"),p=function(){},d=function(e){return"