update process

This commit is contained in:
2025-09-15 09:47:59 +08:00
parent 1d06e25626
commit c5cf6c0c22
48 changed files with 163 additions and 59 deletions

View 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

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,132 @@
(function () {
"use strict";
const APP_ENV = env["2歳以上日誌出力用"];
kintone.events.on("app.record.detail.show", (event) => {
const headerSpace = getHeaderSpace('', true);
const elements = createBtnGroupArea('extract-action-area', '日誌作成', handleButtonClick, {
btnElId: 'extract-btn',
})
if (!elements) {
return;
}
headerSpace.appendChild(elements['extract-action-area']);
});
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();
}
}
}
})();

View File

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

View File

@@ -0,0 +1,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;
}());
})();