Редактировал(а) Кристина Гришкина 10.10.2025

От версии 3.1
отредактировано Кристина Гришкина
на 10.10.2025
Изменить комментарий: К данной версии нет комментариев
К версии 2.2
отредактировано Alexey Semenihin
на 10.10.2025
Изменить комментарий: Добавлен тег [Мобильное приложение, таймшиты, фактические трудозатраты, Табель, учет рабочего времени, текущие задачи, задачи на неделю, списание часов, заполнить трудозатраты, сверхурочные, рабочее время, фактические часы]

Сводка

Подробности

Свойства страницы
Автор документа
... ... @@ -1,1 +1,1 @@
1 -xwiki:XWiki.grishkinakn
1 +xwiki:XWiki.semenihinaa
Содержимое
... ... @@ -1,5 +1,36 @@
1 1  {{velocity}}
2 +## Макрос для отображения подстраниц с отображаемыми именами в алфавитном порядке
3 +#macro(displayDirectChildrenClean)
4 + #set ($currentPage = $doc.fullName)
5 + #set ($children = $xwiki.getDocument($currentPage).getChildren())
6 + #if ($children.size() > 0)
7 + ## Создаем список для хранения пар (отображаемое имя, полное имя)
8 + #set ($childList = [])
9 + #foreach ($child in $children)
10 + #set ($childDoc = $xwiki.getDocument($child))
11 + ## Получаем отображаемое имя (title), если оно не пустое, иначе используем имя документа
12 + #set ($displayName = $childDoc.getPlainTitle())
13 + #if ($displayName == '')
14 + #set ($displayName = $childDoc.getName())
15 + #end
16 + ## Добавляем пару в список
17 + #set ($discard = $childList.add({"displayName": $displayName, "fullName": $child}))
18 + #end
19 + ## Сортируем список по displayName
20 + #set ($sortedChildren = $sorttool.sort($childList, "displayName:asc"))
21 + ## Выводим отсортированный список
22 + #foreach ($item in $sortedChildren)
23 + [[$item.displayName>>$item.fullName]]
24 + #end
25 + #end
26 +#end
27 +## Выводим список
28 +#displayDirectChildrenClean()
29 +{{/velocity}}
2 2  
31 +
32 +{{velocity}}
33 +
3 3  ## Подключаем необходимые JS/CSS для работы вкладок
4 4  $xwiki.jsfx.use('uicomponents/widgets/tabView.js', {'forceSkinAction': true, 'language': 'xwiki/2.1'})
5 5  $xwiki.ssfx.use('uicomponents/widgets/tabView.css', true)
... ... @@ -15,12 +15,6 @@
15 15   attachmentsTab.click();
16 16   }
17 17   // Альтернативный вариант (если не сработал ID):
18 - else {
19 - var tabs = $$('.tab-menu a').find(function(tab) {
20 - return tab.textContent.trim().includes('Вложения');
21 - });
22 - if (tabs && tabs.length > 0) tabs[0].click();
23 - }
24 24  });
25 25  </script>
26 26  {{/html}}
... ... @@ -27,63 +27,227 @@
27 27  {{/velocity}}
28 28  
29 29  {{velocity}}
55 +=== Прикрепите вложения и используйте кнопки для навигации ===
56 +#set($spaceRef = $doc.documentReference.lastSpaceReference.name)
57 +#set($pageName = $doc.documentReference.name)
58 +#set($docFullName = "${spaceRef}.${pageName}")
30 30  #set($attachments = $doc.getAttachmentList())
31 -#foreach($attachment in $attachments)
32 - #set($filename = $attachment.filename)
33 - #set($fileurl = $doc.getAttachmentURL($filename))
34 - #set($fileExt = $filename.substring($filename.lastIndexOf('.') + 1).toLowerCase())
35 -
36 - ## Определяем тип файла
37 - #set($isPdf = $fileExt == 'pdf')
38 - #set($isImage = $fileExt == 'png' || $fileExt == 'jpg' || $fileExt == 'jpeg' || $fileExt == 'gif' || $fileExt == 'bmp' || $fileExt == 'svg')
39 - #set($isOffice = $fileExt == 'doc' || $fileExt == 'docx' || $fileExt == 'xls' || $fileExt == 'xlsx' || $fileExt == 'ppt' || $fileExt == 'pptx' || $fileExt == 'odt' || $fileExt == 'ods' || $fileExt == 'odp')
40 -
41 - ## Обрабатываем только поддерживаемые форматы
42 - #if($isPdf || $isImage || $isOffice)
43 -
44 -
45 - #if($isPdf)
60 +#set($itemsPerPage = 1)
61 +#set($totalPages = ($attachments.size() + $itemsPerPage - 1) / $itemsPerPage)
62 +#set($currentPage = 1)
63 +#if("$!request.page" != "")
64 + #set($currentPage = $mathtool.toInteger($request.page))
65 +#end
66 +#set($startIndex = ($currentPage - 1) * $itemsPerPage)
67 +#set($endIndex = $startIndex + $itemsPerPage - 1)
68 +#if($endIndex >= $attachments.size())
69 + #set($endIndex = $attachments.size() - 1)
70 +#end
71 +
72 +{{html}}
73 +<div class="navigation-controls">
74 + #if($attachments && !$attachments.isEmpty())
75 + <!-- Выпадающий список для выбора вложения -->
76 + <div class="attachment-selector">
77 + <label for="attachment-select">Выберите вложение:</label>
78 + <select id="attachment-select">
79 + #foreach($attachment in $attachments)
80 + <option value="$attachment.filename" #if($velocityCount == $currentPage)selected#end>
81 + $attachment.filename
82 + </option>
83 + #end
84 + </select>
85 + </div>
86 +
87 + <!-- Пагинация -->
88 + <div class="pagination-controls">
89 + #if($currentPage > 1)
90 + #set($prevPage = $currentPage - 1)
91 + <a href="$doc.getURL('view', "page=${prevPage}")" class="btn btn-primary">Назад</a>
92 + #else
93 + <span class="btn btn-disabled">Назад</span>
94 + #end
95 +
96 + <span class="page-info">Страница $currentPage из $totalPages</span>
97 +
98 + #if($currentPage < $totalPages)
99 + #set($nextPage = $currentPage + 1)
100 + <a href="$doc.getURL('view', "page=${nextPage}")" class="btn btn-primary">Далее</a>
101 + #else
102 + <span class="btn btn-disabled">Далее</span>
103 + #end
104 + </div>
105 + #else
106 + <div class="no-attachments-message">
107 + Нет прикрепленных вложений. Пожалуйста, добавьте файлы для просмотра.
108 + </div>
109 + #end
110 +</div>
111 +{{/html}}
112 +
113 +#if($attachments && !$attachments.isEmpty())
114 + #foreach($i in [$startIndex..$endIndex])
115 + #set($attachment = $attachments.get($i))
116 + #set($filename = $attachment.filename)
117 + #set($fileurl = $doc.getAttachmentURL($filename, "download"))
118 + #set($fileExtension = $filename.substring($filename.lastIndexOf('.') + 1).toLowerCase())
119 +
120 + === Документ: $filename ===
121 +
46 46   {{html}}
47 - <div class="pdf-viewer-container">
48 - <iframe
49 - src="/resources/pdfjs/web/viewer.html?file=${fileurl}"
50 - width="100%"
51 - height="600px">
52 - </iframe>
123 + <div class="document-viewer-container" id="document-viewer">
124 + #if($fileExtension == 'pdf')
125 + <!-- PDF Viewer -->
126 + <iframe
127 + id="document-frame"
128 + src="/resources/pdfjs/web/viewer.html?file=${escapetool.url($fileurl)}"
129 + width="100%"
130 + height="600px">
131 + </iframe>
132 + #elseif($fileExtension == 'doc' || $fileExtension == 'docx' || $fileExtension == 'ppt' || $fileExtension == 'pptx' || $fileExtension == 'xls' || $fileExtension == 'xlsx' || $fileExtension == 'mp4')
133 + #if($fileExtension == 'doc' || $fileExtension == 'docx' || $fileExtension == 'ppt' || $fileExtension == 'pptx' || $fileExtension == 'xls' || $fileExtension == 'xlsx')
134 + <!-- Office Viewer -->
135 + #set($officeViewerUrl = "${doc.getURL('view')}?xpage=office&attachment=${escapetool.url($filename)}")
136 + <iframe
137 + id="document-frame"
138 + src="$officeViewerUrl"
139 + width="100%"
140 + height="600px">
141 + </iframe>
142 + #end
143 + #if($fileExtension == 'mp4')
144 + ==ВИДЕО==
145 + <video id="myvideo" width="920" controls>
146 + <source src="${fileurl}" type="video/$fileExtension">
147 + Ваш браузер не поддерживает видео.
148 + </video>
149 + #end
150 + #else
151 + ==Конец==
152 + <div class="unsupported-format">
153 + Формат файла (${fileExtension}) не поддерживается для просмотра.
154 + <a href="${fileurl}">Скачать файл</a>
155 + </div>
156 + #end
53 53   </div>
54 54   {{/html}}
55 -
56 - #elseif($isImage)
57 - [[image:${attachment.filename}]]
58 -
59 - #elseif($isOffice)
60 - {{office attachment="${attachment.filename}" filterStyles="false"/}}
61 -
62 62   #end
63 - #end
160 +#else
161 + {{html}}
162 + <div class="no-attachments-message">
163 + Нет доступных вложений для отображения.
164 + </div>
165 + {{/html}}
64 64  #end
65 65  
66 66  {{html}}
67 67  <style>
68 - .pdf-viewer-container {
170 + .navigation-controls {
171 + display: flex;
172 + flex-direction: column;
173 + gap: 15px;
174 + margin-bottom: 20px;
175 + }
176 + .attachment-selector {
177 + display: flex;
178 + align-items: center;
179 + gap: 10px;
180 + }
181 + .attachment-selector select {
182 + padding: 8px;
183 + border-radius: 4px;
184 + min-width: 300px;
185 + }
186 + .document-viewer-container {
69 69   margin: 20px 0;
70 70   border: 1px solid #eee;
71 71   padding: 10px;
72 72   background: #f9f9f9;
73 73   }
74 -
75 - /* Стили для изображений */
76 - .image-wrapper {
77 - max-width: 100%;
78 - margin: 10px 0;
192 + .pagination-controls {
193 + margin: 20px 0;
194 + display: flex;
195 + justify-content: center;
196 + align-items: center;
197 + gap: 20px;
79 79   }
80 -
81 - /* Стили для офисных документов */
82 - .office-document {
83 - border: 1px solid #ddd;
84 - margin: 15px 0;
85 - min-height: 500px;
199 + .btn {
200 + padding: 8px 16px;
201 + border-radius: 4px;
202 + text-decoration: none;
86 86   }
204 + .btn-primary {
205 + background-color: #3366cc;
206 + color: white;
207 + }
208 + .btn-disabled {
209 + background-color: #eee;
210 + color: #999;
211 + cursor: not-allowed;
212 + }
213 + .page-info {
214 + font-weight: bold;
215 + }
216 + .unsupported-format {
217 + padding: 20px;
218 + text-align: center;
219 + color: #666;
220 + }
221 + .no-attachments-message {
222 + padding: 20px;
223 + text-align: center;
224 + color: #666;
225 + font-style: italic;
226 + border: 1px dashed #ccc;
227 + background-color: #f5f5f5;
228 + }
87 87  </style>
230 +
231 +<script>
232 +//<![CDATA[
233 +document.addEventListener('DOMContentLoaded', function() {
234 + const select = document.getElementById('attachment-select');
235 + const viewerContainer = document.getElementById('document-viewer');
236 +
237 + if (select && viewerContainer) {
238 + select.addEventListener('change', function() {
239 + const filename = this.value;
240 + const fileExtension = filename.split('.').pop().toLowerCase();
241 + const fileurl = "${doc.getURL('download')}" + "/" + encodeURIComponent(filename);
242 + const pdfViewerUrl = "/resources/pdfjs/web/viewer.html?file=" + encodeURIComponent(fileurl);
243 + const baseUrl = "${doc.getURL('view')}";
244 +
245 + let viewerHtml = '';
246 +
247 + if (fileExtension === 'pdf') {
248 + viewerHtml = '<iframe id="document-frame" ' +
249 + 'src="' + pdfViewerUrl + '" ' +
250 + 'width="100%" height="600px"></iframe>';
251 + } else if (['doc', 'docx', 'ppt', 'pptx', 'xls', 'xlsx'].indexOf(fileExtension) >= 0) {
252 + viewerHtml = '<iframe id="document-frame" ' +
253 + 'src="' + baseUrl + '?xpage=office&attachment=' + encodeURIComponent(filename) + '" ' +
254 + 'width="100%" height="600px"></iframe>';
255 + } else if (fileExtension === 'mp4'||fileExtension === 'mov') {
256 + viewerHtml = '<video width="920" controls>' +
257 + '<source src="' + fileurl + '" type="video/' + fileExtension + '">' +
258 + 'Ваш браузер не поддерживает видео.</video>';
259 +} else {
260 + viewerHtml = '<div class="unsupported-format">' +
261 + 'Формат файла (' + fileExtension + ') не поддерживается для просмотра. ' +
262 + '<a href="' + fileurl + '">Скачать файл</a></div>';
263 + }
264 +
265 + viewerContainer.innerHTML = viewerHtml;
266 +
267 + // Обновляем заголовок документа
268 + const titleElement = viewerContainer.previousElementSibling;
269 + if (titleElement && titleElement.tagName === 'H3') {
270 + titleElement.textContent = 'Документ: ' + filename;
271 + }
272 + });
273 + }
274 +});
275 +//]]>
276 +</script>
88 88  {{/html}}
89 89  {{/velocity}}