Merge branch 'master' of https://dev.azure.com/alicorn-dev/kintone-attendance-system/_git/kintone-attendance-system
This commit is contained in:
BIN
document/PVC.one
BIN
document/PVC.one
Binary file not shown.
BIN
document/①仕様書_園児別出欠簿入力_20250321.xlsx
Normal file
BIN
document/①仕様書_園児別出欠簿入力_20250321.xlsx
Normal file
Binary file not shown.
BIN
document/①仕様書_園児別出欠簿入力_20250402.xlsx
Normal file
BIN
document/①仕様書_園児別出欠簿入力_20250402.xlsx
Normal file
Binary file not shown.
BIN
document/⑤仕様書_学年別保育計画_20250214.xlsx
Normal file
BIN
document/⑤仕様書_学年別保育計画_20250214.xlsx
Normal file
Binary file not shown.
BIN
document/⑥仕様書_保育計画月案_20250214.xlsx
Normal file
BIN
document/⑥仕様書_保育計画月案_20250214.xlsx
Normal file
Binary file not shown.
BIN
document/⑦仕様書_保育計画週案_20250214.xlsx
Normal file
BIN
document/⑦仕様書_保育計画週案_20250214.xlsx
Normal file
Binary file not shown.
BIN
document/⑧仕様書_学期反省・評価_20250214.xlsx
Normal file
BIN
document/⑧仕様書_学期反省・評価_20250214.xlsx
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -2,14 +2,13 @@
|
||||
"use strict";
|
||||
const APP_ENV = env["0,1歳日誌出力用"];
|
||||
|
||||
kintone.events.on("app.record.index.show", (event) => {
|
||||
const headerSpace = getHeaderSpace('single-label-line');
|
||||
addApproveFlowAction();
|
||||
|
||||
kintone.events.on("app.record.detail.show", (event) => {
|
||||
const headerSpace = getHeaderSpace('', true);
|
||||
|
||||
const elements = createBtnGroupArea('extract-action-area', '日誌作成', handleButtonClick, {
|
||||
btnElId: 'extract-btn',
|
||||
yearElId: 'extract-year',
|
||||
monthElId: 'extract-month',
|
||||
classElId: 'extract-classroom',
|
||||
})
|
||||
|
||||
if (!elements) {
|
||||
@@ -19,9 +18,104 @@
|
||||
headerSpace.appendChild(elements['extract-action-area']);
|
||||
});
|
||||
|
||||
function handleButtonClick(e, { year, month, className }) {
|
||||
const fileName = getExcelName(APP_ENV, year + month + '_' + className + '組');
|
||||
console.log(fileName);
|
||||
async function handleButtonClick(e) {
|
||||
loading(true, '帳票出力中...');
|
||||
showError(false);
|
||||
const api = new KintoneRestAPIClient();
|
||||
// 本アプリからデータを読み取る
|
||||
const record = kintone.app.record.get().record;
|
||||
if (!record) {
|
||||
// エラー
|
||||
loading(false);
|
||||
return e;
|
||||
}
|
||||
|
||||
const yearStr = record['年'].value;
|
||||
const monthInput = record['月'].value;
|
||||
if (!yearStr || !monthInput) {
|
||||
showError('年/月が設定されていません');
|
||||
loading(false);
|
||||
return e;
|
||||
}
|
||||
const monthStr = String(monthInput).padStart(2, '0');
|
||||
|
||||
const className = record['クラス'].value;
|
||||
if (!className) {
|
||||
showError('クラスが設定されていません');
|
||||
loading(false);
|
||||
return e;
|
||||
}
|
||||
|
||||
const excelName = APP_ENV.excelName;
|
||||
await createExcelAndDownload({
|
||||
api,
|
||||
excelName,
|
||||
exportName: getExcelName(excelName, yearStr + monthStr + '_' + className + '組'),
|
||||
bizLogic: writeExcel(record, className, getJapaneseEraDate(new Date(yearStr, monthInput - 1, 1))),
|
||||
});
|
||||
loading(false);
|
||||
}
|
||||
|
||||
|
||||
function writeExcel(record, className, { era, year, month }) {
|
||||
return async (api, worksheet) => {
|
||||
const baseCells = findCellsInfo(worksheet, ['園長', '出欠', '食事量', '睡眠時間', '1', '11', '21']);
|
||||
fillApproveArea(baseCells, worksheet, record);
|
||||
|
||||
const totalPages = baseCells['出欠'].length;
|
||||
for (let i = 0; i < totalPages; i++) {
|
||||
updateCell(worksheet, { base: baseCells['出欠'][i], up: 1 }, era + ' ' + year + '年 ' + month + '月');
|
||||
updateCell(worksheet, { base: baseCells['食事量'][i], up: 1 }, 'クラス ' + className);
|
||||
updateCell(worksheet, { base: baseCells['睡眠時間'][i], up: 1 }, '園児名 ' + record['園児名'].value);
|
||||
}
|
||||
|
||||
fillMainPage(baseCells, worksheet)
|
||||
}
|
||||
|
||||
function fillMainPage(baseCells, worksheet) {
|
||||
const records = record['帳票出力用_テーブル'].value.map((e) => e.value);
|
||||
const inputMergedObject = getMergedInfo(worksheet, baseCells['1'][0]);
|
||||
const inputMergedRowCnt = inputMergedObject.bottom - inputMergedObject.top + 1;
|
||||
|
||||
[[baseCells['1'][0], 1, 10], [baseCells['11'][0], 11, 10], [baseCells['21'][0], 21, 11]].forEach((obj) => {
|
||||
const baseForDetail = obj[0];
|
||||
const from = obj[1];
|
||||
const count = obj[2];
|
||||
const cols = getLabelColsMapping(worksheet, baseForDetail.row - 1, ['日付', '出欠', '降園', '体温', '食事量', '排便', '睡眠時間', '保護者から', '園での様子_伝達事項', '評価反省']);
|
||||
|
||||
let currentRow = baseForDetail.row;
|
||||
for (let i = 0; i < count; i++) {
|
||||
const index = from + i - 1;
|
||||
const record = records[index];
|
||||
if (!record) {
|
||||
break;
|
||||
}
|
||||
const row = worksheet.getRow(currentRow);
|
||||
cols.forEach(col => {
|
||||
const base = { row: currentRow, col: col.index };
|
||||
if (col.field === '体温') {
|
||||
for (let j = 0; j < 3; j++) {
|
||||
const val1 = record["検温時刻" + (j + 1)].value || ' : ';
|
||||
const val2 = (record["体温" + (j + 1)].value || ' . ').padStart(4, ' ');
|
||||
updateCell(worksheet, { base, down: j }, val1 + ' , ' + val2 + ' ℃');
|
||||
}
|
||||
} else if (col.field === '睡眠時間') {
|
||||
for (let j = 0; j < 2; j++) {
|
||||
const val1 = record["睡眠開始時間" + (j + 1)].value || ': ';
|
||||
const val2 = record["睡眠終了時間" + (j + 1)].value || ' :';
|
||||
updateCell(worksheet, { base, down: j }, val1 + ' ~ ' + val2);
|
||||
}
|
||||
} else {
|
||||
updateCell(row, { base }, record[col.field].value);
|
||||
}
|
||||
});
|
||||
currentRow += inputMergedRowCnt;
|
||||
}
|
||||
worksheet.getRow(currentRow - 1).addPageBreak();
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
})();
|
||||
6
src/0,1歳用日誌/main.mobile.js
Normal file
6
src/0,1歳用日誌/main.mobile.js
Normal file
@@ -0,0 +1,6 @@
|
||||
(function () {
|
||||
"use strict";
|
||||
|
||||
addApproveFlowAction(true);
|
||||
|
||||
})();
|
||||
496
src/0,1歳用日誌/pvc.lib.exceljsUtil.js
Normal file
496
src/0,1歳用日誌/pvc.lib.exceljsUtil.js
Normal file
@@ -0,0 +1,496 @@
|
||||
/** @copyright 2018 Planning Village Corporation Co., Ltd. */
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
// [IE11] Polyfill of Object.values
|
||||
if (!Object.values) {
|
||||
const ownKeys = (
|
||||
(typeof Reflect === 'object' && typeof Reflect.ownKeys === 'function') ? Reflect.ownKeys :
|
||||
// @ts-ignore
|
||||
(typeof Object.getOwnPropertySymbols === 'function') ? (function (O) {
|
||||
// @ts-ignore
|
||||
return Object.getOwnPropertyNames(O).concat(Object.getOwnPropertySymbols(O));
|
||||
}) :
|
||||
Object.getOwnPropertyNames);
|
||||
// @ts-ignore
|
||||
const reduce = Function.bind.call(Function.call, Array.prototype.reduce);
|
||||
// @ts-ignore
|
||||
const isEnumerable = Function.bind.call(Function.call, Object.prototype.propertyIsEnumerable);
|
||||
// @ts-ignore
|
||||
const concat = Function.bind.call(Function.call, Array.prototype.concat);
|
||||
//@ts-ignore
|
||||
Object.values = function values(O) {
|
||||
//@ts-ignore
|
||||
return reduce(ownKeys(O), function (v, k) {
|
||||
return concat(v, typeof k === 'string' && isEnumerable(O, k) ? [O[k]] : [])
|
||||
}, [])
|
||||
};
|
||||
}
|
||||
|
||||
// [IE11] Polyfill of Number.isNaN
|
||||
if (!Number.isNaN) {
|
||||
Number.isNaN = function (value) {
|
||||
return value !== null && (value != value || +value != value);
|
||||
};
|
||||
}
|
||||
|
||||
// [IE11] Polyfill of String.prototype.startsWith
|
||||
if (!String.prototype.startsWith) {
|
||||
Object.defineProperty(String.prototype, 'startsWith', {
|
||||
//@ts-ignore
|
||||
value: function (search, rawPos) {
|
||||
var pos = rawPos > 0 ? rawPos | 0 : 0;
|
||||
return this.substring(pos, pos + search.length) === search;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// [IE11] Polyfill of String.prototype.includes
|
||||
if (!String.prototype.includes) {
|
||||
String.prototype.includes = function (search, start) {
|
||||
'use strict';
|
||||
//@ts-ignore
|
||||
if (search instanceof RegExp) {
|
||||
throw TypeError('first argument must not be a RegExp');
|
||||
}
|
||||
if (start === undefined) {
|
||||
start = 0;
|
||||
}
|
||||
return this.indexOf(search, start) !== -1;
|
||||
};
|
||||
}
|
||||
|
||||
// [IE11] Polyfill of Array.prototype.findIndex
|
||||
if (!Array.prototype.findIndex) {
|
||||
// @ts-ignore
|
||||
Array.prototype.findIndex = function (predicate) {
|
||||
if (this === null) {
|
||||
throw new TypeError('Array.prototype.findIndex called on null or undefined');
|
||||
}
|
||||
if (typeof predicate !== 'function') {
|
||||
throw new TypeError('predicate must be a function');
|
||||
}
|
||||
var list = Object(this);
|
||||
var length = list.length >>> 0;
|
||||
var thisArg = arguments[1];
|
||||
var value;
|
||||
|
||||
for (var i = 0; i < length; i++) {
|
||||
value = list[i];
|
||||
if (predicate.call(thisArg, value, i, list)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
};
|
||||
}
|
||||
|
||||
//@ts-ignore
|
||||
window.pvc = window.pvc || {};
|
||||
//@ts-ignore
|
||||
window.pvc.lib = window.pvc.lib || {};
|
||||
//@ts-ignore
|
||||
window.pvc.lib.exceljsUtil = (function () {
|
||||
const exceljs = {
|
||||
/**
|
||||
* ワークブックの blob を読み取ります。
|
||||
* @param {Blob} blob Blob
|
||||
* @return {Promise<ExcelJS.Workbook>} ワークブック
|
||||
*/
|
||||
loadWorkbookBlob: function (blob) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
var reader = new FileReader();
|
||||
reader.onload = function (e) {
|
||||
// @ts-ignore
|
||||
resolve(e.target.result);
|
||||
};
|
||||
reader.onerror = function (e) {
|
||||
reject(e);
|
||||
}
|
||||
reader.onabort = function (e) {
|
||||
reject(e);
|
||||
}
|
||||
reader.readAsArrayBuffer(blob);
|
||||
}).then(function (arrayBuffer) {
|
||||
// 非公式のメンバー load を使用
|
||||
// @ts-ignore
|
||||
return new ExcelJS.Workbook().xlsx.load(arrayBuffer);
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* ワークブックを Blob に変換します。
|
||||
* @param {ExcelJS.Workbook} workbook ワークブック
|
||||
* @return {Promise<Blob>} Blob
|
||||
*/
|
||||
saveWorkbookToBlob: function (workbook) {
|
||||
// writeBuffer の戻り値 ExcelJS.Buffer はブラウザ環境では Uint8Array となる
|
||||
return workbook.xlsx.writeBuffer().then(function (ua) {
|
||||
return new Blob([ua], {
|
||||
type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* 行をコピーします。
|
||||
* @param {ExcelJS.Worksheet} worksheet ワークシート
|
||||
* @param {number} topRowNumber コピー元の開始行番号(1から開始)
|
||||
* @param {number} [bottomRowNumber] コピー元の終了行番号(1から開始)。省略時は開始行番号と同じ値となります。
|
||||
* @returns {pvc.lib.exceljsUtil.CopiedRowsInfo} 行のコピー情報
|
||||
*/
|
||||
copyRows: function (worksheet, topRowNumber, bottomRowNumber) {
|
||||
const _bottomRowNumber = (bottomRowNumber == null ? topRowNumber : bottomRowNumber);
|
||||
|
||||
if (topRowNumber < 0 || _bottomRowNumber < topRowNumber) {
|
||||
throw new Error('コピー元の領域とが不正です。');
|
||||
}
|
||||
|
||||
// コピー元の領域の情報を収集
|
||||
const rows = [];
|
||||
for (let r = topRowNumber; r <= _bottomRowNumber; r++) {
|
||||
const row = worksheet.getRow(r);
|
||||
const cells = [];
|
||||
for (let c = 1; c <= worksheet.columnCount; c++) {
|
||||
const cell = row.getCell(c);
|
||||
cells.push({
|
||||
value: cell.value,
|
||||
style: cell.style,
|
||||
});
|
||||
}
|
||||
rows.push({
|
||||
cells: cells,
|
||||
height: row.height,
|
||||
// 非公式のメンバー style を使用
|
||||
// @ts-ignore
|
||||
style: row.style,
|
||||
});
|
||||
}
|
||||
|
||||
// コピー元の領域の内部に収まるマージを収集
|
||||
const merges = deepCopyObject(getWorksheetMerges(worksheet).filter(function (merge) {
|
||||
return (topRowNumber <= merge.top && merge.bottom <= _bottomRowNumber);
|
||||
}).map(function (merge) {
|
||||
return {
|
||||
top: merge.top - topRowNumber,
|
||||
right: merge.right,
|
||||
bottom: merge.bottom - topRowNumber,
|
||||
left: merge.left,
|
||||
};
|
||||
}));
|
||||
|
||||
return deepCopyObject({
|
||||
rows: rows,
|
||||
merges: merges
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* 指定された開始行を起点に、コピーした行を貼り付けます。
|
||||
* コピー元の領域と領域外の両方にまたがるセルのマージは貼り付けされません。
|
||||
* コピー先の領域を一部でも含むマージは全て解除されます。
|
||||
* @param {ExcelJS.Worksheet} worksheet ワークシート
|
||||
* @param {number} topRowNumber コピー先の開始行番号(1から開始)
|
||||
* @param {pvc.lib.exceljsUtil.CopiedRowsInfo} copiedRowsInfo 行のコピー情報
|
||||
*/
|
||||
pasteRows: function (worksheet, topRowNumber, copiedRowsInfo) {
|
||||
const bottomRowNumber = topRowNumber + copiedRowsInfo.rows.length - 1;
|
||||
|
||||
if (topRowNumber < 0) {
|
||||
throw new Error('コピー先の領域とが不正です。');
|
||||
}
|
||||
|
||||
// コピー先の行のマージを解除(コピー先の領域を一部でも含むマージは全て解除)
|
||||
getWorksheetMerges(worksheet).filter(function (merge) {
|
||||
return (topRowNumber <= merge.bottom && merge.top <= bottomRowNumber);
|
||||
}).forEach(function (merge) {
|
||||
worksheet.unMergeCells(merge.range);
|
||||
});
|
||||
|
||||
// マージをペースト
|
||||
copiedRowsInfo.merges.forEach(function (mergeInfo) {
|
||||
worksheet.mergeCells(
|
||||
topRowNumber + mergeInfo.top,
|
||||
mergeInfo.left,
|
||||
topRowNumber + mergeInfo.bottom,
|
||||
mergeInfo.right);
|
||||
});
|
||||
|
||||
// セルをペースト
|
||||
copiedRowsInfo.rows.forEach(function (rowInfo, i) {
|
||||
const row = worksheet.getRow(topRowNumber + i);
|
||||
row.height = rowInfo.height;
|
||||
// 非公式のメンバー style を使用
|
||||
// @ts-ignore
|
||||
row.style = rowInfo.style;
|
||||
for (let c = 1; c <= worksheet.columnCount; c++) {
|
||||
const cell = row.getCell(c);
|
||||
const cellInfo = rowInfo.cells[c - 1];
|
||||
if (cellInfo) {
|
||||
cell.value = cellInfo.value;
|
||||
cell.style = cellInfo.style;
|
||||
} else {
|
||||
exceljs.clearCell(cell);
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* 指定された開始行を起点に、コピーした行を挿入します。
|
||||
* コピー元の領域と領域外の両方にまたがるセルのマージは貼り付けされません。
|
||||
* @param {ExcelJS.Worksheet} worksheet ワークシート
|
||||
* @param {number} topRowNumber コピー先の開始行番号(1から開始)
|
||||
* @param {pvc.lib.exceljsUtil.CopiedRowsInfo} copiedRowsInfo 行のコピー情報
|
||||
*/
|
||||
insertRows: function (worksheet, topRowNumber, copiedRowsInfo) {
|
||||
const bottomRows = (
|
||||
topRowNumber <= worksheet.rowCount ?
|
||||
exceljs.copyRows(worksheet, topRowNumber, worksheet.rowCount) :
|
||||
null);
|
||||
exceljs.pasteRows(worksheet, topRowNumber, copiedRowsInfo);
|
||||
if (bottomRows) {
|
||||
exceljs.pasteRows(worksheet, topRowNumber + copiedRowsInfo.rows.length, bottomRows);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 列をコピーします。
|
||||
* @param {ExcelJS.Worksheet} worksheet ワークシート
|
||||
* @param {number | string} leftColumn コピー元の開始列の列番号(1から開始)または列ラベル。終了列の引数を省略して、代わりに "A:B" の形式でコピー元の列の範囲を指定することも可能。
|
||||
* @param {number | string} [rightColumn] コピー元の終了列の列番号(1から開始)または列ラベル。省略時は開始列と同じとみなされます(開始列を "A:B" の形式で指定された場合を除く)。
|
||||
* @returns {pvc.lib.exceljsUtil.CopiedColumnsInfo} 列のコピー情報
|
||||
*/
|
||||
copyColumns: function (worksheet, leftColumn, rightColumn) {
|
||||
if (rightColumn == null) {
|
||||
rightColumn = leftColumn;
|
||||
if (typeof leftColumn === 'string') {
|
||||
const sp = leftColumn.split(':');
|
||||
if (sp.length === 2) {
|
||||
leftColumn = sp[0];
|
||||
rightColumn = sp[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const leftColumnNumber = ((typeof leftColumn === 'number') ? leftColumn : exceljs.columnLetterToColumnNumber(leftColumn));
|
||||
const rightColumnNumber = ((typeof rightColumn === 'number') ? rightColumn : exceljs.columnLetterToColumnNumber(rightColumn));
|
||||
|
||||
if (leftColumnNumber < 0 || rightColumnNumber < leftColumnNumber) {
|
||||
throw new Error('コピー元の領域とが不正です。');
|
||||
}
|
||||
|
||||
// コピー元の領域の情報を収集
|
||||
const columns = [];
|
||||
for (let c = leftColumnNumber; c <= rightColumnNumber; c++) {
|
||||
const column = worksheet.getColumn(c);
|
||||
const cells = [];
|
||||
for (let r = 1; r <= worksheet.rowCount; r++) {
|
||||
const cell = worksheet.getRow(r).getCell(c);
|
||||
cells.push({
|
||||
value: cell.value,
|
||||
style: cell.style,
|
||||
});
|
||||
}
|
||||
columns.push({
|
||||
cells: cells,
|
||||
width: column.width,
|
||||
style: column.style,
|
||||
});
|
||||
}
|
||||
|
||||
// コピー元の領域の内部に収まるマージを収集
|
||||
const merges = deepCopyObject(getWorksheetMerges(worksheet).filter(function (merge) {
|
||||
return (leftColumnNumber <= merge.left && merge.right <= rightColumnNumber);
|
||||
}).map(function (merge) {
|
||||
return {
|
||||
top: merge.top,
|
||||
right: merge.right - leftColumnNumber,
|
||||
bottom: merge.bottom,
|
||||
left: merge.left - leftColumnNumber,
|
||||
};
|
||||
}));
|
||||
|
||||
return {
|
||||
columns: columns,
|
||||
merges: merges
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* 指定された開始列を起点に、コピーした列を貼り付けます。
|
||||
* コピー元の領域と領域外の両方にまたがるセルのマージは貼り付けされません。
|
||||
* コピー先の領域を一部でも含むマージは全て解除されます。
|
||||
* @param {ExcelJS.Worksheet} worksheet ワークシート
|
||||
* @param {number | string} leftColumn コピー先の開始列の列番号(1から開始)または列ラベル
|
||||
* @param {pvc.lib.exceljsUtil.CopiedColumnsInfo} copiedColumnsInfo 列のコピー情報
|
||||
*/
|
||||
pasteColumns: function (worksheet, leftColumn, copiedColumnsInfo) {
|
||||
const leftColumnNumber = ((typeof leftColumn === 'number') ? leftColumn : exceljs.columnLetterToColumnNumber(leftColumn));
|
||||
const rightColumnNumber = leftColumnNumber + copiedColumnsInfo.columns.length - 1;
|
||||
|
||||
if (leftColumnNumber < 0) {
|
||||
throw new Error('コピー先の領域とが不正です。');
|
||||
}
|
||||
|
||||
// コピー先の列のマージを解除(コピー先の領域を一部でも含むマージは全て解除)
|
||||
getWorksheetMerges(worksheet).filter(function (merge) {
|
||||
return (leftColumnNumber <= merge.right && merge.left <= rightColumnNumber);
|
||||
}).forEach(function (merge) {
|
||||
worksheet.unMergeCells(merge.range);
|
||||
});
|
||||
|
||||
// マージをペースト
|
||||
copiedColumnsInfo.merges.forEach(function (mergeInfo) {
|
||||
worksheet.mergeCells(
|
||||
mergeInfo.top,
|
||||
leftColumnNumber + mergeInfo.left,
|
||||
mergeInfo.bottom,
|
||||
leftColumnNumber + mergeInfo.right);
|
||||
});
|
||||
|
||||
// セルをペースト
|
||||
copiedColumnsInfo.columns.forEach(function (columnInfo, i) {
|
||||
const column = worksheet.getColumn(leftColumnNumber + i);
|
||||
column.width = columnInfo.width;
|
||||
column.style = columnInfo.style;
|
||||
for (let r = 1; r <= worksheet.rowCount; r++) {
|
||||
const cell = worksheet.getRow(r).getCell(leftColumnNumber + i);
|
||||
const cellInfo = columnInfo.cells[r - 1];
|
||||
if (cellInfo) {
|
||||
cell.value = cellInfo.value;
|
||||
cell.style = cellInfo.style;
|
||||
} else {
|
||||
exceljs.clearCell(cell);
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* 指定された開始列を起点に、コピーした列を挿入します。
|
||||
* コピー元の領域と領域外の両方にまたがるセルのマージは貼り付けされません。
|
||||
* @param {ExcelJS.Worksheet} worksheet ワークシート
|
||||
* @param {number | string} leftColumn コピー先の開始列の列番号(1から開始)または列ラベル
|
||||
* @param {pvc.lib.exceljsUtil.CopiedColumnsInfo} copiedRowsInfo 列のコピー情報
|
||||
*/
|
||||
insertColumns: function (worksheet, leftColumn, copiedRowsInfo) {
|
||||
const leftColumnNumber = ((typeof leftColumn === 'number') ? leftColumn : exceljs.columnLetterToColumnNumber(leftColumn));
|
||||
const rightColumns = (
|
||||
leftColumnNumber <= worksheet.columnCount ?
|
||||
exceljs.copyColumns(worksheet, leftColumnNumber, worksheet.columnCount) :
|
||||
null);
|
||||
exceljs.pasteColumns(worksheet, leftColumnNumber, copiedRowsInfo);
|
||||
if (rightColumns) {
|
||||
exceljs.pasteColumns(worksheet, leftColumnNumber + copiedRowsInfo.columns.length, rightColumns);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* セルをクリアします。
|
||||
* @param {ExcelJS.Cell} cell セル
|
||||
*/
|
||||
clearCell: function (cell) {
|
||||
cell.value = null;
|
||||
/// @ts-ignore
|
||||
cell.style = cell._mergeStyle(cell._row.style, cell._column.style, {});
|
||||
},
|
||||
|
||||
/**
|
||||
* 列ラベルから列番号(1から開始)を取得します。
|
||||
* @param {string} columnLetter 列ラベル
|
||||
* @return {number} 列番号(1から開始)
|
||||
*/
|
||||
columnLetterToColumnNumber: function (columnLetter) {
|
||||
const letter = columnLetter.toUpperCase();
|
||||
const l = letter.length;
|
||||
const charCodeA = 65;
|
||||
let result = 0;
|
||||
for (let i = 0, j = l - 1; i < l; i++, j--) {
|
||||
result += (letter.charCodeAt(j) - charCodeA + 1) * (i === 0 ? 1 : Math.pow(26, i));
|
||||
}
|
||||
return result;
|
||||
},
|
||||
|
||||
/**
|
||||
* 日付のセルの値を作成します。
|
||||
* @param {Date} date
|
||||
* @returns {any}
|
||||
*/
|
||||
createDateCellValue: function (date) {
|
||||
// UTC にしないと正しく Excel に反映されない
|
||||
return new Date(Date.UTC(date.getFullYear(), date.getMonth(), date.getDate(), date.getHours(), date.getMinutes(), date.getSeconds()));
|
||||
},
|
||||
|
||||
deepCopyObject: deepCopyObject,
|
||||
};
|
||||
|
||||
/**
|
||||
* ワークシートのマージを取得します。
|
||||
* @param {ExcelJS.Worksheet} worksheet ワークシート
|
||||
*/
|
||||
function getWorksheetMerges(worksheet) {
|
||||
// 非公式のメンバー _merges を使用
|
||||
// @ts-ignore
|
||||
const mergesDic = worksheet._merges;
|
||||
return Object.keys(mergesDic).map(function (address) {
|
||||
return mergesDic[address];
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* オブジェクのコピーします。ディープコピーとなります。
|
||||
* @template T
|
||||
* @param {T} obj
|
||||
* @returns {T}
|
||||
*/
|
||||
function deepCopyObject(obj) {
|
||||
return copyObject(obj);
|
||||
|
||||
//@ts-ignore
|
||||
function copyObject(obj) {
|
||||
return (
|
||||
obj == null ? null :
|
||||
Array.isArray(obj) ? copyArray(obj) :
|
||||
isDate(obj) ? copyDate(obj) :
|
||||
isDic(obj) ? copyDic(obj) :
|
||||
obj);
|
||||
}
|
||||
|
||||
//@ts-ignore
|
||||
function copyArray(array) {
|
||||
//@ts-ignore
|
||||
return array.map(function (item) {
|
||||
return copyObject(item);
|
||||
});
|
||||
}
|
||||
|
||||
//@ts-ignore
|
||||
function isDate(obj) {
|
||||
return (obj != null && Object.prototype.toString.call(obj) === '[object Date]');
|
||||
}
|
||||
|
||||
//@ts-ignore
|
||||
function copyDate(date) {
|
||||
return (isNaN(date) ? null : new Date(date.getTime()));
|
||||
}
|
||||
|
||||
//@ts-ignore
|
||||
function isDic(obj) {
|
||||
return (obj != null && typeof obj === 'object');
|
||||
}
|
||||
|
||||
//@ts-ignore
|
||||
function copyDic(dic) {
|
||||
let result = {};
|
||||
for (let key in dic) {
|
||||
//@ts-ignore
|
||||
result[key] = copyObject(dic[key]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return exceljs;
|
||||
}());
|
||||
})();
|
||||
3
src/2歳以上日誌/FileSaver.min.js
vendored
Normal file
3
src/2歳以上日誌/FileSaver.min.js
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
(function(a,b){if("function"==typeof define&&define.amd)define([],b);else if("undefined"!=typeof exports)b();else{b(),a.FileSaver={exports:{}}.exports}})(this,function(){"use strict";function b(a,b){return"undefined"==typeof b?b={autoBom:!1}:"object"!=typeof b&&(console.warn("Deprecated: Expected third argument to be a object"),b={autoBom:!b}),b.autoBom&&/^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(a.type)?new Blob(["\uFEFF",a],{type:a.type}):a}function c(a,b,c){var d=new XMLHttpRequest;d.open("GET",a),d.responseType="blob",d.onload=function(){g(d.response,b,c)},d.onerror=function(){console.error("could not download file")},d.send()}function d(a){var b=new XMLHttpRequest;b.open("HEAD",a,!1);try{b.send()}catch(a){}return 200<=b.status&&299>=b.status}function e(a){try{a.dispatchEvent(new MouseEvent("click"))}catch(c){var b=document.createEvent("MouseEvents");b.initMouseEvent("click",!0,!0,window,0,0,0,80,20,!1,!1,!1,!1,0,null),a.dispatchEvent(b)}}var f="object"==typeof window&&window.window===window?window:"object"==typeof self&&self.self===self?self:"object"==typeof global&&global.global===global?global:void 0,a=/Macintosh/.test(navigator.userAgent)&&/AppleWebKit/.test(navigator.userAgent)&&!/Safari/.test(navigator.userAgent),g=f.saveAs||("object"!=typeof window||window!==f?function(){}:"download"in HTMLAnchorElement.prototype&&!a?function(b,g,h){var i=f.URL||f.webkitURL,j=document.createElement("a");g=g||b.name||"download",j.download=g,j.rel="noopener","string"==typeof b?(j.href=b,j.origin===location.origin?e(j):d(j.href)?c(b,g,h):e(j,j.target="_blank")):(j.href=i.createObjectURL(b),setTimeout(function(){i.revokeObjectURL(j.href)},4E4),setTimeout(function(){e(j)},0))}:"msSaveOrOpenBlob"in navigator?function(f,g,h){if(g=g||f.name||"download","string"!=typeof f)navigator.msSaveOrOpenBlob(b(f,h),g);else if(d(f))c(f,g,h);else{var i=document.createElement("a");i.href=f,i.target="_blank",setTimeout(function(){e(i)})}}:function(b,d,e,g){if(g=g||open("","_blank"),g&&(g.document.title=g.document.body.innerText="downloading..."),"string"==typeof b)return c(b,d,e);var h="application/octet-stream"===b.type,i=/constructor/i.test(f.HTMLElement)||f.safari,j=/CriOS\/[\d]+/.test(navigator.userAgent);if((j||h&&i||a)&&"undefined"!=typeof FileReader){var k=new FileReader;k.onloadend=function(){var a=k.result;a=j?a:a.replace(/^data:[^;]*;/,"data:attachment/file;"),g?g.location.href=a:location=a,g=null},k.readAsDataURL(b)}else{var l=f.URL||f.webkitURL,m=l.createObjectURL(b);g?g.location=m:location.href=m,g=null,setTimeout(function(){l.revokeObjectURL(m)},4E4)}});f.saveAs=g.saveAs=g,"undefined"!=typeof module&&(module.exports=g)});
|
||||
|
||||
//# sourceMappingURL=FileSaver.min.js.map
|
||||
1
src/2歳以上日誌/KintoneRestAPIClient.min.js
vendored
Normal file
1
src/2歳以上日誌/KintoneRestAPIClient.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
3
src/2歳以上日誌/exceljs.min.js
vendored
Normal file
3
src/2歳以上日誌/exceljs.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
2433
src/2歳以上日誌/kuc.min.js
vendored
Normal file
2433
src/2歳以上日誌/kuc.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
@@ -2,15 +2,13 @@
|
||||
"use strict";
|
||||
const APP_ENV = env["2歳以上日誌出力用"];
|
||||
|
||||
kintone.events.on("app.record.index.show", (event) => {
|
||||
const headerSpace = getHeaderSpace('single-label-line');
|
||||
addApproveFlowAction();
|
||||
|
||||
kintone.events.on("app.record.detail.show", (event) => {
|
||||
const headerSpace = getHeaderSpace('', true);
|
||||
|
||||
const elements = createBtnGroupArea('extract-action-area', '日誌作成', handleButtonClick, {
|
||||
btnElId: 'extract-btn',
|
||||
yearElId: 'extract-year',
|
||||
monthElId: 'extract-month',
|
||||
dateElId: 'extract-date',
|
||||
defaultThisMonth: true,
|
||||
})
|
||||
|
||||
if (!elements) {
|
||||
@@ -20,8 +18,117 @@
|
||||
headerSpace.appendChild(elements['extract-action-area']);
|
||||
});
|
||||
|
||||
function handleButtonClick(e, { year, month, date }) {
|
||||
const fileName = getExcelName(APP_ENV, year + month + date);
|
||||
console.log(fileName);
|
||||
async function handleButtonClick(e) {
|
||||
loading(true, '帳票出力中...');
|
||||
showError(false);
|
||||
const api = new KintoneRestAPIClient();
|
||||
|
||||
// 本アプリからデータを読み取る
|
||||
const record = kintone.app.record.get().record;
|
||||
if (!record) {
|
||||
// エラー
|
||||
loading(false);
|
||||
return e;
|
||||
}
|
||||
|
||||
const dateStr = record['登園日'].value;
|
||||
if (!dateStr) {
|
||||
showError('登園日が設定されていません');
|
||||
loading(false);
|
||||
return e;
|
||||
}
|
||||
const date = new Date(dateStr);
|
||||
|
||||
const excelName = APP_ENV.excelName;
|
||||
await createExcelAndDownload({
|
||||
api,
|
||||
excelName,
|
||||
exportName: getExcelName(excelName, record['学年'].value + '_' + getFormatDateString(date).replaceAll('-', '')),
|
||||
bizLogic: writeExcel(record, getJapaneseEraDate(date)),
|
||||
});
|
||||
loading(false);
|
||||
}
|
||||
|
||||
function writeExcel(record, { era, year, month, day }) {
|
||||
return async (api, worksheet) => {
|
||||
const baseCells = findCellsInfo(worksheet, ['園長', '行 事', '主な活動', 'クラス名']);
|
||||
fillPage1(baseCells, worksheet);
|
||||
fillPage2(baseCells, worksheet);
|
||||
}
|
||||
|
||||
function fillPage1(baseCells, worksheet) {
|
||||
fillApproveArea(baseCells, worksheet, record);
|
||||
|
||||
updateCell(worksheet, { base: { row: 1, col: 1 } }, `${era} ${year}年 ${month}月 ${day}日 ${record['曜日'].value}日 天候(${record['天気']?.value || ' '})`);
|
||||
updateCell(worksheet, { base: baseCells['行 事'][0], right: 1 }, record['行事'].value);
|
||||
|
||||
const headerRow = baseCells['主な活動'][0].row;
|
||||
const cols = getLabelColsMapping(worksheet, headerRow, ['活動', '子どもの様子', '反省評価']);
|
||||
const row = headerRow + 1;
|
||||
const inputMergedData = getMergedInfo(worksheet, { row, col: baseCells['主な活動'][0].col });
|
||||
const inputMergedRowCnt = inputMergedData.bottom - inputMergedData.top + 1;
|
||||
|
||||
for (let i = 0; i < 4; i++) {
|
||||
cols.forEach(col => {
|
||||
updateCell(worksheet, { base: { row: row + i * inputMergedRowCnt, col: col.index } }, record[col.field + (i + 1)]?.value);
|
||||
});
|
||||
}
|
||||
|
||||
worksheet.getRow(baseCells['クラス名'][0].row - 2).addPageBreak();
|
||||
}
|
||||
|
||||
function fillPage2(baseCells, worksheet) {
|
||||
const baseForDetail = baseCells['クラス名'][0];
|
||||
const records = record['園児別テーブル'].value.map((e) => e.value);
|
||||
const pageSize = 10;
|
||||
const totalPages = Math.ceil(records.length / pageSize);
|
||||
const inputMergedObject = getMergedInfo(worksheet, { row: baseForDetail.row + 1, col: baseForDetail.col });
|
||||
const inputMergedRowCnt = inputMergedObject.bottom - inputMergedObject.top + 1;
|
||||
|
||||
// make new copy
|
||||
if (totalPages > 1) {
|
||||
const lastPage = 1;
|
||||
const copyPageRowStart = baseForDetail.row - 1;
|
||||
const copyPageRowEnd = baseForDetail.row + (pageSize * inputMergedRowCnt);
|
||||
|
||||
createCopyFromTemplate(worksheet, {
|
||||
startPage: lastPage + 1,
|
||||
totalPages,
|
||||
copyPageRowStart,
|
||||
copyPageRowEnd,
|
||||
callback: (newPage, rowCount) => {
|
||||
['クラス名'].forEach((label) => {
|
||||
const last = baseCells[label][newPage - 2];
|
||||
baseCells[label].push({
|
||||
col: last.col,
|
||||
row: last.row + rowCount
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const cols = getLabelColsMapping(worksheet, baseForDetail.row, ['クラス名', '名前', '子どもの様子', '反省評価_園児別テーブル']);
|
||||
for (let i = 0; i < totalPages; i++) {
|
||||
const childLabelCell = baseCells['クラス名'][i];
|
||||
let currentRow = childLabelCell.row + 1;
|
||||
|
||||
for (let j = 0; j < pageSize; j++) {
|
||||
const index = i * pageSize + j;
|
||||
const record = records[index];
|
||||
if (!record) {
|
||||
break;
|
||||
}
|
||||
const row = worksheet.getRow(currentRow);
|
||||
cols.forEach(col => {
|
||||
updateCell(row, { base: { row: currentRow, col: col.index } }, record[col.field].value);
|
||||
});
|
||||
currentRow += inputMergedRowCnt;
|
||||
}
|
||||
|
||||
worksheet.getRow(childLabelCell.row + pageSize * inputMergedRowCnt).addPageBreak();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
})();
|
||||
6
src/2歳以上日誌/main.mobile.js
Normal file
6
src/2歳以上日誌/main.mobile.js
Normal file
@@ -0,0 +1,6 @@
|
||||
(function () {
|
||||
"use strict";
|
||||
|
||||
addApproveFlowAction(true);
|
||||
|
||||
})();
|
||||
496
src/2歳以上日誌/pvc.lib.exceljsUtil.js
Normal file
496
src/2歳以上日誌/pvc.lib.exceljsUtil.js
Normal file
@@ -0,0 +1,496 @@
|
||||
/** @copyright 2018 Planning Village Corporation Co., Ltd. */
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
// [IE11] Polyfill of Object.values
|
||||
if (!Object.values) {
|
||||
const ownKeys = (
|
||||
(typeof Reflect === 'object' && typeof Reflect.ownKeys === 'function') ? Reflect.ownKeys :
|
||||
// @ts-ignore
|
||||
(typeof Object.getOwnPropertySymbols === 'function') ? (function (O) {
|
||||
// @ts-ignore
|
||||
return Object.getOwnPropertyNames(O).concat(Object.getOwnPropertySymbols(O));
|
||||
}) :
|
||||
Object.getOwnPropertyNames);
|
||||
// @ts-ignore
|
||||
const reduce = Function.bind.call(Function.call, Array.prototype.reduce);
|
||||
// @ts-ignore
|
||||
const isEnumerable = Function.bind.call(Function.call, Object.prototype.propertyIsEnumerable);
|
||||
// @ts-ignore
|
||||
const concat = Function.bind.call(Function.call, Array.prototype.concat);
|
||||
//@ts-ignore
|
||||
Object.values = function values(O) {
|
||||
//@ts-ignore
|
||||
return reduce(ownKeys(O), function (v, k) {
|
||||
return concat(v, typeof k === 'string' && isEnumerable(O, k) ? [O[k]] : [])
|
||||
}, [])
|
||||
};
|
||||
}
|
||||
|
||||
// [IE11] Polyfill of Number.isNaN
|
||||
if (!Number.isNaN) {
|
||||
Number.isNaN = function (value) {
|
||||
return value !== null && (value != value || +value != value);
|
||||
};
|
||||
}
|
||||
|
||||
// [IE11] Polyfill of String.prototype.startsWith
|
||||
if (!String.prototype.startsWith) {
|
||||
Object.defineProperty(String.prototype, 'startsWith', {
|
||||
//@ts-ignore
|
||||
value: function (search, rawPos) {
|
||||
var pos = rawPos > 0 ? rawPos | 0 : 0;
|
||||
return this.substring(pos, pos + search.length) === search;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// [IE11] Polyfill of String.prototype.includes
|
||||
if (!String.prototype.includes) {
|
||||
String.prototype.includes = function (search, start) {
|
||||
'use strict';
|
||||
//@ts-ignore
|
||||
if (search instanceof RegExp) {
|
||||
throw TypeError('first argument must not be a RegExp');
|
||||
}
|
||||
if (start === undefined) {
|
||||
start = 0;
|
||||
}
|
||||
return this.indexOf(search, start) !== -1;
|
||||
};
|
||||
}
|
||||
|
||||
// [IE11] Polyfill of Array.prototype.findIndex
|
||||
if (!Array.prototype.findIndex) {
|
||||
// @ts-ignore
|
||||
Array.prototype.findIndex = function (predicate) {
|
||||
if (this === null) {
|
||||
throw new TypeError('Array.prototype.findIndex called on null or undefined');
|
||||
}
|
||||
if (typeof predicate !== 'function') {
|
||||
throw new TypeError('predicate must be a function');
|
||||
}
|
||||
var list = Object(this);
|
||||
var length = list.length >>> 0;
|
||||
var thisArg = arguments[1];
|
||||
var value;
|
||||
|
||||
for (var i = 0; i < length; i++) {
|
||||
value = list[i];
|
||||
if (predicate.call(thisArg, value, i, list)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
};
|
||||
}
|
||||
|
||||
//@ts-ignore
|
||||
window.pvc = window.pvc || {};
|
||||
//@ts-ignore
|
||||
window.pvc.lib = window.pvc.lib || {};
|
||||
//@ts-ignore
|
||||
window.pvc.lib.exceljsUtil = (function () {
|
||||
const exceljs = {
|
||||
/**
|
||||
* ワークブックの blob を読み取ります。
|
||||
* @param {Blob} blob Blob
|
||||
* @return {Promise<ExcelJS.Workbook>} ワークブック
|
||||
*/
|
||||
loadWorkbookBlob: function (blob) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
var reader = new FileReader();
|
||||
reader.onload = function (e) {
|
||||
// @ts-ignore
|
||||
resolve(e.target.result);
|
||||
};
|
||||
reader.onerror = function (e) {
|
||||
reject(e);
|
||||
}
|
||||
reader.onabort = function (e) {
|
||||
reject(e);
|
||||
}
|
||||
reader.readAsArrayBuffer(blob);
|
||||
}).then(function (arrayBuffer) {
|
||||
// 非公式のメンバー load を使用
|
||||
// @ts-ignore
|
||||
return new ExcelJS.Workbook().xlsx.load(arrayBuffer);
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* ワークブックを Blob に変換します。
|
||||
* @param {ExcelJS.Workbook} workbook ワークブック
|
||||
* @return {Promise<Blob>} Blob
|
||||
*/
|
||||
saveWorkbookToBlob: function (workbook) {
|
||||
// writeBuffer の戻り値 ExcelJS.Buffer はブラウザ環境では Uint8Array となる
|
||||
return workbook.xlsx.writeBuffer().then(function (ua) {
|
||||
return new Blob([ua], {
|
||||
type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* 行をコピーします。
|
||||
* @param {ExcelJS.Worksheet} worksheet ワークシート
|
||||
* @param {number} topRowNumber コピー元の開始行番号(1から開始)
|
||||
* @param {number} [bottomRowNumber] コピー元の終了行番号(1から開始)。省略時は開始行番号と同じ値となります。
|
||||
* @returns {pvc.lib.exceljsUtil.CopiedRowsInfo} 行のコピー情報
|
||||
*/
|
||||
copyRows: function (worksheet, topRowNumber, bottomRowNumber) {
|
||||
const _bottomRowNumber = (bottomRowNumber == null ? topRowNumber : bottomRowNumber);
|
||||
|
||||
if (topRowNumber < 0 || _bottomRowNumber < topRowNumber) {
|
||||
throw new Error('コピー元の領域とが不正です。');
|
||||
}
|
||||
|
||||
// コピー元の領域の情報を収集
|
||||
const rows = [];
|
||||
for (let r = topRowNumber; r <= _bottomRowNumber; r++) {
|
||||
const row = worksheet.getRow(r);
|
||||
const cells = [];
|
||||
for (let c = 1; c <= worksheet.columnCount; c++) {
|
||||
const cell = row.getCell(c);
|
||||
cells.push({
|
||||
value: cell.value,
|
||||
style: cell.style,
|
||||
});
|
||||
}
|
||||
rows.push({
|
||||
cells: cells,
|
||||
height: row.height,
|
||||
// 非公式のメンバー style を使用
|
||||
// @ts-ignore
|
||||
style: row.style,
|
||||
});
|
||||
}
|
||||
|
||||
// コピー元の領域の内部に収まるマージを収集
|
||||
const merges = deepCopyObject(getWorksheetMerges(worksheet).filter(function (merge) {
|
||||
return (topRowNumber <= merge.top && merge.bottom <= _bottomRowNumber);
|
||||
}).map(function (merge) {
|
||||
return {
|
||||
top: merge.top - topRowNumber,
|
||||
right: merge.right,
|
||||
bottom: merge.bottom - topRowNumber,
|
||||
left: merge.left,
|
||||
};
|
||||
}));
|
||||
|
||||
return deepCopyObject({
|
||||
rows: rows,
|
||||
merges: merges
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* 指定された開始行を起点に、コピーした行を貼り付けます。
|
||||
* コピー元の領域と領域外の両方にまたがるセルのマージは貼り付けされません。
|
||||
* コピー先の領域を一部でも含むマージは全て解除されます。
|
||||
* @param {ExcelJS.Worksheet} worksheet ワークシート
|
||||
* @param {number} topRowNumber コピー先の開始行番号(1から開始)
|
||||
* @param {pvc.lib.exceljsUtil.CopiedRowsInfo} copiedRowsInfo 行のコピー情報
|
||||
*/
|
||||
pasteRows: function (worksheet, topRowNumber, copiedRowsInfo) {
|
||||
const bottomRowNumber = topRowNumber + copiedRowsInfo.rows.length - 1;
|
||||
|
||||
if (topRowNumber < 0) {
|
||||
throw new Error('コピー先の領域とが不正です。');
|
||||
}
|
||||
|
||||
// コピー先の行のマージを解除(コピー先の領域を一部でも含むマージは全て解除)
|
||||
getWorksheetMerges(worksheet).filter(function (merge) {
|
||||
return (topRowNumber <= merge.bottom && merge.top <= bottomRowNumber);
|
||||
}).forEach(function (merge) {
|
||||
worksheet.unMergeCells(merge.range);
|
||||
});
|
||||
|
||||
// マージをペースト
|
||||
copiedRowsInfo.merges.forEach(function (mergeInfo) {
|
||||
worksheet.mergeCells(
|
||||
topRowNumber + mergeInfo.top,
|
||||
mergeInfo.left,
|
||||
topRowNumber + mergeInfo.bottom,
|
||||
mergeInfo.right);
|
||||
});
|
||||
|
||||
// セルをペースト
|
||||
copiedRowsInfo.rows.forEach(function (rowInfo, i) {
|
||||
const row = worksheet.getRow(topRowNumber + i);
|
||||
row.height = rowInfo.height;
|
||||
// 非公式のメンバー style を使用
|
||||
// @ts-ignore
|
||||
row.style = rowInfo.style;
|
||||
for (let c = 1; c <= worksheet.columnCount; c++) {
|
||||
const cell = row.getCell(c);
|
||||
const cellInfo = rowInfo.cells[c - 1];
|
||||
if (cellInfo) {
|
||||
cell.value = cellInfo.value;
|
||||
cell.style = cellInfo.style;
|
||||
} else {
|
||||
exceljs.clearCell(cell);
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* 指定された開始行を起点に、コピーした行を挿入します。
|
||||
* コピー元の領域と領域外の両方にまたがるセルのマージは貼り付けされません。
|
||||
* @param {ExcelJS.Worksheet} worksheet ワークシート
|
||||
* @param {number} topRowNumber コピー先の開始行番号(1から開始)
|
||||
* @param {pvc.lib.exceljsUtil.CopiedRowsInfo} copiedRowsInfo 行のコピー情報
|
||||
*/
|
||||
insertRows: function (worksheet, topRowNumber, copiedRowsInfo) {
|
||||
const bottomRows = (
|
||||
topRowNumber <= worksheet.rowCount ?
|
||||
exceljs.copyRows(worksheet, topRowNumber, worksheet.rowCount) :
|
||||
null);
|
||||
exceljs.pasteRows(worksheet, topRowNumber, copiedRowsInfo);
|
||||
if (bottomRows) {
|
||||
exceljs.pasteRows(worksheet, topRowNumber + copiedRowsInfo.rows.length, bottomRows);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 列をコピーします。
|
||||
* @param {ExcelJS.Worksheet} worksheet ワークシート
|
||||
* @param {number | string} leftColumn コピー元の開始列の列番号(1から開始)または列ラベル。終了列の引数を省略して、代わりに "A:B" の形式でコピー元の列の範囲を指定することも可能。
|
||||
* @param {number | string} [rightColumn] コピー元の終了列の列番号(1から開始)または列ラベル。省略時は開始列と同じとみなされます(開始列を "A:B" の形式で指定された場合を除く)。
|
||||
* @returns {pvc.lib.exceljsUtil.CopiedColumnsInfo} 列のコピー情報
|
||||
*/
|
||||
copyColumns: function (worksheet, leftColumn, rightColumn) {
|
||||
if (rightColumn == null) {
|
||||
rightColumn = leftColumn;
|
||||
if (typeof leftColumn === 'string') {
|
||||
const sp = leftColumn.split(':');
|
||||
if (sp.length === 2) {
|
||||
leftColumn = sp[0];
|
||||
rightColumn = sp[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const leftColumnNumber = ((typeof leftColumn === 'number') ? leftColumn : exceljs.columnLetterToColumnNumber(leftColumn));
|
||||
const rightColumnNumber = ((typeof rightColumn === 'number') ? rightColumn : exceljs.columnLetterToColumnNumber(rightColumn));
|
||||
|
||||
if (leftColumnNumber < 0 || rightColumnNumber < leftColumnNumber) {
|
||||
throw new Error('コピー元の領域とが不正です。');
|
||||
}
|
||||
|
||||
// コピー元の領域の情報を収集
|
||||
const columns = [];
|
||||
for (let c = leftColumnNumber; c <= rightColumnNumber; c++) {
|
||||
const column = worksheet.getColumn(c);
|
||||
const cells = [];
|
||||
for (let r = 1; r <= worksheet.rowCount; r++) {
|
||||
const cell = worksheet.getRow(r).getCell(c);
|
||||
cells.push({
|
||||
value: cell.value,
|
||||
style: cell.style,
|
||||
});
|
||||
}
|
||||
columns.push({
|
||||
cells: cells,
|
||||
width: column.width,
|
||||
style: column.style,
|
||||
});
|
||||
}
|
||||
|
||||
// コピー元の領域の内部に収まるマージを収集
|
||||
const merges = deepCopyObject(getWorksheetMerges(worksheet).filter(function (merge) {
|
||||
return (leftColumnNumber <= merge.left && merge.right <= rightColumnNumber);
|
||||
}).map(function (merge) {
|
||||
return {
|
||||
top: merge.top,
|
||||
right: merge.right - leftColumnNumber,
|
||||
bottom: merge.bottom,
|
||||
left: merge.left - leftColumnNumber,
|
||||
};
|
||||
}));
|
||||
|
||||
return {
|
||||
columns: columns,
|
||||
merges: merges
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* 指定された開始列を起点に、コピーした列を貼り付けます。
|
||||
* コピー元の領域と領域外の両方にまたがるセルのマージは貼り付けされません。
|
||||
* コピー先の領域を一部でも含むマージは全て解除されます。
|
||||
* @param {ExcelJS.Worksheet} worksheet ワークシート
|
||||
* @param {number | string} leftColumn コピー先の開始列の列番号(1から開始)または列ラベル
|
||||
* @param {pvc.lib.exceljsUtil.CopiedColumnsInfo} copiedColumnsInfo 列のコピー情報
|
||||
*/
|
||||
pasteColumns: function (worksheet, leftColumn, copiedColumnsInfo) {
|
||||
const leftColumnNumber = ((typeof leftColumn === 'number') ? leftColumn : exceljs.columnLetterToColumnNumber(leftColumn));
|
||||
const rightColumnNumber = leftColumnNumber + copiedColumnsInfo.columns.length - 1;
|
||||
|
||||
if (leftColumnNumber < 0) {
|
||||
throw new Error('コピー先の領域とが不正です。');
|
||||
}
|
||||
|
||||
// コピー先の列のマージを解除(コピー先の領域を一部でも含むマージは全て解除)
|
||||
getWorksheetMerges(worksheet).filter(function (merge) {
|
||||
return (leftColumnNumber <= merge.right && merge.left <= rightColumnNumber);
|
||||
}).forEach(function (merge) {
|
||||
worksheet.unMergeCells(merge.range);
|
||||
});
|
||||
|
||||
// マージをペースト
|
||||
copiedColumnsInfo.merges.forEach(function (mergeInfo) {
|
||||
worksheet.mergeCells(
|
||||
mergeInfo.top,
|
||||
leftColumnNumber + mergeInfo.left,
|
||||
mergeInfo.bottom,
|
||||
leftColumnNumber + mergeInfo.right);
|
||||
});
|
||||
|
||||
// セルをペースト
|
||||
copiedColumnsInfo.columns.forEach(function (columnInfo, i) {
|
||||
const column = worksheet.getColumn(leftColumnNumber + i);
|
||||
column.width = columnInfo.width;
|
||||
column.style = columnInfo.style;
|
||||
for (let r = 1; r <= worksheet.rowCount; r++) {
|
||||
const cell = worksheet.getRow(r).getCell(leftColumnNumber + i);
|
||||
const cellInfo = columnInfo.cells[r - 1];
|
||||
if (cellInfo) {
|
||||
cell.value = cellInfo.value;
|
||||
cell.style = cellInfo.style;
|
||||
} else {
|
||||
exceljs.clearCell(cell);
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* 指定された開始列を起点に、コピーした列を挿入します。
|
||||
* コピー元の領域と領域外の両方にまたがるセルのマージは貼り付けされません。
|
||||
* @param {ExcelJS.Worksheet} worksheet ワークシート
|
||||
* @param {number | string} leftColumn コピー先の開始列の列番号(1から開始)または列ラベル
|
||||
* @param {pvc.lib.exceljsUtil.CopiedColumnsInfo} copiedRowsInfo 列のコピー情報
|
||||
*/
|
||||
insertColumns: function (worksheet, leftColumn, copiedRowsInfo) {
|
||||
const leftColumnNumber = ((typeof leftColumn === 'number') ? leftColumn : exceljs.columnLetterToColumnNumber(leftColumn));
|
||||
const rightColumns = (
|
||||
leftColumnNumber <= worksheet.columnCount ?
|
||||
exceljs.copyColumns(worksheet, leftColumnNumber, worksheet.columnCount) :
|
||||
null);
|
||||
exceljs.pasteColumns(worksheet, leftColumnNumber, copiedRowsInfo);
|
||||
if (rightColumns) {
|
||||
exceljs.pasteColumns(worksheet, leftColumnNumber + copiedRowsInfo.columns.length, rightColumns);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* セルをクリアします。
|
||||
* @param {ExcelJS.Cell} cell セル
|
||||
*/
|
||||
clearCell: function (cell) {
|
||||
cell.value = null;
|
||||
/// @ts-ignore
|
||||
cell.style = cell._mergeStyle(cell._row.style, cell._column.style, {});
|
||||
},
|
||||
|
||||
/**
|
||||
* 列ラベルから列番号(1から開始)を取得します。
|
||||
* @param {string} columnLetter 列ラベル
|
||||
* @return {number} 列番号(1から開始)
|
||||
*/
|
||||
columnLetterToColumnNumber: function (columnLetter) {
|
||||
const letter = columnLetter.toUpperCase();
|
||||
const l = letter.length;
|
||||
const charCodeA = 65;
|
||||
let result = 0;
|
||||
for (let i = 0, j = l - 1; i < l; i++, j--) {
|
||||
result += (letter.charCodeAt(j) - charCodeA + 1) * (i === 0 ? 1 : Math.pow(26, i));
|
||||
}
|
||||
return result;
|
||||
},
|
||||
|
||||
/**
|
||||
* 日付のセルの値を作成します。
|
||||
* @param {Date} date
|
||||
* @returns {any}
|
||||
*/
|
||||
createDateCellValue: function (date) {
|
||||
// UTC にしないと正しく Excel に反映されない
|
||||
return new Date(Date.UTC(date.getFullYear(), date.getMonth(), date.getDate(), date.getHours(), date.getMinutes(), date.getSeconds()));
|
||||
},
|
||||
|
||||
deepCopyObject: deepCopyObject,
|
||||
};
|
||||
|
||||
/**
|
||||
* ワークシートのマージを取得します。
|
||||
* @param {ExcelJS.Worksheet} worksheet ワークシート
|
||||
*/
|
||||
function getWorksheetMerges(worksheet) {
|
||||
// 非公式のメンバー _merges を使用
|
||||
// @ts-ignore
|
||||
const mergesDic = worksheet._merges;
|
||||
return Object.keys(mergesDic).map(function (address) {
|
||||
return mergesDic[address];
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* オブジェクのコピーします。ディープコピーとなります。
|
||||
* @template T
|
||||
* @param {T} obj
|
||||
* @returns {T}
|
||||
*/
|
||||
function deepCopyObject(obj) {
|
||||
return copyObject(obj);
|
||||
|
||||
//@ts-ignore
|
||||
function copyObject(obj) {
|
||||
return (
|
||||
obj == null ? null :
|
||||
Array.isArray(obj) ? copyArray(obj) :
|
||||
isDate(obj) ? copyDate(obj) :
|
||||
isDic(obj) ? copyDic(obj) :
|
||||
obj);
|
||||
}
|
||||
|
||||
//@ts-ignore
|
||||
function copyArray(array) {
|
||||
//@ts-ignore
|
||||
return array.map(function (item) {
|
||||
return copyObject(item);
|
||||
});
|
||||
}
|
||||
|
||||
//@ts-ignore
|
||||
function isDate(obj) {
|
||||
return (obj != null && Object.prototype.toString.call(obj) === '[object Date]');
|
||||
}
|
||||
|
||||
//@ts-ignore
|
||||
function copyDate(date) {
|
||||
return (isNaN(date) ? null : new Date(date.getTime()));
|
||||
}
|
||||
|
||||
//@ts-ignore
|
||||
function isDic(obj) {
|
||||
return (obj != null && typeof obj === 'object');
|
||||
}
|
||||
|
||||
//@ts-ignore
|
||||
function copyDic(dic) {
|
||||
let result = {};
|
||||
for (let key in dic) {
|
||||
//@ts-ignore
|
||||
result[key] = copyObject(dic[key]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return exceljs;
|
||||
}());
|
||||
})();
|
||||
13
src/env.js
13
src/env.js
@@ -5,8 +5,8 @@ const env = {
|
||||
appId: 19,
|
||||
excelName: "出欠集計表",
|
||||
view: {
|
||||
'0,1歳日誌データ連携用途': 13352636,
|
||||
'2歳以上日誌データ連携用途': 13352638,
|
||||
linkFor0to1: 13352636,
|
||||
linkForOthers: 13352638,
|
||||
}
|
||||
},
|
||||
"0,1歳日誌出力用": {
|
||||
@@ -24,6 +24,15 @@ const env = {
|
||||
"園児台帳": {
|
||||
appId: 16,
|
||||
},
|
||||
"保育・教育日数マスタ": {
|
||||
appId: 41,
|
||||
},
|
||||
"Excelテンプレート": {
|
||||
appId: 46
|
||||
},
|
||||
"担任マスタ": {
|
||||
appId: 52
|
||||
}
|
||||
};
|
||||
|
||||
const warekiStartYear = {
|
||||
|
||||
18
src/main.css
18
src/main.css
@@ -21,24 +21,24 @@
|
||||
|
||||
.btn-group-area .month,
|
||||
.btn-group-area .date,
|
||||
.btn-group-area .classroom {
|
||||
.btn-group-area .term {
|
||||
--kuc-combobox-toggle-width: calc(2em + 16px);
|
||||
--kuc-combobox-toggle-height: 48px;
|
||||
}
|
||||
|
||||
.btn-group-area .classroom {
|
||||
--kuc-combobox-toggle-width: calc(3em + 16px);
|
||||
.btn-group-area .term {
|
||||
--kuc-combobox-toggle-width: calc(4em + 16px);
|
||||
}
|
||||
|
||||
.btn-group-area .month input[class^='kuc-combobox'],
|
||||
.btn-group-area .date input[class^='kuc-combobox'],
|
||||
.btn-group-area .classroom 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 .classroom input + div[class$="icon"] {
|
||||
.btn-group-area .term input + div[class$="icon"] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@@ -46,6 +46,14 @@
|
||||
margin: 0 8px;
|
||||
}
|
||||
|
||||
.customized-record-header-space {
|
||||
padding-top: 16px;
|
||||
padding-left: 8px;
|
||||
}
|
||||
.customized-record-header-space > .btn-group-area {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
.customized-header-space-wrapper.single-label-line {
|
||||
margin-top: 33px;
|
||||
}
|
||||
|
||||
95
src/main.mobile.css
Normal file
95
src/main.mobile.css
Normal file
@@ -0,0 +1,95 @@
|
||||
.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;
|
||||
}
|
||||
206
src/utils-mobile.js
Normal file
206
src/utils-mobile.js
Normal file
@@ -0,0 +1,206 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
349
src/utils.js
349
src/utils.js
@@ -1,5 +1,7 @@
|
||||
const Kuc = Kucs['1.19.0'];
|
||||
|
||||
const WEEK = ['日', '月', '火', '水', '木', '金', '土']
|
||||
|
||||
const monthItems = Array.from({ length: 12 }, (_, i) => {
|
||||
const month = "" + (i + 1);
|
||||
return { label: month, value: month.padStart(2, '0') };
|
||||
@@ -18,8 +20,18 @@ const classItems = [
|
||||
{ label: "ゆり", value: "ゆり" },
|
||||
]
|
||||
|
||||
let errorEl;
|
||||
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歳児" },
|
||||
]
|
||||
|
||||
let notificationEl;
|
||||
let loadingEl;
|
||||
let dialogEl;
|
||||
|
||||
function getHeaderSpace(className, isDetailPage) {
|
||||
const headerSpace = (isDetailPage ? kintone.app.record : kintone.app).getHeaderMenuSpaceElement();
|
||||
@@ -35,7 +47,7 @@ function getHeaderSpace(className, isDetailPage) {
|
||||
return headerSpace;
|
||||
}
|
||||
|
||||
function createBtnGroupArea(groupId, btnLabel, btnOnClick, { btnElId = false, yearElId = false, monthElId = false, dateElId = false, classElId = false, defaultThisMonth = false, }) {
|
||||
function createBtnGroupArea(groupId, btnLabel, btnOnClick, { btnElId = false, yearElId = false, monthElId = false, dateElId = false, termElId = false, defaultThisMonth = false, }) {
|
||||
const result = {};
|
||||
|
||||
if (document.getElementById(groupId)) {
|
||||
@@ -56,11 +68,6 @@ function createBtnGroupArea(groupId, btnLabel, btnOnClick, { btnElId = false, ye
|
||||
});
|
||||
result[yearElId] = yearEl;
|
||||
btnGroupAreaEl.appendChild(yearEl);
|
||||
|
||||
// const label = document.createElement('div');
|
||||
// label.classList = 'label'
|
||||
// label.textContent = '年';
|
||||
// btnGroupAreaEl.appendChild(label);
|
||||
}
|
||||
|
||||
if (monthElId) {
|
||||
@@ -73,11 +80,6 @@ function createBtnGroupArea(groupId, btnLabel, btnOnClick, { btnElId = false, ye
|
||||
});
|
||||
result[monthElId] = monthEl;
|
||||
btnGroupAreaEl.appendChild(monthEl);
|
||||
|
||||
// const label = document.createElement('div');
|
||||
// label.classList = 'label'
|
||||
// label.textContent = '月';
|
||||
// btnGroupAreaEl.appendChild(label);
|
||||
}
|
||||
|
||||
if (dateElId) {
|
||||
@@ -90,27 +92,17 @@ function createBtnGroupArea(groupId, btnLabel, btnOnClick, { btnElId = false, ye
|
||||
});
|
||||
result[dateElId] = dateEl;
|
||||
btnGroupAreaEl.appendChild(dateEl);
|
||||
|
||||
// const label = document.createElement('div');
|
||||
// label.classList = 'label'
|
||||
// label.textContent = '日';
|
||||
// btnGroupAreaEl.appendChild(label);
|
||||
}
|
||||
|
||||
if (classElId) {
|
||||
// const label = document.createElement('div');
|
||||
// label.classList = 'label'
|
||||
// label.textContent = 'クラス';
|
||||
// btnGroupAreaEl.appendChild(label);
|
||||
|
||||
const classEl = new Kuc.Combobox({
|
||||
id: classElId,
|
||||
items: classItems,
|
||||
className: "classroom input",
|
||||
label: 'クラス',
|
||||
if (termElId) {
|
||||
const termEl = new Kuc.Combobox({
|
||||
id: termElId,
|
||||
items: termItems,
|
||||
className: "term input",
|
||||
label: '学年',
|
||||
});
|
||||
result[classElId] = classEl;
|
||||
btnGroupAreaEl.appendChild(classEl);
|
||||
result[termElId] = termEl;
|
||||
btnGroupAreaEl.appendChild(termEl);
|
||||
}
|
||||
|
||||
const btnEl = new Kuc.Button({
|
||||
@@ -122,7 +114,7 @@ function createBtnGroupArea(groupId, btnLabel, btnOnClick, { btnElId = false, ye
|
||||
result[btnElId] = btnEl;
|
||||
btnEl.addEventListener('click', (e) => {
|
||||
showError(false);
|
||||
const checkResult = checkInputData(result, { btnLabel, yearElId, monthElId, dateElId, classElId });
|
||||
const checkResult = checkInputData(result, { btnLabel, yearElId, monthElId, dateElId, termElId });
|
||||
if (checkResult) {
|
||||
btnOnClick(e, checkResult);
|
||||
}
|
||||
@@ -132,11 +124,11 @@ function createBtnGroupArea(groupId, btnLabel, btnOnClick, { btnElId = false, ye
|
||||
return result;
|
||||
}
|
||||
|
||||
function checkInputData(map, { btnLabel, yearElId, monthElId, dateElId, classElId }) {
|
||||
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;
|
||||
const className = classElId && map[classElId].value;
|
||||
const date = dateElId && (map[dateElId].value === 'end' ? getLastDate(year, month).getDate() : map[dateElId].value);
|
||||
const term = termElId && map[termElId].value;
|
||||
|
||||
const errorMsgs = [];
|
||||
|
||||
@@ -152,8 +144,8 @@ function checkInputData(map, { btnLabel, yearElId, monthElId, dateElId, classElI
|
||||
if (dateElId && !date) {
|
||||
errorMsgs.push(' · 日を選択してください。');
|
||||
}
|
||||
if (classElId && !className) {
|
||||
errorMsgs.push(' · クラスを選択してください。');
|
||||
if (termElId && !term) {
|
||||
errorMsgs.push(' · 学年を選択してください。');
|
||||
}
|
||||
if (errorMsgs.length > 0) {
|
||||
showError(true, btnLabel + 'エラー\n' + errorMsgs.join('\n'))
|
||||
@@ -164,10 +156,15 @@ function checkInputData(map, { btnLabel, yearElId, monthElId, dateElId, classElI
|
||||
year,
|
||||
month,
|
||||
date,
|
||||
className,
|
||||
term,
|
||||
}
|
||||
}
|
||||
|
||||
function getLastDate(year, month) {
|
||||
// month は 1-12 の数値で入力する
|
||||
return new Date(year, month, 0);
|
||||
}
|
||||
|
||||
function createBtn(id, label, onClick) {
|
||||
const btnEl = new Kuc.Button({
|
||||
text: label,
|
||||
@@ -187,7 +184,7 @@ function hideSpaceField(ids) {
|
||||
});
|
||||
}
|
||||
|
||||
function getExcelName({ excelName }, nameSuffix = '', suffix = '.xlsx') {
|
||||
function getExcelName(excelName, nameSuffix = '', suffix = '.xlsx') {
|
||||
return excelName + (nameSuffix ? (nameSuffix.startsWith('_') ? nameSuffix : ('_' + nameSuffix)) : '') + suffix;
|
||||
}
|
||||
|
||||
@@ -225,12 +222,18 @@ function convertToWesternYear(year, era) {
|
||||
return warekiStartYear[era] + year - 1;
|
||||
}
|
||||
|
||||
function getFormatDateString(date) {
|
||||
const year = date.getFullYear();
|
||||
const month = String(date.getMonth() + 1).padStart(2, '0');
|
||||
const day = String(date.getDate()).padStart(2, '0');
|
||||
function getFormatDateString(dateObjOrYear, month, date) {
|
||||
let year = dateObjOrYear;
|
||||
if (typeof dateObjOrYear === "object" && !month && !date) {
|
||||
year = dateObjOrYear.getFullYear();
|
||||
month = dateObjOrYear.getMonth() + 1;
|
||||
date = dateObjOrYear.getDate();
|
||||
}
|
||||
const formatY = year;
|
||||
const formatM = String(month).padStart(2, '0');
|
||||
const formatD = String(date).padStart(2, '0');
|
||||
|
||||
return `${year}-${month}-${day}`;
|
||||
return `${formatY}-${formatM}-${formatD}`;
|
||||
}
|
||||
|
||||
function loading(show, text) {
|
||||
@@ -249,17 +252,257 @@ function loading(show, text) {
|
||||
}
|
||||
|
||||
function showError(show, text) {
|
||||
if (!errorEl) {
|
||||
errorEl = new Kuc.Notification({
|
||||
type: 'danger',
|
||||
text
|
||||
});
|
||||
} else {
|
||||
errorEl.close();
|
||||
errorEl.text = text;
|
||||
}
|
||||
if (show) {
|
||||
errorEl.open();
|
||||
buildNotification('danger', text);
|
||||
notificationEl.open();
|
||||
console.error(text);
|
||||
} else {
|
||||
notificationEl && notificationEl.close();
|
||||
}
|
||||
}
|
||||
|
||||
function showSuccess(show, text, time = 3000) {
|
||||
if (show) {
|
||||
buildNotification('success', text, time);
|
||||
notificationEl.open();
|
||||
} else {
|
||||
notificationEl && notificationEl.close();
|
||||
}
|
||||
}
|
||||
|
||||
function buildNotification(type, text, duration = -1) {
|
||||
const param = {
|
||||
type,
|
||||
text,
|
||||
duration
|
||||
}
|
||||
if (!notificationEl) {
|
||||
notificationEl = new Kuc.Notification(param);
|
||||
} else {
|
||||
Object.assign(notificationEl, param);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
options: {
|
||||
icon: '' | 'info' | 'success' | 'error' | 'warning' | 'question',
|
||||
title: string,
|
||||
content: string|HTMLElement,
|
||||
header: string|HTMLElement,
|
||||
footer: string|HTMLElement,
|
||||
|
||||
dataHolder: {},
|
||||
// ↓ if not footer ↓
|
||||
ok: string = 'OK',
|
||||
cancel: boolean|string = 'キャンセル',
|
||||
onOk: (dataHolder, e) => void,
|
||||
onCancel: (dataHolder, e) => void,
|
||||
onClose: (dataHolder, e) => void,
|
||||
}
|
||||
*/
|
||||
function showDialog(options) {
|
||||
if (!dialogEl) {
|
||||
createDialogEl(options);
|
||||
} else {
|
||||
Object.assign(dialogEl, options);
|
||||
}
|
||||
dialogEl.open();
|
||||
}
|
||||
|
||||
function createDialogEl({ ok, cancel, onOk, onCancel, onClose, ...options }) {
|
||||
if (!options.footer) {
|
||||
const divEl = document.createElement('div');
|
||||
divEl.style.textAlign = 'right';
|
||||
|
||||
if (cancel !== false) {
|
||||
const cancelButton = new Kuc.Button({
|
||||
text: cancel || 'Cancel',
|
||||
type: 'normal'
|
||||
});
|
||||
cancelButton.style.paddingRight = '8px';
|
||||
cancelButton.addEventListener('click', (event) => {
|
||||
onCancel && onCancel(dialogEl.dataHolder, event);
|
||||
dialogEl.close();
|
||||
});
|
||||
divEl.appendChild(cancelButton);
|
||||
}
|
||||
|
||||
const okButton = new Kuc.Button({
|
||||
text: ok || 'OK',
|
||||
type: 'submit'
|
||||
});
|
||||
okButton.addEventListener('click', (event) => {
|
||||
onOk && onOk(dialogEl.dataHolder, event);
|
||||
dialogEl.close();
|
||||
});
|
||||
divEl.appendChild(okButton);
|
||||
options.footer = divEl;
|
||||
}
|
||||
|
||||
dialogEl = new Kuc.Dialog(options);
|
||||
if (onClose) {
|
||||
dialogEl.addEventListener('close', (event) => {
|
||||
onClose(dialogEl.dataHolder, event);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async function createExcelAndDownload({ bizLogic, api, excelName, exportName }) {
|
||||
const arrayBuffer = await getTemplateBuffer(api, excelName);
|
||||
if (!arrayBuffer) {
|
||||
// エラー
|
||||
return;
|
||||
}
|
||||
|
||||
const workbook = new ExcelJS.Workbook();
|
||||
await workbook.xlsx.load(arrayBuffer);
|
||||
|
||||
const worksheet = workbook.getWorksheet();
|
||||
try {
|
||||
await bizLogic(api, worksheet);
|
||||
} catch (e) {
|
||||
showError(true, '帳票出力エラー\n - ' + e);
|
||||
return;
|
||||
}
|
||||
const blob = await pvc.lib.exceljsUtil.saveWorkbookToBlob(workbook);
|
||||
saveAs(blob, exportName);
|
||||
}
|
||||
|
||||
async function getTemplateBuffer(api, excelName) {
|
||||
try {
|
||||
const templateObj = await api.record.getAllRecordsWithId({
|
||||
app: env["Excelテンプレート"].appId,
|
||||
condition: `テンプレート名 = "${excelName}"`
|
||||
});
|
||||
const fileKey = templateObj[0]["テンプレートファイル"].value[0].fileKey;
|
||||
return await api.file.downloadFile({
|
||||
fileKey
|
||||
});
|
||||
} catch (e) {
|
||||
showError(true, '本アプリのExcelテンプレート読み取りエラー\n - ' + e);
|
||||
}
|
||||
}
|
||||
|
||||
function findCellsInfo(worksheet, ids) {
|
||||
const result = ids.reduce((acc, key) => {
|
||||
acc[key] = [];
|
||||
return acc;
|
||||
}, {});
|
||||
|
||||
let lastColVal;
|
||||
worksheet.eachRow((row, rowNumber) => {
|
||||
row.eachCell((cell, colNumber) => {
|
||||
const value = cell.value;
|
||||
if (value !== lastColVal && result[value]) {
|
||||
result[value].push({
|
||||
row: rowNumber,
|
||||
col: colNumber,
|
||||
});
|
||||
}
|
||||
lastColVal = value;
|
||||
});
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
function getLabelColsMapping(worksheet, row, fields) {
|
||||
const arr = worksheet.getRow(row).values;
|
||||
const changedIndices = [];
|
||||
for (let i = 1; i < arr.length; i++) {
|
||||
if (arr[i] !== arr[i - 1]) {
|
||||
changedIndices.push({
|
||||
index: i,
|
||||
field: fields[changedIndices.length]
|
||||
});
|
||||
}
|
||||
}
|
||||
return changedIndices;
|
||||
}
|
||||
|
||||
function createCopyFromTemplate(worksheet, { startPage,
|
||||
totalPages,
|
||||
copyPageRowStart,
|
||||
copyPageRowEnd,
|
||||
callback }) {
|
||||
|
||||
const rowCount = copyPageRowEnd - copyPageRowStart + 1;
|
||||
let newPageRow = copyPageRowEnd + 1;
|
||||
|
||||
for (let p = startPage; p <= totalPages; p++) {
|
||||
const copyRow = pvc.lib.exceljsUtil.copyRows(worksheet, copyPageRowStart, copyPageRowEnd);
|
||||
pvc.lib.exceljsUtil.insertRows(worksheet, newPageRow, copyRow);
|
||||
newPageRow += rowCount;
|
||||
callback(p, rowCount);
|
||||
}
|
||||
}
|
||||
|
||||
function updateCell(worksheetOrRow, { base, left = 0, right = 0, up = 0, down = 0 }, data) {
|
||||
let cellObj;
|
||||
const row = base.row + (down - up);
|
||||
const col = base.col + (right - left);
|
||||
if (!worksheetOrRow._worksheet) {
|
||||
const worksheet = worksheetOrRow;
|
||||
cellObj = worksheet.getCell(row, col);
|
||||
} else {
|
||||
const rowObj = worksheetOrRow;
|
||||
cellObj = rowObj.getCell(col)
|
||||
}
|
||||
|
||||
cellObj.value = data;
|
||||
if (!cellObj.alignment) {
|
||||
cellObj.alignment = {};
|
||||
}
|
||||
cellObj.alignment.wrapText = true;
|
||||
}
|
||||
|
||||
function getMergedInfo(worksheet, { row, col }) {
|
||||
const key = columnToLetter(col) + row;
|
||||
return worksheet._merges[key];
|
||||
}
|
||||
|
||||
function columnToLetter(columnIndex) {
|
||||
let letter = '';
|
||||
while (columnIndex > 0) {
|
||||
let remainder = (columnIndex - 1) % 26;
|
||||
letter = String.fromCharCode(65 + remainder) + letter;
|
||||
columnIndex = Math.floor((columnIndex - 1) / 26);
|
||||
}
|
||||
return letter;
|
||||
}
|
||||
|
||||
function fillApproveArea(baseCells, worksheet, record) {
|
||||
const signLabels = ['園長', '主幹', '指導', '担任'];
|
||||
const signRow = baseCells['園長'][0].row + 1;
|
||||
for (let i = 0; i < signLabels.length; i++) {
|
||||
worksheet.getCell(signRow, baseCells['園長'][0].col + i).value = (record[signLabels[i]]?.value || '');
|
||||
}
|
||||
}
|
||||
|
||||
function groupingBySex(list) {
|
||||
return list.reduce(([male, female], record) => {
|
||||
if (record['性別'].value === '男') {
|
||||
return [male.concat(record), female];
|
||||
} else if (record['性別'].value === '女') {
|
||||
return [male, female.concat(record)];
|
||||
}
|
||||
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;
|
||||
});
|
||||
}
|
||||
5
src/保育計画月案/env.js
Normal file
5
src/保育計画月案/env.js
Normal file
@@ -0,0 +1,5 @@
|
||||
const statusFieldMap = {
|
||||
'主幹確認中': '指導',
|
||||
'園長確認中': '主幹',
|
||||
'完了': '園長'
|
||||
}
|
||||
12
src/保育計画月案/main.js
Normal file
12
src/保育計画月案/main.js
Normal file
@@ -0,0 +1,12 @@
|
||||
(function () {
|
||||
"use strict";
|
||||
|
||||
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;
|
||||
});
|
||||
|
||||
})();
|
||||
12
src/保育計画月案/main.mobile.js
Normal file
12
src/保育計画月案/main.mobile.js
Normal file
@@ -0,0 +1,12 @@
|
||||
(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;
|
||||
});
|
||||
|
||||
})();
|
||||
9
src/保育計画週案/env.js
Normal file
9
src/保育計画週案/env.js
Normal file
@@ -0,0 +1,9 @@
|
||||
const statusFieldMap = {
|
||||
'主幹確認中(4週目)': '指導',
|
||||
'園長確認中(4週目)': '主幹',
|
||||
'完了(4週目)': '園長',
|
||||
'担任作成中(5週目)': '園長',
|
||||
'主幹確認中(5週目)': '指導',
|
||||
'園長確認中(5週目)': '主幹',
|
||||
'完了(5週目)': '園長',
|
||||
}
|
||||
12
src/保育計画週案/main.js
Normal file
12
src/保育計画週案/main.js
Normal file
@@ -0,0 +1,12 @@
|
||||
(function () {
|
||||
"use strict";
|
||||
|
||||
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;
|
||||
});
|
||||
|
||||
})();
|
||||
12
src/保育計画週案/main.mobile.js
Normal file
12
src/保育計画週案/main.mobile.js
Normal file
@@ -0,0 +1,12 @@
|
||||
(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;
|
||||
});
|
||||
|
||||
})();
|
||||
3
src/個別配慮/FileSaver.min.js
vendored
Normal file
3
src/個別配慮/FileSaver.min.js
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
(function(a,b){if("function"==typeof define&&define.amd)define([],b);else if("undefined"!=typeof exports)b();else{b(),a.FileSaver={exports:{}}.exports}})(this,function(){"use strict";function b(a,b){return"undefined"==typeof b?b={autoBom:!1}:"object"!=typeof b&&(console.warn("Deprecated: Expected third argument to be a object"),b={autoBom:!b}),b.autoBom&&/^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(a.type)?new Blob(["\uFEFF",a],{type:a.type}):a}function c(a,b,c){var d=new XMLHttpRequest;d.open("GET",a),d.responseType="blob",d.onload=function(){g(d.response,b,c)},d.onerror=function(){console.error("could not download file")},d.send()}function d(a){var b=new XMLHttpRequest;b.open("HEAD",a,!1);try{b.send()}catch(a){}return 200<=b.status&&299>=b.status}function e(a){try{a.dispatchEvent(new MouseEvent("click"))}catch(c){var b=document.createEvent("MouseEvents");b.initMouseEvent("click",!0,!0,window,0,0,0,80,20,!1,!1,!1,!1,0,null),a.dispatchEvent(b)}}var f="object"==typeof window&&window.window===window?window:"object"==typeof self&&self.self===self?self:"object"==typeof global&&global.global===global?global:void 0,a=/Macintosh/.test(navigator.userAgent)&&/AppleWebKit/.test(navigator.userAgent)&&!/Safari/.test(navigator.userAgent),g=f.saveAs||("object"!=typeof window||window!==f?function(){}:"download"in HTMLAnchorElement.prototype&&!a?function(b,g,h){var i=f.URL||f.webkitURL,j=document.createElement("a");g=g||b.name||"download",j.download=g,j.rel="noopener","string"==typeof b?(j.href=b,j.origin===location.origin?e(j):d(j.href)?c(b,g,h):e(j,j.target="_blank")):(j.href=i.createObjectURL(b),setTimeout(function(){i.revokeObjectURL(j.href)},4E4),setTimeout(function(){e(j)},0))}:"msSaveOrOpenBlob"in navigator?function(f,g,h){if(g=g||f.name||"download","string"!=typeof f)navigator.msSaveOrOpenBlob(b(f,h),g);else if(d(f))c(f,g,h);else{var i=document.createElement("a");i.href=f,i.target="_blank",setTimeout(function(){e(i)})}}:function(b,d,e,g){if(g=g||open("","_blank"),g&&(g.document.title=g.document.body.innerText="downloading..."),"string"==typeof b)return c(b,d,e);var h="application/octet-stream"===b.type,i=/constructor/i.test(f.HTMLElement)||f.safari,j=/CriOS\/[\d]+/.test(navigator.userAgent);if((j||h&&i||a)&&"undefined"!=typeof FileReader){var k=new FileReader;k.onloadend=function(){var a=k.result;a=j?a:a.replace(/^data:[^;]*;/,"data:attachment/file;"),g?g.location.href=a:location=a,g=null},k.readAsDataURL(b)}else{var l=f.URL||f.webkitURL,m=l.createObjectURL(b);g?g.location=m:location.href=m,g=null,setTimeout(function(){l.revokeObjectURL(m)},4E4)}});f.saveAs=g.saveAs=g,"undefined"!=typeof module&&(module.exports=g)});
|
||||
|
||||
//# sourceMappingURL=FileSaver.min.js.map
|
||||
1
src/個別配慮/KintoneRestAPIClient.min.js
vendored
Normal file
1
src/個別配慮/KintoneRestAPIClient.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
3
src/個別配慮/exceljs.min.js
vendored
Normal file
3
src/個別配慮/exceljs.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
2433
src/個別配慮/kuc.min.js
vendored
Normal file
2433
src/個別配慮/kuc.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
107
src/個別配慮/main.js
107
src/個別配慮/main.js
@@ -2,6 +2,8 @@
|
||||
"use strict";
|
||||
const APP_ENV = env["個別配慮"];
|
||||
|
||||
addApproveFlowAction();
|
||||
|
||||
kintone.events.on("app.record.index.show", (event) => {
|
||||
const headerSpace = getHeaderSpace('single-label-line');
|
||||
|
||||
@@ -18,8 +20,105 @@
|
||||
headerSpace.appendChild(elements['extract-action-area']);
|
||||
});
|
||||
|
||||
function handleButtonClick(e, { year, month }) {
|
||||
const fileName = getExcelName(APP_ENV, year + month);
|
||||
console.log(fileName);
|
||||
async function handleButtonClick(e, { year, month }) {
|
||||
loading(true, '帳票出力中...');
|
||||
showError(false);
|
||||
const api = new KintoneRestAPIClient();
|
||||
|
||||
// 本アプリからデータを読み取る
|
||||
const currentAppRecords = await getRecords(api, year, month);
|
||||
if (!currentAppRecords) {
|
||||
// エラー
|
||||
loading(false);
|
||||
return e;
|
||||
}
|
||||
|
||||
const excelName = APP_ENV.excelName;
|
||||
await createExcelAndDownload({
|
||||
api,
|
||||
excelName,
|
||||
exportName: getExcelName(excelName, year + month),
|
||||
bizLogic: writeExcel(currentAppRecords, year, month),
|
||||
});
|
||||
loading(false);
|
||||
}
|
||||
})();
|
||||
|
||||
async function getRecords(api, year, month) {
|
||||
const firstDate = getFormatDateString(year, month, 1)
|
||||
const lastDate = getFormatDateString(getLastDate(year, month));
|
||||
try {
|
||||
return await api.record.getAllRecordsWithId({
|
||||
app: env["個別配慮"].appId,
|
||||
condition: `日付 >= "${firstDate}" and 日付 <= "${lastDate}"`
|
||||
});
|
||||
} catch (e) {
|
||||
showError(true, '本アプリのデータ読み取りエラー\n - ' + e);
|
||||
}
|
||||
}
|
||||
|
||||
function writeExcel(records, year, month) {
|
||||
return async (api, worksheet) => {
|
||||
if (!records || !records.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
const baseCells = findCellsInfo(worksheet, ['月', '児童名']);
|
||||
|
||||
const pageSize = 10;
|
||||
const totalPages = Math.ceil(records.length / pageSize);
|
||||
|
||||
// make new copy
|
||||
if (totalPages > 2) {
|
||||
const lastPage = 2;
|
||||
const copyPageRowStart = baseCells['月'][lastPage - 1].row - 1;
|
||||
const copyPageRowEnd = baseCells['児童名'][lastPage - 1].row + pageSize;
|
||||
|
||||
createCopyFromTemplate(worksheet, {
|
||||
startPage: lastPage + 1,
|
||||
totalPages,
|
||||
copyPageRowStart,
|
||||
copyPageRowEnd,
|
||||
callback: (newPage, rowCount) => {
|
||||
['月', '児童名'].forEach((label) => {
|
||||
const last = baseCells[label][newPage - 2];
|
||||
baseCells[label].push({
|
||||
col: last.col,
|
||||
row: last.row + rowCount
|
||||
});
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const cols = getLabelColsMapping(worksheet, baseCells['児童名'][0].row, ['児童名', '子どもの姿', '保育者援助_配慮_環境構成']);
|
||||
const sortedRecords = records.sort((a, b) => Number(a['レコード番号'].value) - Number(b['レコード番号'].value));
|
||||
|
||||
for (let i = 0; i < totalPages; i++) {
|
||||
const monthLabelCell = baseCells['月'][i];
|
||||
updateCell(worksheet, { base: monthLabelCell, left: 1 }, Number(month));
|
||||
|
||||
const childLabelCell = baseCells['児童名'][i];
|
||||
let currentRow = childLabelCell.row + 1;
|
||||
|
||||
for (let j = 0; j < pageSize; j++) {
|
||||
const index = i * pageSize + j;
|
||||
const record = sortedRecords[index];
|
||||
if (!record) {
|
||||
break;
|
||||
}
|
||||
const row = worksheet.getRow(currentRow);
|
||||
cols.forEach(col => {
|
||||
updateCell(row, { base: { row: currentRow, col: col.index } }, record[col.field].value);
|
||||
});
|
||||
currentRow++;
|
||||
}
|
||||
|
||||
worksheet.getRow(childLabelCell.row + pageSize).addPageBreak();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
})();
|
||||
|
||||
6
src/個別配慮/main.mobile.js
Normal file
6
src/個別配慮/main.mobile.js
Normal file
@@ -0,0 +1,6 @@
|
||||
(function () {
|
||||
"use strict";
|
||||
|
||||
addApproveFlowAction(true);
|
||||
|
||||
})();
|
||||
496
src/個別配慮/pvc.lib.exceljsUtil.js
Normal file
496
src/個別配慮/pvc.lib.exceljsUtil.js
Normal file
@@ -0,0 +1,496 @@
|
||||
/** @copyright 2018 Planning Village Corporation Co., Ltd. */
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
// [IE11] Polyfill of Object.values
|
||||
if (!Object.values) {
|
||||
const ownKeys = (
|
||||
(typeof Reflect === 'object' && typeof Reflect.ownKeys === 'function') ? Reflect.ownKeys :
|
||||
// @ts-ignore
|
||||
(typeof Object.getOwnPropertySymbols === 'function') ? (function (O) {
|
||||
// @ts-ignore
|
||||
return Object.getOwnPropertyNames(O).concat(Object.getOwnPropertySymbols(O));
|
||||
}) :
|
||||
Object.getOwnPropertyNames);
|
||||
// @ts-ignore
|
||||
const reduce = Function.bind.call(Function.call, Array.prototype.reduce);
|
||||
// @ts-ignore
|
||||
const isEnumerable = Function.bind.call(Function.call, Object.prototype.propertyIsEnumerable);
|
||||
// @ts-ignore
|
||||
const concat = Function.bind.call(Function.call, Array.prototype.concat);
|
||||
//@ts-ignore
|
||||
Object.values = function values(O) {
|
||||
//@ts-ignore
|
||||
return reduce(ownKeys(O), function (v, k) {
|
||||
return concat(v, typeof k === 'string' && isEnumerable(O, k) ? [O[k]] : [])
|
||||
}, [])
|
||||
};
|
||||
}
|
||||
|
||||
// [IE11] Polyfill of Number.isNaN
|
||||
if (!Number.isNaN) {
|
||||
Number.isNaN = function (value) {
|
||||
return value !== null && (value != value || +value != value);
|
||||
};
|
||||
}
|
||||
|
||||
// [IE11] Polyfill of String.prototype.startsWith
|
||||
if (!String.prototype.startsWith) {
|
||||
Object.defineProperty(String.prototype, 'startsWith', {
|
||||
//@ts-ignore
|
||||
value: function (search, rawPos) {
|
||||
var pos = rawPos > 0 ? rawPos | 0 : 0;
|
||||
return this.substring(pos, pos + search.length) === search;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// [IE11] Polyfill of String.prototype.includes
|
||||
if (!String.prototype.includes) {
|
||||
String.prototype.includes = function (search, start) {
|
||||
'use strict';
|
||||
//@ts-ignore
|
||||
if (search instanceof RegExp) {
|
||||
throw TypeError('first argument must not be a RegExp');
|
||||
}
|
||||
if (start === undefined) {
|
||||
start = 0;
|
||||
}
|
||||
return this.indexOf(search, start) !== -1;
|
||||
};
|
||||
}
|
||||
|
||||
// [IE11] Polyfill of Array.prototype.findIndex
|
||||
if (!Array.prototype.findIndex) {
|
||||
// @ts-ignore
|
||||
Array.prototype.findIndex = function (predicate) {
|
||||
if (this === null) {
|
||||
throw new TypeError('Array.prototype.findIndex called on null or undefined');
|
||||
}
|
||||
if (typeof predicate !== 'function') {
|
||||
throw new TypeError('predicate must be a function');
|
||||
}
|
||||
var list = Object(this);
|
||||
var length = list.length >>> 0;
|
||||
var thisArg = arguments[1];
|
||||
var value;
|
||||
|
||||
for (var i = 0; i < length; i++) {
|
||||
value = list[i];
|
||||
if (predicate.call(thisArg, value, i, list)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
};
|
||||
}
|
||||
|
||||
//@ts-ignore
|
||||
window.pvc = window.pvc || {};
|
||||
//@ts-ignore
|
||||
window.pvc.lib = window.pvc.lib || {};
|
||||
//@ts-ignore
|
||||
window.pvc.lib.exceljsUtil = (function () {
|
||||
const exceljs = {
|
||||
/**
|
||||
* ワークブックの blob を読み取ります。
|
||||
* @param {Blob} blob Blob
|
||||
* @return {Promise<ExcelJS.Workbook>} ワークブック
|
||||
*/
|
||||
loadWorkbookBlob: function (blob) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
var reader = new FileReader();
|
||||
reader.onload = function (e) {
|
||||
// @ts-ignore
|
||||
resolve(e.target.result);
|
||||
};
|
||||
reader.onerror = function (e) {
|
||||
reject(e);
|
||||
}
|
||||
reader.onabort = function (e) {
|
||||
reject(e);
|
||||
}
|
||||
reader.readAsArrayBuffer(blob);
|
||||
}).then(function (arrayBuffer) {
|
||||
// 非公式のメンバー load を使用
|
||||
// @ts-ignore
|
||||
return new ExcelJS.Workbook().xlsx.load(arrayBuffer);
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* ワークブックを Blob に変換します。
|
||||
* @param {ExcelJS.Workbook} workbook ワークブック
|
||||
* @return {Promise<Blob>} Blob
|
||||
*/
|
||||
saveWorkbookToBlob: function (workbook) {
|
||||
// writeBuffer の戻り値 ExcelJS.Buffer はブラウザ環境では Uint8Array となる
|
||||
return workbook.xlsx.writeBuffer().then(function (ua) {
|
||||
return new Blob([ua], {
|
||||
type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* 行をコピーします。
|
||||
* @param {ExcelJS.Worksheet} worksheet ワークシート
|
||||
* @param {number} topRowNumber コピー元の開始行番号(1から開始)
|
||||
* @param {number} [bottomRowNumber] コピー元の終了行番号(1から開始)。省略時は開始行番号と同じ値となります。
|
||||
* @returns {pvc.lib.exceljsUtil.CopiedRowsInfo} 行のコピー情報
|
||||
*/
|
||||
copyRows: function (worksheet, topRowNumber, bottomRowNumber) {
|
||||
const _bottomRowNumber = (bottomRowNumber == null ? topRowNumber : bottomRowNumber);
|
||||
|
||||
if (topRowNumber < 0 || _bottomRowNumber < topRowNumber) {
|
||||
throw new Error('コピー元の領域とが不正です。');
|
||||
}
|
||||
|
||||
// コピー元の領域の情報を収集
|
||||
const rows = [];
|
||||
for (let r = topRowNumber; r <= _bottomRowNumber; r++) {
|
||||
const row = worksheet.getRow(r);
|
||||
const cells = [];
|
||||
for (let c = 1; c <= worksheet.columnCount; c++) {
|
||||
const cell = row.getCell(c);
|
||||
cells.push({
|
||||
value: cell.value,
|
||||
style: cell.style,
|
||||
});
|
||||
}
|
||||
rows.push({
|
||||
cells: cells,
|
||||
height: row.height,
|
||||
// 非公式のメンバー style を使用
|
||||
// @ts-ignore
|
||||
style: row.style,
|
||||
});
|
||||
}
|
||||
|
||||
// コピー元の領域の内部に収まるマージを収集
|
||||
const merges = deepCopyObject(getWorksheetMerges(worksheet).filter(function (merge) {
|
||||
return (topRowNumber <= merge.top && merge.bottom <= _bottomRowNumber);
|
||||
}).map(function (merge) {
|
||||
return {
|
||||
top: merge.top - topRowNumber,
|
||||
right: merge.right,
|
||||
bottom: merge.bottom - topRowNumber,
|
||||
left: merge.left,
|
||||
};
|
||||
}));
|
||||
|
||||
return deepCopyObject({
|
||||
rows: rows,
|
||||
merges: merges
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* 指定された開始行を起点に、コピーした行を貼り付けます。
|
||||
* コピー元の領域と領域外の両方にまたがるセルのマージは貼り付けされません。
|
||||
* コピー先の領域を一部でも含むマージは全て解除されます。
|
||||
* @param {ExcelJS.Worksheet} worksheet ワークシート
|
||||
* @param {number} topRowNumber コピー先の開始行番号(1から開始)
|
||||
* @param {pvc.lib.exceljsUtil.CopiedRowsInfo} copiedRowsInfo 行のコピー情報
|
||||
*/
|
||||
pasteRows: function (worksheet, topRowNumber, copiedRowsInfo) {
|
||||
const bottomRowNumber = topRowNumber + copiedRowsInfo.rows.length - 1;
|
||||
|
||||
if (topRowNumber < 0) {
|
||||
throw new Error('コピー先の領域とが不正です。');
|
||||
}
|
||||
|
||||
// コピー先の行のマージを解除(コピー先の領域を一部でも含むマージは全て解除)
|
||||
getWorksheetMerges(worksheet).filter(function (merge) {
|
||||
return (topRowNumber <= merge.bottom && merge.top <= bottomRowNumber);
|
||||
}).forEach(function (merge) {
|
||||
worksheet.unMergeCells(merge.range);
|
||||
});
|
||||
|
||||
// マージをペースト
|
||||
copiedRowsInfo.merges.forEach(function (mergeInfo) {
|
||||
worksheet.mergeCells(
|
||||
topRowNumber + mergeInfo.top,
|
||||
mergeInfo.left,
|
||||
topRowNumber + mergeInfo.bottom,
|
||||
mergeInfo.right);
|
||||
});
|
||||
|
||||
// セルをペースト
|
||||
copiedRowsInfo.rows.forEach(function (rowInfo, i) {
|
||||
const row = worksheet.getRow(topRowNumber + i);
|
||||
row.height = rowInfo.height;
|
||||
// 非公式のメンバー style を使用
|
||||
// @ts-ignore
|
||||
row.style = rowInfo.style;
|
||||
for (let c = 1; c <= worksheet.columnCount; c++) {
|
||||
const cell = row.getCell(c);
|
||||
const cellInfo = rowInfo.cells[c - 1];
|
||||
if (cellInfo) {
|
||||
cell.value = cellInfo.value;
|
||||
cell.style = cellInfo.style;
|
||||
} else {
|
||||
exceljs.clearCell(cell);
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* 指定された開始行を起点に、コピーした行を挿入します。
|
||||
* コピー元の領域と領域外の両方にまたがるセルのマージは貼り付けされません。
|
||||
* @param {ExcelJS.Worksheet} worksheet ワークシート
|
||||
* @param {number} topRowNumber コピー先の開始行番号(1から開始)
|
||||
* @param {pvc.lib.exceljsUtil.CopiedRowsInfo} copiedRowsInfo 行のコピー情報
|
||||
*/
|
||||
insertRows: function (worksheet, topRowNumber, copiedRowsInfo) {
|
||||
const bottomRows = (
|
||||
topRowNumber <= worksheet.rowCount ?
|
||||
exceljs.copyRows(worksheet, topRowNumber, worksheet.rowCount) :
|
||||
null);
|
||||
exceljs.pasteRows(worksheet, topRowNumber, copiedRowsInfo);
|
||||
if (bottomRows) {
|
||||
exceljs.pasteRows(worksheet, topRowNumber + copiedRowsInfo.rows.length, bottomRows);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 列をコピーします。
|
||||
* @param {ExcelJS.Worksheet} worksheet ワークシート
|
||||
* @param {number | string} leftColumn コピー元の開始列の列番号(1から開始)または列ラベル。終了列の引数を省略して、代わりに "A:B" の形式でコピー元の列の範囲を指定することも可能。
|
||||
* @param {number | string} [rightColumn] コピー元の終了列の列番号(1から開始)または列ラベル。省略時は開始列と同じとみなされます(開始列を "A:B" の形式で指定された場合を除く)。
|
||||
* @returns {pvc.lib.exceljsUtil.CopiedColumnsInfo} 列のコピー情報
|
||||
*/
|
||||
copyColumns: function (worksheet, leftColumn, rightColumn) {
|
||||
if (rightColumn == null) {
|
||||
rightColumn = leftColumn;
|
||||
if (typeof leftColumn === 'string') {
|
||||
const sp = leftColumn.split(':');
|
||||
if (sp.length === 2) {
|
||||
leftColumn = sp[0];
|
||||
rightColumn = sp[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const leftColumnNumber = ((typeof leftColumn === 'number') ? leftColumn : exceljs.columnLetterToColumnNumber(leftColumn));
|
||||
const rightColumnNumber = ((typeof rightColumn === 'number') ? rightColumn : exceljs.columnLetterToColumnNumber(rightColumn));
|
||||
|
||||
if (leftColumnNumber < 0 || rightColumnNumber < leftColumnNumber) {
|
||||
throw new Error('コピー元の領域とが不正です。');
|
||||
}
|
||||
|
||||
// コピー元の領域の情報を収集
|
||||
const columns = [];
|
||||
for (let c = leftColumnNumber; c <= rightColumnNumber; c++) {
|
||||
const column = worksheet.getColumn(c);
|
||||
const cells = [];
|
||||
for (let r = 1; r <= worksheet.rowCount; r++) {
|
||||
const cell = worksheet.getRow(r).getCell(c);
|
||||
cells.push({
|
||||
value: cell.value,
|
||||
style: cell.style,
|
||||
});
|
||||
}
|
||||
columns.push({
|
||||
cells: cells,
|
||||
width: column.width,
|
||||
style: column.style,
|
||||
});
|
||||
}
|
||||
|
||||
// コピー元の領域の内部に収まるマージを収集
|
||||
const merges = deepCopyObject(getWorksheetMerges(worksheet).filter(function (merge) {
|
||||
return (leftColumnNumber <= merge.left && merge.right <= rightColumnNumber);
|
||||
}).map(function (merge) {
|
||||
return {
|
||||
top: merge.top,
|
||||
right: merge.right - leftColumnNumber,
|
||||
bottom: merge.bottom,
|
||||
left: merge.left - leftColumnNumber,
|
||||
};
|
||||
}));
|
||||
|
||||
return {
|
||||
columns: columns,
|
||||
merges: merges
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* 指定された開始列を起点に、コピーした列を貼り付けます。
|
||||
* コピー元の領域と領域外の両方にまたがるセルのマージは貼り付けされません。
|
||||
* コピー先の領域を一部でも含むマージは全て解除されます。
|
||||
* @param {ExcelJS.Worksheet} worksheet ワークシート
|
||||
* @param {number | string} leftColumn コピー先の開始列の列番号(1から開始)または列ラベル
|
||||
* @param {pvc.lib.exceljsUtil.CopiedColumnsInfo} copiedColumnsInfo 列のコピー情報
|
||||
*/
|
||||
pasteColumns: function (worksheet, leftColumn, copiedColumnsInfo) {
|
||||
const leftColumnNumber = ((typeof leftColumn === 'number') ? leftColumn : exceljs.columnLetterToColumnNumber(leftColumn));
|
||||
const rightColumnNumber = leftColumnNumber + copiedColumnsInfo.columns.length - 1;
|
||||
|
||||
if (leftColumnNumber < 0) {
|
||||
throw new Error('コピー先の領域とが不正です。');
|
||||
}
|
||||
|
||||
// コピー先の列のマージを解除(コピー先の領域を一部でも含むマージは全て解除)
|
||||
getWorksheetMerges(worksheet).filter(function (merge) {
|
||||
return (leftColumnNumber <= merge.right && merge.left <= rightColumnNumber);
|
||||
}).forEach(function (merge) {
|
||||
worksheet.unMergeCells(merge.range);
|
||||
});
|
||||
|
||||
// マージをペースト
|
||||
copiedColumnsInfo.merges.forEach(function (mergeInfo) {
|
||||
worksheet.mergeCells(
|
||||
mergeInfo.top,
|
||||
leftColumnNumber + mergeInfo.left,
|
||||
mergeInfo.bottom,
|
||||
leftColumnNumber + mergeInfo.right);
|
||||
});
|
||||
|
||||
// セルをペースト
|
||||
copiedColumnsInfo.columns.forEach(function (columnInfo, i) {
|
||||
const column = worksheet.getColumn(leftColumnNumber + i);
|
||||
column.width = columnInfo.width;
|
||||
column.style = columnInfo.style;
|
||||
for (let r = 1; r <= worksheet.rowCount; r++) {
|
||||
const cell = worksheet.getRow(r).getCell(leftColumnNumber + i);
|
||||
const cellInfo = columnInfo.cells[r - 1];
|
||||
if (cellInfo) {
|
||||
cell.value = cellInfo.value;
|
||||
cell.style = cellInfo.style;
|
||||
} else {
|
||||
exceljs.clearCell(cell);
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* 指定された開始列を起点に、コピーした列を挿入します。
|
||||
* コピー元の領域と領域外の両方にまたがるセルのマージは貼り付けされません。
|
||||
* @param {ExcelJS.Worksheet} worksheet ワークシート
|
||||
* @param {number | string} leftColumn コピー先の開始列の列番号(1から開始)または列ラベル
|
||||
* @param {pvc.lib.exceljsUtil.CopiedColumnsInfo} copiedRowsInfo 列のコピー情報
|
||||
*/
|
||||
insertColumns: function (worksheet, leftColumn, copiedRowsInfo) {
|
||||
const leftColumnNumber = ((typeof leftColumn === 'number') ? leftColumn : exceljs.columnLetterToColumnNumber(leftColumn));
|
||||
const rightColumns = (
|
||||
leftColumnNumber <= worksheet.columnCount ?
|
||||
exceljs.copyColumns(worksheet, leftColumnNumber, worksheet.columnCount) :
|
||||
null);
|
||||
exceljs.pasteColumns(worksheet, leftColumnNumber, copiedRowsInfo);
|
||||
if (rightColumns) {
|
||||
exceljs.pasteColumns(worksheet, leftColumnNumber + copiedRowsInfo.columns.length, rightColumns);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* セルをクリアします。
|
||||
* @param {ExcelJS.Cell} cell セル
|
||||
*/
|
||||
clearCell: function (cell) {
|
||||
cell.value = null;
|
||||
/// @ts-ignore
|
||||
cell.style = cell._mergeStyle(cell._row.style, cell._column.style, {});
|
||||
},
|
||||
|
||||
/**
|
||||
* 列ラベルから列番号(1から開始)を取得します。
|
||||
* @param {string} columnLetter 列ラベル
|
||||
* @return {number} 列番号(1から開始)
|
||||
*/
|
||||
columnLetterToColumnNumber: function (columnLetter) {
|
||||
const letter = columnLetter.toUpperCase();
|
||||
const l = letter.length;
|
||||
const charCodeA = 65;
|
||||
let result = 0;
|
||||
for (let i = 0, j = l - 1; i < l; i++, j--) {
|
||||
result += (letter.charCodeAt(j) - charCodeA + 1) * (i === 0 ? 1 : Math.pow(26, i));
|
||||
}
|
||||
return result;
|
||||
},
|
||||
|
||||
/**
|
||||
* 日付のセルの値を作成します。
|
||||
* @param {Date} date
|
||||
* @returns {any}
|
||||
*/
|
||||
createDateCellValue: function (date) {
|
||||
// UTC にしないと正しく Excel に反映されない
|
||||
return new Date(Date.UTC(date.getFullYear(), date.getMonth(), date.getDate(), date.getHours(), date.getMinutes(), date.getSeconds()));
|
||||
},
|
||||
|
||||
deepCopyObject: deepCopyObject,
|
||||
};
|
||||
|
||||
/**
|
||||
* ワークシートのマージを取得します。
|
||||
* @param {ExcelJS.Worksheet} worksheet ワークシート
|
||||
*/
|
||||
function getWorksheetMerges(worksheet) {
|
||||
// 非公式のメンバー _merges を使用
|
||||
// @ts-ignore
|
||||
const mergesDic = worksheet._merges;
|
||||
return Object.keys(mergesDic).map(function (address) {
|
||||
return mergesDic[address];
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* オブジェクのコピーします。ディープコピーとなります。
|
||||
* @template T
|
||||
* @param {T} obj
|
||||
* @returns {T}
|
||||
*/
|
||||
function deepCopyObject(obj) {
|
||||
return copyObject(obj);
|
||||
|
||||
//@ts-ignore
|
||||
function copyObject(obj) {
|
||||
return (
|
||||
obj == null ? null :
|
||||
Array.isArray(obj) ? copyArray(obj) :
|
||||
isDate(obj) ? copyDate(obj) :
|
||||
isDic(obj) ? copyDic(obj) :
|
||||
obj);
|
||||
}
|
||||
|
||||
//@ts-ignore
|
||||
function copyArray(array) {
|
||||
//@ts-ignore
|
||||
return array.map(function (item) {
|
||||
return copyObject(item);
|
||||
});
|
||||
}
|
||||
|
||||
//@ts-ignore
|
||||
function isDate(obj) {
|
||||
return (obj != null && Object.prototype.toString.call(obj) === '[object Date]');
|
||||
}
|
||||
|
||||
//@ts-ignore
|
||||
function copyDate(date) {
|
||||
return (isNaN(date) ? null : new Date(date.getTime()));
|
||||
}
|
||||
|
||||
//@ts-ignore
|
||||
function isDic(obj) {
|
||||
return (obj != null && typeof obj === 'object');
|
||||
}
|
||||
|
||||
//@ts-ignore
|
||||
function copyDic(dic) {
|
||||
let result = {};
|
||||
for (let key in dic) {
|
||||
//@ts-ignore
|
||||
result[key] = copyObject(dic[key]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return exceljs;
|
||||
}());
|
||||
})();
|
||||
@@ -16,23 +16,51 @@ class BatchCreateHandler {
|
||||
const api = new KintoneRestAPIClient();
|
||||
|
||||
// 園児台帳アプリからデータを読み取る
|
||||
const result = await this.getMasterRecords(api);
|
||||
if (!result) {
|
||||
const masterRecords = await this.getMasterRecords(api);
|
||||
if (!masterRecords) {
|
||||
// エラー
|
||||
loading(false);
|
||||
return;
|
||||
}
|
||||
|
||||
const today = new Date();
|
||||
const todayString = getFormatDateString(today);
|
||||
const records = this.generateRecords(today, todayString, result);
|
||||
const records = this.generateRecords(today, todayString, masterRecords);
|
||||
// console.log(records);
|
||||
|
||||
const createResult = await this.createData(api, records, todayString);
|
||||
location.reload();
|
||||
const result = await this.createData(api, records, todayString);
|
||||
// showSuccess(true, "出欠簿一括作成完了");
|
||||
if (result) {
|
||||
this.showSuccessDialog(result);
|
||||
}
|
||||
|
||||
loading(false);
|
||||
}
|
||||
|
||||
generateRecords = (today, todayString, result) => {
|
||||
return result.reduce((acc, masterRecord) => {
|
||||
showSuccessDialog(result) {
|
||||
const contentEl = document.createElement('div');
|
||||
contentEl.style.fontSize = '16px';
|
||||
if (result.updateResult && result.insertResult) {
|
||||
contentEl.innerHTML = `${result.insertResult.records.length}件のデータを更新し、${result.insertResult.records.length}件のデータを新規作成しました。`
|
||||
} else if (result.updateResult) {
|
||||
contentEl.innerHTML = `${result.updateResult.records.length}件のデータを更新しました。`;
|
||||
} else if (result.insertResult) {
|
||||
contentEl.innerHTML = `${result.insertResult.records.length}件のデータを生成しました。`;
|
||||
} else {
|
||||
contentEl.innerHTML = `データの更新はありません。既に最新の状態です。`
|
||||
}
|
||||
|
||||
showDialog({
|
||||
title: '出欠簿一括作成完了',
|
||||
content: contentEl,
|
||||
ok: '更新して確認',
|
||||
cancel: false,
|
||||
onClose: () => { location.reload() }
|
||||
});
|
||||
}
|
||||
|
||||
generateRecords = (today, todayString, masterRecords) => {
|
||||
return masterRecords.reduce((acc, masterRecord) => {
|
||||
if (this.needCreateData(masterRecord, today)) {
|
||||
acc.push(this.createRecord(masterRecord, todayString));
|
||||
}
|
||||
@@ -61,6 +89,8 @@ class BatchCreateHandler {
|
||||
return {
|
||||
'登園日': { 'value': todayString },
|
||||
'園児ユニークキー': { 'value': record['ユニークキー'].value },
|
||||
'担任': { 'value': record['担当者名'].value.map((x)=>x.name).join('、') },
|
||||
'保護者ログインID': { 'value': record['保護者ログインID'].value },
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,11 +98,10 @@ class BatchCreateHandler {
|
||||
try {
|
||||
return await api.record.getAllRecordsWithId({
|
||||
app: env["園児台帳"].appId,
|
||||
fields: ['ユニークキー', "和暦_退園年月日", "年_退園年月日", "月_退園年月日", "日_退園年月日"],
|
||||
fields: ['ユニークキー', '担当者名', "保護者ログインID", "和暦_退園年月日", "年_退園年月日", "月_退園年月日", "日_退園年月日"],
|
||||
});
|
||||
} catch (e) {
|
||||
showError(true, '園児台帳アプリのデータ読み取りエラー\n - ' + e);
|
||||
loading(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,16 +114,40 @@ class BatchCreateHandler {
|
||||
return;
|
||||
}
|
||||
|
||||
const filteredRecords = records.filter((each) => !alreadyGeneratedKeys[each["園児ユニークキー"].value])
|
||||
if (!filteredRecords.length) {
|
||||
return;
|
||||
const param = {
|
||||
app: env["園児別出欠簿入力"].appId,
|
||||
}
|
||||
|
||||
const addResult = await api.record.addAllRecords({
|
||||
app: env["園児別出欠簿入力"].appId,
|
||||
records: filteredRecords
|
||||
const insert = [];
|
||||
const update = [];
|
||||
records.forEach(record => {
|
||||
const id = alreadyGeneratedKeys[record["園児ユニークキー"].value]
|
||||
if (id) {
|
||||
update.push({
|
||||
id,
|
||||
record
|
||||
});
|
||||
} else {
|
||||
insert.push(record);
|
||||
}
|
||||
});
|
||||
return addResult;
|
||||
|
||||
let insertResult;
|
||||
if (insert.length) {
|
||||
param.records = insert;
|
||||
insertResult = await api.record.addAllRecords(param);
|
||||
}
|
||||
|
||||
let updateResult;
|
||||
if (update.length) {
|
||||
param.records = update;
|
||||
// 本アプリの当日データでテーブルを上書きし、対応する園児データがない行を【削除】します
|
||||
updateResult = await api.record.updateAllRecords(param);
|
||||
}
|
||||
return {
|
||||
insertResult,
|
||||
updateResult
|
||||
}
|
||||
} catch (e) {
|
||||
showError(true, '本アプリのデータ作成失敗\n - ' + e);
|
||||
}
|
||||
@@ -109,7 +162,7 @@ class BatchCreateHandler {
|
||||
condition: `登園日 = "${todayString}" and 園児ユニークキー in (${needCreateUniqueKeys})`
|
||||
})
|
||||
return alreadyGeneratedResult.reduce((map, each) => {
|
||||
map[each["園児ユニークキー"].value] = true;
|
||||
map[each["園児ユニークキー"].value] = each["$id"].value;
|
||||
return map;
|
||||
}, {});
|
||||
} catch (e) {
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
class ExtractHandler {
|
||||
|
||||
constructor(headerSpace) {
|
||||
const elements = createBtnGroupArea('extract-action-area', '出欠集計表出力', this.handleExtractData, {
|
||||
btnElId: 'extract-btn',
|
||||
yearElId: 'extract-year',
|
||||
monthElId: 'extract-month',
|
||||
classElId: 'extract-classroom'
|
||||
termElId: 'extract-term'
|
||||
})
|
||||
if (!elements) {
|
||||
return;
|
||||
@@ -12,9 +13,341 @@ class ExtractHandler {
|
||||
headerSpace.appendChild(elements['extract-action-area']);
|
||||
}
|
||||
|
||||
handleExtractData(e, { year, month, className }) {
|
||||
const fileName = getExcelName(env["園児別出欠簿入力"], year + month + '_' + className + '組');
|
||||
console.log(fileName);
|
||||
handleExtractData = async (e, { year, month, term }) => {
|
||||
loading(true, '帳票出力中...');
|
||||
showError(false);
|
||||
const api = new KintoneRestAPIClient();
|
||||
// 本アプリからデータを読み取る
|
||||
const records = await this.getRecords(api, year, month, term);
|
||||
if (!records) {
|
||||
// エラー
|
||||
loading(false);
|
||||
return e;
|
||||
}
|
||||
const recordMap = this.buildRecordMap(records);
|
||||
|
||||
const childMaster = await this.getChildMstRecords(api, year, month, term, Object.keys(recordMap.byId));
|
||||
if (!childMaster) {
|
||||
// エラー
|
||||
loading(false);
|
||||
return e;
|
||||
}
|
||||
|
||||
const dayMaster = await this.getDayMstRecords(api, year, month);
|
||||
if (!dayMaster) {
|
||||
// エラー
|
||||
loading(false);
|
||||
return e;
|
||||
}
|
||||
|
||||
const termTeacher = await this.getTermTeacherMstRecords(api, term);
|
||||
if (termTeacher === undefined) {
|
||||
// エラー
|
||||
loading(false);
|
||||
return e;
|
||||
}
|
||||
|
||||
const excelName = env["園児別出欠簿入力"].excelName;
|
||||
await createExcelAndDownload({
|
||||
api,
|
||||
excelName,
|
||||
exportName: getExcelName(excelName, year + month + '_' + term),
|
||||
bizLogic: this.writeExcel({ records, recordMap, childMaster, dayMaster, termTeacher }, term, getJapaneseEraDate(new Date(year, month - 1, 1))),
|
||||
});
|
||||
loading(false);
|
||||
}
|
||||
|
||||
getRecords = async (api, year, month, term) => {
|
||||
const firstDate = getFormatDateString(year, month, 1)
|
||||
const lastDate = getFormatDateString(getLastDate(year, month));
|
||||
try {
|
||||
return await api.record.getAllRecordsWithId({
|
||||
app: env["園児別出欠簿入力"].appId,
|
||||
condition: `登園日 >= "${firstDate}" and 登園日 <= "${lastDate}" and 学年 in ("${term}")`
|
||||
});
|
||||
} catch (e) {
|
||||
showError(true, '本アプリのデータ読み取りエラー\n - ' + e);
|
||||
}
|
||||
}
|
||||
|
||||
getChildMstRecords = async (api, year, month, term, uniqueKeys) => {
|
||||
const date = getJapaneseEraDate(new Date(year, month - 1, 1))
|
||||
const prevMonth = getJapaneseEraDate(getLastDate(year, month - 1));
|
||||
const result = {};
|
||||
try {
|
||||
result['入園'] = await api.record.getAllRecordsWithId({
|
||||
app: env["園児台帳"].appId,
|
||||
fields: ['性別'],
|
||||
condition: `和暦_入園年月日 in ("${date.era}") and 年_入園年月日 = "${date.year}" and 月_入園年月日 = "${date.month}" and 学年 in ("${term}")`
|
||||
});
|
||||
result['退園'] = await api.record.getAllRecordsWithId({
|
||||
app: env["園児台帳"].appId,
|
||||
fields: ['性別'],
|
||||
condition: `和暦_退園年月日 in ("${prevMonth.era}") and 年_退園年月日 = "${prevMonth.year}" and 月_退園年月日 = "${prevMonth.month}" and 学年 in ("${term}")`
|
||||
});
|
||||
if (uniqueKeys?.length) {
|
||||
result['在籍'] = await api.record.getAllRecordsWithId({
|
||||
app: env["園児台帳"].appId,
|
||||
fields: ['ユニークキー', '性別'],
|
||||
condition: `ユニークキー in ("${uniqueKeys.join('", "')}")`
|
||||
});
|
||||
}
|
||||
return result;
|
||||
} catch (e) {
|
||||
showError(true, '園児台帳のデータ読み取りエラー\n - ' + e);
|
||||
}
|
||||
}
|
||||
|
||||
getDayMstRecords = async (api, yearStr, monthStr) => {
|
||||
let year = Number(yearStr);
|
||||
const month = Number(monthStr);
|
||||
// ※年度=4月~翌年3月までの区切りとする(例:2025年3月→2024年度)
|
||||
if (month < 4) {
|
||||
year--;
|
||||
}
|
||||
try {
|
||||
const data = await api.record.getAllRecordsWithId({
|
||||
app: env["保育・教育日数マスタ"].appId,
|
||||
fields: ['教育日数' + month, '保育日数' + month],
|
||||
condition: `年度 = "${year}"`
|
||||
});
|
||||
return data && data[0];
|
||||
} catch (e) {
|
||||
showError(true, '保育・教育日数マスタのデータ読み取りエラー\n - ' + e);
|
||||
}
|
||||
}
|
||||
|
||||
getTermTeacherMstRecords = async (api, term) => {
|
||||
try {
|
||||
const data = await api.record.getAllRecordsWithId({
|
||||
app: env["担任マスタ"].appId,
|
||||
fields: ['担任'],
|
||||
condition: `学年 in ("${term}")`
|
||||
});
|
||||
return data && data[0] && data[0]['担任']?.value.map((x)=>x.name).join('、') || '';
|
||||
} catch (e) {
|
||||
showError(true, '担任マスタのデータ読み取りエラー\n - ' + e);
|
||||
}
|
||||
}
|
||||
|
||||
writeExcel = ({ records, recordMap, childMaster, dayMaster, termTeacher }, term, { era, year, westernYear, month }) => {
|
||||
const teachDays = Number(dayMaster['教育日数' + month].value);
|
||||
const careDays = Number(dayMaster['保育日数' + month].value);
|
||||
|
||||
return async (api, worksheet) => {
|
||||
const baseCells = findCellsInfo(worksheet, ['13', '16', '19', '25', '(担 任)', '1', '番号']);
|
||||
|
||||
// header
|
||||
updateCell(worksheet, { base: baseCells['13'][0], up: 1 }, era);
|
||||
updateCell(worksheet, { base: baseCells['16'][0], up: 1 }, year + '年');
|
||||
updateCell(worksheet, { base: baseCells['19'][0], up: 1 }, month + '月');
|
||||
updateCell(worksheet, { base: baseCells['25'][0], up: 1 }, term);
|
||||
|
||||
const weekRow = worksheet.getRow(baseCells['1'][0].row + 1);
|
||||
const startCol = baseCells['1'][0].col;
|
||||
const weekStart = new Date(westernYear, month - 1, 1).getDay();
|
||||
const lastDate = getLastDate(westernYear, month).getDate();
|
||||
for (let i = 0; i < lastDate; i++) {
|
||||
updateCell(weekRow, { base: { col: startCol + i } }, WEEK[(weekStart + i) % 7]);
|
||||
}
|
||||
|
||||
if (!records.length) {
|
||||
return;
|
||||
}
|
||||
updateCell(worksheet, { base: baseCells['(担 任)'][0], down: 1 }, termTeacher);
|
||||
|
||||
fillMainPage(baseCells, worksheet, recordMap);
|
||||
fillFooter(worksheet, recordMap);
|
||||
}
|
||||
|
||||
function fillMainPage(baseCells, worksheet, recordMap) {
|
||||
baseCells['番号'] = baseCells['番号'].filter((_, index) => index % 2 !== 0);
|
||||
const sortedRecords = Object.values(recordMap.byId).sort((a, b) => a['idKey'].localeCompare(b['idKey']));
|
||||
|
||||
const lastPage = 2;
|
||||
const baseForTemplate = baseCells['番号'][lastPage - 1]; // 番号 merged 2 rows
|
||||
const pageSize = 15;
|
||||
const totalPages = Math.ceil(sortedRecords.length / pageSize);
|
||||
|
||||
// make new copy
|
||||
if (totalPages > 2) {
|
||||
const copyPageRowStart = baseForTemplate.row - 2;
|
||||
const copyPageRowEnd = baseForTemplate.row + (pageSize);
|
||||
|
||||
createCopyFromTemplate(worksheet, {
|
||||
startPage: lastPage + 1,
|
||||
totalPages,
|
||||
copyPageRowStart,
|
||||
copyPageRowEnd,
|
||||
callback: (newPage, rowCount) => {
|
||||
['番号'].forEach((label) => {
|
||||
const last = baseCells[label][newPage - 2];
|
||||
baseCells[label].push({
|
||||
col: last.col,
|
||||
row: last.row + rowCount
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
for (let i = 0; i < totalPages; i++) {
|
||||
const childLabelCell = baseCells['番号'][i];
|
||||
let currentRow = childLabelCell.row + 1;
|
||||
|
||||
for (let j = 0; j < pageSize; j++) {
|
||||
const index = i * pageSize + j;
|
||||
const recordWrapper = sortedRecords[index];
|
||||
if (!recordWrapper) {
|
||||
break;
|
||||
}
|
||||
const row = worksheet.getRow(currentRow);
|
||||
const base = { row: currentRow, col: 1 };
|
||||
// 番号
|
||||
updateCell(row, { base }, recordWrapper['id']);
|
||||
// 児 童 氏 名
|
||||
updateCell(row, { base, right: 1 }, recordWrapper['name']);
|
||||
|
||||
const reasons = [];
|
||||
const sum = {
|
||||
'出席': 0,
|
||||
'出席停止': 0,
|
||||
'病欠': 0,
|
||||
'自欠': 0,
|
||||
}
|
||||
// 日
|
||||
recordWrapper.list.forEach((record, i) => {
|
||||
const res = record["出欠"].value;
|
||||
sum[res]++;
|
||||
if (res === '出席') {
|
||||
return;
|
||||
}
|
||||
if (res === '出席停止' && record["出席停止理由"].value) {
|
||||
reasons.push(record["出席停止理由"].value);
|
||||
}
|
||||
updateCell(row, { base, right: 2 + i }, res === '出席停止' ? '×' : '/');
|
||||
})
|
||||
|
||||
// 出 席
|
||||
updateCell(row, { base, right: 33 }, sum['出席']);
|
||||
updateCell(row, { base, right: 34 }, sum['出席停止']);
|
||||
// 欠 席
|
||||
updateCell(row, { base, right: 35 }, sum['病欠']);
|
||||
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: 38 }, reasons.join("\n"));
|
||||
|
||||
currentRow += 1;
|
||||
}
|
||||
|
||||
worksheet.getRow(childLabelCell.row + pageSize + 1).addPageBreak();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function fillFooter(worksheet, recordMap) {
|
||||
const baseCells = findCellsInfo(worksheet, ['合 計', '保 育 日 数', '男', '女', '欠 席 総 数', '出 席 率', '%']);
|
||||
// 合 計
|
||||
const totalAreaRow = worksheet.getRow(baseCells['合 計'][0].row);
|
||||
const totalAreaRow2 = worksheet.getRow(baseCells['合 計'][1].row);
|
||||
const totalAreaRow3 = worksheet.getRow(baseCells['合 計'][2].row);
|
||||
const base = { col: 3 };
|
||||
const dateList = recordMap.sum.list;
|
||||
for (let i = 0; i < dateList.length; i++) {
|
||||
if (dateList[i]) {
|
||||
updateCell(totalAreaRow, { base, right: i }, dateList[i]['出席']);
|
||||
updateCell(totalAreaRow2, { base, right: i }, dateList[i]['出停']);
|
||||
updateCell(totalAreaRow3, { base, right: i }, dateList[i]['欠席']);
|
||||
}
|
||||
}
|
||||
|
||||
// 保 育 日 数
|
||||
updateCell(worksheet, { base: baseCells['保 育 日 数'][0], down: 1 }, careDays);
|
||||
|
||||
// 入 園 数
|
||||
let list = childMaster['入園'];
|
||||
let [male, female] = groupingBySex(list);
|
||||
updateCell(worksheet, { base: baseCells['男'][0], right: 1 }, male.length);
|
||||
updateCell(worksheet, { base: baseCells['女'][0], right: 1 }, female.length);
|
||||
// 退 園 数
|
||||
list = childMaster['退園'];
|
||||
[male, female] = groupingBySex(list);
|
||||
updateCell(worksheet, { base: baseCells['男'][1], right: 1 }, male.length);
|
||||
updateCell(worksheet, { base: baseCells['女'][1], right: 1 }, female.length);
|
||||
// 在 籍 数
|
||||
list = childMaster['在籍'];
|
||||
[male, female] = groupingBySex(list);
|
||||
updateCell(worksheet, { base: baseCells['男'][2], right: 1 }, male.length);
|
||||
updateCell(worksheet, { base: baseCells['女'][2], right: 1 }, female.length);
|
||||
|
||||
const total = recordMap.sum['欠席'] + recordMap.sum['出席'];
|
||||
if (total) {
|
||||
// 出 席 総 数
|
||||
updateCell(worksheet, { base: baseCells['欠 席 総 数'][0], left: 1 }, recordMap.sum['出席']);
|
||||
// 欠 席 総 数
|
||||
updateCell(worksheet, { base: baseCells['出 席 率'][0], left: 1 }, recordMap.sum['欠席']);
|
||||
// 出 席 率
|
||||
updateCell(worksheet, { base: baseCells['%'][0], right: 1 }, Math.round(recordMap.sum['出席'] / total * 1000) / 10 + '%');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
buildRecordMap = (records) => {
|
||||
const recordMap = {
|
||||
sum: {
|
||||
'出席': 0,
|
||||
'欠席': 0,
|
||||
list: []
|
||||
},
|
||||
byId: {}
|
||||
}
|
||||
|
||||
records.forEach((record) => {
|
||||
const dateIndex = Number(record['登園日'].value.split('-')[2]) - 1;
|
||||
const idKey = record['園児ユニークキー'].value;
|
||||
let attendance = recordMap.byId[idKey];
|
||||
if (!attendance) {
|
||||
attendance = {
|
||||
idKey,
|
||||
id: record['出席番号'].value,
|
||||
name: record['園児名'].value,
|
||||
list: [],
|
||||
};
|
||||
recordMap.byId[idKey] = attendance
|
||||
}
|
||||
attendance.list[dateIndex] = record;
|
||||
|
||||
const status = record["出欠"].value;
|
||||
if (status === '出席' || status === '出席停止') {
|
||||
recordMap.sum['出席']++;
|
||||
} else if (status === '病欠' || status === '自欠') {
|
||||
recordMap.sum['欠席']++;
|
||||
}
|
||||
|
||||
let dateSum = recordMap.sum.list[dateIndex];
|
||||
if (!dateSum) {
|
||||
dateSum = {
|
||||
'出席': 0,
|
||||
'出停': 0,
|
||||
'欠席': 0,
|
||||
};
|
||||
recordMap.sum.list[dateIndex] = dateSum
|
||||
}
|
||||
if (status === '出席') {
|
||||
dateSum['出席']++;
|
||||
} else if (status === '出席停止') {
|
||||
dateSum['出停']++;
|
||||
} else if (status === '病欠' || status === '自欠') {
|
||||
dateSum['欠席']++;
|
||||
}
|
||||
});
|
||||
return recordMap;
|
||||
}
|
||||
|
||||
static getInstance(headerSpace) {
|
||||
|
||||
@@ -12,7 +12,197 @@ class Link1Handler {
|
||||
headerSpace.appendChild(elements['link-1-action-area']);
|
||||
}
|
||||
|
||||
handleLink(e, { year, month }) {
|
||||
handleLink = async (e, { year, month }) => {
|
||||
loading(true, '日誌データ連携中...');
|
||||
showError(false);
|
||||
const api = new KintoneRestAPIClient();
|
||||
|
||||
// 本アプリからデータを読み取る
|
||||
const currentAppRecords = await this.getRecords(api, year, month);
|
||||
if (!currentAppRecords) {
|
||||
// エラー
|
||||
loading(false);
|
||||
return;
|
||||
}
|
||||
|
||||
// console.log(currentAppRecords);
|
||||
const recordsWrapper = await this.generateRecords(api, year, month, currentAppRecords);
|
||||
// console.log(recordsWrapper);
|
||||
|
||||
const result = await this.insertOrUpdateData(api, recordsWrapper);
|
||||
if (result) {
|
||||
// showSuccess(true, "日誌データ連携作成完了");
|
||||
this.showSuccessDialog(result, year, month);
|
||||
}
|
||||
loading(false);
|
||||
}
|
||||
|
||||
showSuccessDialog(result, year, month) {
|
||||
const dateString = year + '年' + month + '月';
|
||||
const contentEl = document.createElement('div');
|
||||
contentEl.style.fontSize = '16px';
|
||||
if (result.updateResult && result.insertResult) {
|
||||
contentEl.innerHTML = `${dateString}の${result.updateResult.records.length}人の園児の日誌を更新し、${result.insertResult.records.length}人の園児の日誌を新規作成しました。`
|
||||
} else if (result.updateResult) {
|
||||
contentEl.innerHTML = `${dateString}の${result.updateResult.records.length}人の園児の日誌が更新されました。`;
|
||||
} else if (result.insertResult) {
|
||||
contentEl.innerHTML = `${dateString}の${result.insertResult.records.length}人の園児の日誌が生成されました`;
|
||||
} else {
|
||||
contentEl.innerHTML = `${dateString}の園児の日誌に生成するデータはありませんでした。`
|
||||
}
|
||||
showDialog({
|
||||
title: '日誌データ連携作成完了',
|
||||
content: contentEl,
|
||||
ok: 'アプリへ行く',
|
||||
cancel: '閉じる',
|
||||
onOk: () => { window.open(`${location.origin}/k/${env["0,1歳日誌出力用"].appId}/`) },
|
||||
});
|
||||
}
|
||||
|
||||
insertOrUpdateData = async (api, recordsWrapper) => {
|
||||
try {
|
||||
const param = {
|
||||
app: env["0,1歳日誌出力用"].appId,
|
||||
}
|
||||
|
||||
let insertResult;
|
||||
if (recordsWrapper['insert'].length) {
|
||||
param.records = recordsWrapper['insert'];
|
||||
insertResult = await api.record.addAllRecords(param);
|
||||
}
|
||||
|
||||
let updateResult;
|
||||
if (recordsWrapper['update'].length) {
|
||||
param.records = recordsWrapper['update'];
|
||||
// 本アプリの当日データでテーブルを上書きし、対応する園児データがない行を【削除】します
|
||||
updateResult = await api.record.updateAllRecords(param);
|
||||
}
|
||||
|
||||
return {
|
||||
recordsWrapper,
|
||||
insertResult,
|
||||
updateResult
|
||||
};
|
||||
} catch (e) {
|
||||
showError(true, '日誌データ連携作成失敗\n - ' + e);
|
||||
}
|
||||
};
|
||||
|
||||
generateRecords = async (api, year, month, records) => {
|
||||
const generatedRecordIdMap = await this.getGeneratedRecordIdMap(api, year, month);
|
||||
if (!generatedRecordIdMap) {
|
||||
// エラー
|
||||
loading(false);
|
||||
return;
|
||||
}
|
||||
|
||||
const kidsMap = {};
|
||||
records.forEach((record) => {
|
||||
const uniqueKey = record['園児ユニークキー'].value;
|
||||
let map = kidsMap[uniqueKey];
|
||||
if (!map) {
|
||||
map = {
|
||||
existId: generatedRecordIdMap[uniqueKey],
|
||||
list: [],
|
||||
'年': { 'value': Number(year) },
|
||||
'月': { 'value': Number(month) },
|
||||
'クラス': { 'value': record['クラス'].value },
|
||||
'出席番号': { 'value': record['出席番号'].value },
|
||||
'園児名': { 'value': record['園児名'].value },
|
||||
'園児ユニークキー': { 'value': uniqueKey },
|
||||
'帳票出力用_テーブル': { 'value': undefined },
|
||||
};
|
||||
kidsMap[uniqueKey] = map
|
||||
}
|
||||
record['date'] = Number(record['登園日'].value.split('-')[2]);
|
||||
map.list.push(record);
|
||||
});
|
||||
// console.log(generatedRecordIdMap);
|
||||
// console.log(kidsMap);
|
||||
|
||||
const result = {
|
||||
'update': [],
|
||||
'insert': []
|
||||
}
|
||||
|
||||
Object.values(kidsMap).forEach((recordWrapper) => {
|
||||
const subtable = Array.from({ length: 31 }, (_e, i) => ({
|
||||
value: {
|
||||
'日付': { 'value': i + 1 },
|
||||
}
|
||||
}));
|
||||
recordWrapper.list.forEach((record) => {
|
||||
subtable[record['date'] - 1] = {
|
||||
value: {
|
||||
'日付': { 'value': record['date'] },
|
||||
'出欠': { 'value': record['出欠'].value },
|
||||
'降園': { 'value': record['帰園時刻'].value },
|
||||
'検温時刻1': { 'value': record['検温時刻1'].value },
|
||||
'体温1': { 'value': record['体温1'].value },
|
||||
'検温時刻2': { 'value': record['検温時刻2'].value },
|
||||
'体温2': { 'value': record['体温2'].value },
|
||||
'検温時刻3': { 'value': record['検温時刻3'].value },
|
||||
'体温3': { 'value': record['体温3'].value },
|
||||
'食事量': { 'value': record['食事量_結合'].value },
|
||||
'排便': { 'value': record['排便'].value },
|
||||
'睡眠開始時間1': { 'value': record['睡眠開始時間1'].value },
|
||||
'睡眠終了時間1': { 'value': record['睡眠終了時間1'].value },
|
||||
'睡眠開始時間2': { 'value': record['睡眠開始時間2'].value },
|
||||
'睡眠終了時間2': { 'value': record['睡眠終了時間2'].value },
|
||||
'保護者から': { 'value': record['保護者から'].value },
|
||||
'園での様子_伝達事項': { 'value': record['園での様子_伝達事項'].value },
|
||||
'評価反省': { 'value': record['評価反省'].value },
|
||||
}
|
||||
}
|
||||
})
|
||||
recordWrapper['帳票出力用_テーブル'].value = subtable;
|
||||
const id = recordWrapper['existId'];
|
||||
delete recordWrapper['list'];
|
||||
delete recordWrapper['existId'];
|
||||
if (id) {
|
||||
result['update'].push({
|
||||
id,
|
||||
record: recordWrapper
|
||||
});
|
||||
} else {
|
||||
result['insert'].push(recordWrapper);
|
||||
}
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
getRecords = async (api, year, month) => {
|
||||
const firstDate = getFormatDateString(year, month, 1)
|
||||
const lastDate = getFormatDateString(getLastDate(year, month));
|
||||
try {
|
||||
return await api.record.getAllRecordsWithId({
|
||||
app: env["園児別出欠簿入力"].appId,
|
||||
condition: `学年 in ("0歳児", "1歳児") and 登園日 >= "${firstDate}" and 登園日 <= "${lastDate}"`
|
||||
});
|
||||
} catch (e) {
|
||||
showError(true, '本アプリのデータ読み取りエラー\n - ' + e);
|
||||
loading(false);
|
||||
}
|
||||
}
|
||||
|
||||
getGeneratedRecordIdMap = async (api, year, month) => {
|
||||
try {
|
||||
const result = await api.record.getAllRecordsWithId({
|
||||
app: env["0,1歳日誌出力用"].appId,
|
||||
fields: ["$id", "園児ユニークキー"],
|
||||
condition: `年 = ${year} and 月 = ${month}`
|
||||
});
|
||||
const map = {}
|
||||
result.forEach((record) => {
|
||||
const uniqueKey = record['園児ユニークキー'].value;
|
||||
map[uniqueKey] = record['$id'].value;
|
||||
});
|
||||
return map;
|
||||
} catch (e) {
|
||||
showError(true, '日誌データ読み取りエラー\n - ' + e);
|
||||
loading(false);
|
||||
}
|
||||
}
|
||||
|
||||
static getInstance(headerSpace) {
|
||||
|
||||
@@ -15,9 +15,189 @@ class Link2Handler {
|
||||
}
|
||||
|
||||
|
||||
handleLink(e, { year, month, date }) {
|
||||
handleLink = async (e, { year, month, date }) => {
|
||||
loading(true, '日誌データ連携中...');
|
||||
showError(false);
|
||||
const api = new KintoneRestAPIClient();
|
||||
|
||||
const dateString = getFormatDateString(year, month, date)
|
||||
// 本アプリからデータを読み取る
|
||||
const currentAppRecords = await this.getRecords(api, dateString);
|
||||
if (!currentAppRecords) {
|
||||
// エラー
|
||||
loading(false);
|
||||
return;
|
||||
}
|
||||
|
||||
const groupedRecords = this.groupingAndSort(currentAppRecords);
|
||||
|
||||
const records = [];
|
||||
for (const item of groupedRecords) {
|
||||
records.push(this.generateRecord(dateString, item));
|
||||
}
|
||||
|
||||
const result = await this.insertOrUpdateData(api, records, dateString);
|
||||
if (result) {
|
||||
// showSuccess(true, "日誌データ連携作成完了");
|
||||
this.showSuccessDialog(result, year, month, date);
|
||||
}
|
||||
loading(false);
|
||||
}
|
||||
|
||||
showSuccessDialog(result, year, month, date) {
|
||||
const dateString = year + '年' + month + '月' + date + '日';
|
||||
const contentEl = document.createElement('div');
|
||||
contentEl.style.fontSize = '16px';
|
||||
if (!result.size) {
|
||||
contentEl.innerHTML = `${dateString}の園児別テーブルに追加するデータはありませんでした。`;
|
||||
} else if (!result.insert) {
|
||||
contentEl.innerHTML = `${dateString}の園児別テーブルに${result.size}件のデータを再作成しました。`;
|
||||
} else if (!result.update) {
|
||||
contentEl.innerHTML = `${dateString}の日誌は生成しましたが、園児別テーブルに${result.size}件のデータを追加しました。`;
|
||||
} else {
|
||||
contentEl.innerHTML = `${dateString}の${result.update}人の園児の日誌を更新し、${result.insert}人の園児の日誌を新規作成しました。`
|
||||
}
|
||||
showDialog({
|
||||
title: '日誌データ連携作成完了',
|
||||
content: contentEl,
|
||||
ok: 'アプリへ行く',
|
||||
cancel: '閉じる',
|
||||
dataHolder: result,
|
||||
onOk: () => { window.open(`${location.origin}/k/${env["2歳以上日誌出力用"].appId}/`) },
|
||||
});
|
||||
}
|
||||
|
||||
getRecords = async (api, dateString) => {
|
||||
try {
|
||||
return await api.record.getAllRecordsWithId({
|
||||
app: env["園児別出欠簿入力"].appId,
|
||||
fields: ['クラス', '学年', "園児名", "園での様子_伝達事項", "評価反省"],
|
||||
condition: `学年 not in ("", "0歳児", "1歳児") and 登園日 = "${dateString}"`
|
||||
});
|
||||
} catch (e) {
|
||||
showError(true, '本アプリのデータ読み取りエラー\n - ' + e);
|
||||
loading(false);
|
||||
}
|
||||
}
|
||||
|
||||
groupingAndSort = (data) => {
|
||||
const groupedByGrade = {};
|
||||
// 1. group by 学年
|
||||
data.forEach((record) => {
|
||||
const grade = record['学年'].value;
|
||||
if (!groupedByGrade[grade]) {
|
||||
groupedByGrade[grade] = [];
|
||||
}
|
||||
groupedByGrade[grade].push(record);
|
||||
});
|
||||
|
||||
// 2. sort by クラス
|
||||
const classOrder = {};
|
||||
classItems.forEach((item, index) => {
|
||||
classOrder[item.value] = index;
|
||||
});
|
||||
for (const grade in groupedByGrade) {
|
||||
groupedByGrade[grade].sort((a, b) => {
|
||||
return classOrder[a["クラス"].value] - classOrder[b["クラス"].value];
|
||||
});
|
||||
}
|
||||
|
||||
// 3. return a list
|
||||
return termItems.reduce((acc, term) => {
|
||||
const grade = term.value;
|
||||
// Skip 0歳児 and 1歳児
|
||||
if (grade === "0歳児" || grade === "1歳児") {
|
||||
return acc;
|
||||
}
|
||||
acc.push({
|
||||
grade: grade,
|
||||
items: groupedByGrade[grade] || []
|
||||
});
|
||||
return acc;
|
||||
}, []);
|
||||
}
|
||||
|
||||
generateRecord = (todayString, groupedRecords) => {
|
||||
return {
|
||||
'登園日': { 'value': todayString },
|
||||
'学年': { 'value': groupedRecords.grade },
|
||||
'園児別テーブル': {
|
||||
'value': groupedRecords.items.map((record) => {
|
||||
return {
|
||||
'value': {
|
||||
'クラス名': { 'value': record['クラス'].value },
|
||||
'名前': { 'value': record['園児名'].value },
|
||||
'子どもの様子': { 'value': record['園での様子_伝達事項'].value },
|
||||
'反省評価_園児別テーブル': { 'value': record['評価反省'].value },
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
insertOrUpdateData = async (api, records, dateString) => {
|
||||
const results = [];
|
||||
const generatedRecords = await api.record.getAllRecordsWithId({
|
||||
app: env["2歳以上日誌出力用"].appId,
|
||||
fields: ["$id", "学年"],
|
||||
condition: `登園日 = "${dateString}"`
|
||||
})
|
||||
const existIdMap = generatedRecords.reduce((map, item) => {
|
||||
const grade = item['学年'].value;
|
||||
const id = item['$id'].value;
|
||||
map[grade] = id;
|
||||
return map;
|
||||
}, {});
|
||||
|
||||
for (const record of records) {
|
||||
try {
|
||||
const generatedRecordId = existIdMap[record["学年"].value];
|
||||
const param = {
|
||||
app: env["2歳以上日誌出力用"].appId,
|
||||
record
|
||||
}
|
||||
const result = {
|
||||
id: generatedRecordId,
|
||||
type: generatedRecordId ? 'update' : 'insert',
|
||||
size: record["園児別テーブル"].value.length,
|
||||
};
|
||||
|
||||
let awaitResult;
|
||||
|
||||
if (result.type === 'update') {
|
||||
param.id = generatedRecordId;
|
||||
// 本アプリの当日データでテーブルを上書きし、対応する園児データがない行を【削除】します
|
||||
awaitResult = await api.record.updateRecord(param);
|
||||
} else {
|
||||
awaitResult = await api.record.addRecord(param);
|
||||
}
|
||||
Object.assign(result, awaitResult);
|
||||
results.push(result);
|
||||
} catch (e) {
|
||||
showError(true, '日誌データ連携作成失敗\n - ' + e);
|
||||
}
|
||||
}
|
||||
|
||||
return results.reduce((result, item) => {
|
||||
// Sum all sizes
|
||||
result.size += item.size;
|
||||
|
||||
// Sum based on type
|
||||
if (item.type === 'insert') {
|
||||
result.insert += item.size;
|
||||
} else if (item.type === 'update') {
|
||||
result.update += item.size;
|
||||
}
|
||||
|
||||
return result;
|
||||
}, {
|
||||
size: 0, // Total sum of all sizes
|
||||
insert: 0, // Sum of insert sizes
|
||||
update: 0 // Sum of update sizes
|
||||
});;
|
||||
};
|
||||
|
||||
static getInstance(headerSpace) {
|
||||
if (!Link2Handler.instance) {
|
||||
Link2Handler.instance = new Link2Handler(headerSpace);
|
||||
|
||||
57
src/園児別出欠簿入力/clock-btn-desktop-mobile.js
Normal file
57
src/園児別出欠簿入力/clock-btn-desktop-mobile.js
Normal file
@@ -0,0 +1,57 @@
|
||||
|
||||
(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}`;
|
||||
}
|
||||
})();
|
||||
3
src/園児別出欠簿入力/lib/FileSaver.min.js
vendored
Normal file
3
src/園児別出欠簿入力/lib/FileSaver.min.js
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
(function(a,b){if("function"==typeof define&&define.amd)define([],b);else if("undefined"!=typeof exports)b();else{b(),a.FileSaver={exports:{}}.exports}})(this,function(){"use strict";function b(a,b){return"undefined"==typeof b?b={autoBom:!1}:"object"!=typeof b&&(console.warn("Deprecated: Expected third argument to be a object"),b={autoBom:!b}),b.autoBom&&/^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(a.type)?new Blob(["\uFEFF",a],{type:a.type}):a}function c(a,b,c){var d=new XMLHttpRequest;d.open("GET",a),d.responseType="blob",d.onload=function(){g(d.response,b,c)},d.onerror=function(){console.error("could not download file")},d.send()}function d(a){var b=new XMLHttpRequest;b.open("HEAD",a,!1);try{b.send()}catch(a){}return 200<=b.status&&299>=b.status}function e(a){try{a.dispatchEvent(new MouseEvent("click"))}catch(c){var b=document.createEvent("MouseEvents");b.initMouseEvent("click",!0,!0,window,0,0,0,80,20,!1,!1,!1,!1,0,null),a.dispatchEvent(b)}}var f="object"==typeof window&&window.window===window?window:"object"==typeof self&&self.self===self?self:"object"==typeof global&&global.global===global?global:void 0,a=/Macintosh/.test(navigator.userAgent)&&/AppleWebKit/.test(navigator.userAgent)&&!/Safari/.test(navigator.userAgent),g=f.saveAs||("object"!=typeof window||window!==f?function(){}:"download"in HTMLAnchorElement.prototype&&!a?function(b,g,h){var i=f.URL||f.webkitURL,j=document.createElement("a");g=g||b.name||"download",j.download=g,j.rel="noopener","string"==typeof b?(j.href=b,j.origin===location.origin?e(j):d(j.href)?c(b,g,h):e(j,j.target="_blank")):(j.href=i.createObjectURL(b),setTimeout(function(){i.revokeObjectURL(j.href)},4E4),setTimeout(function(){e(j)},0))}:"msSaveOrOpenBlob"in navigator?function(f,g,h){if(g=g||f.name||"download","string"!=typeof f)navigator.msSaveOrOpenBlob(b(f,h),g);else if(d(f))c(f,g,h);else{var i=document.createElement("a");i.href=f,i.target="_blank",setTimeout(function(){e(i)})}}:function(b,d,e,g){if(g=g||open("","_blank"),g&&(g.document.title=g.document.body.innerText="downloading..."),"string"==typeof b)return c(b,d,e);var h="application/octet-stream"===b.type,i=/constructor/i.test(f.HTMLElement)||f.safari,j=/CriOS\/[\d]+/.test(navigator.userAgent);if((j||h&&i||a)&&"undefined"!=typeof FileReader){var k=new FileReader;k.onloadend=function(){var a=k.result;a=j?a:a.replace(/^data:[^;]*;/,"data:attachment/file;"),g?g.location.href=a:location=a,g=null},k.readAsDataURL(b)}else{var l=f.URL||f.webkitURL,m=l.createObjectURL(b);g?g.location=m:location.href=m,g=null,setTimeout(function(){l.revokeObjectURL(m)},4E4)}});f.saveAs=g.saveAs=g,"undefined"!=typeof module&&(module.exports=g)});
|
||||
|
||||
//# sourceMappingURL=FileSaver.min.js.map
|
||||
1
src/園児別出欠簿入力/lib/KintoneRestAPIClient.min.js
vendored
Normal file
1
src/園児別出欠簿入力/lib/KintoneRestAPIClient.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
3
src/園児別出欠簿入力/lib/exceljs.min.js
vendored
Normal file
3
src/園児別出欠簿入力/lib/exceljs.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
2433
src/園児別出欠簿入力/lib/kuc.min.js
vendored
Normal file
2433
src/園児別出欠簿入力/lib/kuc.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
496
src/園児別出欠簿入力/lib/pvc.lib.exceljsUtil.js
Normal file
496
src/園児別出欠簿入力/lib/pvc.lib.exceljsUtil.js
Normal file
@@ -0,0 +1,496 @@
|
||||
/** @copyright 2018 Planning Village Corporation Co., Ltd. */
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
// [IE11] Polyfill of Object.values
|
||||
if (!Object.values) {
|
||||
const ownKeys = (
|
||||
(typeof Reflect === 'object' && typeof Reflect.ownKeys === 'function') ? Reflect.ownKeys :
|
||||
// @ts-ignore
|
||||
(typeof Object.getOwnPropertySymbols === 'function') ? (function (O) {
|
||||
// @ts-ignore
|
||||
return Object.getOwnPropertyNames(O).concat(Object.getOwnPropertySymbols(O));
|
||||
}) :
|
||||
Object.getOwnPropertyNames);
|
||||
// @ts-ignore
|
||||
const reduce = Function.bind.call(Function.call, Array.prototype.reduce);
|
||||
// @ts-ignore
|
||||
const isEnumerable = Function.bind.call(Function.call, Object.prototype.propertyIsEnumerable);
|
||||
// @ts-ignore
|
||||
const concat = Function.bind.call(Function.call, Array.prototype.concat);
|
||||
//@ts-ignore
|
||||
Object.values = function values(O) {
|
||||
//@ts-ignore
|
||||
return reduce(ownKeys(O), function (v, k) {
|
||||
return concat(v, typeof k === 'string' && isEnumerable(O, k) ? [O[k]] : [])
|
||||
}, [])
|
||||
};
|
||||
}
|
||||
|
||||
// [IE11] Polyfill of Number.isNaN
|
||||
if (!Number.isNaN) {
|
||||
Number.isNaN = function (value) {
|
||||
return value !== null && (value != value || +value != value);
|
||||
};
|
||||
}
|
||||
|
||||
// [IE11] Polyfill of String.prototype.startsWith
|
||||
if (!String.prototype.startsWith) {
|
||||
Object.defineProperty(String.prototype, 'startsWith', {
|
||||
//@ts-ignore
|
||||
value: function (search, rawPos) {
|
||||
var pos = rawPos > 0 ? rawPos | 0 : 0;
|
||||
return this.substring(pos, pos + search.length) === search;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// [IE11] Polyfill of String.prototype.includes
|
||||
if (!String.prototype.includes) {
|
||||
String.prototype.includes = function (search, start) {
|
||||
'use strict';
|
||||
//@ts-ignore
|
||||
if (search instanceof RegExp) {
|
||||
throw TypeError('first argument must not be a RegExp');
|
||||
}
|
||||
if (start === undefined) {
|
||||
start = 0;
|
||||
}
|
||||
return this.indexOf(search, start) !== -1;
|
||||
};
|
||||
}
|
||||
|
||||
// [IE11] Polyfill of Array.prototype.findIndex
|
||||
if (!Array.prototype.findIndex) {
|
||||
// @ts-ignore
|
||||
Array.prototype.findIndex = function (predicate) {
|
||||
if (this === null) {
|
||||
throw new TypeError('Array.prototype.findIndex called on null or undefined');
|
||||
}
|
||||
if (typeof predicate !== 'function') {
|
||||
throw new TypeError('predicate must be a function');
|
||||
}
|
||||
var list = Object(this);
|
||||
var length = list.length >>> 0;
|
||||
var thisArg = arguments[1];
|
||||
var value;
|
||||
|
||||
for (var i = 0; i < length; i++) {
|
||||
value = list[i];
|
||||
if (predicate.call(thisArg, value, i, list)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
};
|
||||
}
|
||||
|
||||
//@ts-ignore
|
||||
window.pvc = window.pvc || {};
|
||||
//@ts-ignore
|
||||
window.pvc.lib = window.pvc.lib || {};
|
||||
//@ts-ignore
|
||||
window.pvc.lib.exceljsUtil = (function () {
|
||||
const exceljs = {
|
||||
/**
|
||||
* ワークブックの blob を読み取ります。
|
||||
* @param {Blob} blob Blob
|
||||
* @return {Promise<ExcelJS.Workbook>} ワークブック
|
||||
*/
|
||||
loadWorkbookBlob: function (blob) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
var reader = new FileReader();
|
||||
reader.onload = function (e) {
|
||||
// @ts-ignore
|
||||
resolve(e.target.result);
|
||||
};
|
||||
reader.onerror = function (e) {
|
||||
reject(e);
|
||||
}
|
||||
reader.onabort = function (e) {
|
||||
reject(e);
|
||||
}
|
||||
reader.readAsArrayBuffer(blob);
|
||||
}).then(function (arrayBuffer) {
|
||||
// 非公式のメンバー load を使用
|
||||
// @ts-ignore
|
||||
return new ExcelJS.Workbook().xlsx.load(arrayBuffer);
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* ワークブックを Blob に変換します。
|
||||
* @param {ExcelJS.Workbook} workbook ワークブック
|
||||
* @return {Promise<Blob>} Blob
|
||||
*/
|
||||
saveWorkbookToBlob: function (workbook) {
|
||||
// writeBuffer の戻り値 ExcelJS.Buffer はブラウザ環境では Uint8Array となる
|
||||
return workbook.xlsx.writeBuffer().then(function (ua) {
|
||||
return new Blob([ua], {
|
||||
type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* 行をコピーします。
|
||||
* @param {ExcelJS.Worksheet} worksheet ワークシート
|
||||
* @param {number} topRowNumber コピー元の開始行番号(1から開始)
|
||||
* @param {number} [bottomRowNumber] コピー元の終了行番号(1から開始)。省略時は開始行番号と同じ値となります。
|
||||
* @returns {pvc.lib.exceljsUtil.CopiedRowsInfo} 行のコピー情報
|
||||
*/
|
||||
copyRows: function (worksheet, topRowNumber, bottomRowNumber) {
|
||||
const _bottomRowNumber = (bottomRowNumber == null ? topRowNumber : bottomRowNumber);
|
||||
|
||||
if (topRowNumber < 0 || _bottomRowNumber < topRowNumber) {
|
||||
throw new Error('コピー元の領域とが不正です。');
|
||||
}
|
||||
|
||||
// コピー元の領域の情報を収集
|
||||
const rows = [];
|
||||
for (let r = topRowNumber; r <= _bottomRowNumber; r++) {
|
||||
const row = worksheet.getRow(r);
|
||||
const cells = [];
|
||||
for (let c = 1; c <= worksheet.columnCount; c++) {
|
||||
const cell = row.getCell(c);
|
||||
cells.push({
|
||||
value: cell.value,
|
||||
style: cell.style,
|
||||
});
|
||||
}
|
||||
rows.push({
|
||||
cells: cells,
|
||||
height: row.height,
|
||||
// 非公式のメンバー style を使用
|
||||
// @ts-ignore
|
||||
style: row.style,
|
||||
});
|
||||
}
|
||||
|
||||
// コピー元の領域の内部に収まるマージを収集
|
||||
const merges = deepCopyObject(getWorksheetMerges(worksheet).filter(function (merge) {
|
||||
return (topRowNumber <= merge.top && merge.bottom <= _bottomRowNumber);
|
||||
}).map(function (merge) {
|
||||
return {
|
||||
top: merge.top - topRowNumber,
|
||||
right: merge.right,
|
||||
bottom: merge.bottom - topRowNumber,
|
||||
left: merge.left,
|
||||
};
|
||||
}));
|
||||
|
||||
return deepCopyObject({
|
||||
rows: rows,
|
||||
merges: merges
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* 指定された開始行を起点に、コピーした行を貼り付けます。
|
||||
* コピー元の領域と領域外の両方にまたがるセルのマージは貼り付けされません。
|
||||
* コピー先の領域を一部でも含むマージは全て解除されます。
|
||||
* @param {ExcelJS.Worksheet} worksheet ワークシート
|
||||
* @param {number} topRowNumber コピー先の開始行番号(1から開始)
|
||||
* @param {pvc.lib.exceljsUtil.CopiedRowsInfo} copiedRowsInfo 行のコピー情報
|
||||
*/
|
||||
pasteRows: function (worksheet, topRowNumber, copiedRowsInfo) {
|
||||
const bottomRowNumber = topRowNumber + copiedRowsInfo.rows.length - 1;
|
||||
|
||||
if (topRowNumber < 0) {
|
||||
throw new Error('コピー先の領域とが不正です。');
|
||||
}
|
||||
|
||||
// コピー先の行のマージを解除(コピー先の領域を一部でも含むマージは全て解除)
|
||||
getWorksheetMerges(worksheet).filter(function (merge) {
|
||||
return (topRowNumber <= merge.bottom && merge.top <= bottomRowNumber);
|
||||
}).forEach(function (merge) {
|
||||
worksheet.unMergeCells(merge.range);
|
||||
});
|
||||
|
||||
// マージをペースト
|
||||
copiedRowsInfo.merges.forEach(function (mergeInfo) {
|
||||
worksheet.mergeCells(
|
||||
topRowNumber + mergeInfo.top,
|
||||
mergeInfo.left,
|
||||
topRowNumber + mergeInfo.bottom,
|
||||
mergeInfo.right);
|
||||
});
|
||||
|
||||
// セルをペースト
|
||||
copiedRowsInfo.rows.forEach(function (rowInfo, i) {
|
||||
const row = worksheet.getRow(topRowNumber + i);
|
||||
row.height = rowInfo.height;
|
||||
// 非公式のメンバー style を使用
|
||||
// @ts-ignore
|
||||
row.style = rowInfo.style;
|
||||
for (let c = 1; c <= worksheet.columnCount; c++) {
|
||||
const cell = row.getCell(c);
|
||||
const cellInfo = rowInfo.cells[c - 1];
|
||||
if (cellInfo) {
|
||||
cell.value = cellInfo.value;
|
||||
cell.style = cellInfo.style;
|
||||
} else {
|
||||
exceljs.clearCell(cell);
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* 指定された開始行を起点に、コピーした行を挿入します。
|
||||
* コピー元の領域と領域外の両方にまたがるセルのマージは貼り付けされません。
|
||||
* @param {ExcelJS.Worksheet} worksheet ワークシート
|
||||
* @param {number} topRowNumber コピー先の開始行番号(1から開始)
|
||||
* @param {pvc.lib.exceljsUtil.CopiedRowsInfo} copiedRowsInfo 行のコピー情報
|
||||
*/
|
||||
insertRows: function (worksheet, topRowNumber, copiedRowsInfo) {
|
||||
const bottomRows = (
|
||||
topRowNumber <= worksheet.rowCount ?
|
||||
exceljs.copyRows(worksheet, topRowNumber, worksheet.rowCount) :
|
||||
null);
|
||||
exceljs.pasteRows(worksheet, topRowNumber, copiedRowsInfo);
|
||||
if (bottomRows) {
|
||||
exceljs.pasteRows(worksheet, topRowNumber + copiedRowsInfo.rows.length, bottomRows);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 列をコピーします。
|
||||
* @param {ExcelJS.Worksheet} worksheet ワークシート
|
||||
* @param {number | string} leftColumn コピー元の開始列の列番号(1から開始)または列ラベル。終了列の引数を省略して、代わりに "A:B" の形式でコピー元の列の範囲を指定することも可能。
|
||||
* @param {number | string} [rightColumn] コピー元の終了列の列番号(1から開始)または列ラベル。省略時は開始列と同じとみなされます(開始列を "A:B" の形式で指定された場合を除く)。
|
||||
* @returns {pvc.lib.exceljsUtil.CopiedColumnsInfo} 列のコピー情報
|
||||
*/
|
||||
copyColumns: function (worksheet, leftColumn, rightColumn) {
|
||||
if (rightColumn == null) {
|
||||
rightColumn = leftColumn;
|
||||
if (typeof leftColumn === 'string') {
|
||||
const sp = leftColumn.split(':');
|
||||
if (sp.length === 2) {
|
||||
leftColumn = sp[0];
|
||||
rightColumn = sp[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const leftColumnNumber = ((typeof leftColumn === 'number') ? leftColumn : exceljs.columnLetterToColumnNumber(leftColumn));
|
||||
const rightColumnNumber = ((typeof rightColumn === 'number') ? rightColumn : exceljs.columnLetterToColumnNumber(rightColumn));
|
||||
|
||||
if (leftColumnNumber < 0 || rightColumnNumber < leftColumnNumber) {
|
||||
throw new Error('コピー元の領域とが不正です。');
|
||||
}
|
||||
|
||||
// コピー元の領域の情報を収集
|
||||
const columns = [];
|
||||
for (let c = leftColumnNumber; c <= rightColumnNumber; c++) {
|
||||
const column = worksheet.getColumn(c);
|
||||
const cells = [];
|
||||
for (let r = 1; r <= worksheet.rowCount; r++) {
|
||||
const cell = worksheet.getRow(r).getCell(c);
|
||||
cells.push({
|
||||
value: cell.value,
|
||||
style: cell.style,
|
||||
});
|
||||
}
|
||||
columns.push({
|
||||
cells: cells,
|
||||
width: column.width,
|
||||
style: column.style,
|
||||
});
|
||||
}
|
||||
|
||||
// コピー元の領域の内部に収まるマージを収集
|
||||
const merges = deepCopyObject(getWorksheetMerges(worksheet).filter(function (merge) {
|
||||
return (leftColumnNumber <= merge.left && merge.right <= rightColumnNumber);
|
||||
}).map(function (merge) {
|
||||
return {
|
||||
top: merge.top,
|
||||
right: merge.right - leftColumnNumber,
|
||||
bottom: merge.bottom,
|
||||
left: merge.left - leftColumnNumber,
|
||||
};
|
||||
}));
|
||||
|
||||
return {
|
||||
columns: columns,
|
||||
merges: merges
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* 指定された開始列を起点に、コピーした列を貼り付けます。
|
||||
* コピー元の領域と領域外の両方にまたがるセルのマージは貼り付けされません。
|
||||
* コピー先の領域を一部でも含むマージは全て解除されます。
|
||||
* @param {ExcelJS.Worksheet} worksheet ワークシート
|
||||
* @param {number | string} leftColumn コピー先の開始列の列番号(1から開始)または列ラベル
|
||||
* @param {pvc.lib.exceljsUtil.CopiedColumnsInfo} copiedColumnsInfo 列のコピー情報
|
||||
*/
|
||||
pasteColumns: function (worksheet, leftColumn, copiedColumnsInfo) {
|
||||
const leftColumnNumber = ((typeof leftColumn === 'number') ? leftColumn : exceljs.columnLetterToColumnNumber(leftColumn));
|
||||
const rightColumnNumber = leftColumnNumber + copiedColumnsInfo.columns.length - 1;
|
||||
|
||||
if (leftColumnNumber < 0) {
|
||||
throw new Error('コピー先の領域とが不正です。');
|
||||
}
|
||||
|
||||
// コピー先の列のマージを解除(コピー先の領域を一部でも含むマージは全て解除)
|
||||
getWorksheetMerges(worksheet).filter(function (merge) {
|
||||
return (leftColumnNumber <= merge.right && merge.left <= rightColumnNumber);
|
||||
}).forEach(function (merge) {
|
||||
worksheet.unMergeCells(merge.range);
|
||||
});
|
||||
|
||||
// マージをペースト
|
||||
copiedColumnsInfo.merges.forEach(function (mergeInfo) {
|
||||
worksheet.mergeCells(
|
||||
mergeInfo.top,
|
||||
leftColumnNumber + mergeInfo.left,
|
||||
mergeInfo.bottom,
|
||||
leftColumnNumber + mergeInfo.right);
|
||||
});
|
||||
|
||||
// セルをペースト
|
||||
copiedColumnsInfo.columns.forEach(function (columnInfo, i) {
|
||||
const column = worksheet.getColumn(leftColumnNumber + i);
|
||||
column.width = columnInfo.width;
|
||||
column.style = columnInfo.style;
|
||||
for (let r = 1; r <= worksheet.rowCount; r++) {
|
||||
const cell = worksheet.getRow(r).getCell(leftColumnNumber + i);
|
||||
const cellInfo = columnInfo.cells[r - 1];
|
||||
if (cellInfo) {
|
||||
cell.value = cellInfo.value;
|
||||
cell.style = cellInfo.style;
|
||||
} else {
|
||||
exceljs.clearCell(cell);
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* 指定された開始列を起点に、コピーした列を挿入します。
|
||||
* コピー元の領域と領域外の両方にまたがるセルのマージは貼り付けされません。
|
||||
* @param {ExcelJS.Worksheet} worksheet ワークシート
|
||||
* @param {number | string} leftColumn コピー先の開始列の列番号(1から開始)または列ラベル
|
||||
* @param {pvc.lib.exceljsUtil.CopiedColumnsInfo} copiedRowsInfo 列のコピー情報
|
||||
*/
|
||||
insertColumns: function (worksheet, leftColumn, copiedRowsInfo) {
|
||||
const leftColumnNumber = ((typeof leftColumn === 'number') ? leftColumn : exceljs.columnLetterToColumnNumber(leftColumn));
|
||||
const rightColumns = (
|
||||
leftColumnNumber <= worksheet.columnCount ?
|
||||
exceljs.copyColumns(worksheet, leftColumnNumber, worksheet.columnCount) :
|
||||
null);
|
||||
exceljs.pasteColumns(worksheet, leftColumnNumber, copiedRowsInfo);
|
||||
if (rightColumns) {
|
||||
exceljs.pasteColumns(worksheet, leftColumnNumber + copiedRowsInfo.columns.length, rightColumns);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* セルをクリアします。
|
||||
* @param {ExcelJS.Cell} cell セル
|
||||
*/
|
||||
clearCell: function (cell) {
|
||||
cell.value = null;
|
||||
/// @ts-ignore
|
||||
cell.style = cell._mergeStyle(cell._row.style, cell._column.style, {});
|
||||
},
|
||||
|
||||
/**
|
||||
* 列ラベルから列番号(1から開始)を取得します。
|
||||
* @param {string} columnLetter 列ラベル
|
||||
* @return {number} 列番号(1から開始)
|
||||
*/
|
||||
columnLetterToColumnNumber: function (columnLetter) {
|
||||
const letter = columnLetter.toUpperCase();
|
||||
const l = letter.length;
|
||||
const charCodeA = 65;
|
||||
let result = 0;
|
||||
for (let i = 0, j = l - 1; i < l; i++, j--) {
|
||||
result += (letter.charCodeAt(j) - charCodeA + 1) * (i === 0 ? 1 : Math.pow(26, i));
|
||||
}
|
||||
return result;
|
||||
},
|
||||
|
||||
/**
|
||||
* 日付のセルの値を作成します。
|
||||
* @param {Date} date
|
||||
* @returns {any}
|
||||
*/
|
||||
createDateCellValue: function (date) {
|
||||
// UTC にしないと正しく Excel に反映されない
|
||||
return new Date(Date.UTC(date.getFullYear(), date.getMonth(), date.getDate(), date.getHours(), date.getMinutes(), date.getSeconds()));
|
||||
},
|
||||
|
||||
deepCopyObject: deepCopyObject,
|
||||
};
|
||||
|
||||
/**
|
||||
* ワークシートのマージを取得します。
|
||||
* @param {ExcelJS.Worksheet} worksheet ワークシート
|
||||
*/
|
||||
function getWorksheetMerges(worksheet) {
|
||||
// 非公式のメンバー _merges を使用
|
||||
// @ts-ignore
|
||||
const mergesDic = worksheet._merges;
|
||||
return Object.keys(mergesDic).map(function (address) {
|
||||
return mergesDic[address];
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* オブジェクのコピーします。ディープコピーとなります。
|
||||
* @template T
|
||||
* @param {T} obj
|
||||
* @returns {T}
|
||||
*/
|
||||
function deepCopyObject(obj) {
|
||||
return copyObject(obj);
|
||||
|
||||
//@ts-ignore
|
||||
function copyObject(obj) {
|
||||
return (
|
||||
obj == null ? null :
|
||||
Array.isArray(obj) ? copyArray(obj) :
|
||||
isDate(obj) ? copyDate(obj) :
|
||||
isDic(obj) ? copyDic(obj) :
|
||||
obj);
|
||||
}
|
||||
|
||||
//@ts-ignore
|
||||
function copyArray(array) {
|
||||
//@ts-ignore
|
||||
return array.map(function (item) {
|
||||
return copyObject(item);
|
||||
});
|
||||
}
|
||||
|
||||
//@ts-ignore
|
||||
function isDate(obj) {
|
||||
return (obj != null && Object.prototype.toString.call(obj) === '[object Date]');
|
||||
}
|
||||
|
||||
//@ts-ignore
|
||||
function copyDate(date) {
|
||||
return (isNaN(date) ? null : new Date(date.getTime()));
|
||||
}
|
||||
|
||||
//@ts-ignore
|
||||
function isDic(obj) {
|
||||
return (obj != null && typeof obj === 'object');
|
||||
}
|
||||
|
||||
//@ts-ignore
|
||||
function copyDic(dic) {
|
||||
let result = {};
|
||||
for (let key in dic) {
|
||||
//@ts-ignore
|
||||
result[key] = copyObject(dic[key]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return exceljs;
|
||||
}());
|
||||
})();
|
||||
@@ -2,15 +2,17 @@
|
||||
"use strict";
|
||||
const APP_ENV = env["園児別出欠簿入力"];
|
||||
|
||||
addApproveFlowAction();
|
||||
|
||||
kintone.events.on("app.record.index.show", (event) => {
|
||||
const headerSpace = getHeaderSpace('single-label-line');
|
||||
|
||||
if (event.viewId === APP_ENV.view["0,1歳日誌データ連携用途"]) {
|
||||
if (event.viewId === APP_ENV.view.linkFor0to1) {
|
||||
Link1Handler.getInstance(headerSpace);
|
||||
return event;
|
||||
}
|
||||
|
||||
if (event.viewId === APP_ENV.view["2歳以上日誌データ連携用途"]) {
|
||||
if (event.viewId === APP_ENV.view.linkForOthers) {
|
||||
Link2Handler.getInstance(headerSpace);
|
||||
return event;
|
||||
}
|
||||
|
||||
21
src/園児別出欠簿入力/main.mobile.js
Normal file
21
src/園児別出欠簿入力/main.mobile.js
Normal file
@@ -0,0 +1,21 @@
|
||||
(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);
|
||||
});
|
||||
})();
|
||||
@@ -29,7 +29,7 @@
|
||||
}
|
||||
|
||||
// ------------------- 編集画面保存時の処理 -------------------
|
||||
kintone.events.on(['app.record.create.submit', 'app.record.edit.submit'], function (event) {
|
||||
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;
|
||||
});
|
||||
|
||||
41
src/園児台帳/main.mobile.js
Normal file
41
src/園児台帳/main.mobile.js
Normal file
@@ -0,0 +1,41 @@
|
||||
|
||||
(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);
|
||||
}
|
||||
|
||||
})();
|
||||
6
src/学年別保育計画/env.js
Normal file
6
src/学年別保育計画/env.js
Normal file
@@ -0,0 +1,6 @@
|
||||
const statusFieldMap = {
|
||||
'指導教諭確認中': '担任',
|
||||
'主幹確認中': '指導',
|
||||
'園長確認中': '主幹',
|
||||
'完了': '園長'
|
||||
}
|
||||
12
src/学年別保育計画/main.js
Normal file
12
src/学年別保育計画/main.js
Normal file
@@ -0,0 +1,12 @@
|
||||
(function () {
|
||||
"use strict";
|
||||
|
||||
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;
|
||||
});
|
||||
|
||||
})();
|
||||
12
src/学年別保育計画/main.mobile.js
Normal file
12
src/学年別保育計画/main.mobile.js
Normal file
@@ -0,0 +1,12 @@
|
||||
(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;
|
||||
});
|
||||
|
||||
})();
|
||||
13
src/学期反省・評価/env.js
Normal file
13
src/学期反省・評価/env.js
Normal file
@@ -0,0 +1,13 @@
|
||||
const statusFieldMap = {
|
||||
'主幹確認中(1学期)': '指導1',
|
||||
'園長確認中(1学期)': '主幹1',
|
||||
'完了(1学期)': '園長1',
|
||||
'担任作成中(2学期)': '園長1',
|
||||
'主幹確認中(2学期)': '指導2',
|
||||
'園長確認中(2学期)': '主幹2',
|
||||
'完了(2学期)': '園長2',
|
||||
'担任作成中(3学期)': '園長2',
|
||||
'主幹確認中(3学期)': '指導3',
|
||||
'園長確認中(3学期)': '主幹3',
|
||||
'完了(3学期)': '園長3',
|
||||
}
|
||||
12
src/学期反省・評価/main.js
Normal file
12
src/学期反省・評価/main.js
Normal file
@@ -0,0 +1,12 @@
|
||||
(function () {
|
||||
"use strict";
|
||||
|
||||
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;
|
||||
});
|
||||
|
||||
})();
|
||||
12
src/学期反省・評価/main.mobile.js
Normal file
12
src/学期反省・評価/main.mobile.js
Normal file
@@ -0,0 +1,12 @@
|
||||
(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;
|
||||
});
|
||||
|
||||
})();
|
||||
Reference in New Issue
Block a user