✨ 签到ui改版
|
Before Width: | Height: | Size: 728 KiB After Width: | Height: | Size: 2.0 MiB |
279
resources/template/sign/main.css
Normal file
@ -0,0 +1,279 @@
|
|||||||
|
@font-face {
|
||||||
|
font-family: cr105Font;
|
||||||
|
/* 导入的字体文件 */
|
||||||
|
src: url("./res/font/ChillReunion_105S.otf");
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: cr95Font;
|
||||||
|
/* 导入的字体文件 */
|
||||||
|
src: url("./res/font/ChillReunion_95.otf");
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: cr65sFont;
|
||||||
|
/* 导入的字体文件 */
|
||||||
|
src: url("./res/font/ChillReunion_65S.otf");
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: shFont;
|
||||||
|
/* 导入的字体文件 */
|
||||||
|
src: url("./res/font/SourceHanSansSC-Bold.otf");
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: rxxxtFont;
|
||||||
|
/* 导入的字体文件 */
|
||||||
|
src: url("./res/font/日系小熊可爱体 Regular.ttf");
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: kcytFont;
|
||||||
|
/* 导入的字体文件 */
|
||||||
|
src: url("./res/font/江城圆体 700W.ttf");
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: yshsFont;
|
||||||
|
/* 导入的字体文件 */
|
||||||
|
src: url("/resources/font/YSHaoShenTi-2.ttf");
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
position: absolute;
|
||||||
|
left: -8px;
|
||||||
|
top: -8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wrapper{
|
||||||
|
height: 926px;
|
||||||
|
width: 465px;
|
||||||
|
background-color: #FBE4E4;
|
||||||
|
position: relative;
|
||||||
|
font-family: 'cr105Font'
|
||||||
|
}
|
||||||
|
|
||||||
|
.avatar {
|
||||||
|
height: 120px;
|
||||||
|
width: 120px;
|
||||||
|
border-radius: 50%;
|
||||||
|
margin-top: 38px;
|
||||||
|
margin-left: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.avatar-img {
|
||||||
|
height: 120px;
|
||||||
|
width: 120px;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.top-head {
|
||||||
|
width: 100%;
|
||||||
|
height: 179px;
|
||||||
|
color: #D37B8D;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nickname {
|
||||||
|
margin-top: 43px;
|
||||||
|
margin-left: 30px;
|
||||||
|
font-size: 47px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.uid {
|
||||||
|
font-size: 21px;
|
||||||
|
position: absolute;
|
||||||
|
width: 255px;
|
||||||
|
top: 84px;
|
||||||
|
left: 30px;
|
||||||
|
font-family: 'cr95Font'
|
||||||
|
}
|
||||||
|
|
||||||
|
.rl-img {
|
||||||
|
height: 90px;
|
||||||
|
width: 90px;
|
||||||
|
position: absolute;
|
||||||
|
top: 27px;
|
||||||
|
left: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.zx-img {
|
||||||
|
height:238px;
|
||||||
|
width: 120px;
|
||||||
|
left: 306px;
|
||||||
|
position: absolute;
|
||||||
|
z-index: 999;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-day {
|
||||||
|
font-size: 25px;
|
||||||
|
margin-left: 130px;
|
||||||
|
margin-top: 46px;
|
||||||
|
font-family: 'shFont';
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-zx {
|
||||||
|
font-family: 'cr65sFont';
|
||||||
|
position: absolute;
|
||||||
|
top: 72px;
|
||||||
|
left: 130px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sign-content{
|
||||||
|
width: 100%;
|
||||||
|
height: 160px;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sign-top {
|
||||||
|
background-color: #D47E8F;
|
||||||
|
width:445px;
|
||||||
|
height: 150px;
|
||||||
|
position: absolute;
|
||||||
|
left: 9px;
|
||||||
|
color: #FBE4E4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sign-bottom {
|
||||||
|
background-color: #953B50;
|
||||||
|
width: 445px;
|
||||||
|
height: 150px;
|
||||||
|
position: absolute;
|
||||||
|
top: 10px;
|
||||||
|
left: 15px
|
||||||
|
}
|
||||||
|
|
||||||
|
.qian {
|
||||||
|
position: absolute;
|
||||||
|
left: 15px;
|
||||||
|
top: 16px;
|
||||||
|
height: 132px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sign-data{
|
||||||
|
width: 100%;
|
||||||
|
height: 207px;
|
||||||
|
font-family: 'kcytFont';
|
||||||
|
position: relative;
|
||||||
|
color: #D47E8F;
|
||||||
|
}
|
||||||
|
|
||||||
|
.today-text {
|
||||||
|
font-size: 50px;
|
||||||
|
position: absolute;
|
||||||
|
top: -40px;
|
||||||
|
left: 130px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.abs-text {
|
||||||
|
position: absolute;
|
||||||
|
font-size: 30px;
|
||||||
|
z-index: 2;
|
||||||
|
width: 465px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gift {
|
||||||
|
text-align: center;
|
||||||
|
/* float: left; */
|
||||||
|
/* margin-top: 150px; */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.sign-text {
|
||||||
|
font-size: 30px;
|
||||||
|
position: absolute;
|
||||||
|
top: 60px;
|
||||||
|
left: 140px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sign-num {
|
||||||
|
font-size: 30px;
|
||||||
|
position: absolute;
|
||||||
|
top: 60px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.line {
|
||||||
|
background-color: #D1778A;
|
||||||
|
width: 435px;
|
||||||
|
height: 3px;
|
||||||
|
margin-left: 15px;
|
||||||
|
}
|
||||||
|
.bottom-foot{
|
||||||
|
width: 100%;
|
||||||
|
height: 376px;
|
||||||
|
position: relative;
|
||||||
|
font-family: 'rxxxtFont';
|
||||||
|
color: #D47E8F;
|
||||||
|
}
|
||||||
|
|
||||||
|
.heart-list {
|
||||||
|
position: absolute;
|
||||||
|
top: 76px;
|
||||||
|
left: 15px;
|
||||||
|
width: 435px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.heart-img {
|
||||||
|
height: 30px;
|
||||||
|
width: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cur-text {
|
||||||
|
font-size: 32px;
|
||||||
|
left: 10px;
|
||||||
|
top: -21px;
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bot-text {
|
||||||
|
font-size: 30px;
|
||||||
|
position: absolute;
|
||||||
|
top: 85px;
|
||||||
|
left: 15px;
|
||||||
|
width: 435px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress-border {
|
||||||
|
position: absolute;
|
||||||
|
top: 273px;
|
||||||
|
left: 19px;
|
||||||
|
width: 313px;
|
||||||
|
height: 30px;
|
||||||
|
border: #DF9DA8 1px solid;
|
||||||
|
}
|
||||||
|
.progress-bar {
|
||||||
|
height: 30px;
|
||||||
|
background-color: #D47E8F;
|
||||||
|
}
|
||||||
|
|
||||||
|
.weather-img {
|
||||||
|
width: 70px;
|
||||||
|
height: 70px;
|
||||||
|
position: absolute;
|
||||||
|
top: 37px;
|
||||||
|
left: 371px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mbl-img {
|
||||||
|
width: 132px;
|
||||||
|
height: 164px;
|
||||||
|
position: absolute;
|
||||||
|
top: 145px;
|
||||||
|
left: 333px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wd{
|
||||||
|
position: absolute;
|
||||||
|
font-size: 35px;
|
||||||
|
top: 60px;
|
||||||
|
left: 377px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.date {
|
||||||
|
position: absolute;
|
||||||
|
font-size: 20px;
|
||||||
|
top: 350px;
|
||||||
|
left: 260px;
|
||||||
|
font-family: 'yshsFont';
|
||||||
|
}
|
||||||
78
resources/template/sign/main.html
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
|
||||||
|
</html>
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-cn">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>test</title>
|
||||||
|
<!-- <link rel="stylesheet" href="./res/font-awesome/css/font-awesome.min.css"> -->
|
||||||
|
<link rel="stylesheet" href="main.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="wrapper">
|
||||||
|
<div class="top-head">
|
||||||
|
<div style="display: flex;">
|
||||||
|
<div class="avatar">
|
||||||
|
<img class="avatar-img" src="{{data.ava}}" alt="">
|
||||||
|
</div>
|
||||||
|
<div style="position: relative;">
|
||||||
|
<p class="nickname">{{data.name}}</p>
|
||||||
|
<p class="uid">UID:{{data.uid}}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="sign-content">
|
||||||
|
<div class="sign-bottom">
|
||||||
|
</div>
|
||||||
|
<div class="sign-top">
|
||||||
|
<img class="rl-img" class="avatar-img" src="res/img/rl.png" alt="">
|
||||||
|
<img class="zx-img" class="avatar-img" src="res/img/1.png" alt="">
|
||||||
|
<p class="text-day">累计签到{{data.sign_count}}天</p>
|
||||||
|
<p class="text-zx">真寻说: {{data.message}}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="sign-data">
|
||||||
|
<img class="qian" src="res/img/3.png" alt="">
|
||||||
|
<p class="today-text">今日签到</p>
|
||||||
|
<div class="abs-text" style="top: 42px;">
|
||||||
|
<p class="gift">{{data.impression}}</p>
|
||||||
|
</div>
|
||||||
|
<div class="abs-text" style="top: 83px;">
|
||||||
|
<p class="gift">{{data.gold}}</p></div>
|
||||||
|
<div class="abs-text" style="top: 123px;">
|
||||||
|
<p class="gift">{{data.gift}}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="line"></div>
|
||||||
|
<div class="bottom-foot">
|
||||||
|
<p class="cur-text">当前好感度: {{data.cur_impression}}</p>
|
||||||
|
<div class="heart-list">
|
||||||
|
{% for i in data.heart2 %}
|
||||||
|
<img class="heart-img" src="res/img/h2.png" alt=""/>
|
||||||
|
{% endfor %}
|
||||||
|
{% for i in data.heart1 %}
|
||||||
|
<img class="heart-img" src="res/img/h1.png" alt=""/>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
<div class="bot-text">
|
||||||
|
<p style="position: absolute; top: 9px">好感度等级: {{data.level}}</p>
|
||||||
|
<p style="position: absolute; top: 58px">小真寻对你的态度: {{data.attitude}}</p>
|
||||||
|
<p style="position: absolute; top: 111px"">距离升级还差{{data.interpolation}}好感度</p>
|
||||||
|
</div>
|
||||||
|
<div class="progress-border">
|
||||||
|
<div class="progress-bar" style="width: {{ data.process }}%;"></div>
|
||||||
|
</div>
|
||||||
|
<img class="weather-img" src="res/img/weather/0.png" alt="">
|
||||||
|
<p class="wd" >28℃</p>
|
||||||
|
<img class="mbl-img" src="res/img/2.png" alt="">
|
||||||
|
<div class="date">
|
||||||
|
{{data.date}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
<script type="text/javascript" src="main.js">
|
||||||
|
</script>
|
||||||
|
</html>
|
||||||
17
resources/template/sign/main.js
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
let wdDom = document.querySelector(".wd")
|
||||||
|
|
||||||
|
let wd = Math.floor(Math.random() * 40) + 1
|
||||||
|
|
||||||
|
wdDom.innerHTML = wd + "℃"
|
||||||
|
|
||||||
|
let weatherDom = document.querySelector(".weather-img")
|
||||||
|
|
||||||
|
let r = Math.floor(Math.random() * 12)
|
||||||
|
|
||||||
|
weatherDom.src = "res/img/weather/" + r + ".png"
|
||||||
|
|
||||||
|
let qianDom = document.querySelector(".qian")
|
||||||
|
|
||||||
|
let r1 = Math.floor(Math.random() * 6)
|
||||||
|
|
||||||
|
qianDom.src = "res/img/tag/" + r1 + ".png"
|
||||||
BIN
resources/template/sign/res/font/ChillReunion_105S.otf
Normal file
BIN
resources/template/sign/res/font/ChillReunion_65S.otf
Normal file
BIN
resources/template/sign/res/font/ChillReunion_95.otf
Normal file
BIN
resources/template/sign/res/font/方正复古粗宋简体.TTF
Normal file
BIN
resources/template/sign/res/font/日系小熊可爱体 Regular.ttf
Normal file
BIN
resources/template/sign/res/img/1.png
Normal file
|
After Width: | Height: | Size: 238 KiB |
BIN
resources/template/sign/res/img/2.png
Normal file
|
After Width: | Height: | Size: 1.5 MiB |
BIN
resources/template/sign/res/img/3.png
Normal file
|
After Width: | Height: | Size: 8.7 KiB |
BIN
resources/template/sign/res/img/h1.png
Normal file
|
After Width: | Height: | Size: 5.3 KiB |
BIN
resources/template/sign/res/img/h2.png
Normal file
|
After Width: | Height: | Size: 3.7 KiB |
BIN
resources/template/sign/res/img/rl.png
Normal file
|
After Width: | Height: | Size: 4.7 KiB |
BIN
resources/template/sign/res/img/tag/0.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
resources/template/sign/res/img/tag/1.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
resources/template/sign/res/img/tag/2.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
resources/template/sign/res/img/tag/3.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
resources/template/sign/res/img/tag/4.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
resources/template/sign/res/img/tag/5.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
resources/template/sign/res/img/weather/0.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
resources/template/sign/res/img/weather/1.png
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
resources/template/sign/res/img/weather/10.png
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
resources/template/sign/res/img/weather/11.png
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
resources/template/sign/res/img/weather/2.png
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
resources/template/sign/res/img/weather/3.png
Normal file
|
After Width: | Height: | Size: 2.1 KiB |
BIN
resources/template/sign/res/img/weather/4.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
resources/template/sign/res/img/weather/5.png
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
resources/template/sign/res/img/weather/6.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
resources/template/sign/res/img/weather/7.png
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
resources/template/sign/res/img/weather/8.png
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
resources/template/sign/res/img/weather/9.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
@ -62,8 +62,8 @@ async def _():
|
|||||||
group_user = []
|
group_user = []
|
||||||
try:
|
try:
|
||||||
group_user = await GroupInfoUser.filter(uid__isnull=False).all()
|
group_user = await GroupInfoUser.filter(uid__isnull=False).all()
|
||||||
except Exception:
|
except Exception as e:
|
||||||
logger.warning("获取GroupInfoUser数据uid失败...")
|
logger.warning("获取GroupInfoUser数据uid失败...", e=e)
|
||||||
user2uid = {u.user_id: u.uid for u in group_user}
|
user2uid = {u.user_id: u.uid for u in group_user}
|
||||||
db = Tortoise.get_connection("default")
|
db = Tortoise.get_connection("default")
|
||||||
old_sign_list = await db.execute_query_dict(SIGN_SQL)
|
old_sign_list = await db.execute_query_dict(SIGN_SQL)
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import nonebot
|
|
||||||
from nonebot.adapters import Bot
|
from nonebot.adapters import Bot
|
||||||
from nonebot.permission import SUPERUSER
|
from nonebot.permission import SUPERUSER
|
||||||
from nonebot.plugin import PluginMetadata
|
from nonebot.plugin import PluginMetadata
|
||||||
|
from nonebot.rule import to_me
|
||||||
from nonebot_plugin_alconna import Alconna, Args, Match, on_alconna
|
from nonebot_plugin_alconna import Alconna, Args, Match, on_alconna
|
||||||
from nonebot_plugin_session import EventSession
|
from nonebot_plugin_session import EventSession
|
||||||
|
|
||||||
@ -47,6 +47,7 @@ _matcher = on_alconna(
|
|||||||
priority=1,
|
priority=1,
|
||||||
block=True,
|
block=True,
|
||||||
permission=SUPERUSER,
|
permission=SUPERUSER,
|
||||||
|
rule=to_me(),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -66,22 +67,3 @@ async def _(bot: Bot, session: EventSession, ver_type: Match[str]):
|
|||||||
if result:
|
if result:
|
||||||
await MessageUtils.build_message(result).finish()
|
await MessageUtils.build_message(result).finish()
|
||||||
await MessageUtils.build_message("更新版本失败...").finish()
|
await MessageUtils.build_message("更新版本失败...").finish()
|
||||||
|
|
||||||
|
|
||||||
# driver = nonebot.get_driver()
|
|
||||||
|
|
||||||
|
|
||||||
# @driver.on_startup
|
|
||||||
# async def _():
|
|
||||||
# result = await UpdateManage.check_version()
|
|
||||||
# print("-----------------------")
|
|
||||||
# print("-----------------------")
|
|
||||||
# print(result)
|
|
||||||
# print("-----------------------")
|
|
||||||
# print("-----------------------")
|
|
||||||
# result = await UpdateManage.update(None, "", "dev")
|
|
||||||
# print("-----------------------")
|
|
||||||
# print("-----------------------")
|
|
||||||
# print(result)
|
|
||||||
# print("-----------------------")
|
|
||||||
# print("-----------------------")
|
|
||||||
|
|||||||
@ -72,6 +72,12 @@ __plugin_meta__ = PluginMetadata(
|
|||||||
default_value=0.05,
|
default_value=0.05,
|
||||||
type=float,
|
type=float,
|
||||||
),
|
),
|
||||||
|
RegisterConfig(
|
||||||
|
key="IMAGE_STYLE",
|
||||||
|
value="zhenxun",
|
||||||
|
help="签到图片样式, [normal, zhenxun]",
|
||||||
|
default_value="zhenxun",
|
||||||
|
),
|
||||||
],
|
],
|
||||||
limits=[PluginCdBlock()],
|
limits=[PluginCdBlock()],
|
||||||
).dict(),
|
).dict(),
|
||||||
|
|||||||
@ -7,9 +7,10 @@ from pathlib import Path
|
|||||||
import nonebot
|
import nonebot
|
||||||
import pytz
|
import pytz
|
||||||
from nonebot.drivers import Driver
|
from nonebot.drivers import Driver
|
||||||
|
from nonebot_plugin_htmlrender import template_to_pic
|
||||||
|
|
||||||
from zhenxun.configs.config import NICKNAME, Config
|
from zhenxun.configs.config import NICKNAME, Config
|
||||||
from zhenxun.configs.path_config import IMAGE_PATH
|
from zhenxun.configs.path_config import IMAGE_PATH, TEMPLATE_PATH
|
||||||
from zhenxun.models.sign_log import SignLog
|
from zhenxun.models.sign_log import SignLog
|
||||||
from zhenxun.models.sign_user import SignUser
|
from zhenxun.models.sign_user import SignUser
|
||||||
from zhenxun.utils.image_utils import BuildImage
|
from zhenxun.utils.image_utils import BuildImage
|
||||||
@ -25,8 +26,27 @@ from .config import (
|
|||||||
lik2relation,
|
lik2relation,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
AVA_URL = "http://q1.qlogo.cn/g?b=qq&nk={}&s=160"
|
||||||
|
|
||||||
driver: Driver = nonebot.get_driver()
|
driver: Driver = nonebot.get_driver()
|
||||||
|
|
||||||
|
base_config = Config.get("sign_in")
|
||||||
|
|
||||||
|
|
||||||
|
MORNING_MESSAGE = [
|
||||||
|
"早上好,希望今天是美好的一天!",
|
||||||
|
"醒了吗,今天也要元气满满哦!",
|
||||||
|
"早上好呀,今天也要开心哦!",
|
||||||
|
"早安,愿你拥有美好的一天!",
|
||||||
|
]
|
||||||
|
|
||||||
|
LG_MESSAGE = [
|
||||||
|
"今天要早点休息哦~",
|
||||||
|
"可不要熬夜到太晚呀",
|
||||||
|
"请尽早休息吧!",
|
||||||
|
"不要熬夜啦!",
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
@driver.on_startup
|
@driver.on_startup
|
||||||
async def init_image():
|
async def init_image():
|
||||||
@ -73,9 +93,14 @@ async def get_card(
|
|||||||
if card_file.exists():
|
if card_file.exists():
|
||||||
return card_file
|
return card_file
|
||||||
is_card_view = True
|
is_card_view = True
|
||||||
return await _generate_card(
|
if base_config.get("IMAGE_STYLE") == "zhenxun":
|
||||||
user, nickname, add_impression, gold, gift, is_double, is_card_view
|
return await _generate_html_card(
|
||||||
)
|
user, nickname, add_impression, gold, gift, is_double, is_card_view
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
return await _generate_card(
|
||||||
|
user, nickname, add_impression, gold, gift, is_double, is_card_view
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
async def _generate_card(
|
async def _generate_card(
|
||||||
@ -237,8 +262,8 @@ async def _generate_card(
|
|||||||
_type = "sign"
|
_type = "sign"
|
||||||
current_date = datetime.now()
|
current_date = datetime.now()
|
||||||
current_datetime_str = current_date.strftime("%Y-%m-%d %a %H:%M:%S")
|
current_datetime_str = current_date.strftime("%Y-%m-%d %a %H:%M:%S")
|
||||||
data = current_date.date()
|
date = current_date.date()
|
||||||
data_img = await BuildImage.build_text_image(
|
date_img = await BuildImage.build_text_image(
|
||||||
f"时间:{current_datetime_str}", size=20
|
f"时间:{current_datetime_str}", size=20
|
||||||
)
|
)
|
||||||
await bk.paste(nickname_img, (30, 15))
|
await bk.paste(nickname_img, (30, 15))
|
||||||
@ -249,7 +274,7 @@ async def _generate_card(
|
|||||||
# await bk.paste(sign_day_img, (398, 158))
|
# await bk.paste(sign_day_img, (398, 158))
|
||||||
# await bk.text((_x, 167), "days")
|
# await bk.text((_x, 167), "days")
|
||||||
await bk.paste(tip_image, (10, 167))
|
await bk.paste(tip_image, (10, 167))
|
||||||
await bk.paste(data_img, (220, 370))
|
await bk.paste(date_img, (220, 370))
|
||||||
await bk.paste(lik_text1_img, (220, 240))
|
await bk.paste(lik_text1_img, (220, 240))
|
||||||
await bk.paste(lik_text2_img, (262, 234))
|
await bk.paste(lik_text2_img, (262, 234))
|
||||||
await bk.paste(bar_bk, (225, 275))
|
await bk.paste(bar_bk, (225, 275))
|
||||||
@ -257,8 +282,8 @@ async def _generate_card(
|
|||||||
await bk.paste(today_sign_text_img, (550, 180))
|
await bk.paste(today_sign_text_img, (550, 180))
|
||||||
await bk.paste(today_data, (580, 220))
|
await bk.paste(today_data, (580, 220))
|
||||||
await bk.paste(watermark, (15, 400))
|
await bk.paste(watermark, (15, 400))
|
||||||
await bk.save(SIGN_TODAY_CARD_PATH / f"{user.user_id}_{_type}_{data}.png")
|
await bk.save(SIGN_TODAY_CARD_PATH / f"{user.user_id}_{_type}_{date}.png")
|
||||||
return IMAGE_PATH / "sign" / "today_card" / f"{user.user_id}_{_type}_{data}.png"
|
return IMAGE_PATH / "sign" / "today_card" / f"{user.user_id}_{_type}_{date}.png"
|
||||||
|
|
||||||
|
|
||||||
async def generate_progress_bar_pic():
|
async def generate_progress_bar_pic():
|
||||||
@ -333,3 +358,98 @@ def clear_sign_data_pic():
|
|||||||
for file in os.listdir(SIGN_TODAY_CARD_PATH):
|
for file in os.listdir(SIGN_TODAY_CARD_PATH):
|
||||||
if str(date) not in file:
|
if str(date) not in file:
|
||||||
os.remove(SIGN_TODAY_CARD_PATH / file)
|
os.remove(SIGN_TODAY_CARD_PATH / file)
|
||||||
|
|
||||||
|
|
||||||
|
async def _generate_html_card(
|
||||||
|
user: SignUser,
|
||||||
|
nickname: str,
|
||||||
|
impression: float,
|
||||||
|
gold: int | None,
|
||||||
|
gift: str,
|
||||||
|
is_double: bool = False,
|
||||||
|
is_card_view: bool = False,
|
||||||
|
) -> Path:
|
||||||
|
"""生成签到卡片
|
||||||
|
|
||||||
|
参数:
|
||||||
|
user: SignUser
|
||||||
|
nickname: 用户昵称
|
||||||
|
impression: 新增的好感度
|
||||||
|
gold: 金币
|
||||||
|
gift: 礼物
|
||||||
|
is_double: 是否触发双倍.
|
||||||
|
is_card_view: 是否展示好感度卡片.
|
||||||
|
|
||||||
|
返回:
|
||||||
|
Path: 卡片路径
|
||||||
|
"""
|
||||||
|
user_console = await user.user_console
|
||||||
|
if user_console and user_console.uid:
|
||||||
|
uid = f"{user_console.uid}".rjust(12, "0")
|
||||||
|
uid = uid[:4] + " " + uid[4:8] + " " + uid[8:]
|
||||||
|
else:
|
||||||
|
uid = "XXXX XXXX XXXX"
|
||||||
|
level, next_impression, previous_impression = get_level_and_next_impression(
|
||||||
|
impression
|
||||||
|
)
|
||||||
|
interpolation = next_impression - impression
|
||||||
|
if level == "9":
|
||||||
|
level = "8"
|
||||||
|
interpolation = 0
|
||||||
|
message = f"{NICKNAME}希望你天天开心!"
|
||||||
|
hour = datetime.now().hour
|
||||||
|
if hour > 6 and hour < 10:
|
||||||
|
message = random.choice(MORNING_MESSAGE)
|
||||||
|
elif hour >= 0 and hour < 6:
|
||||||
|
message = random.choice(LG_MESSAGE)
|
||||||
|
_impression = impression
|
||||||
|
if is_double:
|
||||||
|
_impression = f"{impression}(×2)"
|
||||||
|
process = 1 - (next_impression - user.impression) / (
|
||||||
|
next_impression - previous_impression
|
||||||
|
)
|
||||||
|
if next_impression == 0:
|
||||||
|
process = 0
|
||||||
|
now = datetime.now()
|
||||||
|
data = {
|
||||||
|
"ava": AVA_URL.format(user.user_id),
|
||||||
|
"name": nickname,
|
||||||
|
"uid": uid,
|
||||||
|
"sign_count": f"{user.sign_count}",
|
||||||
|
"message": message,
|
||||||
|
"cur_impression": f"{user.impression:.2f}",
|
||||||
|
"impression": f"好感度+{_impression}",
|
||||||
|
"gold": f"金币+{gold}",
|
||||||
|
"gift": gift,
|
||||||
|
"level": f"{level} [{lik2relation[level]}]",
|
||||||
|
"attitude": level2attitude[level],
|
||||||
|
"interpolation": f"{interpolation:.2f}",
|
||||||
|
"heart2": [1 for _ in range(int(level))],
|
||||||
|
"heart1": [1 for _ in range(9 - int(level))],
|
||||||
|
"process": process,
|
||||||
|
"date": str(now.replace(microsecond=0)),
|
||||||
|
}
|
||||||
|
if is_card_view:
|
||||||
|
value_list = (
|
||||||
|
await SignUser.annotate()
|
||||||
|
.order_by("-impression")
|
||||||
|
.values_list("user_id", flat=True)
|
||||||
|
)
|
||||||
|
index = value_list.index(user.user_id) + 1 # type: ignore
|
||||||
|
data["impression"] = f"好感度排名第 {index} 位"
|
||||||
|
data["gold"] = f"总金币:{gold}"
|
||||||
|
data["gift"] = ""
|
||||||
|
pic = await template_to_pic(
|
||||||
|
template_path=str((TEMPLATE_PATH / "sign").absolute()),
|
||||||
|
template_name="main.html",
|
||||||
|
templates={"data": data},
|
||||||
|
pages={
|
||||||
|
"viewport": {"width": 465, "height": 926},
|
||||||
|
"base_url": f"file://{TEMPLATE_PATH}",
|
||||||
|
},
|
||||||
|
wait=2,
|
||||||
|
)
|
||||||
|
image = BuildImage.open(pic)
|
||||||
|
date = now.date()
|
||||||
|
await image.save(SIGN_TODAY_CARD_PATH / f"{user.user_id}_sign_{date}.png")
|
||||||
|
return IMAGE_PATH / "sign" / "today_card" / f"{user.user_id}_sign_{date}.png"
|
||||||
|
|||||||
@ -45,7 +45,7 @@ class BuildImage:
|
|||||||
mode: ModeType = "RGBA",
|
mode: ModeType = "RGBA",
|
||||||
font: str | Path | FreeTypeFont = "HYWenHei-85W.ttf",
|
font: str | Path | FreeTypeFont = "HYWenHei-85W.ttf",
|
||||||
font_size: int = 20,
|
font_size: int = 20,
|
||||||
background: str | BytesIO | Path | None = None,
|
background: str | BytesIO | Path | bytes | None = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
self.uid = uuid.uuid1()
|
self.uid = uuid.uuid1()
|
||||||
self.width = width
|
self.width = width
|
||||||
@ -57,7 +57,10 @@ class BuildImage:
|
|||||||
else font
|
else font
|
||||||
)
|
)
|
||||||
if background:
|
if background:
|
||||||
self.markImg = Image.open(background)
|
if isinstance(background, bytes):
|
||||||
|
self.markImg = Image.open(BytesIO(background))
|
||||||
|
else:
|
||||||
|
self.markImg = Image.open(background)
|
||||||
if width and height:
|
if width and height:
|
||||||
self.markImg = self.markImg.resize((width, height), Image.LANCZOS)
|
self.markImg = self.markImg.resize((width, height), Image.LANCZOS)
|
||||||
else:
|
else:
|
||||||
@ -74,7 +77,7 @@ class BuildImage:
|
|||||||
return self.markImg.size
|
return self.markImg.size
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def open(cls, path: str | Path) -> Self:
|
def open(cls, path: str | Path | bytes) -> Self:
|
||||||
"""打开图片
|
"""打开图片
|
||||||
|
|
||||||
参数:
|
参数:
|
||||||
|
|||||||