Initial project
This commit is contained in:
@@ -0,0 +1,101 @@
|
||||
server:
|
||||
port: 8091
|
||||
shutdown: graceful
|
||||
|
||||
# 开发环境语言,激活开发配置时,多语言系统始终使用此语言环境
|
||||
dev:
|
||||
lang: zh_CN
|
||||
|
||||
# 日志配置
|
||||
logging:
|
||||
config: config/logback.xml
|
||||
|
||||
# Spring
|
||||
spring:
|
||||
profiles:
|
||||
active: prod
|
||||
servlet:
|
||||
multipart:
|
||||
max-file-size: 4GB
|
||||
max-request-size: 4GB
|
||||
lifecycle:
|
||||
timeout-per-shutdown-phase: 32s
|
||||
async:
|
||||
thread-pool:
|
||||
core-pool-size: 16
|
||||
max-pool-size: 32
|
||||
queueCapacity: 16
|
||||
keep-alive-seconds: 60
|
||||
thread-name-prefix: thread-pool-task-executor-
|
||||
await-termination-seconds: 60
|
||||
mail: # 邮件配置
|
||||
host: smtp.qq.com
|
||||
username: imyeyu@qq.com
|
||||
password: saodifhaposjfoas
|
||||
properties:
|
||||
mail:
|
||||
smtp:
|
||||
auth: true
|
||||
starttls:
|
||||
enable: true
|
||||
required: true
|
||||
default-encoding: UTF-8
|
||||
mvc: # JSON 序列化
|
||||
converters:
|
||||
preferred-json-mapper: gson # 返回 JSON 序列化使用 GSON
|
||||
redis: # Redis 数据库
|
||||
host: dev.vm.imyeyu.test
|
||||
port: 6379
|
||||
password:
|
||||
timeout: 8000
|
||||
database:
|
||||
locker: 0 # ID: Integer 全局锁,ID 规范:应用:模块:业务:方法
|
||||
multilingual: 1 # ID: Multilingual 多语言缓存
|
||||
multilingual-map: 2 # Key: ID 多语言键缓存
|
||||
article-ranking: 3 # AID: ArticleRanking(JSON) 热门文章排位
|
||||
article-read: 4 # IP: [AID..] IP 阅读文章记录
|
||||
user-token: 5 # TOKEN: LONG 用户登录令牌
|
||||
user-exp-flag: 6 # UID: NULL 用户登录经验标记,暂时没有值,数据死亡时间为次日零时
|
||||
user-email-verify: 7 # AES_KEY: UID 邮箱验证密钥缓存
|
||||
user-reset-pw-verify: 8 # AES_KEY: UID 重置密码密钥缓存
|
||||
qps-limit: 9 # APP.IP.method: COUNT_IN_LIFE_CYCLE 接口访问频率控制(多个系统公用,需要 App 标记)
|
||||
setting: 10 # Setting: SettingValue 系统配置
|
||||
fmc-player-token: 11 # TOKEN: USER_ID|PLAYER_ID MC 登录缓存
|
||||
lettuce: # 连接池配置
|
||||
pool:
|
||||
max-wait: -1
|
||||
max-idle: 8
|
||||
min-idle: 0
|
||||
max-active: 8
|
||||
datasource: # 数据库配置
|
||||
timiserver:
|
||||
jdbc-url: jdbc:mysql://dev.vm.imyeyu.test:3306/timi_server?serverTimezone=UTC&characterEncoding=UTF-8
|
||||
username: root
|
||||
password: 123123
|
||||
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||
forevermc:
|
||||
jdbc-url: jdbc:mysql://dev.vm.imyeyu.test:3306/authme?serverTimezone=UTC&characterEncoding=UTF-8
|
||||
username: root
|
||||
password: 123123
|
||||
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||
gitea:
|
||||
jdbc-url: jdbc:mysql://dev.vm.imyeyu.test:3306/authme?serverTimezone=UTC&characterEncoding=UTF-8
|
||||
username: root
|
||||
password: 123123
|
||||
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||
data:
|
||||
mongodb:
|
||||
host: dev.vm.imyeyu.test
|
||||
port: 27017
|
||||
database: db
|
||||
username: root
|
||||
password: qweqwe123
|
||||
|
||||
# CORS 跨域
|
||||
cors:
|
||||
# 允许访问的客户端域名,如:http://web.xxx.com,* 表示不做任何限制(不做任何限制时 allow-credentials 无效)
|
||||
allow-origin:
|
||||
- "http://localhost:8080"
|
||||
allow-methods: "*" # 允许请求的方法名,多个方法名逗号分割,如:GET, POST, PUT, DELETE, OPTIONS
|
||||
allow-credentials: true # 是否允许请求带有验证信息,若要获取客户端域下的 Cookie 或 Session 时,设置为 true
|
||||
allow-headers: "*" # 允许服务端访问的客户端请求头,多个请求头逗号分割,如:Content-BizType
|
||||
@@ -0,0 +1,9 @@
|
||||
______ _ __ _ _
|
||||
/ __\ (_)_ __ ___ _ _ ___ _ _ _ _ ___ ___ _ __ ___ \ \ \ \
|
||||
/ . . \ ' | | '_ _ \| | | |/ _ \ | | | | | | / __/ _ \| '_ _ \ \ \ \ \
|
||||
( ) | | | | | | | |_| | __/ |_| | |_| || (_| (_) | | | | | | ) ) ) )
|
||||
'\ ___ /' |_|_| |_| |_|\__, |\___|\__, |\__,_(_)___\___/|_| |_| |_| / / / /
|
||||
--'---'-------------------|___/------|___/-----------------------------/_/_/_/
|
||||
|
||||
Banner drawn by https://patorjk.com/software/taag for Ivrit
|
||||
Spring Boot Version: ${spring-boot.version}
|
||||
@@ -0,0 +1,25 @@
|
||||
<configuration>
|
||||
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder>
|
||||
<charset>UTF-8</charset>
|
||||
<pattern>[%d{HH:mm:ss.SSS}][%-5level][%-54logger{54}] %msg%n</pattern>
|
||||
</encoder>
|
||||
<filter class="com.imyeyu.server.modules.system.util.LoggerFilter" />
|
||||
</appender>
|
||||
<appender name="file" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<file>./logs/debug.log</file>
|
||||
<encoder>
|
||||
<charset>UTF-8</charset>
|
||||
<pattern>[%d{HH:mm:ss.SSS}][%-5level][%-54logger{54}] %msg%n</pattern>
|
||||
</encoder>
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||
<fileNamePattern>./logs/debug/debug.%d{yyyy-MM-dd}.log</fileNamePattern>
|
||||
<maxHistory>30</maxHistory>
|
||||
</rollingPolicy>
|
||||
<filter class="com.imyeyu.server.modules.system.util.LoggerFilter" />
|
||||
</appender>
|
||||
<root level="info">
|
||||
<appender-ref ref="file" />
|
||||
<appender-ref ref="console" />
|
||||
</root>
|
||||
</configuration>
|
||||
@@ -0,0 +1,65 @@
|
||||
<?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.imyeyu.server.modules.blog.mapper.ArticleMapper">
|
||||
<sql id="table">article</sql>
|
||||
|
||||
<!-- 查询列表的文章字段 -->
|
||||
<sql id="listColumn">
|
||||
article.id,
|
||||
article.type,
|
||||
article.title,
|
||||
article.digest,
|
||||
article.likes,
|
||||
article.reads,
|
||||
article.created_at,
|
||||
article.updated_at
|
||||
</sql>
|
||||
|
||||
|
||||
<!-- 主页列表 -->
|
||||
<sql id="normalCondition">
|
||||
FROM
|
||||
article
|
||||
WHERE
|
||||
1 < article.id
|
||||
AND article.deleted_at IS NULL
|
||||
</sql>
|
||||
<select id="count" resultType="long">
|
||||
SELECT COUNT(1) <include refid="normalCondition" />
|
||||
</select>
|
||||
<select id="list" resultType="com.imyeyu.server.modules.blog.entity.Article">
|
||||
SELECT
|
||||
<include refid="listColumn" />
|
||||
<include refid="normalCondition" />
|
||||
ORDER BY
|
||||
COALESCE(article.updated_at, article.created_at) DESC
|
||||
LIMIT
|
||||
#{offset}, #{limit}
|
||||
</select>
|
||||
|
||||
|
||||
<!-- 根据关键字获取列表 -->
|
||||
<sql id="byKeywordCondition">
|
||||
FROM
|
||||
article
|
||||
WHERE
|
||||
1 < article.id
|
||||
AND (
|
||||
article.title LIKE CONCAT('%', #{keyword}, '%')
|
||||
OR article.digest LIKE CONCAT('%', #{keyword}, '%')
|
||||
)
|
||||
AND article.deleted_at IS NULL
|
||||
</sql>
|
||||
<select id="countByKeyword" resultType="long">
|
||||
SELECT COUNT(1) <include refid="byKeywordCondition" />
|
||||
</select>
|
||||
<select id="selectByKeyword" resultType="com.imyeyu.server.modules.blog.entity.Article">
|
||||
SELECT
|
||||
<include refid="listColumn" />
|
||||
<include refid="byKeywordCondition" />
|
||||
ORDER BY
|
||||
COALESCE(article.updated_at, article.created_at) DESC
|
||||
LIMIT
|
||||
#{offset}, #{limit}
|
||||
</select>
|
||||
</mapper>
|
||||
@@ -0,0 +1,22 @@
|
||||
<?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.imyeyu.server.modules.common.mapper.AttachmentMapper">
|
||||
<sql id="table">attachment</sql>
|
||||
<select id="listByAttachType" resultType="com.imyeyu.server.modules.common.entity.Attachment">
|
||||
SELECT
|
||||
*
|
||||
FROM
|
||||
<include refid="table" />
|
||||
WHERE
|
||||
biz_type = #{bizType}
|
||||
AND biz_id = #{bizId}
|
||||
<if test="attachTypes != null and 0 < attachTypes.length">
|
||||
AND attach_type IN
|
||||
<foreach collection="attachTypes" item="item" open="(" separator="," close=")">
|
||||
#{item}
|
||||
</foreach>
|
||||
</if>
|
||||
AND deleted_at IS NULL
|
||||
AND destroy_at IS NULL
|
||||
</select>
|
||||
</mapper>
|
||||
@@ -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.imyeyu.server.modules.common.mapper.CommentMapper">
|
||||
<sql id="table">comment</sql>
|
||||
<!-- 主评论 -->
|
||||
<select id="list" resultMap="listResult">
|
||||
SELECT
|
||||
-- 主评论
|
||||
comment.id,
|
||||
comment.biz_type,
|
||||
comment.biz_id,
|
||||
comment.user_id,
|
||||
comment.nick,
|
||||
comment.content,
|
||||
comment.created_at,
|
||||
|
||||
-- 回复数量
|
||||
reply_count.reply_length,
|
||||
|
||||
-- 回复
|
||||
reply.id AS reply_id,
|
||||
reply.comment_id,
|
||||
reply.sender_id,
|
||||
reply.sender_nick,
|
||||
reply.receiver_id,
|
||||
reply.receiver_nick,
|
||||
reply.content AS reply_content,
|
||||
reply.created_at AS reply_created_at
|
||||
FROM (
|
||||
-- 查询主评论
|
||||
SELECT
|
||||
*
|
||||
FROM
|
||||
<include refid="table" />
|
||||
WHERE
|
||||
biz_type = #{bizType}
|
||||
AND biz_id = #{bizId}
|
||||
AND deleted_at IS NULL
|
||||
ORDER BY
|
||||
created_at ${orderMap.createdAt}
|
||||
LIMIT
|
||||
#{offset}, #{limit}
|
||||
) AS comment
|
||||
LEFT JOIN (
|
||||
-- 查询前 6 条回复(时间升序)
|
||||
SELECT
|
||||
*
|
||||
FROM (
|
||||
SELECT
|
||||
comment_reply.*,
|
||||
ROW_NUMBER() OVER (
|
||||
PARTITION BY comment_id
|
||||
ORDER BY created_at ASC
|
||||
) AS seq
|
||||
FROM
|
||||
comment_reply
|
||||
WHERE
|
||||
deleted_at IS NULL
|
||||
) AS reply
|
||||
WHERE
|
||||
seq < 7
|
||||
) AS reply
|
||||
ON
|
||||
reply.comment_id = comment.id
|
||||
LEFT JOIN(
|
||||
-- 统计回复总数
|
||||
SELECT
|
||||
comment_id AS id,
|
||||
COUNT(*) AS reply_length
|
||||
FROM
|
||||
comment_reply
|
||||
WHERE
|
||||
deleted_at IS NULL
|
||||
GROUP BY
|
||||
comment_id
|
||||
) AS reply_count
|
||||
ON
|
||||
reply_count.id = comment.id
|
||||
</select>
|
||||
<resultMap id="listResult" type="com.imyeyu.server.modules.common.vo.comment.CommentView">
|
||||
<id property="id" column="id" />
|
||||
<result property="userId" column="user_id" />
|
||||
<result property="nick" column="nick" />
|
||||
<result property="content" column="content" />
|
||||
<result property="repliesLength" column="reply_length" />
|
||||
<result property="createdAt" column="created_at" />
|
||||
<!-- 关联回复 -->
|
||||
<collection property="replies" ofType="com.imyeyu.server.modules.common.vo.comment.CommentReplyView">
|
||||
<id property="id" column="reply_id" />
|
||||
<result property="commentId" column="comment_id" />
|
||||
<result property="senderId" column="sender_id" />
|
||||
<result property="senderNick" column="sender_nick" />
|
||||
<result property="receiverId" column="receiver_id" />
|
||||
<result property="receiverNick" column="receiver_nick" />
|
||||
<result property="content" column="reply_content" />
|
||||
<result property="createdAt" column="reply_created_at" />
|
||||
</collection>
|
||||
</resultMap>
|
||||
<select id="countAll" resultType="long">
|
||||
SELECT
|
||||
SUM(result.total_comment + result.total_reply)
|
||||
FROM (
|
||||
SELECT
|
||||
COUNT(DISTINCT comment.id) AS total_comment,
|
||||
COUNT(comment_reply.comment_id) AS total_reply
|
||||
FROM
|
||||
comment
|
||||
LEFT JOIN
|
||||
comment_reply
|
||||
ON
|
||||
comment_reply.comment_id = comment.id
|
||||
WHERE
|
||||
comment.biz_type = #{bizType}
|
||||
AND comment.biz_id = #{bizId}
|
||||
AND comment.deleted_at IS NULL
|
||||
AND comment_reply.deleted_at IS NULL
|
||||
) AS result
|
||||
</select>
|
||||
|
||||
<sql id="byUserIdCondition">
|
||||
FROM
|
||||
<include refid="table" />
|
||||
WHERE
|
||||
user_id = #{userId}
|
||||
AND deleted_at IS NULL
|
||||
</sql>
|
||||
<select id="countByUserId" resultType="long">
|
||||
SELECT COUNT(1) <include refid="byUserIdCondition" />
|
||||
</select>
|
||||
<select id="listByUserId" resultType="com.imyeyu.server.modules.common.vo.comment.CommentView">
|
||||
SELECT
|
||||
id,
|
||||
biz_type,
|
||||
biz_id,
|
||||
content,
|
||||
created_at
|
||||
<include refid="byUserIdCondition" />
|
||||
ORDER BY
|
||||
created_at ${orderMap.createdAt}
|
||||
LIMIT
|
||||
#{offset}, #{limit}
|
||||
</select>
|
||||
</mapper>
|
||||
@@ -0,0 +1,35 @@
|
||||
<?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.imyeyu.server.modules.common.mapper.IconMapper">
|
||||
<sql id="table">icon</sql>
|
||||
<!-- 根据标签获取部分 -->
|
||||
<sql id="byLabel">
|
||||
FROM (
|
||||
SELECT
|
||||
id
|
||||
FROM
|
||||
icon_labels
|
||||
WHERE
|
||||
${lang} LIKE CONCAT('%', #{label}, '%')
|
||||
AND icon_labels.deleted_at IS NULL
|
||||
) AS labels
|
||||
LEFT JOIN
|
||||
icon_label
|
||||
ON
|
||||
icon_label.icon_label_id = labels.id
|
||||
AND labels.id IS NOT NULL
|
||||
LEFT JOIN
|
||||
<include refid="table" />
|
||||
ON
|
||||
icon.id = icon_label.icon_id
|
||||
WHERE
|
||||
icon.id IS NOT NULL
|
||||
AND icon.deleted_at IS NULL
|
||||
</sql>
|
||||
<select id="countByLabel" resultType="long">
|
||||
SELECT COUNT(1) <include refid="byLabel" />
|
||||
</select>
|
||||
<select id="listByLabel" resultType="com.imyeyu.server.modules.common.entity.Icon">
|
||||
SELECT icon.* <include refid="byLabel" /> LIMIT #{offset}, #{limit}
|
||||
</select>
|
||||
</mapper>
|
||||
@@ -0,0 +1,11 @@
|
||||
<?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.imyeyu.server.modules.common.mapper.MultilingualMapper">
|
||||
<select id="selectByKeyList" resultType="com.imyeyu.server.modules.common.entity.Multilingual">
|
||||
SELECT * FROM multilingual WHERE key IN
|
||||
<foreach collection='keys' item='item' open='(' separator=',' close=')'>
|
||||
#{item}
|
||||
</foreach>
|
||||
AND deleted_at IS NULL
|
||||
</select>
|
||||
</mapper>
|
||||
@@ -0,0 +1,16 @@
|
||||
<?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.imyeyu.server.modules.common.mapper.SettingMapper">
|
||||
<sql id="table">setting</sql>
|
||||
<select id="listByKeys">
|
||||
SELECT
|
||||
*
|
||||
FROM
|
||||
<include refid="table" />
|
||||
WHERE
|
||||
key IN
|
||||
<foreach collection="keys" item="key" open="(" separator="," close=")">
|
||||
#{key}
|
||||
</foreach>
|
||||
</select>
|
||||
</mapper>
|
||||
@@ -0,0 +1,55 @@
|
||||
<?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.imyeyu.server.modules.common.mapper.TaskMapper">
|
||||
<!-- 所有公开任务 -->
|
||||
<select id="listAll4Public" resultMap="findAll4PublicResult">
|
||||
SELECT
|
||||
id,
|
||||
name,
|
||||
digest,
|
||||
status,
|
||||
td.*
|
||||
FROM
|
||||
task
|
||||
LEFT JOIN (
|
||||
SELECT
|
||||
*
|
||||
FROM (
|
||||
-- 任务详情
|
||||
SELECT
|
||||
id AS detial_id,
|
||||
task_id,
|
||||
bizType,
|
||||
status AS tdStatus,
|
||||
digest AS tdDigest,
|
||||
created_at,
|
||||
ROW_NUMBER() OVER (PARTITION BY task_id ORDER BY created_at DESC) AS seq
|
||||
FROM
|
||||
task_detail
|
||||
WHERE
|
||||
deleted_at IS NULL
|
||||
) AS cr
|
||||
WHERE
|
||||
seq < 7
|
||||
) AS td
|
||||
ON
|
||||
td.task_id = task.id
|
||||
WHERE
|
||||
is_public = 1
|
||||
AND deleted_at IS NULL
|
||||
</select>
|
||||
<resultMap id="findAll4PublicResult" type="com.imyeyu.server.modules.common.entity.Task">
|
||||
<id property="id" column="id"/>
|
||||
<result property="name" column="name"/>
|
||||
<result property="digest" column="digest"/>
|
||||
<result property="status" column="status"/>
|
||||
<!-- 关联任务 -->
|
||||
<collection property="details" ofType="com.imyeyu.server.modules.common.entity.TaskDetail">
|
||||
<id property="id" column="detial_id"/>
|
||||
<result property="bizType" column="bizType"/>
|
||||
<result property="status" column="tdStatus"/>
|
||||
<result property="digest" column="tdDigest"/>
|
||||
<result property="createdAt" column="created_at"/>
|
||||
</collection>
|
||||
</resultMap>
|
||||
</mapper>
|
||||
@@ -0,0 +1,5 @@
|
||||
<?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.imyeyu.server.modules.common.mapper.UserConfigMapper">
|
||||
<sql id="table">user_config</sql>
|
||||
</mapper>
|
||||
@@ -0,0 +1,4 @@
|
||||
<?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.imyeyu.server.modules.common.mapper.UserPrivacyMapper">
|
||||
</mapper>
|
||||
@@ -0,0 +1,5 @@
|
||||
<?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.imyeyu.server.modules.common.mapper.UserProfileMapper">
|
||||
<sql id="table">user_profile</sql>
|
||||
</mapper>
|
||||
@@ -0,0 +1,40 @@
|
||||
<?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.imyeyu.server.modules.git.mapper.IssueMapper">
|
||||
<sql id="table">git_issue</sql>
|
||||
<sql id="pageCondition">
|
||||
repository_id = #{issuePage.repositoryId}
|
||||
<if test="issuePage.type != null">
|
||||
AND type = #{issuePage.type}
|
||||
</if>
|
||||
<if test="issuePage.status != null">
|
||||
AND status = #{issuePage.status}
|
||||
</if>
|
||||
<if test="issuePage.keyword != null and issuePage.keyword != ''">
|
||||
AND (
|
||||
title LIKE CONCAT('%', #{issuePage.keyword}, '%')
|
||||
OR description LIKE CONCAT('%', #{issuePage.keyword}, '%')
|
||||
)
|
||||
</if>
|
||||
AND deleted_at IS NULL
|
||||
</sql>
|
||||
<select id="countByIssuePage" resultType="long">
|
||||
SELECT COUNT(1) FROM <include refid="table" /> WHERE <include refid="pageCondition" />
|
||||
</select>
|
||||
<select id="listByIssuePage" resultType="com.imyeyu.server.modules.git.entity.Issue">
|
||||
SELECT
|
||||
id,
|
||||
title,
|
||||
type,
|
||||
status,
|
||||
created_at
|
||||
FROM
|
||||
<include refid="table" />
|
||||
WHERE
|
||||
<include refid="pageCondition" />
|
||||
ORDER BY
|
||||
COALESCE(updated_at, created_at) DESC
|
||||
LIMIT
|
||||
#{offset}, #{limit}
|
||||
</select>
|
||||
</mapper>
|
||||
@@ -0,0 +1,40 @@
|
||||
<?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.imyeyu.server.modules.git.mapper.MergeMapper">
|
||||
<sql id="table">git_merge</sql>
|
||||
<sql id="pageCondition">
|
||||
repository_id = #{mergePage.repositoryId}
|
||||
<if test="mergePage.type != null">
|
||||
AND type = #{mergePage.type}
|
||||
</if>
|
||||
<if test="mergePage.status != null">
|
||||
AND status = #{mergePage.status}
|
||||
</if>
|
||||
<if test="mergePage.keyword != null and mergePage.keyword != ''">
|
||||
AND (
|
||||
title LIKE CONCAT('%', #{mergePage.keyword}, '%')
|
||||
OR description LIKE CONCAT('%', #{mergePage.keyword}, '%')
|
||||
)
|
||||
</if>
|
||||
AND deleted_at IS NULL
|
||||
</sql>
|
||||
<select id="countByMergePage" resultType="long">
|
||||
SELECT COUNT(1) FROM <include refid="table" /> WHERE <include refid="pageCondition" />
|
||||
</select>
|
||||
<select id="listByMergePage" resultType="com.imyeyu.server.modules.git.entity.Merge">
|
||||
SELECT
|
||||
id,
|
||||
title,
|
||||
type,
|
||||
status,
|
||||
created_at
|
||||
FROM
|
||||
<include refid="table" />
|
||||
WHERE
|
||||
<include refid="pageCondition" />
|
||||
ORDER BY
|
||||
COALESCE(updated_at, created_at) DESC
|
||||
LIMIT
|
||||
#{offset}, #{limit}
|
||||
</select>
|
||||
</mapper>
|
||||
@@ -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.imyeyu.server.modules.git.mapper.ReleaseMapper">
|
||||
<sql id="table">git_release</sql>
|
||||
<select id="listByRepositoryId" resultMap="listByRepositoryIdResult">
|
||||
SELECT
|
||||
release.*,
|
||||
attachment.id AS attachmentId,
|
||||
attachment.biz_type,
|
||||
attachment.biz_id,
|
||||
attachment.lid_title,
|
||||
attachment.name,
|
||||
attachment.size
|
||||
FROM
|
||||
<include refid="table" /> AS release
|
||||
LEFT JOIN
|
||||
attachment
|
||||
ON
|
||||
attachment.biz_type = '${@com.imyeyu.timiserver.modules.common.entity.Attachment$BizType@GIT}'
|
||||
AND attachment.biz_id = release.id
|
||||
AND attachment.attach_type = '${@com.imyeyu.timiserver.modules.git.bean.AttachType@RELEASE}'
|
||||
AND attachment.deleted_at IS NULL
|
||||
WHERE
|
||||
release.repository_id = #{repositoryId}
|
||||
AND release.deleted_at IS NULL
|
||||
ORDER BY
|
||||
COALESCE(release.updated_at, release.created_at) DESC
|
||||
LIMIT
|
||||
#{offset}, #{limit}
|
||||
</select>
|
||||
<resultMap id="listByRepositoryIdResult" type="com.imyeyu.server.modules.git.vo.release.ReleaseView" autoMapping="true">
|
||||
<id property="id" column="id" />
|
||||
<!-- 关联附件 -->
|
||||
<collection property="attachmentList" ofType="com.imyeyu.server.modules.common.vo.attachment.AttachmentView">
|
||||
<id property="id" column="attachmentId" />
|
||||
<result property="bizType" column="biz_type" />
|
||||
<result property="bizId" column="biz_id" />
|
||||
<result property="lidTitle" column="lid_title" />
|
||||
<result property="name" column="name" />
|
||||
<result property="size" column="size" />
|
||||
</collection>
|
||||
</resultMap>
|
||||
</mapper>
|
||||
@@ -0,0 +1,52 @@
|
||||
<?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.imyeyu.server.modules.gitea.mapper.ActionMapper">
|
||||
<select id="count" resultType="long">
|
||||
SELECT
|
||||
COUNT(*)
|
||||
FROM
|
||||
action
|
||||
WHERE
|
||||
1 = 1
|
||||
<if test="repoId != null">
|
||||
AND action.repo_id = #{repoId}
|
||||
</if>
|
||||
<if test="branch != null">
|
||||
AND action.ref_name LIKE CONCAT('%', #{branch})
|
||||
</if>
|
||||
<if test="operation != null">
|
||||
AND action.op_type = #{operation.value}
|
||||
</if>
|
||||
</select>
|
||||
<select id="list" resultType="com.imyeyu.server.modules.gitea.bean.ActionLogDTO">
|
||||
SELECT
|
||||
repository.id AS repo_id,
|
||||
repository.name AS repo_name,
|
||||
operator.id AS operator_id,
|
||||
action.ref_name,
|
||||
action.content,
|
||||
action.created_unix * 1000 AS operatedAt
|
||||
FROM
|
||||
action
|
||||
INNER JOIN
|
||||
repository ON action.repo_id = repository.id
|
||||
INNER JOIN
|
||||
user AS operator ON action.act_user_id = operator.id
|
||||
WHERE
|
||||
1 = 1
|
||||
<if test="repoId != null">
|
||||
AND action.repo_id = #{repoId}
|
||||
</if>
|
||||
<if test="branch != null">
|
||||
AND action.ref_name LIKE CONCAT('%', #{branch})
|
||||
</if>
|
||||
<if test="operation != null">
|
||||
AND action.op_type = #{operation.value}
|
||||
</if>
|
||||
ORDER BY
|
||||
action.created_unix DESC,
|
||||
action.id DESC
|
||||
LIMIT
|
||||
#{offset}, #{limit}
|
||||
</select>
|
||||
</mapper>
|
||||
@@ -0,0 +1,33 @@
|
||||
<?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.imyeyu.server.modules.minecraft.mapper.PackMapper">
|
||||
<!-- 获取 -->
|
||||
<select id="listPacks" resultMap="listPacksResult">
|
||||
SELECT
|
||||
pack.*,
|
||||
source.name AS sourceName,
|
||||
source.type AS sourceType,
|
||||
source.data AS sourceData,
|
||||
source.is_default
|
||||
FROM
|
||||
minecraft_pack AS pack
|
||||
LEFT JOIN
|
||||
minecraft_pack_source AS source
|
||||
ON
|
||||
source.pack_id = pack.id
|
||||
WHERE
|
||||
pack.deleted_at IS NULL
|
||||
AND source.deleted_at IS NULL
|
||||
ORDER BY
|
||||
pack.is_deprecated, pack.created_at DESC, source.order ASC
|
||||
</select>
|
||||
<resultMap id="listPacksResult" type="com.imyeyu.server.modules.minecraft.entity.MinecraftPack" autoMapping="true">
|
||||
<id property="id" column="id" />
|
||||
<collection property="sourceList" ofType="com.imyeyu.server.modules.minecraft.entity.MinecraftPackSource" autoMapping="false">
|
||||
<result property="name" column="sourceName" />
|
||||
<result property="type" column="sourceType" />
|
||||
<result property="data" column="sourceData" />
|
||||
<result property="isDefault" column="is_default" />
|
||||
</collection>
|
||||
</resultMap>
|
||||
</mapper>
|
||||
@@ -0,0 +1,4 @@
|
||||
<?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.imyeyu.server.modules.minecraft.mapper.PlayerMapper">
|
||||
</mapper>
|
||||
@@ -0,0 +1,56 @@
|
||||
<?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.imyeyu.server.modules.system.mapper.AsyncTaskMapper">
|
||||
<sql id="table">async_task</sql>
|
||||
<insert id="insert">
|
||||
INSERT INTO <include refid="table" /> (
|
||||
uuid,
|
||||
name,
|
||||
type,
|
||||
message,
|
||||
status,
|
||||
progress,
|
||||
can_pause,
|
||||
can_interrupt,
|
||||
is_periodical,
|
||||
cron,
|
||||
start_at,
|
||||
interrupt_at,
|
||||
error_at,
|
||||
died_at,
|
||||
created_at
|
||||
) VALUES (
|
||||
#{uuid},
|
||||
#{name},
|
||||
#{type},
|
||||
#{message},
|
||||
#{status},
|
||||
#{progress},
|
||||
#{canPause},
|
||||
#{canInterrupt},
|
||||
#{isPeriodical},
|
||||
#{cron},
|
||||
#{startAt},
|
||||
#{interruptAt},
|
||||
#{errorAt},
|
||||
#{diedAt},
|
||||
#{createdAt}
|
||||
)
|
||||
</insert>
|
||||
<update id="update" parameterType="com.imyeyu.server.modules.system.entity.AsyncTask">
|
||||
UPDATE
|
||||
<include refid="table" />
|
||||
SET
|
||||
name = #{name},
|
||||
type = #{type},
|
||||
message = #{message},
|
||||
status = #{status},
|
||||
progress = #{progress},
|
||||
start_at = #{startAt},
|
||||
interrupt_at = #{interruptAt},
|
||||
error_at = #{errorAt},
|
||||
died_at = #{diedAt}
|
||||
WHERE
|
||||
uuid = #{uuid}
|
||||
</update>
|
||||
</mapper>
|
||||
@@ -0,0 +1,58 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>Title</title>
|
||||
<style>
|
||||
<#include "StyleSheet.ftl" />
|
||||
</style>
|
||||
<style>
|
||||
.btn {
|
||||
color: #FFF !important;
|
||||
width: 7rem;
|
||||
margin: 32px auto 48px auto;
|
||||
border: none;
|
||||
display: block;
|
||||
padding: 8px 24px;
|
||||
font-size: 15px;
|
||||
text-align: center;
|
||||
background: #53BD93;
|
||||
text-decoration: none !important;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background: #5AC79B;
|
||||
}
|
||||
|
||||
.tips {
|
||||
margin: 12px 0 6px 0;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="root">
|
||||
<div class="mail">
|
||||
<#if user.data.hasWrapper>
|
||||
<img
|
||||
class="wrapper ir-${user.data.wrapperType?lower_case}"
|
||||
src="https://res.imyeyu.net/user/wrapper/${user.id}.png"
|
||||
/>
|
||||
<#else>
|
||||
<img class="wrapper ir-pixelated" src="https://res.imyeyu.net/user/wrapper/default.png" />
|
||||
</#if>
|
||||
<h4 class="title">
|
||||
<span class="pink bold">${user.name} </span>
|
||||
<span>您好,您正在验证</span>
|
||||
<span class="pink bold"> 夜雨博客 </span>
|
||||
<span>的邮箱绑定,请在 10 分钟内点击下面的按钮完成校验,让我确定这是你的电子邮箱,不要泄露此邮件内容。</span>
|
||||
</h4>
|
||||
<a class="btn" href="${url}" multilingualField="_blank">继续完成验证</a>
|
||||
<aside class="tips center gray">如果这不是你本人操作,请无视此邮件</aside>
|
||||
<#include "Footer.ftl" />
|
||||
</div>
|
||||
<div class="line1"></div>
|
||||
<div class="line2"></div>
|
||||
<div class="line3"></div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,11 @@
|
||||
<footer class="footer font12 center">
|
||||
<p>这是由系统自动发送的邮件,请不要回复</p>
|
||||
<p>
|
||||
<span>如果这封邮件打扰到您,请直接屏蔽本邮箱或登录</span>
|
||||
<a href="https://www.imyeyu.net">夜雨博客</a>
|
||||
<span>个人空间中的设置随时关闭</span>
|
||||
</p>
|
||||
<p> </p>
|
||||
<p>朝朝频顾惜,夜夜不相忘</p>
|
||||
<p>Copyright © 2017 - ${.now?string["yyyy"]} 夜雨 All Rights Reserved 版权所有</p>
|
||||
</footer>
|
||||
@@ -0,0 +1,92 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>Title</title>
|
||||
<style>
|
||||
<#include "StyleSheet.ftl" />
|
||||
</style>
|
||||
<style>
|
||||
.comment {
|
||||
width: 80%;
|
||||
display: flex;
|
||||
margin: 16px auto 4px auto;
|
||||
font-size: 14px;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.comment .content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.comment .content .avatar {
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
border: 1px solid #777;
|
||||
margin-right: 4px;
|
||||
}
|
||||
|
||||
.comment .content h4 {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.comment .content .data {
|
||||
width: 15rem;
|
||||
}
|
||||
|
||||
.sign-in-tips {
|
||||
margin-top: 20px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="root">
|
||||
<div class="mail">
|
||||
<#if user.data.hasWrapper>
|
||||
<img
|
||||
class="wrapper ir-${user.data.wrapperType?lower_case}"
|
||||
src="https://res.imyeyu.net/user/wrapper/${user.id}.png"
|
||||
/>
|
||||
<#else>
|
||||
<img class="wrapper ir-pixelated" src="https://res.imyeyu.net/user/wrapper/default.png" />
|
||||
</#if>
|
||||
<h4 class="title">
|
||||
<span class="pink bold">${user.name} </span>
|
||||
<span>您好,您在</span>
|
||||
<span class="pink bold"> 夜雨博客 </span>
|
||||
<span>的评论收到以下回复</span>
|
||||
<span class="gray">(24 小时内)</span>
|
||||
</h4>
|
||||
<#list reminds as remind>
|
||||
<section class="comment">
|
||||
<div class="content">
|
||||
<#if remind.reply.sender??>
|
||||
<#if remind.reply.sender.data.avatarType>
|
||||
<img
|
||||
class="avatar ir-${remind.reply.sender.data.avatarType?lower_case}"
|
||||
src="https://res.imyeyu.net/user/avatar/${remind.reply.sender.id}.png"
|
||||
/>
|
||||
<#else>
|
||||
<img class="avatar ir-pixelated" src="https://res.imyeyu.net/user/avatar/default.png" />
|
||||
</#if>
|
||||
<h4>${remind.reply.sender.name} 说:</h4>
|
||||
<#else>
|
||||
<img class="avatar ir-pixelated" src="https://res.imyeyu.net/user/avatar/default.png" />
|
||||
<h4>${remind.reply.senderNick} 说:</h4>
|
||||
</#if>
|
||||
<p class="data clip-text">${remind.reply.data}</p>
|
||||
</div>
|
||||
<span class="gray time font12">${remind.reply.createdAt?number_to_datetime?string("yyyy-MM-dd HH:mm:ss")}</span>
|
||||
</section>
|
||||
</#list>
|
||||
<p class="sign-in-tips gray font12 center">本邮件仅作摘要提醒,登录博客查看详细信息</p>
|
||||
<#include "Footer.ftl" />
|
||||
</div>
|
||||
<div class="line1"></div>
|
||||
<div class="line2"></div>
|
||||
<div class="line3"></div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,63 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>Title</title>
|
||||
<style>
|
||||
<#include "StyleSheet.ftl" />
|
||||
</style>
|
||||
<style>
|
||||
.btn {
|
||||
color: #FFF !important;
|
||||
width: 7rem;
|
||||
margin: 32px auto 48px auto;
|
||||
border: none;
|
||||
display: block;
|
||||
padding: 8px 24px;
|
||||
font-size: 15px;
|
||||
text-align: center;
|
||||
background: #53BD93;
|
||||
text-decoration: none !important;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background: #5AC79B;
|
||||
}
|
||||
|
||||
.tips {
|
||||
margin: 12px 0 6px 0;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="root">
|
||||
<div class="mail">
|
||||
<#if user.data.hasWrapper>
|
||||
<img
|
||||
class="wrapper ir-${user.data.wrapperType?lower_case}"
|
||||
src="https://res.imyeyu.net/user/wrapper/${user.id}.png"
|
||||
alt="user wrapper"
|
||||
/>
|
||||
<#else>
|
||||
<img
|
||||
class="wrapper ir-pixelated"
|
||||
src="https://res.imyeyu.net/user/wrapper/default.png"
|
||||
alt="user wrapper"
|
||||
/>
|
||||
</#if>
|
||||
<h4 class="title">
|
||||
<span class="pink bold">${user.name} </span>
|
||||
<span>您好,</span>
|
||||
<span class="pink bold">夜雨博客 </span>
|
||||
<span>收到了您的重置密码请求,请在 10 分钟内点击下面的按钮继续完成,不要泄露此邮件内容。</span>
|
||||
</h4>
|
||||
<a class="btn" href="${url}" multilingualField="_blank">重置密码</a>
|
||||
<aside class="tips center gray">如果这不是你本人操作,请无视此邮件</aside>
|
||||
<#include "Footer.ftl" />
|
||||
</div>
|
||||
<div class="line1"></div>
|
||||
<div class="line2"></div>
|
||||
<div class="line3"></div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,163 @@
|
||||
/* 基本样式 */
|
||||
.font12 {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.gray {
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.pink {
|
||||
color: #FF7A9B;
|
||||
}
|
||||
|
||||
.bold {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.center {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
a {
|
||||
cursor: pointer !important;
|
||||
}
|
||||
|
||||
p {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.clip-text {
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.ir-pixelated {
|
||||
image-rendering: pixelated;
|
||||
}
|
||||
|
||||
.ir-auto {
|
||||
image-rendering: auto;
|
||||
}
|
||||
|
||||
.ir-smooth {
|
||||
image-rendering: smooth;
|
||||
}
|
||||
|
||||
/* 布局样式 */
|
||||
|
||||
.root {
|
||||
width: 42rem;
|
||||
margin: 24px auto;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.mail {
|
||||
margin: 0 3rem;
|
||||
box-shadow: 0 0 8px rgba(0, 0, 0, .5);
|
||||
background: #F4F4F4;
|
||||
}
|
||||
|
||||
.wrapper {
|
||||
width: 100%;
|
||||
display: block;
|
||||
border-bottom: 1px solid #CDDEF0;
|
||||
}
|
||||
|
||||
.title {
|
||||
margin: 4px 12px;
|
||||
}
|
||||
|
||||
.footer {
|
||||
color: #555;
|
||||
padding: 12px 0;
|
||||
margin-top: 32px;
|
||||
}
|
||||
|
||||
.line1 {
|
||||
height: 3px;
|
||||
z-index: -1;
|
||||
position: relative;
|
||||
margin-top: -50px;
|
||||
background: #FF7A9B;
|
||||
}
|
||||
|
||||
.line1::before {
|
||||
content: "";
|
||||
left: 0;
|
||||
width: 50%;
|
||||
height: 3px;
|
||||
bottom: 0;
|
||||
position: absolute;
|
||||
background: #FF7A9B;
|
||||
transform: rotate(-30deg);
|
||||
transform-origin: 0 0;
|
||||
}
|
||||
|
||||
.line1::after {
|
||||
content: "";
|
||||
right: 0;
|
||||
width: 50%;
|
||||
height: 3px;
|
||||
bottom: 0;
|
||||
position: absolute;
|
||||
background: #FF7A9B;
|
||||
transform: rotate(30deg);
|
||||
transform-origin: 100% 0;
|
||||
}
|
||||
|
||||
.line2,
|
||||
.line3 {
|
||||
width: 3px;
|
||||
height: 200px;
|
||||
position: absolute;
|
||||
background: linear-gradient(to bottom, rgba(255,122,155,1) 0%, rgba(255,255,255,0) 100%);;
|
||||
}
|
||||
|
||||
.line2::before,
|
||||
.line3::before {
|
||||
content: "";
|
||||
width: 200px;
|
||||
height: 40px;
|
||||
position: absolute;
|
||||
background: #FFF;
|
||||
}
|
||||
|
||||
.line2::before {
|
||||
top: 33px;
|
||||
left: 12px;
|
||||
transform: rotate(16deg);
|
||||
}
|
||||
|
||||
.line3::before {
|
||||
top: 32px;
|
||||
right: 12px;
|
||||
transform: rotate(-16deg);
|
||||
}
|
||||
|
||||
.line2::after,
|
||||
.line3::after {
|
||||
content: "";
|
||||
top: -1px;
|
||||
width: 21.8rem;
|
||||
height: 3px;
|
||||
position: absolute;
|
||||
background: #FF7A9B;
|
||||
}
|
||||
|
||||
.line2::after {
|
||||
left: 2px;
|
||||
transform: rotate(16deg);
|
||||
transform-origin: 0 0;
|
||||
}
|
||||
|
||||
.line3::after {
|
||||
right: 2px;
|
||||
transform: rotate(-16deg);
|
||||
transform-origin: 100% 0;
|
||||
}
|
||||
|
||||
.line3 {
|
||||
right: 0;
|
||||
}
|
||||
Reference in New Issue
Block a user