update docs

This commit is contained in:
2026-07-22 14:11:18 +07:00
parent a836645728
commit 166276d19b
14 changed files with 1308 additions and 17 deletions

View File

@@ -0,0 +1,161 @@
<%- include('partials/page-start') %>
<section class="page document-page">
<div class="page-header">
<div>
<div class="breadcrumb"><a href="/documents">Tài liệu</a><span>/</span><span><%= helpers.documentCategoryLabel(document.category) %></span></div>
<h1><%= document.title %></h1>
<p><%= document.summary || 'Tài liệu nội bộ Robot Installer.' %></p>
</div>
<div class="page-actions">
<% if (document.filePath) { %>
<a class="btn btn-secondary" href="/documents/<%= document.id %>/file?download=1">
<span class="material-symbols-outlined">download</span>
Tải file
</a>
<% } %>
<button class="btn btn-primary" type="button" data-modal-open="editDocumentModal">
<span class="material-symbols-outlined">edit</span>
Chỉnh sửa
</button>
<form method="post" action="/documents/<%= document.id %>/delete" data-confirm-submit="Xóa tài liệu <%= document.title %> và file đính kèm?">
<button class="btn btn-danger" type="submit">
<span class="material-symbols-outlined">delete</span>
Xóa
</button>
</form>
</div>
</div>
<div class="document-detail-grid">
<section class="panel document-meta-panel">
<div class="panel-header">
<div>
<h2>Thông tin tài liệu</h2>
<p>Thông tin phân loại và tệp lưu trữ.</p>
</div>
</div>
<dl class="detail-list">
<div><dt>Nhóm</dt><dd><span class="badge badge-info"><%= helpers.documentCategoryLabel(document.category) %></span></dd></div>
<div><dt>Người tạo</dt><dd><%= document.createdBy %></dd></div>
<div><dt>Ngày tạo</dt><dd><%= document.createdAt %></dd></div>
<div><dt>Cập nhật</dt><dd><%= document.updatedAt %></dd></div>
<div><dt>File</dt><dd><%= document.originalFileName || 'Không có' %></dd></div>
<div><dt>Dung lượng</dt><dd><%= document.fileSize || '-' %></dd></div>
</dl>
</section>
<section class="panel document-reader-panel">
<div class="panel-header">
<div>
<h2>Nội dung</h2>
<p>Đọc nội dung và xem trước file được trình duyệt hỗ trợ.</p>
</div>
<% if (document.filePath) { %>
<a class="text-link" href="/documents/<%= document.id %>/file" target="_blank" rel="noopener">Mở file</a>
<% } %>
</div>
<div class="document-reader">
<% if (document.content) { %>
<article class="document-copy"><%= document.content %></article>
<% } %>
<% if (document.filePath && documentPreviewKind) { %>
<section class="document-preview-block">
<div class="document-section-heading">
<span class="material-symbols-outlined">attach_file</span>
<strong>Xem trước: <%= document.originalFileName %></strong>
</div>
<% if (documentPreviewKind === 'image') { %>
<img class="document-image-preview" src="/documents/<%= document.id %>/file" alt="<%= document.title %>">
<% } else { %>
<iframe
class="document-file-preview"
src="/documents/<%= document.id %>/file"
title="Xem trước <%= document.originalFileName %>"
<% if (documentPreviewKind === 'text') { %>sandbox<% } %>
></iframe>
<% } %>
</section>
<% } else if (document.filePath) { %>
<div class="document-attachment-state">
<span class="material-symbols-outlined">description</span>
<div>
<strong><%= document.originalFileName %></strong>
<p>Trình duyệt không xem trực tiếp định dạng này. Hãy tải file để mở bằng ứng dụng phù hợp.</p>
</div>
<a class="btn btn-secondary" href="/documents/<%= document.id %>/file?download=1">Tải file</a>
</div>
<% } %>
<% if (!document.content && !document.filePath) { %>
<div class="table-empty">Tài liệu chưa có nội dung.</div>
<% } %>
</div>
</section>
</div>
</section>
<div id="editDocumentModal" class="modal-backdrop" role="dialog" aria-modal="true" aria-labelledby="editDocumentModalTitle">
<div class="modal-content wide">
<div class="modal-header">
<div>
<h3 id="editDocumentModalTitle">Chỉnh sửa tài liệu</h3>
<p>Cập nhật nội dung hoặc thay thế file đính kèm hiện tại.</p>
</div>
<button class="icon-button subtle" type="button" data-modal-close aria-label="Đóng">
<span class="material-symbols-outlined">close</span>
</button>
</div>
<form class="modal-form" method="post" action="/documents/<%= document.id %>/edit" enctype="multipart/form-data">
<div class="form-stack">
<div class="form-grid">
<label class="form-field">
<span>Tiêu đề</span>
<input type="text" name="title" maxlength="200" required value="<%= document.title %>">
</label>
<label class="form-field">
<span>Nhóm tài liệu</span>
<select name="category" required>
<% documentCategories.forEach((category) => { %>
<option value="<%= category.id %>" <%= document.category === category.id ? 'selected' : '' %>><%= category.label %></option>
<% }) %>
</select>
</label>
</div>
<label class="form-field">
<span>Mô tả ngắn</span>
<textarea name="summary" rows="3" maxlength="1000"><%= document.summary %></textarea>
</label>
<label class="form-field">
<span>Nội dung đọc trực tiếp</span>
<textarea name="content" rows="8" maxlength="500000"><%= document.content %></textarea>
</label>
<label class="form-field">
<span>Thay file đính kèm</span>
<input
type="file"
name="documentFile"
accept=".pdf,.doc,.docx,.odt,.rtf,.txt,.md,.png,.jpg,.jpeg,.webp,.ppt,.pptx,.xls,.xlsx"
>
<small>Để trống nếu muốn giữ file hiện tại. File mới sẽ thay thế file cũ.</small>
</label>
<% if (document.filePath) { %>
<label class="document-remove-option">
<input type="checkbox" name="removeAttachment" value="1">
<span>Xóa file hiện tại: <strong><%= document.originalFileName %></strong></span>
</label>
<% } %>
</div>
<div class="modal-actions">
<button class="btn btn-secondary" type="button" data-modal-close>Hủy</button>
<button class="btn btn-primary" type="submit">
<span class="material-symbols-outlined">save</span>
Lưu thay đổi
</button>
</div>
</form>
</div>
</div>
<%- include('partials/page-end') %>

View File

@@ -0,0 +1,161 @@
<%- include('partials/page-start') %>
<section class="page">
<div class="page-header">
<div>
<h1>Tài liệu</h1>
<p>Lưu trữ và tra cứu tài liệu giới thiệu, hướng dẫn sử dụng, quy trình và tài liệu kỹ thuật.</p>
</div>
<div class="page-actions">
<button class="btn btn-primary" type="button" data-modal-open="createDocumentModal">
<span class="material-symbols-outlined">note_add</span>
Thêm tài liệu
</button>
</div>
</div>
<div class="page-filters">
<label class="filter-field">
<span>Nhóm tài liệu</span>
<select data-filter-select data-filter-column="category" data-filter-table="documentsTable">
<option value="">Tất cả</option>
<% documentCategories.forEach((category) => { %>
<option value="<%= category.id %>"><%= category.label %></option>
<% }) %>
</select>
</label>
<label class="filter-field wide">
<span>Tìm kiếm</span>
<input type="search" placeholder="Tìm theo tiêu đề, mô tả, tác giả..." data-table-search="documentsTable">
</label>
</div>
<section class="table-panel">
<div class="table-wrap">
<table id="documentsTable" class="data-table documents-table">
<thead>
<tr>
<th>Tài liệu</th>
<th>Nhóm</th>
<th>File đính kèm</th>
<th>Cập nhật</th>
<th>Người tạo</th>
<th class="action-col">Thao tác</th>
</tr>
</thead>
<tbody>
<% if (documents.length === 0) { %>
<tr>
<td colspan="6" class="table-empty">Chưa có tài liệu. Bấm Thêm tài liệu để tạo nội dung đầu tiên.</td>
</tr>
<% } %>
<% documents.forEach((item) => { %>
<tr
data-search="<%= `${item.title} ${item.summary} ${item.createdBy} ${helpers.documentCategoryLabel(item.category)}`.toLowerCase() %>"
data-category="<%= item.category %>"
>
<td class="document-title-cell">
<a class="table-title" href="/documents/<%= item.id %>"><%= item.title %></a>
<span class="table-subtitle"><%= item.summary || (item.hasContent ? 'Có nội dung đọc trực tiếp' : 'Tài liệu đính kèm') %></span>
</td>
<td><span class="badge badge-info"><%= helpers.documentCategoryLabel(item.category) %></span></td>
<td>
<% if (item.filePath) { %>
<span class="document-file-name" title="<%= item.originalFileName %>"><%= item.originalFileName %></span>
<span class="table-subtitle"><%= item.fileSize %></span>
<% } else { %>
<span class="table-subtitle">Không có file</span>
<% } %>
</td>
<td><%= item.updatedAt %></td>
<td><%= item.createdBy %></td>
<td class="action-col">
<div class="action-group">
<a class="icon-button subtle" href="/documents/<%= item.id %>" title="Đọc tài liệu" aria-label="Đọc tài liệu <%= item.title %>">
<span class="material-symbols-outlined">visibility</span>
</a>
<% if (item.filePath) { %>
<a class="icon-button subtle" href="/documents/<%= item.id %>/file?download=1" title="Tải file" aria-label="Tải file <%= item.title %>">
<span class="material-symbols-outlined">download</span>
</a>
<% } %>
<form method="post" action="/documents/<%= item.id %>/delete" data-confirm-submit="Xóa tài liệu <%= item.title %> và file đính kèm?">
<button class="icon-button danger" type="submit" title="Xóa tài liệu" aria-label="Xóa tài liệu <%= item.title %>">
<span class="material-symbols-outlined">delete</span>
</button>
</form>
</div>
</td>
</tr>
<% }) %>
</tbody>
</table>
</div>
<div class="page-pager">
<span>Hiển thị <%= documents.length %> tài liệu</span>
<div>
<button type="button" disabled>Trước</button>
<span>Trang 1 / 1</span>
<button type="button" disabled>Sau</button>
</div>
</div>
</section>
</section>
<div id="createDocumentModal" class="modal-backdrop" role="dialog" aria-modal="true" aria-labelledby="createDocumentModalTitle">
<div class="modal-content wide">
<div class="modal-header">
<div>
<h3 id="createDocumentModalTitle">Thêm tài liệu</h3>
<p>Nhập nội dung để đọc trực tiếp, đính kèm file, hoặc sử dụng cả hai.</p>
</div>
<button class="icon-button subtle" type="button" data-modal-close aria-label="Đóng">
<span class="material-symbols-outlined">close</span>
</button>
</div>
<form class="modal-form" method="post" action="/documents" enctype="multipart/form-data">
<div class="form-stack">
<div class="form-grid">
<label class="form-field">
<span>Tiêu đề</span>
<input type="text" name="title" maxlength="200" required placeholder="Ví dụ: Hướng dẫn cài đặt Robot">
</label>
<label class="form-field">
<span>Nhóm tài liệu</span>
<select name="category" required>
<% documentCategories.forEach((category) => { %>
<option value="<%= category.id %>"><%= category.label %></option>
<% }) %>
</select>
</label>
</div>
<label class="form-field">
<span>Mô tả ngắn</span>
<textarea name="summary" rows="3" maxlength="1000" placeholder="Nội dung chính và đối tượng sử dụng tài liệu này."></textarea>
</label>
<label class="form-field">
<span>Nội dung đọc trực tiếp</span>
<textarea name="content" rows="8" maxlength="500000" placeholder="Nhập nội dung hướng dẫn tại đây. Xuống dòng và khoảng trắng sẽ được giữ nguyên khi hiển thị."></textarea>
</label>
<label class="form-field">
<span>File đính kèm</span>
<input
type="file"
name="documentFile"
accept=".pdf,.doc,.docx,.odt,.rtf,.txt,.md,.png,.jpg,.jpeg,.webp,.ppt,.pptx,.xls,.xlsx"
>
<small>Hỗ trợ PDF, Word, OpenDocument, text/Markdown, ảnh, PowerPoint và Excel; tối đa 50 MB mặc định.</small>
</label>
</div>
<div class="modal-actions">
<button class="btn btn-secondary" type="button" data-modal-close>Hủy</button>
<button class="btn btn-primary" type="submit">
<span class="material-symbols-outlined">save</span>
Lưu tài liệu
</button>
</div>
</form>
</div>
</div>
<%- include('partials/page-end') %>

View File

@@ -114,6 +114,7 @@
data-user-updated-at="<%= user.updatedAt %>"
data-user-package-count="<%= user.packageCount %>"
data-user-application-count="<%= user.applicationCount %>"
data-user-document-count="<%= user.documentCount %>"
>
<td>
<span class="table-title"><%= user.name %></span>
@@ -126,6 +127,7 @@
<td>
<span class="table-subtitle"><%= user.packageCount %> packages</span>
<span class="table-subtitle"><%= user.applicationCount %> apps</span>
<span class="table-subtitle"><%= user.documentCount %> tài liệu</span>
</td>
<td>
<% if (user.id === currentUser.id) { %>