Jelajahi Sumber

知识库,点击量功能调整,添加查看详情功能

徐滕 1 Minggu lalu
induk
melakukan
2ca8637475

+ 43 - 0
src/main/java/com/jeeplus/modules/WorkKnowledgeBase/dao/WorkKnowledgeBaseClickRecordDao.java

@@ -0,0 +1,43 @@
+package com.jeeplus.modules.WorkKnowledgeBase.dao;
+
+import com.jeeplus.common.persistence.CrudDao;
+import com.jeeplus.common.persistence.Page;
+import com.jeeplus.common.persistence.annotation.MyBatisDao;
+import com.jeeplus.modules.WorkKnowledgeBase.entity.WorkKnowledgeBaseClickRecord;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+/**
+ * 知识库点击记录 DAO
+ * @author 徐滕
+ * @version 2026-07-06
+ */
+@MyBatisDao
+public interface WorkKnowledgeBaseClickRecordDao extends CrudDao<WorkKnowledgeBaseClickRecord> {
+
+    /**
+     * 根据文件ID和用户ID查询点击记录
+     */
+    WorkKnowledgeBaseClickRecord findByFileIdAndUserId(@Param("fileId") String fileId, @Param("userId") String userId);
+
+    /**
+     * 更新点击记录(增加点击次数,更新最近点击时间)
+     */
+    void updateClickRecord(WorkKnowledgeBaseClickRecord record);
+
+    /**
+     * 统计文件的点击人数(去重用户数)
+     */
+    Integer countClickersByFileId(@Param("fileId") String fileId);
+
+    /**
+     * 统计文件的总点击量(所有用户的点击次数之和)
+     */
+    Integer countClicksByFileId(@Param("fileId") String fileId);
+
+    /**
+     * 查询文件的点击详情列表(分页)
+     */
+    List<WorkKnowledgeBaseClickRecord> findClickDetailPage(Page<WorkKnowledgeBaseClickRecord> page, @Param("fileId") String fileId);
+}

+ 95 - 0
src/main/java/com/jeeplus/modules/WorkKnowledgeBase/entity/WorkKnowledgeBaseClickRecord.java

@@ -0,0 +1,95 @@
+package com.jeeplus.modules.WorkKnowledgeBase.entity;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.jeeplus.common.persistence.DataEntity;
+import com.jeeplus.modules.sys.entity.User;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.util.Date;
+
+/**
+ * 知识库点击记录实体
+ * 对应表 work_knowledge_base_click_record
+ * @author 徐滕
+ * @version 2026-07-06
+ */
+public class WorkKnowledgeBaseClickRecord extends DataEntity<WorkKnowledgeBaseClickRecord> {
+
+    /** 文件ID(关联 work_knowledge_base_share_info.id) */
+    private String fileId;
+
+    /** 点击人ID */
+    private String userId;
+
+    /** 点击人对象(用于关联查询) */
+    private User user;
+
+    /** 首次点击时间 */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date firstClickTime;
+
+    /** 最近点击时间 */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date lastClickTime;
+
+    /** 点击次数 */
+    private Integer clickCount;
+
+    public WorkKnowledgeBaseClickRecord() {
+        super();
+    }
+
+    public WorkKnowledgeBaseClickRecord(String id) {
+        super(id);
+    }
+
+    public String getFileId() {
+        return fileId;
+    }
+
+    public void setFileId(String fileId) {
+        this.fileId = fileId;
+    }
+
+    public String getUserId() {
+        return userId;
+    }
+
+    public void setUserId(String userId) {
+        this.userId = userId;
+    }
+
+    public User getUser() {
+        return user;
+    }
+
+    public void setUser(User user) {
+        this.user = user;
+    }
+
+    public Date getFirstClickTime() {
+        return firstClickTime;
+    }
+
+    public void setFirstClickTime(Date firstClickTime) {
+        this.firstClickTime = firstClickTime;
+    }
+
+    public Date getLastClickTime() {
+        return lastClickTime;
+    }
+
+    public void setLastClickTime(Date lastClickTime) {
+        this.lastClickTime = lastClickTime;
+    }
+
+    public Integer getClickCount() {
+        return clickCount;
+    }
+
+    public void setClickCount(Integer clickCount) {
+        this.clickCount = clickCount;
+    }
+}

+ 49 - 1
src/main/java/com/jeeplus/modules/WorkKnowledgeBase/service/WorkKnowledgeBaseShareService.java

@@ -124,6 +124,9 @@ public class WorkKnowledgeBaseShareService extends CrudService<WorkKnowledgeBase
     @Autowired
     private WorkKnowledgeBaseViolationRecordDao violationRecordDao;
 
+    @Autowired
+    private WorkKnowledgeBaseClickRecordDao clickRecordDao;
+
     /**
      * 根据文件id加载附件列表(编辑表单回显用)
      */
@@ -2270,11 +2273,56 @@ public class WorkKnowledgeBaseShareService extends CrudService<WorkKnowledgeBase
 
     /**
      * 点击量+1(每次点击都记录,不去重,不受审核状态限制)
+     * 同时记录点击明细到 click_record 表
      * @param id 文件ID
+     * @param userId 点击人ID
      */
     @Transactional(readOnly = false)
-    public void incrementClickCount(String id) {
+    public void incrementClickCount(String id, String userId) {
+        // 更新 share_info 表的 click_count 汇总字段
         dao.incrementClickCount(id);
+
+        // 记录/更新点击明细
+        if (StringUtils.isNotBlank(userId)) {
+            WorkKnowledgeBaseClickRecord existingRecord = clickRecordDao.findByFileIdAndUserId(id, userId);
+            if (existingRecord != null) {
+                // 已有记录:更新最近点击时间和点击次数
+                existingRecord.setLastClickTime(new Date());
+                existingRecord.setClickCount(existingRecord.getClickCount() + 1);
+                existingRecord.preUpdate();
+                clickRecordDao.updateClickRecord(existingRecord);
+            } else {
+                // 首次点击:创建新记录
+                WorkKnowledgeBaseClickRecord newRecord = new WorkKnowledgeBaseClickRecord();
+                newRecord.setFileId(id);
+                newRecord.setUserId(userId);
+                Date now = new Date();
+                newRecord.setFirstClickTime(now);
+                newRecord.setLastClickTime(now);
+                newRecord.setClickCount(1);
+                newRecord.preInsert();
+                clickRecordDao.insert(newRecord);
+            }
+        }
+    }
+
+    /**
+     * 查询文件的点击详情列表(分页)
+     */
+    public Page<WorkKnowledgeBaseClickRecord> findClickDetailPage(Page<WorkKnowledgeBaseClickRecord> page, String fileId) {
+        page.setList(clickRecordDao.findClickDetailPage(page, fileId));
+        return page;
+    }
+
+    /**
+     * 统计文件的总点击量
+     */
+    public Integer getClickCount(String fileId) {
+        if (StringUtils.isBlank(fileId)) {
+            return 0;
+        }
+        Integer count = clickRecordDao.countClicksByFileId(fileId);
+        return count != null ? count : 0;
     }
 
     // ==================== 手动赋分功能(独立于审核流程) ====================

+ 9 - 7
src/main/java/com/jeeplus/modules/WorkKnowledgeBase/web/WorkKnowledgeBaseReadLikeController.java

@@ -2,6 +2,7 @@ package com.jeeplus.modules.WorkKnowledgeBase.web;
 
 import com.jeeplus.common.persistence.Page;
 import com.jeeplus.common.web.BaseController;
+import com.jeeplus.modules.WorkKnowledgeBase.entity.WorkKnowledgeBaseClickRecord;
 import com.jeeplus.modules.WorkKnowledgeBase.entity.WorkKnowledgeBaseLikeRecord;
 import com.jeeplus.modules.WorkKnowledgeBase.entity.WorkKnowledgeBaseReadRecord;
 import com.jeeplus.modules.WorkKnowledgeBase.service.WorkKnowledgeBaseReadLikeService;
@@ -216,14 +217,15 @@ public class WorkKnowledgeBaseReadLikeController extends BaseController {
     }
 
     /**
-     * 点击量+1(任何状态都记录)
+     * 点击量+1(任何状态都记录),同时记录点击明细
      */
     @RequestMapping(value = "incrementClick")
     @ResponseBody
     public Map<String, Object> incrementClick(@RequestParam String fileId) {
         Map<String, Object> result = new HashMap<>();
         try {
-            shareService.incrementClickCount(fileId);
+            String userId = UserUtils.getUser().getId();
+            shareService.incrementClickCount(fileId, userId);
             result.put("success", true);
         } catch (Exception e) {
             result.put("success", false);
@@ -233,7 +235,7 @@ public class WorkKnowledgeBaseReadLikeController extends BaseController {
     }
 
     /**
-     * 点击详情页面(展示的阅读详情数据与阅读量详情一致
+     * 点击详情页面(展示每个用户的点击记录
      */
     @RequestMapping(value = "clickDetailPage")
     public String clickDetailPage(@RequestParam String fileId,
@@ -242,7 +244,7 @@ public class WorkKnowledgeBaseReadLikeController extends BaseController {
                                    Model model) {
         model.addAttribute("fileId", fileId);
         
-        Page<WorkKnowledgeBaseReadRecord> page = new Page<>();
+        Page<WorkKnowledgeBaseClickRecord> page = new Page<>();
         if (pageNo != null && pageNo > 0) {
             page.setPageNo(pageNo);
         }
@@ -252,10 +254,10 @@ public class WorkKnowledgeBaseReadLikeController extends BaseController {
             page.setPageSize(10);
         }
         
-        Page<WorkKnowledgeBaseReadRecord> detailPage = readLikeService.findReadDetailPage(page, fileId);
+        Page<WorkKnowledgeBaseClickRecord> detailPage = shareService.findClickDetailPage(page, fileId);
         model.addAttribute("page", detailPage);
-        model.addAttribute("totalCount", readLikeService.getReadCount(fileId));
+        model.addAttribute("totalCount", shareService.getClickCount(fileId));
         
-        return "modules/WorkKnowledgeBase/workKnowledgeBaseReadDetail";
+        return "modules/WorkKnowledgeBase/workKnowledgeBaseClickDetail";
     }
 }

+ 143 - 0
src/main/resources/mappings/modules/WorkKnowledgeBase/WorkKnowledgeBaseClickRecordDao.xml

@@ -0,0 +1,143 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.jeeplus.modules.WorkKnowledgeBase.dao.WorkKnowledgeBaseClickRecordDao">
+
+    <sql id="clickRecordColumns">
+        a.id AS "id",
+        a.file_id AS "fileId",
+        a.user_id AS "userId",
+        a.first_click_time AS "firstClickTime",
+        a.last_click_time AS "lastClickTime",
+        a.click_count AS "clickCount",
+        a.create_by AS "createBy.id",
+        a.create_date AS "createDate",
+        a.update_by AS "updateBy.id",
+        a.update_date AS "updateDate",
+        a.remarks AS "remarks",
+        a.del_flag AS "delFlag"
+    </sql>
+
+    <select id="get" resultType="com.jeeplus.modules.WorkKnowledgeBase.entity.WorkKnowledgeBaseClickRecord">
+        SELECT
+            <include refid="clickRecordColumns"/>
+        FROM work_knowledge_base_click_record a
+        WHERE a.id = #{id}
+    </select>
+
+    <select id="findList" resultType="com.jeeplus.modules.WorkKnowledgeBase.entity.WorkKnowledgeBaseClickRecord">
+        SELECT
+            <include refid="clickRecordColumns"/>
+        FROM work_knowledge_base_click_record a
+        <where>
+            a.del_flag = '0'
+            <if test="fileId != null and fileId != ''">
+                AND a.file_id = #{fileId}
+            </if>
+            <if test="userId != null and userId != ''">
+                AND a.user_id = #{userId}
+            </if>
+        </where>
+        ORDER BY a.create_date DESC
+    </select>
+
+    <insert id="insert">
+        INSERT INTO work_knowledge_base_click_record(
+            id,
+            file_id,
+            user_id,
+            first_click_time,
+            last_click_time,
+            click_count,
+            create_by,
+            create_date,
+            update_by,
+            update_date,
+            remarks,
+            del_flag
+        ) VALUES (
+            #{id},
+            #{fileId},
+            #{userId},
+            #{firstClickTime},
+            #{lastClickTime},
+            #{clickCount},
+            #{createBy.id},
+            #{createDate},
+            #{updateBy.id},
+            #{updateDate},
+            #{remarks},
+            #{delFlag}
+        )
+    </insert>
+
+    <update id="update">
+        UPDATE work_knowledge_base_click_record SET
+            last_click_time = #{lastClickTime},
+            click_count = #{clickCount},
+            update_by = #{updateBy.id},
+            update_date = #{updateDate},
+            remarks = #{remarks}
+        WHERE id = #{id}
+    </update>
+
+    <update id="delete">
+        UPDATE work_knowledge_base_click_record SET
+            del_flag = #{DEL_FLAG_DELETE}
+        WHERE id = #{id}
+    </update>
+
+    <!-- 根据文件ID和用户ID查询点击记录 -->
+    <select id="findByFileIdAndUserId" resultType="com.jeeplus.modules.WorkKnowledgeBase.entity.WorkKnowledgeBaseClickRecord">
+        SELECT
+            <include refid="clickRecordColumns"/>
+        FROM work_knowledge_base_click_record a
+        WHERE a.file_id = #{fileId}
+          AND a.user_id = #{userId}
+          AND a.del_flag = '0'
+        LIMIT 1
+    </select>
+
+    <!-- 更新点击记录(增加点击次数,更新最近点击时间) -->
+    <update id="updateClickRecord">
+        UPDATE work_knowledge_base_click_record SET
+            last_click_time = #{lastClickTime},
+            click_count = #{clickCount},
+            update_by = #{updateBy.id},
+            update_date = #{updateDate}
+        WHERE id = #{id}
+    </update>
+
+    <!-- 统计文件的点击人数(去重用户数) -->
+    <select id="countClickersByFileId" resultType="java.lang.Integer">
+        SELECT COUNT(DISTINCT a.user_id)
+        FROM work_knowledge_base_click_record a
+        WHERE a.file_id = #{fileId}
+          AND a.del_flag = '0'
+    </select>
+
+    <!-- 统计文件的总点击量(所有用户的点击次数之和) -->
+    <select id="countClicksByFileId" resultType="java.lang.Integer">
+        SELECT COALESCE(SUM(a.click_count), 0)
+        FROM work_knowledge_base_click_record a
+        WHERE a.file_id = #{fileId}
+          AND a.del_flag = '0'
+    </select>
+
+    <!-- 查询文件的点击详情列表(分页) -->
+    <select id="findClickDetailPage" resultType="com.jeeplus.modules.WorkKnowledgeBase.entity.WorkKnowledgeBaseClickRecord">
+        SELECT
+            a.id AS "id",
+            a.file_id AS "fileId",
+            a.user_id AS "userId",
+            u.name AS "user.name",
+            a.first_click_time AS "firstClickTime",
+            a.last_click_time AS "lastClickTime",
+            a.click_count AS "clickCount"
+        FROM work_knowledge_base_click_record a
+        LEFT JOIN sys_user u ON u.id = a.user_id
+        WHERE a.file_id = #{fileId}
+          AND a.del_flag = '0'
+        ORDER BY a.click_count DESC, a.last_click_time DESC
+    </select>
+
+</mapper>

+ 64 - 0
src/main/webapp/webpage/modules/WorkKnowledgeBase/workKnowledgeBaseClickDetail.jsp

@@ -0,0 +1,64 @@
+<%@ page contentType="text/html;charset=UTF-8" %>
+<%@ include file="/webpage/include/taglib.jsp" %>
+<html>
+<head>
+    <title>点击详情</title>
+    <meta name="decorator" content="default"/>
+    <script type="text/javascript">
+        $(document).ready(function() {
+            // 初始化逻辑
+        });
+    </script>
+</head>
+<body>
+<div class="wrapper wrapper-content">
+    <div class="layui-row">
+        <div class="full-width fl">
+            <div class="contentShadow layui-form contentDetails">
+                <table class="oa-table layui-table" id="contentTable"></table>
+                <table:page page="${page}"></table:page>
+                <div style="clear:both;"></div>
+                <div style="margin-top:15px;text-align:right;color:#666;padding:10px;">
+                    <strong>总点击量:</strong><span style="color:#009688;font-size:16px;">${totalCount}</span>
+                </div>
+            </div>
+        </div>
+    </div>
+</div>
+<script src="${ctxStatic}/layer-v2.3/layui/layui.all.js" charset="utf-8"></script>
+<script>
+    layui.use('table', function(){
+        layui.table.render({
+            elem: '#contentTable'
+            ,page: false
+            ,cols: [[
+                {field:'serialNo', align:'center', title: '序号', width:80, templet: function(d){
+                    return d.serialNo || ((d.LAY_TABLE_INDEX != null ? d.LAY_TABLE_INDEX + 1 : ''));
+                }}
+                ,{field:'userName', align: 'center', title: '点击人', minWidth: 120}
+                ,{field:'firstClickTime', align: 'center', title: '首次点击时间', minWidth: 180}
+                ,{field:'lastClickTime', align: 'center', title: '最近点击时间', minWidth: 180}
+                ,{field:'clickCount', align: 'center', title: '点击次数', width: 100}
+            ]]
+            ,data: [
+                <c:choose>
+                    <c:when test="${not empty page.list}">
+                        <c:forEach items="${page.list}" var="row" varStatus="st">
+                            <c:if test="${st.index != 0}">,</c:if>
+                            {
+                                "serialNo": "${st.index + 1 + (page.pageNo - 1) * page.pageSize}"
+                                ,"userName": "<c:out value='${row.user.name}'/>"
+                                ,"firstClickTime": "<fmt:formatDate value='${row.firstClickTime}' pattern='yyyy-MM-dd HH:mm:ss'/>"
+                                ,"lastClickTime": "<fmt:formatDate value='${row.lastClickTime}' pattern='yyyy-MM-dd HH:mm:ss'/>"
+                                ,"clickCount": "${row.clickCount}"
+                            }
+                        </c:forEach>
+                    </c:when>
+                    <c:otherwise></c:otherwise>
+                </c:choose>
+            ]
+        });
+    });
+</script>
+</body>
+</html>

+ 14 - 1
src/main/webapp/webpage/modules/WorkKnowledgeBase/workKnowledgeBaseShareList.jsp

@@ -621,6 +621,19 @@
             });
         }
 
+        /** 显示点击详情弹窗 */
+        function showClickDetail(fileId) {
+            top.layer.open({
+                type: 2,
+                area: ['80%', '80%'],
+                title: '点击详情',
+                maxmin: true,
+                content: '${ctx}/workKnowledgeBase/readLike/clickDetailPage?fileId=' + fileId,
+                btn: ['关闭'],
+                btn1: function(index) { top.layer.close(index); }
+            });
+        }
+
         /** 点赞操作 */
         function likeFile(fileId) {
             $.ajax({
@@ -1031,7 +1044,7 @@
             {field: 'createTime', align: 'center', title: '创建时间', width: 160},
             // 点击量(仅展示,通过点击文件名称/文件地址触发递增)
             {field: 'clickCount', align: 'center', title: '点击量', width: 100, templet: function(d){
-                return '<span style="color:#009688;">' + (d.clickCount || 0) + '</span>';
+                return '<a href="javascript:void(0)" onclick="showClickDetail(\'' + d.id + '\')" style="color:#009688;cursor:pointer;">' + (d.clickCount || 0) + '</a>';
             }},
             {field: 'readCount', align: 'center', title: '阅读量', width: 100, templet: function(d){
                 return '<a href="javascript:void(0)" onclick="showReadDetail(\'' + d.id + '\')" style="color:#1e9fff;cursor:pointer;">' + (d.readCount || 0) + '</a>';