Merge pull request 'test-env' (#1) from test-env into master

Reviewed-on: #1
This commit is contained in:
2025-09-22 08:01:42 +00:00
125 changed files with 16720 additions and 629 deletions

View File

@@ -0,0 +1,12 @@
下記アプリについて項目等の変更があります。
スペーステンプレートをお送りしておりますので、お手数ですが環境の差し替えをお願いいたします。
■個別配慮
・入力項目を4月翌年3月分追加
・システム情報にユーザー名出力用項目追加
■20250911にお送りした仕様書の全アプリ
・プロセス管理を変更
また、「個別支援計画」アプリは前回までにアプリになります。
見積もりには含めているアプリですが、私の方で標準の範囲で作成しております。

View File

@@ -0,0 +1,197 @@
### 2025年8月22日 15:48
**发件人:** 清水優太(PVC)
**收件人:** 馬 小哲;薛 家豪
**主题:** 【横山台こども園様】仕様書をお送りします
アリコーン
馬様、薛様
いつもお世話になっております。
プランニングヴィレッヂの清水です。
先ほどは横山台こども園様の開発引き継ぎに
ご参加いただきありがとうございました。
画面共有していた仕様書及び
スペーステンプレートをお送りいたしますので、
ご確認いただけますと幸いです。
現在確認中の内容については、
固まり次第追ってご連絡いたします。
何かご不明な点等ございましたらご連絡ください。
引き続きよろしくお願いいたします。
---
### 2025年8月25日 16:38
**发件人:** 馬 小哲
**收件人:** 清水優太(PVC)
**抄送:** 小山嘉久(PVC);薛 家豪
**主题:** RE: 【横山台こども園様】仕様書をお送りします
プランニングヴィレッヂ
清水様
いつもお世話になっております。
アリコーンの馬です。
先日は仕様のご説明ありがとうございました。
ご送付いただく仕様書を拝見し、以下の点をご確認ください。
1. 「園児別出欠簿入力」の「園での様子入力者」自動入力機能について:
編集者による変更を許可するかご確認:
・変更不可の場合、「園での様子入力者」欄を編集画面で非表示とする必要があるか?
・変更可の場合、「園での様子入力者」変更がない場合のみ、保存時にログインユーザーで上書きする仕様を想定しています。
2. 「個別配慮」の輸出順について:
現在の仕様は「1.学年, 2出席番号」ですが、クラスが異なる園児で出席番号が重複する可能性がありますか
重複がある場合、「学年→クラス→出席番号」へのソート条件変更をご検討ください。
3. 「個別配慮」の入力単位変更について:
・月次から年次への変更仕様はまだ確定していない認識でよろしいでしょうか?
・年次に変更する場合、Excelレイアウト変更が必要がありますか
・また、輸出件数が園児数×月数になるため、パフォーマンスへの影響も懸念されます。
4. 「保育・教育日数マスタ」の休日自動取得について:
・保存時に休日データのソートおよび重複除去が必要か
※年間休日が120日以上のため、ソートされないと操作性に影響する可能性があります。
5. 一括承認機能について:
現在、仕様が未確定という認識でよろしいでしょうか?
6. 現在ご提示いただいている見積工数について、下記の対応工数が含まれているかご確認ください。
・「個別配慮」の年次対応
・一括承認機能の追加開発
含まれていない場合、追加工数として見積可能かどうかもあわせてご教示ください。
以上、ご確認のほどよろしくお願いいたします。
引き続きよろしくお願いいたします。
---
### 2025年8月25日 18:09
**发件人:** 清水優太(PVC)
**收件人:** 馬 小哲
**抄送:** 小山嘉久(PVC);薛 家豪
**主题:** Re: 【横山台こども園様】仕様書をお送りします
アリコーン
馬様
いつもお世話になっております。
プランニングヴィレッヂの清水です。
仕様の方ご確認いただきありがとうございます。
ご質問につきまして下記回答いたします。
1. 「園児別出欠簿入力」の「園での様子入力者」自動入力機能について
編集者による手修正の考慮が抜けており申し訳ございません。
こちらは後者の「変更可の場合~」を採用してください。
2. 「個別配慮」の輸出順について
同じ学年で複数のクラスは存在しないので、学年→出席番号のソート順で問題ございません。
3. 「個別配慮」の入力単位変更について
すみません、こちらの仕様はまだお客様検討中です。
年次の場合もフォーマットの変更はございません。
また、Excelの輸出件数は変わらないため、パフォーマンスはさほど影響ないと考えますが、
これについては私が間違っているかもしれません。
いずれにしても本機能は実装いただけますと助かります。
4. 「保育・教育日数マスタ」の休日自動取得について
ソートや重複除去が可能でしたら。実装いただけると大変ありがたいです。
5. 一括承認機能について
こちらもお客様確認中ですが、動作としては概ね以下のような形になります。
作業者=ログインユーザーで絞りこんだ一覧にボタンを配置し、押下で一括承認する仕組みです。
6. 現在ご提示いただいている見積工数について、下記の対応工数が含まれているかご確認ください
こちらは双方とも含んだ形で見積もり工数をお出ししております。
資料の方が曖昧な記載で申し訳ございません。
以上になります。
ご確認の程よろしくお願いいたします。
清水
---
### 2025年8月28日 10:44
**发件人:** 馬 小哲
**收件人:** 清水優太(PVC)
**抄送:** 小山嘉久(PVC);薛 家豪
**主题:** RE: 【横山台こども園様】仕様書をお送りします
プランニングヴィレッヂ
清水様
いつもお世話になっております。
アリコーンの馬です。
以下の点についてご確認させていただきたく、ご連絡いたしました。
1. 教育日数の計算式について、
現在は「教育日数-欠勤日数(病欠+自欠)」となっておりますが、
今回の仕様変更により、欠勤日が休日の場合は除外することになっております。
こちらの対応に問題はございませんが、Excel表に記載されている欠勤病欠自欠の合計数についても、
休日分を除外する必要があるかご教示いただけますでしょうか。
2. 保育・教育日数マスタについて
「教育日数+休日数」がその月の月日数と一致している必要があるか、ご確認をお願いいたします。
3. 台帳の園児名変更について
台帳の園児名が変更された場合、園児別出欠簿入力以外に、
以下のアプリの園児名も同様に変更する必要があるか、ご確認いただけますでしょうか。
- 0・1歳日誌出力用
- 2歳以上日誌出力用
- 個別配慮
お忙しいところ恐縮ですが、ご確認のほどよろしくお願いいたします。
---
### 2025年8月29日 09:50
**发件人:** 清水優太(PVC)
**收件人:** 馬 小哲
**抄送:** 小山嘉久(PVC);薛 家豪
**主题:** Re: 【横山台こども園様】仕様書をお送りします
アリコーン
馬様
いつもお世話になっております。
プランニングヴィレッヂの清水です。
ご質問いただきました件につきまして下記回答いたします。
> 1.教育日数の計算式について
欠勤の合計につきましては今までの計算式(病欠+自欠)で構いません。
> 2.保育・教育日数マスタについて
そこまでのチェックは必要ございません。
> 3.台帳の園児名変更について
確かに他アプリも全て変更されるのが望ましいですが、
下記3点の理由により実装しなくて良いと考えます。
①お客様の方でアプリをいくつか追加する予定があり、
 本開発進行中に作成されるとそれも対応しなくてはならなくなる可能性あり
②日誌については再輸出してもらえばよく、
個別配慮は数が多くないので手直しにて対応可能
③そもそもそれほど費用(工数)をいただいていない。
以上になります。
また、お客様に確認中の事項につきまして、
現状まだ回答をいただいておりませんため、
未確定部分の仕様書の送付は来週になるかもしれません。
ご迷惑をお掛けし申し訳ございませんが、よろしくお願いいたします。
清水

View File

@@ -1,6 +0,0 @@
(function () {
"use strict";
addApproveFlowAction(true);
})();

View File

@@ -1,6 +0,0 @@
(function () {
"use strict";
addApproveFlowAction(true);
})();

View File

@@ -1,8 +1,9 @@
"use strict";
// https://alicorn.cybozu.com/k/#/space/15/thread/22
const env = {
"園児別出欠簿入力": {
appId: 19,
appId: 250,
excelName: "出欠集計表",
view: {
linkFor0to1: 13352636,
@@ -10,28 +11,28 @@ const env = {
}
},
"0,1歳日誌出力用": {
appId: 47,
appId: 255,
excelName: "ゆり・つき1視診表",
},
"2歳以上日誌出力用": {
appId: 48,
appId: 256,
excelName: "幼児日誌",
},
"個別配慮": {
appId: 23,
appId: 251,
excelName: "個別配慮",
},
"園児台帳": {
appId: 16,
appId: 247,
},
"保育・教育日数マスタ": {
appId: 41,
appId: 253,
},
"Excelテンプレート": {
appId: 46
appId: 254
},
"担任マスタ": {
appId: 52
appId: 259
}
};

View File

@@ -1,95 +0,0 @@
.btn-group-area {
display: flex;
/* margin-left: 2.5em; */
align-items: flex-end;
}
.btn-group-area .label {
margin: 0 4px;
}
.btn-group-area .input {
padding-left: 8px;
}
.btn-group-area .year {
--kuc-text-input-width: calc(4em + 16px);
--kuc-text-input-height: 48px;
}
.btn-group-area .year input {
text-align: center;
}
.btn-group-area .month,
.btn-group-area .date,
.btn-group-area .term {
--kuc-combobox-toggle-width: calc(2em + 16px);
--kuc-combobox-toggle-height: 48px;
}
.btn-group-area .term {
--kuc-combobox-toggle-width: calc(3em + 16px);
}
.btn-group-area .month input[class^='kuc-combobox'],
.btn-group-area .date input[class^='kuc-combobox'],
.btn-group-area .term input[class^='kuc-combobox'] {
text-align: center;
padding-right: 8px;
}
.btn-group-area .month input + div[class$="icon"],
.btn-group-area .date input + div[class$="icon"],
.btn-group-area .term input + div[class$="icon"] {
display: none;
}
.action-btn {
margin: 0 8px;
}
.customized-record-header-space {
padding-top: 16px;
padding-left: 8px;
}
.customized-record-header-space > .btn-group-area {
padding: 0;
margin: 0;
}
.kintone-app-headermenu-space {
height: auto;
display: inline-flex;
}
#user-js-header-clocking-btn-area {
margin: 4px 0;
text-align: center;
}
#user-js-header-clocking-btn-area > .action-btn {
--kuc-button-width: 6em
}
#user-js-header-clocking-btn-area > .action-btn:first-child {
margin-right: 1em;
}
#user-js-clock-in-btn-area > .action-btn,
#user-js-clock-out-btn-area > .action-btn {
--kuc-mobile-button-height: 35px;
margin: .5em 12px;
}
.kuc--has-spinner {
position: relative;
}
div[class^='kuc-spinner'][class$='__spinner'] {
margin-top: 89px;
height: calc(100% - 89px);
position: absolute;
--kuc-spinner-text-color: #3498db;
--kuc-spinner-loader-color: #3498db;
}
div[class^='kuc-spinner'][class$='mask'] {
top: 89px;
position: absolute;
background-color: white;
}

View File

@@ -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}<br>${failedText}<br><br>合計: ${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;
})();

View File

@@ -222,6 +222,18 @@ function convertToWesternYear(year, era) {
return warekiStartYear[era] + year - 1;
}
function getYearRange() {
const today = new Date();
let year = today.getFullYear();
if (today.getMonth() + 1 < 4) {
year -= 1;
}
return {
'start': getFormatDateString(year, 4, 1),
'end': getFormatDateString(year + 1, 3, 31)
}
}
function getFormatDateString(dateObjOrYear, month, date) {
let year = dateObjOrYear;
if (typeof dateObjOrYear === "object" && !month && !date) {
@@ -489,20 +501,3 @@ function groupingBySex(list) {
return [male, female];
}, [[], []]);
}
const statusFieldMap = {
'指導教諭確認中': '担任',
'主幹確認中': '指導',
'園長確認中': '主幹',
'完了': '園長'
}
function addApproveFlowAction() {
return kintone.events.on("app.record.detail.process.proceed", (event) => {
const field = statusFieldMap[event.nextStatus.value];
if (field) {
event.record[field].value = kintone.getLoginUser().name;
}
return event;
});
}

View File

@@ -1,206 +0,0 @@
const Kuc = Kucs['1.19.0'];
let notificationEl;
function getHeaderSpace(className, isDetailPage) {
const headerSpace = kintone.mobile.app.getHeaderSpaceElement();
if (!headerSpace) {
throw new Error('このページではヘッダー要素が利用できません。');
};
const _className = isDetailPage ? 'customized-record-header-space' : 'customized-header-space';
headerSpace.className += (' ' + _className + ' ' + className);
headerSpace.parentElement.className += (' ' + _className + '-wrapper ' + className);
return headerSpace;
}
const classItems = [
{ label: "にじ", value: "にじ" },
{ label: "ほし", value: "ほし" },
{ label: "つき", value: "つき" },
{ label: "ゆり", value: "ゆり" },
]
const termItems = [
{ label: "0歳児", value: "0歳児" },
{ label: "1歳児", value: "1歳児" },
{ label: "2歳児", value: "2歳児" },
{ label: "3歳児", value: "3歳児" },
{ label: "4歳児", value: "4歳児" },
{ label: "5歳児", value: "5歳児" },
]
function createBtnGroupArea(groupId, btnLabel, btnOnClick, { btnElId = false, yearElId = false, monthElId = false, dateElId = false, termElId = false, defaultThisMonth = false, }) {
const result = {};
if (document.getElementById(groupId)) {
return;
}
const btnGroupAreaEl = document.createElement('div');
btnGroupAreaEl.id = groupId;
btnGroupAreaEl.className = 'btn-group-area'
result[groupId] = btnGroupAreaEl;
if (yearElId) {
const yearEl = new Kuc.MobileText({
value: "" + new Date().getFullYear(),
id: yearElId,
label: '年',
className: 'year input'
});
result[yearElId] = yearEl;
btnGroupAreaEl.appendChild(yearEl);
}
if (monthElId) {
const monthEl = new Kuc.MobileDropdown({
value: defaultThisMonth ? monthItems[new Date().getMonth()].value : undefined,
id: monthElId,
className: 'month input',
label: '月',
items: monthItems,
});
result[monthElId] = monthEl;
btnGroupAreaEl.appendChild(monthEl);
}
if (dateElId) {
const dateEl = new Kuc.MobileDropdown({
value: dateItems[new Date().getDate() - 1].value,
id: dateElId,
items: dateItems,
label: '日',
className: "date input",
});
result[dateElId] = dateEl;
btnGroupAreaEl.appendChild(dateEl);
}
if (termElId) {
const termEl = new Kuc.MobileDropdown({
id: termElId,
items: termItems,
className: "term input",
label: '学年',
});
result[termElId] = termEl;
btnGroupAreaEl.appendChild(termEl);
}
const btnEl = new Kuc.MobileButton({
text: btnLabel,
type: "submit",
className: "action-btn",
id: btnElId,
});
result[btnElId] = btnEl;
btnEl.addEventListener('click', (e) => {
showError(false);
const checkResult = checkInputData(result, { btnLabel, yearElId, monthElId, dateElId, termElId });
if (checkResult) {
btnOnClick(e, checkResult);
}
});
btnGroupAreaEl.appendChild(btnEl);
return result;
}
function checkInputData(map, { btnLabel, yearElId, monthElId, dateElId, termElId }) {
const year = yearElId && map[yearElId].value;
const month = monthElId && map[monthElId].value;
const date = dateElId && (map[dateElId].value === 'end' ? getLastDate(year, month).getDate() : map[dateElId].value);
const term = termElId && map[termElId].value;
const errorMsgs = [];
if (yearElId) {
const yearRegex = /^\d+$/;
if (!yearRegex.test(year)) {
errorMsgs.push(' · 年は整数で入力してください。');
}
}
if (monthElId && !month) {
errorMsgs.push(' · 月を選択してください。');
}
if (dateElId && !date) {
errorMsgs.push(' · 日を選択してください。');
}
if (termElId && !term) {
errorMsgs.push(' · 学年を選択してください。');
}
if (errorMsgs.length > 0) {
showError(true, btnLabel + 'エラー\n' + errorMsgs.join('\n'))
return;
}
return {
year,
month,
date,
term,
}
}
function createBtn(id, label, onClick) {
const btnEl = new Kuc.MobileButton({
text: label,
type: "submit",
className: "action-btn",
id,
});
btnEl.addEventListener('click', onClick);
return btnEl;
}
function hideSpaceField(ids) {
ids.forEach(id => {
const area = kintone.mobile.app.record.getSpaceElement(id);
area.parentElement.style.minWidth = '0';
area.parentElement.style.display = 'none';
});
}
const statusFieldMap = {
'指導教諭確認中': '担任',
'主幹確認中': '指導',
'園長確認中': '主幹',
'完了': '園長'
}
function addApproveFlowAction() {
return kintone.events.on("mobile.app.record.detail.process.proceed", (event) => {
const field = statusFieldMap[event.nextStatus.value];
if (field) {
event.record[field].value = kintone.getLoginUser().name;
}
return event;
});
}
function showError(show, text) {
if (show) {
buildNotification('danger', text);
notificationEl.open();
console.error(text);
} else {
notificationEl && notificationEl.close();
}
}
function buildNotification(type, text, duration = -1) {
const param = {
type,
text,
duration
}
if (!notificationEl) {
notificationEl = new Kuc.MobileNotification(param);
} else {
Object.assign(notificationEl, param);
}
}

View File

@@ -0,0 +1,77 @@
#legend {
width: 100%;
top: -24px;
position: absolute;
text-align: right;
font-size: 13px;
}
#legend .box {
display: inline-block;
width: 14px;
height: 14px;
background: #ffe3e6;
margin-right: 4px;
vertical-align: middle;
}
/* カレンダーエリア */
#calendar {
width: 100%;
height: 100%;
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-template-rows: repeat(4, 1fr);
gap: 12px;
box-sizing: border-box;
}
.month {
display: grid;
grid-template-columns: repeat(7, 1fr);
grid-template-rows: auto repeat(6, 1fr);
border: 1px solid #aaa;
border-radius: 4px;
}
.month .title {
grid-column: 1/8;
text-align: center;
font-weight: bold;
padding: 4px 0;
}
.month .cell {
display: flex;
align-items: center;
justify-content: center;
font-size: 13px;
}
#calendar:not(.readonly) .month .cell:not(.header):not(:empty) {
cursor: pointer;
}
.month .cell:not(:empty) {
padding: 2px 0;
}
.month .sun {
color: #e74c3c;
}
.month .sat {
color: #2196f3;
}
.month .cell.selected {
background: #ffe3e6;
}
#calendar:not(.readonly) .month .cell:not(.header):not(.selected):not(:empty):hover {
background: #ffe3e677;
}
#calendar:not(.readonly) .month .cell.selected:hover {
background: #ffd3d7;
}

View File

@@ -0,0 +1,312 @@
(() => {
'use strict'
let _CALENDAR
// レコード詳細/新規作成/編集画面表示時にカレンダーを初期化
kintone.events.on(
['app.record.detail.show', 'app.record.create.show', 'app.record.edit.show'],
(event) => {
kintone.app.record.setFieldShown('休日の生データ', false);
initCalendarArea(
event.record,
getHolidayMap(event.record),
event.type === 'app.record.detail.show'
)
return event
}
)
// 年度フィールド変更時に各月の休日をクリアしてカレンダーを再描画
kintone.events.on(
[
'app.record.create.change.年度',
'app.record.edit.change.年度',
'app.record.index.edit.change.年度'
],
(event) => {
forEachRawFields((field) => {
event.record[field].value = ''
})
if (event.type !== 'app.record.index.edit.change.年度') {
initCalendarArea(event.record)
}
return event
}
)
// 一覧編集画面では各月の休日フィールドを編集不可にする
kintone.events.on(
['app.record.index.edit.show'],
(event) => {
forEachRawFields((field) => {
event.record[field].disabled = true
})
return event
}
)
// レコード保存時にカレンダーで選択した休日を各月フィールドへ反映
kintone.events.on(
['app.record.create.submit', 'app.record.edit.submit'],
(event) => {
const resultMap = _CALENDAR.getSelectedDatesMap()
forEachRawFields((field, i) => {
event.record[field].value = resultMap[i].join(',')
})
return event
}
)
/* --------------------------------------------------
* 初期化・データ準備
* -------------------------------------------------- */
// カレンダー表示エリアを初期化
function initCalendarArea(record, map = {}, readonly = false) {
const calendarAreaEl = kintone.app.record.getSpaceElement('calendar-area')
calendarAreaEl.innerHTML = ''
const year = record.年度.value
if (isYearString(year)) {
_CALENDAR = createCalendar(Number(year), map, readonly)
calendarAreaEl.appendChild(_CALENDAR.fragment)
}
}
// 既存レコードに保存されている休日を取得
function getHolidayMap(record) {
const res = {}
forEachRawFields((field, i) => {
const str = record[field].value
if (!str) {
return
}
res[i] = new Set(str.split(','))
})
return res
}
/* --------------------------------------------------
* ユーティリティ
* -------------------------------------------------- */
// 各月フィールドをループ
const forEachRawFields = (callback) => {
for (let i = 1; i <= 12; i++) {
callback(`休日_${i}`, i)
}
}
// ゼロパディング
const padZero = (n) => (n < 10 ? '0' + n : n)
// Date → yyyy-MM-dd
const toYmd = (d) => `${d.getFullYear()}-${padZero(d.getMonth() + 1)}-${padZero(d.getDate())}`
// 土日判定
const isWeekend = (d) => d.getDay() === 0 || d.getDay() === 6
// 年度文字列の妥当性チェック
function isYearString(str) {
// 文字列かつ空でない
if (typeof str !== 'string' || str.length === 0) {
return false
}
// 数字のみ
if (!/^\d+$/.test(str)) {
return false
}
// 4桁
if (str.length !== 4) {
return false
}
// 1900-3000 の範囲
const year = parseInt(str, 10)
return year >= 1900 && year <= 3000
}
/* --------------------------------------------------
* カレンダー生成
* -------------------------------------------------- */
const createCalendar = (year, highlightMap, readonly) => {
const fragment = document.createDocumentFragment()
/* ----- 図例 ----- */
const legend = document.createElement('div')
legend.id = 'legend'
legend.innerHTML = '<span class="box"></span>休日'
fragment.appendChild(legend)
/* ----- カレンダーコンテナ ----- */
const calendar = document.createElement('div')
calendar.id = 'calendar'
if (readonly) {
calendar.classList.add('readonly')
}
fragment.appendChild(calendar)
/* ----- 内部状態 ----- */
const selectedSet = new Set()
const months = buildMonths(year)
months.forEach((m) => {
calendar.appendChild(buildMonth(m))
})
/* ---------- 月情報生成 ---------- */
function buildMonths(year) {
return Array.from({ length: 12 }, (_, i) => {
const monthIndex = 3 + i // 0 基準月で 4 月始まり
const date = new Date(year, monthIndex, 1)
return {
displayMonth: date.getMonth() + 1,
year: date.getFullYear(),
month: date.getMonth(),
label: `${date.getFullYear()}${date.getMonth() + 1}`
}
})
}
/* ---------- 月単位カレンダー生成 ---------- */
function buildMonth({ displayMonth, year, month, label }) {
const monthBox = document.createElement('div')
monthBox.className = 'month'
buildTitle(monthBox, label)
buildHeader(monthBox)
const first = new Date(year, month, 1)
buildPadBlocksStart(first, monthBox)
buildDateBlocks(year, month, displayMonth, monthBox)
buildPadBlocksEnd(monthBox)
return monthBox
}
function buildTitle(monthBox, label) {
const title = document.createElement('div')
title.className = 'title'
title.textContent = label
monthBox.appendChild(title)
}
function buildHeader(monthBox) {
['日', '月', '火', '水', '木', '金', '土'].forEach((day, i) => {
const cell = document.createElement('div')
cell.className = 'cell header'
addWeekendClass(cell, i)
cell.textContent = day
monthBox.appendChild(cell)
})
}
function addWeekendClass(cell, week) {
if (week === 0) {
cell.classList.add('sun')
} else if (week === 6) {
cell.classList.add('sat')
}
}
function buildPadBlocksStart(first, monthBox) {
const startDayInWeek = first.getDay()
for (let i = 0; i < startDayInWeek; i++) {
const cell = document.createElement('div')
cell.className = 'cell'
monthBox.appendChild(cell)
}
}
function buildDateBlocks(year, month, displayMonth, monthBox) {
const last = new Date(year, month + 1, 0)
const highlights = highlightMap[displayMonth] || null
for (let day = 1; day <= last.getDate(); day++) {
const dateObj = new Date(year, month, day)
const ymd = toYmd(dateObj)
const cell = document.createElement('div')
cell.className = 'cell'
cell.textContent = day
cell.dataset.date = ymd
addWeekendClass(cell, dateObj.getDay())
// 初期選択判定
let shouldSelect = false
if (highlights === null) {
shouldSelect = isWeekend(dateObj)
} else if (highlights instanceof Set) {
shouldSelect = highlights.has(ymd)
}
if (shouldSelect) {
cell.classList.add('selected')
selectedSet.add(ymd)
}
// 編集可モードのみクリックイベントを追加
if (!readonly) {
cell.addEventListener('click', () => {
cell.classList.toggle('selected')
if (cell.classList.contains('selected')) {
selectedSet.add(ymd)
} else {
selectedSet.delete(ymd)
}
})
}
monthBox.appendChild(cell)
}
}
function buildPadBlocksEnd(monthBox) {
// 7×7 マスに揃えるための埋め草
while (monthBox.children.length < 49) {
const cell = document.createElement('div')
cell.className = 'cell'
monthBox.appendChild(cell)
}
}
/* ---------- 選択済み日付取得 ---------- */
function getSelectedDatesMap() {
const res = {}
months.forEach(({ month }) => {
res[month + 1] = []
})
// 選択済み日付を振り分け
selectedSet.forEach((ymd) => {
const d = new Date(ymd)
const displayMonth = d.getMonth() + 1
res[displayMonth].push(ymd)
})
// 選択が無い月は全土日を自動追加
Object.keys(res).forEach((monthKey) => {
if (res[monthKey].length === 0) {
const monthInfo = months.find((m) => m.displayMonth == monthKey)
if (monthInfo) {
const year = monthInfo.year
const month = monthInfo.month
const lastDay = new Date(year, month + 1, 0).getDate()
for (let day = 1; day <= lastDay; day++) {
const dateObj = new Date(year, month, day)
if (isWeekend(dateObj)) {
res[monthKey].push(toYmd(dateObj))
}
}
}
}
})
return res
}
return {
fragment,
getSelectedDatesMap
}
}
})()

View File

@@ -1,5 +0,0 @@
const statusFieldMap = {
'主幹確認中': '指導',
'園長確認中': '主幹',
'完了': '園長'
}

View File

@@ -1,12 +0,0 @@
(function () {
"use strict";
kintone.events.on("mobile.app.record.detail.process.proceed", (event) => {
const field = statusFieldMap[event.nextStatus.value];
if (field) {
event.record[field].value = kintone.getLoginUser().name;
}
return event;
});
})();

View File

@@ -1,9 +0,0 @@
const statusFieldMap = {
'主幹確認中4週目': '指導',
'園長確認中4週目': '主幹',
'完了4週目': '園長',
'担任作成中5週目': '園長',
'主幹確認中5週目': '指導',
'園長確認中5週目': '主幹',
'完了5週目': '園長',
}

View File

@@ -1,12 +0,0 @@
(function () {
"use strict";
kintone.events.on("mobile.app.record.detail.process.proceed", (event) => {
const field = statusFieldMap[event.nextStatus.value];
if (field) {
event.record[field].value = kintone.getLoginUser().name;
}
return event;
});
})();

View File

@@ -1,6 +0,0 @@
(function () {
"use strict";
addApproveFlowAction(true);
})();

View File

@@ -1,57 +0,0 @@
(function () {
"use strict";
// ------------------- 詳細画面表示時の処理 -------------------
kintone.events.on('mobile.app.record.detail.show', function (event) {
const area = kintone.mobile.app.record.getSpaceElement('header-clocking-btn-area');
const clockIn = createBtn('clock-in', '登園', dateToFieldInDetail('登園時刻'));
const clockOut = createBtn('clock-out', '帰園', dateToFieldInDetail('帰園時刻'));
area.appendChild(clockIn);
area.appendChild(clockOut);
hideSpaceField(['clock-in-btn-area', 'clock-out-btn-area']);
return event;
});
function dateToFieldInDetail(fieldCode) {
return async function (e) {
await new KintoneRestAPIClient().record.updateRecord({
app: kintone.mobile.app.getId(),
id: kintone.mobile.app.record.getId(),
record: {
[fieldCode]: {
value: getCurrentTime()
}
}
});
location.reload();
}
}
// ------------------- 編集画面表示時の処理 -------------------
kintone.events.on(['mobile.app.record.create.show', 'mobile.app.record.edit.show'], function (event) {
const clockIn = createBtn('clock-in', '登園', dateToFieldInEdit('登園時刻'));
kintone.mobile.app.record.getSpaceElement('clock-in-btn-area').appendChild(clockIn);
const clockOut = createBtn('clock-out', '帰園', dateToFieldInEdit('帰園時刻'));
kintone.mobile.app.record.getSpaceElement('clock-out-btn-area').appendChild(clockOut);
return event;
});
function dateToFieldInEdit(fieldCode) {
return function (e) {
var record = kintone.mobile.app.record.get();
record['record'][fieldCode]['value'] = getCurrentTime();
kintone.mobile.app.record.set(record);
}
}
function getCurrentTime() {
const now = new Date();
const hours = String(now.getHours()).padStart(2, '0');
const minutes = String(now.getMinutes()).padStart(2, '0');
return `${hours}:${minutes}`;
}
})();

View File

@@ -1,21 +0,0 @@
(function () {
"use strict";
addApproveFlowAction(true);
kintone.events.on("mobile.app.record.index.show", (event) => {
const headerSpace = getHeaderSpace('single-label-line');
// if (event.viewId === APP_ENV.view.linkFor0to1) {
// Link1Handler.getInstance(headerSpace);
// return event;
// }
// if (event.viewId === APP_ENV.view.linkForOthers) {
// Link2Handler.getInstance(headerSpace);
// return event;
// }
// BatchCreateHandler.getInstance(headerSpace);
});
})();

View File

@@ -1,41 +0,0 @@
(function () {
"use strict";
const FIELD_CODE = "ユニークキー";
// ------------------- 詳細/印刷/編集画面表示時の処理 -------------------
kintone.events.on(['app.record.detail.show', 'app.record.print.show'], function (event) {
hideField(FIELD_CODE);
return event;
});
// ------------------- 編集画面表示時の処理 -------------------
kintone.events.on(['app.record.edit.show', 'app.record.create.show'], function (event) {
const targetFieldEl = kintone.app.record.getSpaceElement("before-unique-key").parentElement.nextSibling;
targetFieldEl.querySelector('.input-constraints-cybozu').style.display = 'none';
event.record[FIELD_CODE]['value'] = "<自動計算:出席番号+学年+クラス+名前>";
disableField(event.record, FIELD_CODE);
return event;
});
function hideField(fieldCode) {
kintone.app.record.setFieldShown(fieldCode, false);
}
function disableField(record, fieldCode) {
record[fieldCode]['disabled'] = true;
}
// ------------------- 編集画面保存時の処理 -------------------
kintone.events.on(['app.record.create.submit', 'app.record.edit.submit', 'app.record.index.edit.submit'], function (event) {
event.record[FIELD_CODE]['value'] = getUniqueKey(event.record);
return event;
});
function getUniqueKey(record) {
return (record['出席番号']['value'] + '_' + record['学年']['value'] + '_' + record['クラス']['value'] + '_' + record['名前']['value']).substring(0, 64);
}
})();

View File

@@ -1,41 +0,0 @@
(function () {
"use strict";
const FIELD_CODE = "ユニークキー";
// ------------------- 詳細/印刷/編集画面表示時の処理 -------------------
kintone.events.on(['mobile.app.record.detail.show'], function (event) {
hideField(FIELD_CODE);
return event;
});
// ------------------- 編集画面表示時の処理 -------------------
kintone.events.on(['mobile.app.record.edit.show', 'mobile.app.record.create.show'], function (event) {
const targetFieldEl = kintone.mobile.app.record.getSpaceElement("before-unique-key").nextSibling;
targetFieldEl.querySelector('.control-constraints-gaia').style.display = 'none';
event.record[FIELD_CODE]['value'] = "<自動計算:出席番号+学年+クラス+名前>";
disableField(event.record, FIELD_CODE);
return event;
});
function hideField(fieldCode) {
kintone.mobile.app.record.setFieldShown(fieldCode, false);
}
function disableField(record, fieldCode) {
record[fieldCode]['disabled'] = true;
}
// ------------------- 編集画面保存時の処理 -------------------
kintone.events.on(['mobile.app.record.create.submit', 'mobile.app.record.edit.submit'], function (event) {
event.record[FIELD_CODE]['value'] = getUniqueKey(event.record);
return event;
});
function getUniqueKey(record) {
return (record['出席番号']['value'] + '_' + record['学年']['value'] + '_' + record['クラス']['value'] + '_' + record['名前']['value']).substring(0, 64);
}
})();

View File

@@ -1,6 +0,0 @@
const statusFieldMap = {
'指導教諭確認中': '担任',
'主幹確認中': '指導',
'園長確認中': '主幹',
'完了': '園長'
}

View File

@@ -1,12 +0,0 @@
(function () {
"use strict";
kintone.events.on("mobile.app.record.detail.process.proceed", (event) => {
const field = statusFieldMap[event.nextStatus.value];
if (field) {
event.record[field].value = kintone.getLoginUser().name;
}
return event;
});
})();

View File

@@ -1,13 +0,0 @@
const statusFieldMap = {
'主幹確認中1学期': '指導1',
'園長確認中1学期': '主幹1',
'完了1学期': '園長1',
'担任作成中2学期': '園長1',
'主幹確認中2学期': '指導2',
'園長確認中2学期': '主幹2',
'完了2学期': '園長2',
'担任作成中3学期': '園長2',
'主幹確認中3学期': '指導3',
'園長確認中3学期': '主幹3',
'完了3学期': '園長3',
}

View File

@@ -1,12 +0,0 @@
(function () {
"use strict";
kintone.events.on("mobile.app.record.detail.process.proceed", (event) => {
const field = statusFieldMap[event.nextStatus.value];
if (field) {
event.record[field].value = kintone.getLoginUser().name;
}
return event;
});
})();

View File

@@ -108,9 +108,13 @@ class ExtractHandler {
try {
const data = await api.record.getAllRecordsWithId({
app: env["保育・教育日数マスタ"].appId,
fields: ['教育日数' + month, '保育日数' + month],
fields: ['教育日数' + month, '保育日数' + month, '休日_' + month + '月'],
condition: `年度 = "${year}"`
});
if (!data || !data[0]) {
showError(true, '保育・教育日数マスタのデータが存在しません。');
return;
}
return data && data[0];
} catch (e) {
showError(true, '保育・教育日数マスタのデータ読み取りエラー\n - ' + e);
@@ -124,16 +128,23 @@ class ExtractHandler {
fields: ['担任'],
condition: `学年 in ("${term}")`
});
return data && data[0] && data[0]['担任']?.value.map((x)=>x.name).join('、') || '';
return data && data[0] && data[0]['担任']?.value.map((x) => x.name).join('、') || '';
} catch (e) {
showError(true, '担任マスタのデータ読み取りエラー\n - ' + e);
}
}
toHolidaySet = (str) => {
if (!str) {
return new Set();
}
return new Set(str.split(','))
}
writeExcel = ({ records, recordMap, childMaster, dayMaster, termTeacher }, term, { era, year, westernYear, month }) => {
const teachDays = Number(dayMaster['教育日数' + month].value);
const careDays = Number(dayMaster['保育日数' + month].value);
const holidaySet = this.toHolidaySet(dayMaster['休日_' + month + '月'].value);
return async (api, worksheet) => {
const baseCells = findCellsInfo(worksheet, ['13', '16', '19', '25', '(担 任)', '1', '番号']);
@@ -216,6 +227,7 @@ class ExtractHandler {
'出席停止': 0,
'病欠': 0,
'自欠': 0,
'休日欠席': 0
}
// 日
recordWrapper.list.forEach((record, i) => {
@@ -224,10 +236,18 @@ class ExtractHandler {
if (res === '出席') {
return;
}
if (res === '出席停止' && record["出席停止理由"].value) {
reasons.push(record["出席停止理由"].value);
if (res === '出席停止') {
if (record["出席停止理由"].value) {
reasons.push(record["出席停止理由"].value);
}
updateCell(row, { base, right: 2 + i }, '×');
return
}
updateCell(row, { base, right: 2 + i }, res === '出席停止' ? '×' : '');
// 欠席
if (holidaySet.has(record['登園日'].value)) {
sum['休日欠席']++;
}
updateCell(row, { base, right: 2 + i }, '');
})
// 出 席
@@ -238,7 +258,7 @@ class ExtractHandler {
updateCell(row, { base, right: 36 }, sum['自欠']);
// 教育日数
// updateCell(row, { base, right: 37 }, sum['出席'] + sum['出席停止'] - sum['病欠'] - sum['自欠']);
updateCell(row, { base, right: 37 }, teachDays - sum['病欠'] - sum['自欠']);
updateCell(row, { base, right: 37 }, teachDays - sum['病欠'] - sum['自欠'] + sum['休日欠席']);
// 備考
updateCell(row, { base, right: 38 }, reasons.join("\n"));

View File

@@ -7,8 +7,8 @@
// 「登園/帰園」ボタン
const area = kintone.app.record.getSpaceElement('header-clocking-btn-area');
const clockIn = createBtn('clock-in', '登園', dateToFieldInDetailIn('登園時刻'));
const clockOut = createBtn('clock-out', '帰園', dateToFieldInDetail('帰園時刻'));
const clockIn = createBtn('clock-in', '登園', dateToFieldInDetailIn());
const clockOut = createBtn('clock-out', '帰園', dateToFieldInDetailOut());
area.appendChild(clockIn);
area.appendChild(clockOut);
@@ -26,14 +26,18 @@
return grade === "0歳児" || grade === "1歳児";
}
function dateToFieldInDetail(fieldCode) {
//PVC追加
function dateToFieldInDetailIn() {
return async function (e) {
await new KintoneRestAPIClient().record.updateRecord({
app: kintone.app.getId(),
id: kintone.app.record.getId(),
record: {
[fieldCode]: {
'登園時刻': {
value: getCurrentTime()
},
"出欠": {
value: "出席"
}
}
});
@@ -41,18 +45,14 @@
}
}
//PVC追加
function dateToFieldInDetailIn(fieldCode) {
function dateToFieldInDetailOut() {
return async function (e) {
await new KintoneRestAPIClient().record.updateRecord({
app: kintone.app.getId(),
id: kintone.app.record.getId(),
record: {
[fieldCode]: {
'帰園時刻': {
value: getCurrentTime()
},
出欠: {
value: "出席"
}
}
});
@@ -75,9 +75,9 @@
// ------------------- 編集画面表示時の処理 -------------------
kintone.events.on(['app.record.create.show', 'app.record.edit.show'], function (event) {
// 「登園/帰園」ボタン
const clockIn = createBtn('clock-in', '登園', dateToFieldInEditIn('登園時刻','出欠'));
const clockIn = createBtn('clock-in', '登園', dateToFieldInEditIn());
kintone.app.record.getSpaceElement('clock-in-btn-area').appendChild(clockIn);
const clockOut = createBtn('clock-out', '帰園', dateToFieldInEdit('帰園時刻'));
const clockOut = createBtn('clock-out', '帰園', dateToFieldInEditOut());
kintone.app.record.getSpaceElement('clock-out-btn-area').appendChild(clockOut);
// 「伝達事項」
@@ -87,20 +87,46 @@
return event;
});
function dateToFieldInEdit(fieldCode) {
// -------------------「園での様子_入力者」の処理 -------------------
const _DATA_HOLDER_MAP = {}
// 「園での様子_伝達事項」はテキストエリア複数行入力欄であり、app.record.edit.changeイベントをサポートしていません
// したがって、データを事前に保存しておき、保存submit時のタイミングで更新を行います。
kintone.events.on(['app.record.index.edit.show', 'app.record.create.show', 'app.record.edit.show'], function (event) {
_DATA_HOLDER_MAP['isEditorChanged'] = false;
_DATA_HOLDER_MAP['prevSituationValue'] = event.record['園での様子_伝達事項']['value'] || '';
return event;
});
kintone.events.on(['app.record.create.change.園での様子_入力者', 'app.record.edit.change.園での様子_入力者', 'app.record.index.edit.change.園での様子_入力者'], function(event) {
_DATA_HOLDER_MAP['isEditorChanged'] = true;
return event;
});
kintone.events.on(['app.record.create.submit', 'app.record.edit.submit', 'app.record.index.edit.submit'], function (event) {
const current = event.record['園での様子_伝達事項']['value'] || '';
if (_DATA_HOLDER_MAP['prevSituationValue'] != current && !_DATA_HOLDER_MAP['isEditorChanged']) {
event.record['園での様子_入力者']['value'] = [kintone.getLoginUser()];
}
return event;
});
//PVC追加
function dateToFieldInEditIn() {
return function (e) {
var record = kintone.app.record.get();
record['record'][fieldCode]['value'] = getCurrentTime();
record['record']['登園時刻']['value'] = getCurrentTime();
record['record']['出欠']['value'] = "出席";
kintone.app.record.set(record);
}
}
//PVC追加
function dateToFieldInEditIn(fieldCode1,fieldCode2) {
function dateToFieldInEditOut() {
return function (e) {
var record = kintone.app.record.get();
record['record'][fieldCode1]['value'] = getCurrentTime();
record['record'][fieldCode2]['value'] = "出席";
record['record']['帰園時刻']['value'] = getCurrentTime();
kintone.app.record.set(record);
}
}

View File

@@ -2,8 +2,6 @@
"use strict";
const APP_ENV = env["園児別出欠簿入力"];
addApproveFlowAction();
kintone.events.on("app.record.index.show", (event) => {
const headerSpace = getHeaderSpace('single-label-line');

View File

@@ -1,6 +1,15 @@
(function () {
"use strict";
const statusFieldMap = {
'指導教諭確認中': '担任',
'主幹確認中': '指導',
'園長確認中': '主幹',
'完了': '園長'
}
window._StatusFieldMap = statusFieldMap
kintone.events.on("app.record.detail.process.proceed", (event) => {
const field = statusFieldMap[event.nextStatus.value];
if (field) {

View File

@@ -0,0 +1,23 @@
(function () {
"use strict";
kintone.events.on(["app.record.create.show","app.record.edit.show"], function(event) {
var record = event.record;
record.担当_文字列.value = record.担当.value.map(function(user) {return user.name}).join(",");
record.コーディネーター_文字列.value = record.コーディネーター.value.map(function(user) {return user.name}).join(",");
return event;
});
kintone.events.on(["app.record.create.change.担当","app.record.edit.change.担当", "app.record.index.edit.change.担当"], function(event) {
var record = event.record;
record.担当_文字列.value = record.担当.value.map(function(user) {return user.name}).join(",");
return event;
});
kintone.events.on(["app.record.create.change.コーディネーター","app.record.edit.change.コーディネーター", "app.record.index.edit.change.コーディネーター"], function(event) {
var record = event.record;
record.コーディネーター_文字列.value = record.コーディネーター.value.map(function(user) {return user.name}).join(",");
return event;
});
})();

View File

@@ -0,0 +1,23 @@
(function () {
"use strict";
const statusFieldMap = {
"園長確認中1学期": "指導1",
"担任作成中2学期": "園長1",
"園長確認中2学期": "指導2",
"担任作成中3学期": "園長2",
"園長確認中3学期": "指導3",
"完了": "園長3"
}
window._StatusFieldMap = statusFieldMap
kintone.events.on("app.record.detail.process.proceed", (event) => {
const field = statusFieldMap[event.nextStatus.value];
if (field) {
event.record[field].value = kintone.getLoginUser().name;
}
return event;
});
})();

View File

@@ -0,0 +1,54 @@
(function () {
"use strict";
// マイビューのID
const mineView = 13353711;
// 分類フィールドのプレースホルダー
const classifyField = "${classify}";
// ボタン分類マッピング
const btnClassifyMap = {
"0歳児": "0~2歳",
"1歳児": "0~2歳",
"2歳児": "0~2歳",
"3歳児": "3~5歳",
"4歳児": "3~5歳",
"5歳児": "3~5歳",
}
// アクションマッピング
const actionMap = {
"担任作成中": `指導教諭確認依頼${classifyField}`,
"指導教諭確認中": `承認する`,
"園長確認中": `承認する${classifyField}`
}
/**
* ステータスから接頭辞を取得する
* @param {string} status - ステータス文字列
*/
const getStatusPrefix = (status) => {
return status.split("")[0];
};
// kintoneイベントの登録
kintone.events.on("app.record.index.show", (event) => {
// 特定のビューの場合のみ処理を実行
if (event.viewId === mineView) {
// BatchApprovalHandlerクラスのインスタンスを作成
const batchApproval = new BatchApprovalHandler(
mineView,
classifyField,
btnClassifyMap,
actionMap,
getStatusPrefix,
_StatusFieldMap
);
// 一括承認ボタンを作成
batchApproval.createApproveBtn();
}
return event;
});
})();

View File

@@ -2,8 +2,6 @@
"use strict";
const APP_ENV = env["0,1歳日誌出力用"];
addApproveFlowAction();
kintone.events.on("app.record.detail.show", (event) => {
const headerSpace = getHeaderSpace('', true);

View File

@@ -1,6 +1,14 @@
(function () {
"use strict";
const statusFieldMap = {
'指導教諭確認中0~2歳': '担任',
'園長確認中': '指導',
'完了': '園長'
}
window._StatusFieldMap = statusFieldMap
kintone.events.on("app.record.detail.process.proceed", (event) => {
const field = statusFieldMap[event.nextStatus.value];
if (field) {

View File

@@ -2,8 +2,6 @@
"use strict";
const APP_ENV = env["2歳以上日誌出力用"];
addApproveFlowAction();
kintone.events.on("app.record.detail.show", (event) => {
const headerSpace = getHeaderSpace('', true);

View File

@@ -0,0 +1,21 @@
(function () {
"use strict";
const statusFieldMap = {
'指導教諭確認中0~2歳': '担任',
'指導教諭確認中3~5歳': '担任',
'園長確認中': '指導',
'完了': '園長'
}
window._StatusFieldMap = statusFieldMap
kintone.events.on("app.record.detail.process.proceed", (event) => {
const field = statusFieldMap[event.nextStatus.value];
if (field) {
event.record[field].value = kintone.getLoginUser().name;
}
return event;
});
})();

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -5,11 +5,13 @@
"app.record.create.show",
"app.record.edit.show",
"app.record.create.change.担当",
"app.record.edit.change.担当"
"app.record.edit.change.担当",
"app.record.index.edit.change.担当"
];
kintone.events.on(events, function(event) {
var record = event.record;
//kintone.app.record.setFieldShown("担任", false);
record.担任.value = record.担当.value.map(function(user) {return user.name}).join(",");
return event;
});

View File

@@ -1,6 +1,13 @@
(function () {
"use strict";
const statusFieldMap = {
'園長確認中': '指導',
'完了': '園長'
}
window._StatusFieldMap = statusFieldMap
kintone.events.on("app.record.detail.process.proceed", (event) => {
const field = statusFieldMap[event.nextStatus.value];
if (field) {

View File

@@ -0,0 +1,50 @@
(function () {
"use strict";
// マイビューのID
const mineView = 8352036;
// 分類フィールドのプレースホルダー
const classifyField = "${classify}";
// ボタン分類マッピング
const btnClassifyMap = {
"0歳児": "",
}
// アクションマッピング
const actionMap = {
"担任作成中": `指導教諭確認依頼`,
"指導教諭確認中": `承認する`,
"主幹確認中": `承認する`,
"園長確認中": `承認する`
}
/**
* ステータスから接頭辞を取得する
* @param {string} status - ステータス文字列
*/
const getStatusPrefix = (status) => {
return status.split("")[0];
};
// kintoneイベントの登録
kintone.events.on("app.record.index.show", (event) => {
// 特定のビューの場合のみ処理を実行
if (event.viewId === mineView) {
// BatchApprovalHandlerクラスのインスタンスを作成
const batchApproval = new BatchApprovalHandler(
mineView,
classifyField,
btnClassifyMap,
actionMap,
getStatusPrefix,
_StatusFieldMap
);
// 一括承認ボタンを作成
batchApproval.createApproveBtn();
}
return event;
});
})();

File diff suppressed because one or more lines are too long

2433
src/3.保育計画 月案/kuc.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,19 @@
(function () {
"use strict";
var events = [
"app.record.create.show",
"app.record.edit.show",
"app.record.create.change.担当",
"app.record.edit.change.担当",
"app.record.index.edit.change.担当"
];
kintone.events.on(events, function(event) {
var record = event.record;
//kintone.app.record.setFieldShown("担任", false);
record.担任.value = record.担当.value.map(function(user) {return user.name}).join(",");
return event;
});
})();

View File

@@ -1,6 +1,13 @@
(function () {
"use strict";
const statusFieldMap = {
'園長確認中': '指導',
'完了': '園長'
}
window._StatusFieldMap = statusFieldMap
kintone.events.on("app.record.detail.process.proceed", (event) => {
const field = statusFieldMap[event.nextStatus.value];
if (field) {

View File

@@ -0,0 +1,55 @@
(function () {
"use strict";
// マイビューのID
const mineView = 8352036;
// 分類フィールドのプレースホルダー
const classifyField = "${classify}";
// ボタン分類マッピング
const btnClassifyMap = {
"1歳児": "0~2歳",
"2歳児": "0~2歳",
"3歳児": "3~5歳",
"4歳児": "3~5歳",
"5歳児": "3~5歳",
"5歳児": "3~5歳",
}
// アクションマッピング
const actionMap = {
"担任作成中": `指導教諭確認依頼${classifyField}`,
"指導教諭確認中": `承認する`,
"主幹確認中": `承認する`,
"園長確認中": `承認する${classifyField}`
}
/**
* ステータスから接頭辞を取得する
* @param {string} status - ステータス文字列
*/
const getStatusPrefix = (status) => {
return status.split("")[0];
};
// kintoneイベントの登録
kintone.events.on("app.record.index.show", (event) => {
// 特定のビューの場合のみ処理を実行
if (event.viewId === mineView) {
// BatchApprovalHandlerクラスのインスタンスを作成
const batchApproval = new BatchApprovalHandler(
mineView,
classifyField,
btnClassifyMap,
actionMap,
getStatusPrefix,
_StatusFieldMap
);
// 一括承認ボタンを作成
batchApproval.createApproveBtn();
}
return event;
});
})();

File diff suppressed because one or more lines are too long

Some files were not shown because too many files have changed in this diff Show More