個別配慮
This commit is contained in:
BIN
document/PVC.one
BIN
document/PVC.one
Binary file not shown.
Binary file not shown.
@@ -2,14 +2,11 @@
|
||||
"use strict";
|
||||
const APP_ENV = env["0,1歳日誌出力用"];
|
||||
|
||||
kintone.events.on("app.record.index.show", (event) => {
|
||||
const headerSpace = getHeaderSpace('single-label-line');
|
||||
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) {
|
||||
|
||||
@@ -2,15 +2,11 @@
|
||||
"use strict";
|
||||
const APP_ENV = env["2歳以上日誌出力用"];
|
||||
|
||||
kintone.events.on("app.record.index.show", (event) => {
|
||||
const headerSpace = getHeaderSpace('single-label-line');
|
||||
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) {
|
||||
|
||||
@@ -24,6 +24,9 @@ const env = {
|
||||
"園児台帳": {
|
||||
appId: 16,
|
||||
},
|
||||
"Excelテンプレート": {
|
||||
appId: 46
|
||||
}
|
||||
};
|
||||
|
||||
const warekiStartYear = {
|
||||
|
||||
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;
|
||||
}());
|
||||
})();
|
||||
@@ -46,6 +46,14 @@
|
||||
margin: 0 8px;
|
||||
}
|
||||
|
||||
.customized-record-header-space {
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
margin: 16px 0;
|
||||
}
|
||||
.customized-record-header-space > .btn-group-area{
|
||||
padding-right: 0;
|
||||
}
|
||||
.customized-header-space-wrapper.single-label-line {
|
||||
margin-top: 33px;
|
||||
}
|
||||
|
||||
86
src/utils.js
86
src/utils.js
@@ -192,7 +192,7 @@ function hideSpaceField(ids) {
|
||||
});
|
||||
}
|
||||
|
||||
function getExcelName({ excelName }, nameSuffix = '', suffix = '.xlsx') {
|
||||
function getExcelName(excelName, nameSuffix = '', suffix = '.xlsx') {
|
||||
return excelName + (nameSuffix ? (nameSuffix.startsWith('_') ? nameSuffix : ('_' + nameSuffix)) : '') + suffix;
|
||||
}
|
||||
|
||||
@@ -353,4 +353,86 @@ function createDialogEl({ ok, cancel, onOk, onCancel, onClose, ...options }) {
|
||||
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 buffer = await workbook.xlsx.writeBuffer();
|
||||
|
||||
saveFile(buffer, exportName);
|
||||
}
|
||||
|
||||
function saveFile(buffer, fileName) {
|
||||
const blob = new Blob([buffer], {
|
||||
type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
|
||||
});
|
||||
saveAs(blob, fileName);
|
||||
}
|
||||
|
||||
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,
|
||||
value
|
||||
});
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
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
@@ -18,8 +18,109 @@
|
||||
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 signLabels = ['園長', '主幹', '指導', '担任'];
|
||||
const signRow = baseCells['園長'][0].row + 1;
|
||||
for (let i = 0; i < signLabels.length; i++) {
|
||||
worksheet.getCell(signRow, baseCells['園長'][0].col + i).value = records[0][signLabels[i]].value; // TODO force use records[0]?
|
||||
}
|
||||
|
||||
const pageSize = 10;
|
||||
const totalPages = Math.ceil(records.length / pageSize);
|
||||
if (totalPages > 2) {
|
||||
const lastPage = 2;
|
||||
const copyPageRowStart = baseCells['月'][lastPage - 1].row - 1;
|
||||
const copyPageRowEnd = baseCells['児童名'][lastPage - 1].row + pageSize;
|
||||
const rowCount = copyPageRowEnd - copyPageRowStart + 1;
|
||||
let newPageRow = copyPageRowEnd + 1;
|
||||
|
||||
for (let p = 3; p <= totalPages; p++) {
|
||||
const copyRow = pvc.lib.exceljsUtil.copyRows(worksheet, copyPageRowStart, copyPageRowEnd);
|
||||
pvc.lib.exceljsUtil.insertRows(worksheet, newPageRow, copyRow);
|
||||
newPageRow += rowCount;
|
||||
['月', '児童名'].forEach((label) => {
|
||||
const last = baseCells[label][p - 2];
|
||||
baseCells[label].push({
|
||||
...last,
|
||||
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];
|
||||
worksheet.getCell(monthLabelCell.row, monthLabelCell.col - 1).value = 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 => {
|
||||
row.getCell(col.index).value = record[col.field].value;
|
||||
row.getCell(col.index).alignment = { wrapText: true };;
|
||||
});
|
||||
currentRow++;
|
||||
}
|
||||
|
||||
worksheet.getRow(childLabelCell.row + pageSize).addPageBreak();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
})();
|
||||
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;
|
||||
}());
|
||||
})();
|
||||
@@ -28,21 +28,28 @@ class BatchCreateHandler {
|
||||
const records = this.generateRecords(today, todayString, masterRecords);
|
||||
// console.log(records);
|
||||
|
||||
const createResult = await this.createData(api, records, todayString);
|
||||
const result = await this.createData(api, records, todayString);
|
||||
// showSuccess(true, "出欠簿一括作成完了");
|
||||
if (result) {
|
||||
this.showSuccessDialog(result);
|
||||
}
|
||||
|
||||
this.showSuccessDialog(createResult);
|
||||
loading(false);
|
||||
}
|
||||
|
||||
showSuccessDialog(result) {
|
||||
const contentEl = document.createElement('div');
|
||||
contentEl.style.fontSize = '16px';
|
||||
if (!result) {
|
||||
contentEl.innerHTML = "データの更新はありません。既に最新の状態です。";
|
||||
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 = `${result.records.length}件のデータを挿入しました。`;
|
||||
contentEl.innerHTML = `データの更新はありません。既に最新の状態です。`
|
||||
}
|
||||
|
||||
showDialog({
|
||||
title: '出欠簿一括作成完了',
|
||||
content: contentEl,
|
||||
@@ -82,6 +89,7 @@ class BatchCreateHandler {
|
||||
return {
|
||||
'登園日': { 'value': todayString },
|
||||
'園児ユニークキー': { 'value': record['ユニークキー'].value },
|
||||
'担任': { 'value': record['担当者名'].value.map((x)=>x.name).join('、') },
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,7 +97,7 @@ class BatchCreateHandler {
|
||||
try {
|
||||
return await api.record.getAllRecordsWithId({
|
||||
app: env["園児台帳"].appId,
|
||||
fields: ['ユニークキー', "和暦_退園年月日", "年_退園年月日", "月_退園年月日", "日_退園年月日"],
|
||||
fields: ['ユニークキー', '担当者名', "和暦_退園年月日", "年_退園年月日", "月_退園年月日", "日_退園年月日"],
|
||||
});
|
||||
} catch (e) {
|
||||
showError(true, '園児台帳アプリのデータ読み取りエラー\n - ' + e);
|
||||
@@ -105,16 +113,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);
|
||||
}
|
||||
@@ -129,7 +161,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) {
|
||||
|
||||
@@ -31,8 +31,7 @@ class Link1Handler {
|
||||
|
||||
const result = await this.insertOrUpdateData(api, recordsWrapper);
|
||||
if (result) {
|
||||
// TODO dialog
|
||||
showSuccess(true, "日誌データ連携作成完了");
|
||||
// showSuccess(true, "日誌データ連携作成完了");
|
||||
this.showSuccessDialog(result, year, month);
|
||||
}
|
||||
loading(false);
|
||||
@@ -130,7 +129,6 @@ class Link1Handler {
|
||||
const subtable = Array.from({ length: 31 }, (_e, i) => ({
|
||||
value: {
|
||||
'日付': { 'value': i + 1 },
|
||||
'出欠': { 'value': '出席停止' },
|
||||
}
|
||||
}));
|
||||
recordWrapper.list.forEach((record) => {
|
||||
|
||||
Reference in New Issue
Block a user