feat(puzzle): 实现拼图自动填充规则引擎及相关功能

- 新增拼图填充规则管理Controller、DTO、Entity等核心类
- 实现条件评估策略模式,支持多种匹配规则
- 实现数据源解析策略模式,支持多种数据来源
- 新增拼图元素自动填充引擎,支持优先级匹配和动态填充
- 在SourceMapper中增加设备统计和查询相关方法
- 在PuzzleGenerateRequest中新增faceId字段用于触发自动填充
- 完善相关枚举类和工具类,提升系统可维护性和扩展性
This commit is contained in:
2025-11-19 11:10:23 +08:00
parent de421cf0d5
commit 778afaaa83
43 changed files with 4019 additions and 3 deletions

View File

@@ -0,0 +1,43 @@
<?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.ycwl.basic.puzzle.mapper.PuzzleFillRuleItemMapper">
<resultMap id="BaseResultMap" type="com.ycwl.basic.puzzle.entity.PuzzleFillRuleItemEntity">
<id column="id" property="id"/>
<result column="rule_id" property="ruleId"/>
<result column="element_key" property="elementKey"/>
<result column="data_source" property="dataSource"/>
<result column="source_filter" property="sourceFilter"/>
<result column="sort_strategy" property="sortStrategy"/>
<result column="fallback_value" property="fallbackValue"/>
<result column="item_order" property="itemOrder"/>
<result column="create_time" property="createTime"/>
<result column="update_time" property="updateTime"/>
</resultMap>
<select id="listByRuleId" resultMap="BaseResultMap">
SELECT *
FROM puzzle_fill_rule_item
WHERE rule_id = #{ruleId}
ORDER BY item_order ASC, id ASC
</select>
<insert id="batchInsert">
INSERT INTO puzzle_fill_rule_item (
rule_id, element_key, data_source, source_filter,
sort_strategy, fallback_value, item_order
) VALUES
<foreach collection="items" item="item" separator=",">
(
#{item.ruleId}, #{item.elementKey}, #{item.dataSource}, #{item.sourceFilter},
#{item.sortStrategy}, #{item.fallbackValue}, #{item.itemOrder}
)
</foreach>
</insert>
<delete id="deleteByRuleId">
DELETE FROM puzzle_fill_rule_item
WHERE rule_id = #{ruleId}
</delete>
</mapper>

View File

@@ -0,0 +1,39 @@
<?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.ycwl.basic.puzzle.mapper.PuzzleFillRuleMapper">
<resultMap id="BaseResultMap" type="com.ycwl.basic.puzzle.entity.PuzzleFillRuleEntity">
<id column="id" property="id"/>
<result column="template_id" property="templateId"/>
<result column="rule_name" property="ruleName"/>
<result column="condition_type" property="conditionType"/>
<result column="condition_value" property="conditionValue"/>
<result column="priority" property="priority"/>
<result column="enabled" property="enabled"/>
<result column="scenic_id" property="scenicId"/>
<result column="description" property="description"/>
<result column="deleted" property="deleted"/>
<result column="create_time" property="createTime"/>
<result column="update_time" property="updateTime"/>
</resultMap>
<select id="listByTemplateId" resultMap="BaseResultMap">
SELECT *
FROM puzzle_fill_rule
WHERE template_id = #{templateId}
AND enabled = 1
AND deleted = 0
ORDER BY priority DESC, id ASC
</select>
<select id="listByTemplateAndScenic" resultMap="BaseResultMap">
SELECT *
FROM puzzle_fill_rule
WHERE template_id = #{templateId}
AND scenic_id = #{scenicId}
AND enabled = 1
AND deleted = 0
ORDER BY priority DESC, id ASC
</select>
</mapper>

View File

@@ -361,4 +361,57 @@
order by create_time desc
limit 1
</select>
<select id="countDistinctDevicesByFaceId" resultType="java.lang.Integer">
SELECT COUNT(DISTINCT s.device_id)
FROM member_source ms
INNER JOIN source s ON ms.source_id = s.id
WHERE ms.face_id = #{faceId}
AND s.type = 2
AND s.deleted = 0
</select>
<select id="getSourceByFaceAndDeviceIndex" resultType="com.ycwl.basic.model.pc.source.entity.SourceEntity">
WITH ranked_sources AS (
SELECT s.*,
ROW_NUMBER() OVER (PARTITION BY s.device_id
<choose>
<when test='sortStrategy == "LATEST"'>
ORDER BY s.create_time DESC
</when>
<when test='sortStrategy == "EARLIEST"'>
ORDER BY s.create_time ASC
</when>
<when test='sortStrategy == "SCORE_DESC"'>
ORDER BY IFNULL(s.score, 0) DESC, s.create_time DESC
</when>
<when test='sortStrategy == "PURCHASED_FIRST"'>
ORDER BY ms.is_buy DESC, s.create_time DESC
</when>
<otherwise>
ORDER BY s.create_time DESC
</otherwise>
</choose>
) as rn,
ROW_NUMBER() OVER (ORDER BY s.device_id ASC) as device_rank
FROM source s
INNER JOIN member_source ms ON s.id = ms.source_id
WHERE ms.face_id = #{faceId}
AND s.type = #{type}
AND s.deleted = 0
)
SELECT *
FROM ranked_sources
WHERE rn = 1 AND device_rank = #{deviceIndex} + 1
LIMIT 1
</select>
<select id="getDeviceIdsByFaceId" resultType="java.lang.Long">
SELECT DISTINCT s.device_id
FROM member_source ms
INNER JOIN source s ON ms.source_id = s.id
WHERE ms.face_id = #{faceId}
AND s.deleted = 0
ORDER BY s.device_id ASC
</select>
</mapper>