FPSMS-frontend
25개 이상의 토픽을 선택하실 수 없습니다. Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

EXCEL_EXPORT_STANDARD.md 6.0 KiB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. # Excel export standard (FPSMS frontend)
  2. This document defines how **client-side** `.xlsx` exports should look and behave. **Implementation:** `exportChartToXlsx.ts` and `exportMultiSheetToXlsx()` — use these helpers for new reports so styling stays consistent.
  3. ## Scope (important)
  4. | Export path | Follows this `.md`? |
  5. |-------------|---------------------|
  6. | **Next.js** builds the file via `exportChartToXlsx` / `exportMultiSheetToXlsx` (e.g. **PO 入倉記錄** / `rep-014`) | **Yes** — rules are enforced in code. |
  7. | **Backend** returns ready-made `.xlsx` or Excel bytes (JasperReports, Apache POI, etc.; most `print-*` report endpoints) | **No — not automatically.** That code does **not** use this TypeScript module. To match the same **look** (grey headers, number formats, alignment), implement equivalent styling in Java/Kotlin or Jasper templates. See the backend companion doc below. |
  8. **Backend companion (visual parity):**
  9. `FPSMS-backend/docs/EXCEL_EXPORT_STANDARD.md` — same *rules*, for POI/Jasper implementers.
  10. ---
  11. ## 1. Library
  12. | Item | Value |
  13. |------|--------|
  14. | Package | **`xlsx-js-style`** (not the plain `xlsx` community build) |
  15. | Reason | Plain SheetJS **does not persist** cell styles (`fill`, `alignment`, `numFmt`) in the written file. `xlsx-js-style` is a compatible fork that **does**. |
  16. ---
  17. ## 2. Data shape
  18. - Rows are **`Record<string, unknown>[]`** (array of plain objects).
  19. - **First object’s keys** become the **header row** (column titles). Every row should use the **same keys** in the same order for a rectangular sheet.
  20. - Prefer **real JavaScript `number`** values for amounts where possible; the exporter will apply number formats. Strings that look like numbers (e.g. `"1,234.56"`) are parsed for money columns.
  21. ---
  22. ## 3. Processing order (per sheet)
  23. After `json_to_sheet(rows)`:
  24. 1. **`!cols`** — column width heuristic (see §4).
  25. 2. **`applyHeaderRowStyle`** — header row styling (see §5).
  26. 3. **`applyMoneyColumnNumberFormats`** — money columns only, data rows (see §6).
  27. 4. **`applyNumericColumnRightAlign`** — money + quantity columns, **all rows including header** (see §7).
  28. ---
  29. ## 4. Column width (`!cols`)
  30. - For each column: `wch = max(12, headerText.length + 4)`.
  31. - Adjust if a report needs fixed widths; default keeps bilingual headers readable.
  32. ---
  33. ## 5. Header row style (row 0)
  34. Applied to **every** header cell first; numeric columns get alignment overridden in step 4.
  35. | Property | Value |
  36. |----------|--------|
  37. | Font | Bold, black `rgb: "000000"` |
  38. | Fill | Solid, `fgColor: "D9D9D9"` (light grey) |
  39. | Alignment (default) | Horizontal **center**, vertical **center**, `wrapText: true` |
  40. ---
  41. ## 6. Money / amount columns — number format
  42. **Detection:** header label matches (case-insensitive):
  43. ```text
  44. 金額 | 單價 | Amount | Unit Price | Total Amount
  45. ```
  46. (Also matches bilingual headers that contain these fragments, e.g. `Amount / 金額`, `Unit Price / 單價`, `Total Amount / 金額`.)
  47. **Rules:**
  48. - Applies to **data rows only** (not row 0).
  49. - Excel format string: **`#,##0.00`** (thousands separator + 2 decimals). Stored on the cell as `z`.
  50. - Cell type `t: "n"` for numeric values.
  51. - If the cell is a **string**, commas are stripped and the value is parsed to a number when possible.
  52. **Naming new reports:** use header text that matches the patterns above so columns pick up formatting automatically.
  53. ---
  54. ## 7. Quantity columns — alignment only
  55. **Detection:** header label matches:
  56. ```text
  57. Qty | 數量 | Demand
  58. ```
  59. (Covers e.g. `Qty / 數量`, `Demand Qty / 訂單數量`.)
  60. - No default thousands format (quantities may have up to 4 decimals in app code).
  61. - These columns are **right-aligned** together with money columns (see §8).
  62. ---
  63. ## 8. Alignment — numeric columns (header + data)
  64. **Detection:** union of **money** (§6) and **quantity** (§7) header patterns.
  65. | Alignment | Value |
  66. |-----------|--------|
  67. | Horizontal | **`right`** |
  68. | Vertical | **`center`** |
  69. | `wrapText` | Preserved / defaulted to `true` where applicable |
  70. Existing style objects are **merged** (fill, font from header styling are kept).
  71. ---
  72. ## 9. Multi-sheet workbook
  73. | Rule | Detail |
  74. |------|--------|
  75. | API | `exportMultiSheetToXlsx({ name, rows }[], filename)` |
  76. | Sheet name length | Truncated to **31** characters (Excel limit) |
  77. | Each sheet | Same pipeline as §3 if `rows.length > 0` |
  78. ---
  79. ## 10. Empty sheets
  80. If `rows.length === 0`, a minimal sheet is written; no header styling pipeline runs.
  81. ---
  82. ## 11. Reports using this standard today
  83. | Feature | Location |
  84. |---------|----------|
  85. | Chart export | Uses `exportChartToXlsx` |
  86. | GRN / PO 入倉記錄 (`rep-014`) | `src/app/(main)/report/grnReportApi.ts` — builds row objects, calls `exportChartToXlsx` / `exportMultiSheetToXlsx` |
  87. Most other reports on `/report` download Excel/PDF **generated on the server** (Jasper, etc.). Those **do not** run this TypeScript pipeline; use **`FPSMS-backend/docs/EXCEL_EXPORT_STANDARD.md`** if you want the same visual rules there.
  88. ---
  89. ## 12. Checklist for new Excel exports
  90. 1. Import from **`xlsx-js-style`** only if building sheets manually; otherwise call **`exportChartToXlsx`** or **`exportMultiSheetToXlsx`**.
  91. 2. Use **stable header strings** that match §6 / §7 if the column is amount or quantity.
  92. 3. Pass **numbers** for amounts when possible.
  93. 4. If you need a **new** category (e.g. “Rate”, “折扣”), extend the regex constants in `exportChartToXlsx.ts` and **update this document**.
  94. 5. Keep filenames and sheet names user-readable; remember the **31-character** sheet limit.
  95. ---
  96. ## 13. Related files
  97. | File | Role |
  98. |------|------|
  99. | `exportChartToXlsx.ts` | Single-sheet export + styling pipeline |
  100. | `grnReportApi.ts` | Example: bilingual headers, money values, multi-sheet GRN report |
  101. | `FPSMS-backend/docs/EXCEL_EXPORT_STANDARD.md` | Backend Excel (POI/Jasper) — same *rules*, separate code |
  102. ---
  103. *Last aligned with implementation in `exportChartToXlsx.ts` (header fill `#D9D9D9`, money format `#,##0.00`, right-align numeric columns).*