签到ui改版

This commit is contained in:
HibiKier 2024-08-24 12:30:49 +08:00
parent 06b1af46ea
commit 4a9a856df5
47 changed files with 519 additions and 34 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 728 KiB

After

Width:  |  Height:  |  Size: 2.0 MiB

View 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';
}

View 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>

View 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"

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 238 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -62,8 +62,8 @@ async def _():
group_user = []
try:
group_user = await GroupInfoUser.filter(uid__isnull=False).all()
except Exception:
logger.warning("获取GroupInfoUser数据uid失败...")
except Exception as e:
logger.warning("获取GroupInfoUser数据uid失败...", e=e)
user2uid = {u.user_id: u.uid for u in group_user}
db = Tortoise.get_connection("default")
old_sign_list = await db.execute_query_dict(SIGN_SQL)

View File

@ -1,7 +1,7 @@
import nonebot
from nonebot.adapters import Bot
from nonebot.permission import SUPERUSER
from nonebot.plugin import PluginMetadata
from nonebot.rule import to_me
from nonebot_plugin_alconna import Alconna, Args, Match, on_alconna
from nonebot_plugin_session import EventSession
@ -47,6 +47,7 @@ _matcher = on_alconna(
priority=1,
block=True,
permission=SUPERUSER,
rule=to_me(),
)
@ -66,22 +67,3 @@ async def _(bot: Bot, session: EventSession, ver_type: Match[str]):
if result:
await MessageUtils.build_message(result).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("-----------------------")

View File

@ -72,6 +72,12 @@ __plugin_meta__ = PluginMetadata(
default_value=0.05,
type=float,
),
RegisterConfig(
key="IMAGE_STYLE",
value="zhenxun",
help="签到图片样式, [normal, zhenxun]",
default_value="zhenxun",
),
],
limits=[PluginCdBlock()],
).dict(),

View File

@ -7,9 +7,10 @@ from pathlib import Path
import nonebot
import pytz
from nonebot.drivers import Driver
from nonebot_plugin_htmlrender import template_to_pic
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_user import SignUser
from zhenxun.utils.image_utils import BuildImage
@ -25,8 +26,27 @@ from .config import (
lik2relation,
)
AVA_URL = "http://q1.qlogo.cn/g?b=qq&nk={}&s=160"
driver: Driver = nonebot.get_driver()
base_config = Config.get("sign_in")
MORNING_MESSAGE = [
"早上好,希望今天是美好的一天!",
"醒了吗,今天也要元气满满哦!",
"早上好呀,今天也要开心哦!",
"早安,愿你拥有美好的一天!",
]
LG_MESSAGE = [
"今天要早点休息哦~",
"可不要熬夜到太晚呀",
"请尽早休息吧!",
"不要熬夜啦!",
]
@driver.on_startup
async def init_image():
@ -73,9 +93,14 @@ async def get_card(
if card_file.exists():
return card_file
is_card_view = True
return await _generate_card(
user, nickname, add_impression, gold, gift, is_double, is_card_view
)
if base_config.get("IMAGE_STYLE") == "zhenxun":
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(
@ -237,8 +262,8 @@ async def _generate_card(
_type = "sign"
current_date = datetime.now()
current_datetime_str = current_date.strftime("%Y-%m-%d %a %H:%M:%S")
data = current_date.date()
data_img = await BuildImage.build_text_image(
date = current_date.date()
date_img = await BuildImage.build_text_image(
f"时间:{current_datetime_str}", size=20
)
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.text((_x, 167), "days")
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_text2_img, (262, 234))
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_data, (580, 220))
await bk.paste(watermark, (15, 400))
await bk.save(SIGN_TODAY_CARD_PATH / f"{user.user_id}_{_type}_{data}.png")
return IMAGE_PATH / "sign" / "today_card" / 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}_{date}.png"
async def generate_progress_bar_pic():
@ -333,3 +358,98 @@ def clear_sign_data_pic():
for file in os.listdir(SIGN_TODAY_CARD_PATH):
if str(date) not in 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"

View File

@ -45,7 +45,7 @@ class BuildImage:
mode: ModeType = "RGBA",
font: str | Path | FreeTypeFont = "HYWenHei-85W.ttf",
font_size: int = 20,
background: str | BytesIO | Path | None = None,
background: str | BytesIO | Path | bytes | None = None,
) -> None:
self.uid = uuid.uuid1()
self.width = width
@ -57,7 +57,10 @@ class BuildImage:
else font
)
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:
self.markImg = self.markImg.resize((width, height), Image.LANCZOS)
else:
@ -74,7 +77,7 @@ class BuildImage:
return self.markImg.size
@classmethod
def open(cls, path: str | Path) -> Self:
def open(cls, path: str | Path | bytes) -> Self:
"""打开图片
参数: