docs(sdlc): keep short cells on one line, unify QA/Tester

This commit is contained in:
Thanakorn
2026-10-02 16:54:10 +07:00
parent 203b541c59
commit 5d3a7a655b
117 changed files with 14 additions and 11 deletions
+8 -5
View File
@@ -354,7 +354,7 @@ async function tableWidthNeededMm(page) {
* them. Returns the IDs or dates that still stick out of their cell.
*/
async function applyProportionalWidths(page, textMm) {
return page.evaluate(({ availMm, SHORT_COLUMN_MM }) => {
return page.evaluate(({ availMm, SHORT_COLUMN_MM, SHORT_CELL_CHARS }) => {
const mm = 96 / 25.4;
const main = document.querySelector('main.delivery-document');
const probe = document.createElement('style');
@@ -373,7 +373,8 @@ async function applyProportionalWidths(page, textMm) {
const rects = [...range.getClientRects()];
const text = rects.length ? Math.max(...rects.map((r) => r.right)) - Math.min(...rects.map((r) => r.left)) : 0;
const style = getComputedStyle(cell);
return text + parseFloat(style.paddingLeft) + parseFloat(style.paddingRight) + 1;
// 1.2mm slack for the cell borders and glyphs that overhang their advance width.
return text + parseFloat(style.paddingLeft) + parseFloat(style.paddingRight) + 1.2 * mm;
};
const measure = (table, mode) => {
const holder = document.createElement('div');
@@ -384,7 +385,7 @@ async function applyProportionalWidths(page, textMm) {
for (const row of holder.querySelector('table').rows) {
let index = 0;
for (const cell of row.cells) {
if (cell.colSpan === 1) (columns[index] ??= []).push({ width: contentWidth(cell) / mm, head: cell.tagName === 'TH' });
if (cell.colSpan === 1) (columns[index] ??= []).push({ width: contentWidth(cell) / mm, head: cell.tagName === 'TH', short: cell.textContent.trim().length <= SHORT_CELL_CHARS });
index += cell.colSpan;
}
}
@@ -401,7 +402,9 @@ async function applyProportionalWidths(page, textMm) {
let floor = narrow.map((c, i) => Math.min(Math.max(...c.map((x) => x.width)), longest[i]));
// Short columns (IDs, dates, statuses) stay on one line when the page allows;
// the prose columns then share what is left in proportion to their content.
const oneLine = floor.map((f, i) => (longest[i] <= SHORT_COLUMN_MM ? longest[i] : f));
// So do short entries in any column - a status word, a list of initials.
const shortest = line.map((c) => Math.max(0, ...c.filter((x) => x.short && !x.head).map((x) => x.width)));
const oneLine = floor.map((f, i) => (longest[i] <= SHORT_COLUMN_MM ? longest[i] : Math.max(f, shortest[i])));
if (oneLine.reduce((a, b) => a + b, 0) < availMm) floor = oneLine;
const weight = line.map((c) => {
const body = c.filter((x) => !x.head);
@@ -462,7 +465,7 @@ async function applyProportionalWidths(page, textMm) {
.map((span) => span.textContent);
main.style.width = '';
return [...new Set(clipped)];
}, { availMm: textMm, SHORT_COLUMN_MM: 35 });
}, { availMm: textMm, SHORT_COLUMN_MM: 35, SHORT_CELL_CHARS: 16 });
}
main().catch((error) => { console.error(error); process.exit(1); });
+1 -1
View File
@@ -27,7 +27,7 @@ export function stakeholderRegister() {
[2, P.ApS.th, P.ApS.id, 'Project Manager', 'วางแผนและควบคุมโครงการ ติดตามความก้าวหน้า บริหารความเสี่ยงและการเปลี่ยนแปลง', 'A (Accountable), R (Responsible)'],
[3, P.NoC.th, P.NoC.id, 'System Analyst', 'เก็บและวิเคราะห์ความต้องการ ออกแบบระบบและฐานข้อมูล จัดทำเอกสาร SRS และ Design', 'R (Responsible), C (Consult)'],
[4, P.ThS.th, P.ThS.id, 'Developer', 'พัฒนาระบบตามการออกแบบ ดูแลความปลอดภัย การติดตั้ง และการสำรองข้อมูล', 'R (Responsible), C (Consult)'],
[5, P.PaNg.th, P.PaNg.id, 'QA / Tester', 'จัดทำและดำเนินการทดสอบ ตรวจสอบ Work Products และติดตามการแก้ไขข้อบกพร่อง', 'R (Responsible), C (Consult)'],
[5, P.PaNg.th, P.PaNg.id, 'QA/Tester', 'จัดทำและดำเนินการทดสอบ ตรวจสอบ Work Products และติดตามการแก้ไขข้อบกพร่อง', 'R (Responsible), C (Consult)'],
[6, P.YaB.th, P.YaB.id, 'Document Control', 'ควบคุมรหัสเอกสาร เวอร์ชัน การอนุมัติ การจัดเก็บ และหลักฐานของโครงการ', 'R (Responsible)'],
...OTHER_STAKEHOLDERS.map(([name, role, duty, engagement], i) => [7 + i, name, '—', role, duty, engagement]),
], ['c', '', 'c', '', '', '']),
+2 -2
View File
@@ -201,7 +201,7 @@ export function softwareProjectPlan() {
[1, `Project Manager (${P.ApS.id})`, P.ApS.th, P.ApS.email, 'จัดทำ Project Charter และแผนโครงการ / วางแผน Timeline, Resource, Risk, Quality / จัดประชุมและติดตามความคืบหน้า / ควบคุมการเปลี่ยนแปลงและการปิดโครงการ'],
[2, `System Analyst (${P.NoC.id})`, P.NoC.th, P.NoC.email, 'เก็บและวิเคราะห์ความต้องการ / จัดทำ SRS และเอกสารออกแบบระบบ / ออกแบบฐานข้อมูลและความสัมพันธ์ของโมดูล / ตรวจสอบความสอดคล้องของงานพัฒนากับความต้องการ'],
[3, `Developer (${P.ThS.id})`, P.ThS.th, P.ThS.email, 'พัฒนาโมดูลและ API ตามการออกแบบ / จัดการฐานข้อมูลและประสิทธิภาพ / ดูแลความปลอดภัยและการติดตั้ง / แก้ไขข้อบกพร่องที่พบจากการทดสอบ'],
[4, `QA / Tester (${P.PaNg.id})`, P.PaNg.th, P.PaNg.email, 'จัดทำ Test Case และ Test Procedures / ทดสอบระบบและบันทึกผล / ติดตามการแก้ไขข้อบกพร่องและทดสอบซ้ำ / สนับสนุนผู้ใช้งานช่วง UAT'],
[4, `QA/Tester (${P.PaNg.id})`, P.PaNg.th, P.PaNg.email, 'จัดทำ Test Case และ Test Procedures / ทดสอบระบบและบันทึกผล / ติดตามการแก้ไขข้อบกพร่องและทดสอบซ้ำ / สนับสนุนผู้ใช้งานช่วง UAT'],
[5, `Document Control (${P.YaB.id})`, P.YaB.th, P.YaB.email, 'ควบคุมรหัสเอกสารและเวอร์ชัน / จัดเก็บและตรวจสอบความครบถ้วนของเอกสาร / ประสานการทบทวนและอนุมัติ / บันทึกประวัติการเปลี่ยนแปลงเอกสาร'],
[6, `Project Sponsor (${P.SeV.id})`, P.SeV.th, P.SeV.email, 'อนุมัติขอบเขต งบประมาณ และการเปลี่ยนแปลง / ตัดสินใจเชิงกลยุทธ์ / ทดสอบการยอมรับและตรวจรับส่งมอบ / อนุมัติปิดโครงการ'],
], ['c']),
@@ -225,7 +225,7 @@ export function softwareProjectPlan() {
[1, 'Project Manager', 'ควบคุมงาน ประสานงาน ติดตามแผน', 120],
[2, 'System Analyst', 'วิเคราะห์ความต้องการ ออกแบบระบบ', 60],
[3, 'Developer', 'พัฒนาระบบและแก้ไขข้อบกพร่อง', 100],
[4, 'QA / Tester', 'วางแผนทดสอบ ทดสอบระบบ UAT', 40],
[4, 'QA/Tester', 'วางแผนทดสอบ ทดสอบระบบ UAT', 40],
[5, 'Document Control', 'ควบคุมเอกสารและหลักฐานโครงการ', 60],
], ['c', '', '', 'r']),
sec(7, 'Project Resources'),