Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
HTML
<!-- فونت وزیر -->
<link href="https://cdn.jsdelivr.net/gh/rastikerdar/vazir-font@v30.1.0/dist/font-face.css" rel="stylesheet" type="text/css" />

<h2 style="text-align:center; font-family:Vazir, Tahoma; color:#333; font-weight:600; margin-top:20px;">
  مستندات اعتباربخشی
</h2>

<!-- فیلترهای زیبا -->
<div id="search-filters" style="
     display:flex; justify-content:center; flex-wrap:wrap; 
     gap:10px; margin:25px 0; direction:rtl;">

  <select id="filterAxis" onchange="updateSubAxis(); filterTable()"
          style="flex:0 1 160px; padding:10px 15px; border-radius:25px; 
          border:1px solid #ccc; font-family:Vazir, Tahoma; font-size:14px;
          background:#fff; cursor:pointer;">
    <option value="">انتخاب محور</option>
    <option value="modiriyat">رهبری و مدیریت</option>
    <option value="mored">مراقبت و درمان</option>
    <option value="hemayat">حمایت از گیرنده خدمت</option>
  </select>

  <select id="filterSubAxis" onchange="filterTable()"
          style="flex:0 1 160px; padding:10px 15px; border-radius:25px; 
          border:1px solid #ccc; font-family:Vazir, Tahoma; font-size:14px;
          background:#fff; cursor:pointer;">
    <option value="">انتخاب زیرمحور</option>
  </select>
<table id="archiveTable" border="1" style="width:100%; border-collapse:collapse; text-align:center;">
    <thead>
        <tr>
            <th>محور</th>
            <th>زیرمحور</th>
            <th>کمیته</th>
            <th>عنوان سند</th>
            <th>نوع سند</th>
            <th>تاریخ</th>
            <th>کد ویرایش</th>
            <th>فایل</th>
        </tr>
    </thead>
    <tbody id="archiveBody"></tbody>
</table>


<!-- CSS جدول زیبا -->
<style>
#myTable {
  border-collapse: separate;
  border-spacing: 0;
  width: 100%;
  font-family: Vazir, Tahoma;
  direction: rtl;
  box-shadow: 0 2px 8px rgba(0,0,0,0.1);
  border-radius: 10px;
  overflow: hidden;
}
#myTable thead th {
  background-color: #f2f2f2;
  padding: 10px;
  font-weight: 600;
  text-align: center;
  border-bottom: 1px solid #ddd;
}
#myTable tbody td {
  padding: 10px;
  text-align: center;
  border-bottom: 1px solid #eee;
}
#myTable tbody tr:nth-child(even) {
  background-color: #fafafa;
}
#myTable tbody tr:hover {
  background-color: #e6f7ff;
  transition: background-color 0.3s;
}
#myTable thead tr:first-child th:first-child { border-top-right-radius: 10px; }
#myTable thead tr:first-child th:last-child { border-top-left-radius: 10px; }
#myTable tbody tr:last-child td:first-child { border-bottom-right-radius: 10px; }
#myTable tbody tr:last-child td:last-child { border-bottom-left-radius: 10px; }
#search-filters select { transition: all 0.3s; }
#search-filters select:hover { box-shadow: 0 2px 6px rgba(0,0,0,0.15); }
</style>

<!-- JS داینامیک جدول و فیلتر -->
<script>
async function loadArchive() {
    const pageIdArchive = "85045557";
    const archiveName = "archive.json";

    const res = await fetch(`/rest/api/content/${pageIdArchive}/child/attachment?filename=${archiveName}`, {
        credentials: 'include',
        headers: { 'Accept': 'application/json' }
    });

    const data = await res.json();

    if (!data.results || !data.results.length) return [];

    const txt = await fetch(data.results[0]._links.download, {
        credentials: 'include'
    }).then(r => r.text());

    return JSON.parse(txt);
}

async function populateArchiveTable() {
    const tbody = document.getElementById('archiveBody');
    tbody.innerHTML = "";

    const archive = await loadArchive();

    archive.forEach(r => {
        const tr = document.createElement("tr");

        // تعیین اینکه کدام تاریخ باید نمایش داده شود
        let finalDate = "";
        if (r.date_last_edit) finalDate = r.date_last_edit;
        else if (r.date_revision) finalDate = r.date_revision;
        else if (r.date_update) finalDate = r.date_update;

        tr.innerHTML = `
            <td>${r.mahvar || "-"}</td>
  <h2 style="text-align:center; font-family:Vazir,Tahoma; color:#333; font-weight:600;">آرشیو مستندات اعتباربخشی</h2>

<div id="search-filters" style="
     display:flex;
     justify-content:flex-end;
     flex-wrap:wrap; 
     gap:10px;
     margin:25px 0;
     direction:rtl;">

  <select id="filterAxis" onchange="updateSubAxis(); filterTable()"
          style="flex:0 1 160px; padding:10px 15px; border-radius:25px; 
          border:1px solid #ccc; font-family:Vazir, Tahoma; font-size:14px;
          background:#fff; cursor:pointer;">
    <option value="">انتخاب محور</option>
    <option value="رهبری و مدیریت">رهبری و مدیریت</option>
    <option value="مراقبت و درمان">مراقبت و درمان</option>
    <option value="حمایت از گیرنده خدمت">حمایت از گیرنده خدمت</option>
  </select>

  <select id="filterSubAxis" onchange="filterTable()"
          style="flex:0 1 160px; padding:10px 15px; border-radius:25px; 
          border:1px solid #ccc; font-family:Vazir, Tahoma; font-size:14px;
          background:#fff; cursor:pointer;">
    <option value="">انتخاب زیرمحور</option>
  </select>
</div>

<div id="archive-loading" style="font-family:Vazir,Tahoma; direction:rtl; text-align:center; padding:15px; color:#007bff;">
  در حال بارگذاری آرشیو...
</div>

<table id="archiveTable" style="display:none;">
  <thead>
    <tr>
      <th>محور</th>
      <th>زیرمحور</th>
      <th>کمیته</th>
      <th>عنوان سند</th>
      <th>نوع سند</th>
      <th>تاریخ ثبت اولیه</th>
      <th>تاریخ آخرین بازنگری</th>
      <th>تاریخ ویرایش</th>
      <th>کد ویرایش</th>
      <th>فایل / صفحه</th>
    </tr>
  </thead>
  <tbody id="archiveBody"></tbody>
</table>

<div id="archive-empty" style="display:none; font-family:Vazir,Tahoma; direction:rtl; text-align:center; padding:15px; color:#00A9C3; font-weight:600;">
  موردی برای نمایش وجود ندارد.
</div>

<style>
@font-face {
  font-family: "IRANSans";
  src: url("/download/attachments/85045557/IRANSansXVF.woff2") format("woff2");
}
@font-face {
  font-family: "Vazir";
  src: url("/download/attachments/85045557/Vazir-Regular.woff2") format("woff2");
}

#archiveTable {
  width: 100%;
  border-collapse: separate;
  border-spacing: 0;
  font-family: Vazir, Tahoma;
  direction: rtl;
  border-radius: 12px;
  overflow: hidden;
  box-shadow: 0 4px 12px rgba(0,0,0,0.08);
}

#archiveTable thead {
  background-color: #4facfe;
  color: #fff;
  font-weight: 600;
  text-align: center;
}

#archiveTable thead th {
  background-color: #00A9C3;
  color: #fff;
  padding: 12px 10px;
  border-bottom: 1px solid rgba(255,255,255,0.3);
  white-space: nowrap;
}

#archiveTable thead tr:hover th {
  background-color: #00A9C3;
}

#archiveTable tbody td {
  padding: 12px 10px;
  text-align: center;
  border-bottom: 1px solid #f0f0f0;
  background-color: #fff;
  transition: background-color 0.3s;
  vertical-align:middle;
}

#archiveTable tbody tr:nth-child(even) td {
  background-color: #f9f9f9;
}

#archiveTable tbody tr:hover td {
  background-color: #e0f7ff;
}

#archiveTable tbody tr td a,
.archive-link {
  color: #007bff;
  text-decoration: none;
  font-weight: 600;
  cursor:pointer;
}

#archiveTable tbody tr td a:hover,
.archive-link:hover {
  text-decoration: underline;
}
</style>

<script>
const zirmohvarOptions = {
  "رهبری و مدیریت": [
    "رهبری و مدیریت کیفیت",
    "مدیریت خطر، حوادث و بلایا",
    "مدیریت منابع انسانی و سلامت حرفه‌ای",
    "مدیریت خدمات پرستاری",
    "فناوری و مدیریت اطلاعات سلامت",
    "بهداشت محیط",
    "مدیریت تجهیزات پزشکی"
  ],
  "مراقبت و درمان": [
    "مراقبت‌های عمومی بالینی",
    "مراقبت‌های حاد و اورژانس",
    "مراقبت‌های جراحی و بیهوشی",
    "مراقبت‌های مادر و نوزاد",
    "پیشگیری و کنترل عفونت",
    "مدیریت دارویی",
    "خدمات تصویربرداری",
    "خدمات آزمایشگاه",
    "طب انتقال خون",
    "خدمات سرپایی"
  ],
  "حمایت از گیرنده خدمت": [
    "تأمین تسهیلات برای گیرنده خدمت",
    "احترام به حقوق گیرنده خدمت"
  ]
};

function cleanText(v) {
  return String(v || "").replace(/\u00a0/g, " ").replace(/\u200c/g, " ").replace(/\s+/g, " ").trim();
}

function safeText(v) {
  return String(v || "")
    .replace(/&/g, "&")
    .replace(/</g, "<")
    .replace(/>/g, ">");
}

function toAbsoluteUrl(url) {
  url = String(url || "").trim();
  if (!url) return "";
  if (/^https?:\/\//i.test(url)) return url;
  if (url.startsWith("/")) return location.origin + url;
  return location.origin + "/" + url;
}

function updateSubAxis() {
  const filterAxis = document.getElementById("filterAxis");
  const filterSubAxis = document.getElementById("filterSubAxis");
  const selectedAxis = filterAxis.value;

  filterSubAxis.innerHTML = `<option value="">انتخاب زیرمحور</option>`;

  if (selectedAxis && zirmohvarOptions[selectedAxis]) {
    zirmohvarOptions[selectedAxis].forEach(sub => {
      const opt = document.createElement("option");
      opt.value = sub;
      opt.textContent = sub;
      filterSubAxis.appendChild(opt);
    });
  }

  filterSubAxis.value = "";
  filterTable();
}

function filterTable() {
  const axis = cleanText(document.getElementById("filterAxis").value);
  const subAxis = cleanText(document.getElementById("filterSubAxis").value);
  const rows = document.querySelectorAll("#archiveBody tr");

  let visibleCount = 0;

  rows.forEach(row => {
    const rowAxis = cleanText(row.cells[0].textContent);
    const rowSub = cleanText(row.cells[1].textContent);

    let show = true;

    if (axis && rowAxis !== axis) show = false;
    if (subAxis && rowSub !== subAxis) show = false;

    row.style.display = show ? "" : "none";
    if (show) visibleCount++;
  });

  document.getElementById("archive-empty").style.display = visibleCount ? "none" : "block";
}

async function loadArchive() {
  const pageIdArchive = "85045557";
  const archiveName = "archive.json";

  const res = await fetch(`/rest/api/content/${pageIdArchive}/child/attachment?filename=${encodeURIComponent(archiveName)}&cb=${Date.now()}`, {
    credentials: "include",
    headers: { Accept: "application/json" },
    cache: "no-store"
  });

  if (!res.ok) throw new Error("خطا در خواندن attachment آرشیو: " + res.status);

  const data = await res.json();

  if (!data.results || !data.results.length) return [];

  const downloadUrl = toAbsoluteUrl(data.results[0]._links.download);
  const joiner = downloadUrl.includes("?") ? "&" : "?";

  const txt = await fetch(downloadUrl + joiner + "cb=" + Date.now(), {
    credentials: "include",
    cache: "no-store"
  }).then(r => r.text());

  const arr = JSON.parse(txt || "[]");

  return Array.isArray(arr) ? arr : [];
}

function openBase64File(base64Data, fileName) {
  try {
    const arr = String(base64Data || "").split(",");
    const mime = arr[0] && arr[0].match(/:(.*?);/) ? arr[0].match(/:(.*?);/)[1] : "application/octet-stream";
    const bstr = atob(arr[1] || "");
    let n = bstr.length;
    const u8arr = new Uint8Array(n);

    while (n--) {
      u8arr[n] = bstr.charCodeAt(n);
    }

    const blob = new Blob([u8arr], { type: mime });
    const url = URL.createObjectURL(blob);

    const a = document.createElement("a");
    a.href = url;
    a.download = fileName || "file";
    a.click();

    setTimeout(() => URL.revokeObjectURL(url), 60000);
  } catch (e) {
    console.error(e);
    alert("فایل قدیمی Base64 قابل باز شدن نیست.");
  }
}

function createFileCell(record) {
  const wrap = document.createElement("div");

  const fileUrl = cleanText(record.fileUrl || record.file_url || record.downloadUrl || record.download_url || "");
  const pageUrl = cleanText(record.pageUrl || record.page_url || "");
  const pageId = cleanText(record.pageId || record.page_id || "");
  const oldBase64 = cleanText(record.file || record.file_base64 || "");
  const fileName = cleanText(record.file_name || record.document_file_name || record.document_name || "file");

  if (fileUrl) {
    const a = document.createElement("a");
    a.href = toAbsoluteUrl(fileUrl);
    a.target = "_blank";
    a.textContent = "دانلود فایل";
    wrap.appendChild(a);
    return wrap;
  }

  if (pageUrl || pageId) {
    const a = document.createElement("a");
    a.href = pageUrl ? toAbsoluteUrl(pageUrl) : (location.origin + "/pages/viewpage.action?pageId=" + encodeURIComponent(pageId));
    a.target = "_blank";
    a.textContent = "مشاهده صفحه";
    wrap.appendChild(a);
    return wrap;
  }

  if (oldBase64) {
    const btn = document.createElement("span");
    btn.className = "archive-link";
    btn.textContent = "دانلود فایل";
    btn.onclick = function () {
      openBase64File(oldBase64, fileName);
    };
    wrap.appendChild(btn);
    return wrap;
  }

  wrap.textContent = "-";
  return wrap;
}

async function populateArchiveTable() {
  const tbody = document.getElementById("archiveBody");
  const loading = document.getElementById("archive-loading");
  const table = document.getElementById("archiveTable");
  const empty = document.getElementById("archive-empty");

  try {
    loading.style.display = "block";
    table.style.display = "none";
    empty.style.display = "none";
    tbody.innerHTML = "";

    const archive = await loadArchive();

    archive
      .slice()
      .reverse()
      .forEach(r => {
        const tr = document.createElement("tr");

        tr.innerHTML = `
          <td>${safeText(r.mahvar || "-")}</td>
          <td>${safeText(r.zirmohvar || "-")}</td>
          <td>${safeText(r.komiteh || "-")}</td>
          <td>${safeText(r.document_name || "-")}</td>
          <td>${safeText(r.noe_sanad || "-")}</td>
          <td>${safeText(r.date_last_edit || "-")}</td>
          <td>${safeText(r.date_revision || "-")}</td>
          <td>${safeText(r.date_update || "-")}</td>
          <td>${safeText(r.zirmohvaredit_code || "-00")}</td>
          <td></td>
        `;

      <td>${r.komiteh || "-"}</td> tr.cells[9].appendChild(createFileCell(r));
        tbody.appendChild(tr);
    <td>${r.document_name || "-"}</td>});

            <td>${r.noe_sanad || "-"}</td>
    loading.style.display = "none";
    table.style.display = archive.length  <td>${finalDate ||? "table" : "-"}</td>none";
    empty.style.display = archive.length ? "none" : "block";

  <td>${r.revision_code || "00"}</td> filterTable();

  } catch (e) {
    console.error(e);
   <td><a href="${r.file_data}" download="${r.file_name}">دانلود</a></td>
        `;

        tbody.appendChild(tr);
    });
}

// اجرا بعد از لود شدن صفحه
 loading.style.display = "none";
    empty.style.display = "block";
    empty.textContent = "خطا در بارگذاری آرشیو: " + e.message;
  }
}

document.addEventListener("DOMContentLoaded", populateArchiveTable);

</script>