|
|
@@ -21,6 +21,87 @@
|
|
|
homeParam = urlParams.get('home') || '';
|
|
|
})();
|
|
|
|
|
|
+ // ========== 审核浏览行为追踪 ==========
|
|
|
+ var entryTime = null; // 首次查看附件时开始计时(null表示尚未查看附件)
|
|
|
+ var attachmentViewLog = []; // 附件查看行为日志
|
|
|
+
|
|
|
+ // 拦截 openPreview 函数,记录预览行为
|
|
|
+ var originalOpenPreview = window.openPreview;
|
|
|
+ window.openPreview = function(url, type) {
|
|
|
+ // 首次查看附件时开始计时
|
|
|
+ if (entryTime === null) {
|
|
|
+ entryTime = Date.now();
|
|
|
+ }
|
|
|
+ // 记录预览行为
|
|
|
+ var attachName = '';
|
|
|
+ // 尝试从 URL 中提取文件名
|
|
|
+ try {
|
|
|
+ var urlObj = new URL(url);
|
|
|
+ var pathname = urlObj.pathname;
|
|
|
+ attachName = decodeURIComponent(pathname.split('/').pop() || '');
|
|
|
+ } catch(e) {
|
|
|
+ attachName = url.substring(0, 50);
|
|
|
+ }
|
|
|
+ attachmentViewLog.push({
|
|
|
+ name: attachName,
|
|
|
+ action: 'preview',
|
|
|
+ time: new Date().toLocaleString('zh-CN', {hour12: false})
|
|
|
+ });
|
|
|
+ // 调用原始函数
|
|
|
+ if (originalOpenPreview) {
|
|
|
+ originalOpenPreview(url, type);
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ // 监听下载按钮点击(强制下载,阻止浏览器直接打开预览)
|
|
|
+ $(document).on('click', '.op-btn-download', function(e) {
|
|
|
+ e.preventDefault(); // 阻止默认的链接行为
|
|
|
+
|
|
|
+ // 首次查看附件时开始计时
|
|
|
+ if (entryTime === null) {
|
|
|
+ entryTime = Date.now();
|
|
|
+ }
|
|
|
+
|
|
|
+ var $btn = $(this);
|
|
|
+ var href = $btn.attr('href') || '';
|
|
|
+ var attachName = $btn.attr('download') || href.substring(href.lastIndexOf('/') + 1) || 'file';
|
|
|
+ // 对文件名进行 URL 解码
|
|
|
+ try {
|
|
|
+ attachName = decodeURIComponent(attachName);
|
|
|
+ } catch(e) {
|
|
|
+ // 解码失败,使用原始值
|
|
|
+ }
|
|
|
+
|
|
|
+ // 记录行为日志
|
|
|
+ attachmentViewLog.push({
|
|
|
+ name: attachName,
|
|
|
+ action: 'download',
|
|
|
+ time: new Date().toLocaleString('zh-CN', {hour12: false})
|
|
|
+ });
|
|
|
+
|
|
|
+ // 通过 fetch 获取文件并强制下载
|
|
|
+ if (href) {
|
|
|
+ fetch(href)
|
|
|
+ .then(function(response) {
|
|
|
+ return response.blob();
|
|
|
+ })
|
|
|
+ .then(function(blob) {
|
|
|
+ var blobUrl = URL.createObjectURL(blob);
|
|
|
+ var a = document.createElement('a');
|
|
|
+ a.href = blobUrl;
|
|
|
+ a.download = attachName;
|
|
|
+ document.body.appendChild(a);
|
|
|
+ a.click();
|
|
|
+ document.body.removeChild(a);
|
|
|
+ URL.revokeObjectURL(blobUrl);
|
|
|
+ })
|
|
|
+ .catch(function(err) {
|
|
|
+ // 如果 fetch 失败(如跨域),回退到直接打开
|
|
|
+ window.location.href = href;
|
|
|
+ });
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
function doSubmit(obj){
|
|
|
console.log('doSubmit called, obj=', obj);
|
|
|
if (!canAuditFlag) {
|
|
|
@@ -36,9 +117,30 @@
|
|
|
$('#inputForm input[name="auditOpinion"]').remove();
|
|
|
$('#inputForm input[name="score"]').remove();
|
|
|
$('#inputForm input[name="result"]').remove();
|
|
|
+ $('#inputForm input[name="viewDurationSeconds"]').remove();
|
|
|
+ $('#inputForm input[name="attachmentViewDetail"]').remove();
|
|
|
+ $('#inputForm input[name="isViewedAttachment"]').remove();
|
|
|
+
|
|
|
+ // 计算附件查看时长(秒):从首次查看附件开始计时,未查看过则为0
|
|
|
+ var viewDurationSeconds = entryTime !== null ? Math.floor((Date.now() - entryTime) / 1000) : 0;
|
|
|
+ // 是否查看过附件
|
|
|
+ var isViewedAttachment = attachmentViewLog.length > 0 ? 1 : 0;
|
|
|
+ // 附件查看行为 JSON
|
|
|
+ var attachmentViewDetail = JSON.stringify(attachmentViewLog);
|
|
|
|
|
|
if (obj == 1) {
|
|
|
- // 通过:审核意见为空时默认"同意"
|
|
|
+ // ========== 前端校验:停留时长和附件查看(仅“通过”操作) ==========
|
|
|
+ var minStaySeconds = ${minStaySeconds != null ? minStaySeconds : 30};
|
|
|
+ if (isViewedAttachment != 1) {
|
|
|
+ parent.layer.msg('您还没有查看附件信息,请认真查看附件内容至少' + minStaySeconds + '秒后再审核', {icon: 5, time: 5000});
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ if (viewDurationSeconds < minStaySeconds) {
|
|
|
+ parent.layer.msg('您查看附件仅' + viewDurationSeconds + '秒,低于最低要求' + minStaySeconds + '秒,请认真查看附件内容后再审核', {icon: 5, time: 5000});
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 通过:审核意见为空时默认“同意”
|
|
|
if (!opinion || opinion.trim() === '') {
|
|
|
opinion = '同意';
|
|
|
}
|
|
|
@@ -83,25 +185,33 @@
|
|
|
<c:if test="${treeName == '技术总结' || treeName == '培训心得' || (treeName == '典型案例' && entity.contentAttribute == '0')}">
|
|
|
$('#inputForm').append('<input type="hidden" name="score" value="' + $('#scoreValue').val() + '" />');
|
|
|
</c:if>
|
|
|
-
|
|
|
+ // 添加浏览行为追踪字段
|
|
|
+ $('#inputForm').append('<input type="hidden" name="viewDurationSeconds" value="' + viewDurationSeconds + '" />');
|
|
|
+ $('#inputForm').append('<input type="hidden" name="attachmentViewDetail" value="' + encodeURIComponent(attachmentViewDetail) + '" />');
|
|
|
+ $('#inputForm').append('<input type="hidden" name="isViewedAttachment" value="' + isViewedAttachment + '" />');
|
|
|
+
|
|
|
// 提交表单
|
|
|
$("#inputForm").submit();
|
|
|
return true;
|
|
|
} else {
|
|
|
- // 驳回:审核意见为空时默认"驳回"
|
|
|
+ // 驳回:审核意见为空时默认“驳回”
|
|
|
if (!opinion || opinion.trim() === '') {
|
|
|
opinion = '驳回';
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
// 设置表单action为新的auditPassForm方法(驳回也走同一个接口,只是result不同)
|
|
|
var formAction = '${ctx}/workKnowledgeBase/share/auditPassForm?id=${entity.id}&home=' + encodeURIComponent(homeParam);
|
|
|
$("#inputForm").attr("action", formAction);
|
|
|
console.log('Form action set to:', formAction);
|
|
|
-
|
|
|
+
|
|
|
// 添加隐藏字段传递审核意见(驳回时不传score)
|
|
|
$('#inputForm').append('<input type="hidden" name="auditOpinion" value="' + escapeHtml(opinion) + '" />');
|
|
|
$('#inputForm').append('<input type="hidden" name="result" value="2" />');
|
|
|
-
|
|
|
+ // 添加浏览行为追踪字段(驳回也记录)
|
|
|
+ $('#inputForm').append('<input type="hidden" name="viewDurationSeconds" value="' + viewDurationSeconds + '" />');
|
|
|
+ $('#inputForm').append('<input type="hidden" name="attachmentViewDetail" value="' + encodeURIComponent(attachmentViewDetail) + '" />');
|
|
|
+ $('#inputForm').append('<input type="hidden" name="isViewedAttachment" value="' + isViewedAttachment + '" />');
|
|
|
+
|
|
|
// 提交表单
|
|
|
$("#inputForm").submit();
|
|
|
return true;
|
|
|
@@ -435,7 +545,7 @@
|
|
|
<td><fmt:formatDate value="${attach.createDate}" type="both"/></td>
|
|
|
<td>${attach.fileSize}</td>
|
|
|
<td>
|
|
|
- <a href="${attach.temporaryUrl}" class="op-btn op-btn-download">
|
|
|
+ <a href="${attach.temporaryUrl}" download="${attach.attachmentName}" class="op-btn op-btn-download">
|
|
|
<i class="fa fa-download"></i> 下载
|
|
|
</a>
|
|
|
</td>
|