[CLAUDE] App+Infra+FE-Admin: DynamicForm + .doc/.xls auto-convert on upload
Some checks failed
Deploy SOLUTION_ERP / build-deploy (push) Failing after 1m17s
Some checks failed
Deploy SOLUTION_ERP / build-deploy (push) Failing after 1m17s
Tier 3 iter2 — form builder UI dùng FieldSpec thay raw JSON textarea.
FE:
- DynamicForm component — parse FieldSpec JSON (record of FieldDef với
label/type/required/placeholder/hint/options) và render inputs
dynamic theo type: text/textarea/number/date/currency/select.
- FormsPage render dialog thêm toggle Form ↔ JSON (segmented control).
Mặc định Form mode khi template có FieldSpec, JSON mode khi không.
Khi mở dialog cho row khác, reset formValues + chọn đúng default mode.
- parseFieldSpec helper trả { spec, error } — UI báo lỗi nếu JSON
không parse được, fallback JSON textarea.
BE — generalize converter thành IDocumentConverter:
- IPdfConverter → IDocumentConverter (ConvertAsync(bytes, src, tgt, ct))
— đủ gánh cả pdf, docx, xlsx targets.
- LibreOfficeDocumentConverter — 1 shell-out pattern cho mọi conversion
(docx→pdf, doc→docx, xls→xlsx, xlsx→pdf), target arg truyền vào
--convert-to.
- ExportTemplatePdfCommand update dùng "pdf" target.
Auto-convert .doc/.xls trên upload:
- Validator accept thêm .doc/.xls (thêm note "sẽ tự convert").
- UploadContractTemplateCommandHandler: nếu ext là doc/xls → read stream
→ converter.ConvertAsync → lưu file .docx/.xlsx thay vì format gốc.
File rendering pipeline (DocxRenderer/XlsxRenderer) chỉ support docx/
xlsx — convert đảm bảo consistent.
- Display FileName preserve original name nhưng đổi extension.
Unblock 3 file .doc legacy template — admin giờ upload .doc bình thường,
system tự convert.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@ -1,9 +1,14 @@
|
||||
namespace SolutionErp.Application.Common.Interfaces;
|
||||
|
||||
// Convert .docx/.xlsx bytes to PDF. The Infrastructure impl shells out to
|
||||
// LibreOffice headless (soffice.exe --headless --convert-to pdf). Future swap:
|
||||
// QuestPDF re-render if we want zero external dep, or Aspose.Words for quality.
|
||||
public interface IPdfConverter
|
||||
// Convert document bytes between office formats. Infrastructure impl shells out
|
||||
// to LibreOffice headless (soffice.exe --headless --convert-to TARGET).
|
||||
//
|
||||
// Supported source/target combos are whatever LibreOffice supports, commonly:
|
||||
// docx → pdf, doc → docx, xlsx → pdf, xls → xlsx
|
||||
//
|
||||
// Future swap: QuestPDF for PDF-only, Aspose.Words for quality, or cloud API —
|
||||
// without touching callers.
|
||||
public interface IDocumentConverter
|
||||
{
|
||||
Task<byte[]> ConvertAsync(byte[] sourceBytes, string sourceExt, CancellationToken ct = default);
|
||||
Task<byte[]> ConvertAsync(byte[] sourceBytes, string sourceExt, string targetExt, CancellationToken ct = default);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user