#角色 列表支持展示宝箱数字

This commit is contained in:
Kokomi 2023-02-11 21:22:09 +08:00
parent 558bdae30a
commit 549a8c7a1d
9 changed files with 307 additions and 109 deletions

View File

@ -51,10 +51,20 @@ export async function profileStat (e) {
level: player.level
}
let info = player.getInfo()
info.stats = info.stats || {}
info.statMap = {
achievement: '成就',
wayPoint: '锚点',
avatar: '角色',
avatar5: '五星角色',
goldCount: '金卡总数'
}
return await Common.render(isAvatarList ? 'character/avatar-list' : 'character/profile-stat', {
save_id: uid,
uid,
info: player.getInfo(),
info,
updateTime: player.getUpdateTime(),
isSelfCookie: e.isSelfCookie,
talentLvMap: '0,1,1,1,2,2,3,3,3,4,5'.split(','),

View File

@ -210,8 +210,8 @@ async function abyssTeam (e) {
let data = {}
let noAvatar = {}
lodash.forEach(avatarData, (avatar) => {
let t = avatar.talent
avatarRet[avatar.id] = Math.min(avatar.level, avatar.weapon?.level || 1) * 100 + Math.max(t.a?.original, t.e?.original, t.q?.original) * 1000
let t = avatar.originalTalent
avatarRet[avatar.id] = Math.min(avatar.level, avatar.weapon?.level || 1) * 100 + Math.max(t?.a, t?.e, t?.q) * 1000
})
let getTeamCfg = (str) => {

View File

@ -173,48 +173,25 @@ export default class Player extends Base {
}
getInfo () {
let ret = {
...(this.info || {}),
statMap: {
achievement: '成就数',
commonChest: '普通宝箱',
exquisiteChest: '精致宝箱',
preciousChest: '珍贵宝箱',
luxuriousChest: '豪华宝箱'
}
}
if (ret?.stats?.activeDay) {
let num = ret?.stats?.activeDay
let year = Math.floor(num / 365)
let month = Math.floor((num % 365) / 30.41)
let day = Math.floor((num % 365) % 30.41)
let msg = ''
if (year > 0) {
msg += year + '年'
}
if (month > 0) {
msg += month + '个月'
}
if (day > 0) {
msg += day + '天'
}
ret.activeDay = msg
}
lodash.forEach(ret)
return ret
return MysAvatar.getInfo(this)
}
// 更新面板
async refreshProfile (force = true) {
async refreshProfile (force = 1) {
return await Profile.refreshProfile(this, force)
}
// 更新米游社数据
async refreshMysDetail (force = false) {
/**
* 更新米游社数据
* @param force: 0:不强制长超时时间 1短超时时间 2无视缓存强制刷新
* @returns {Promise<boolean>}
*/
async refreshMysDetail (force = 0) {
return MysAvatar.refreshMysDetail(this, force)
}
async refreshMysInfo (force = false) {
async refreshMysInfo (force = 0) {
return await MysAvatar.refreshMysInfo(this, force)
}
@ -224,7 +201,7 @@ export default class Player extends Base {
}
// 使用MysApi刷新指定角色的天赋信息
async refreshTalent (ids = '', force = false) {
async refreshTalent (ids = '', force = 0) {
return await MysAvatar.refreshTalent(this, ids, force)
}
@ -236,11 +213,11 @@ export default class Player extends Base {
async refreshAndGetAvatarData (cfg) {
// 更新角色信息
await this.refreshMysDetail(cfg.force)
await this.refreshMysDetail(cfg.force || 0)
// 更新天赋信息
if (cfg.refreshTalent !== false) {
await this.refreshTalent(cfg.ids, cfg.force)
await this.refreshTalent(cfg.ids, cfg.force || 0)
}
let rank = false

View File

@ -3,6 +3,17 @@ import { Common, Data } from '../../components/index.js'
import moment from 'moment'
const MysAvatar = {
needRefresh (time, force = 0, forceMap = {}) {
if (!time) {
return true
}
let duration = new Date() * 1 - time * 1
if (isNaN(duration) || duration < 0) {
return true
}
return duration > (forceMap[force] || 60) * 60 * 1000
},
/**
* 更新米游社角色信息
* @param player
@ -10,13 +21,12 @@ const MysAvatar = {
* @param force
* @returns {Promise<boolean>}
*/
async refreshMysDetail (player, force = false) {
async refreshMysDetail (player, force = 0) {
let mys = player?.e?._mys
if (!mys) {
return false
}
// 不必要更新
if ((new Date() * 1 - player._mys < 10 * 60 * 1000) && !force) {
if (!MysAvatar.needRefresh(player._mys, force, { 0: 60, 1: 2, 2: 0 })) {
return false
}
let charData = await mys.getCharacter()
@ -32,12 +42,12 @@ const MysAvatar = {
* @param force
* @returns {Promise<boolean>}
*/
async refreshMysInfo (player, force = false) {
async refreshMysInfo (player, force = 0) {
let mys = player?.e?._mys
if (!mys) {
return false
} // 不必要更新
if (player._info && (new Date() * 1 - player._info < 10 * 60 * 1000) && !force) {
if (!MysAvatar.needRefresh(player._info, force, { 0: 60, 1: 2, 2: 0 })) {
return false
}
let infoData = await mys.getIndex()
@ -130,9 +140,10 @@ const MysAvatar = {
* 获取当前角色需要更新天赋的角色ID
* @param player
* @param ids 角色列表若传入则查询指定角色列表不传入查询全部
* @param force
* @returns {*[]}
*/
getNeedRefreshIds (player, ids) {
getNeedRefreshIds (player, ids, force = 0) {
let ret = []
if (!ids) {
ids = lodash.keys(player._avatars)
@ -141,7 +152,7 @@ const MysAvatar = {
}
lodash.forEach(ids, (id) => {
let avatar = player.getAvatar(id)
if (avatar.needRefreshTalent) {
if (!avatar.hasTalent || MysAvatar.needRefresh(avatar._talent, force, { 0: 60 * 24, 1: 60, 2: 0 })) {
ret.push(avatar.id)
}
})
@ -155,13 +166,13 @@ const MysAvatar = {
* @param force
* @returns {Promise<boolean>}
*/
async refreshTalent (player, ids, force) {
async refreshTalent (player, ids, force = 0) {
let e = player?.e
let mys = e?._mys
if (!e || !mys) {
return false
}
let needReqIds = MysAvatar.getNeedRefreshIds(player, ids)
let needReqIds = MysAvatar.getNeedRefreshIds(player, ids, force)
if (needReqIds.length > 0) {
if (needReqIds.length > 8) {
e && e.reply('正在获取角色信息,请稍候...')
@ -221,6 +232,56 @@ const MysAvatar = {
getDate (time) {
return time ? moment(new Date(time)).format('MM-DD HH:mm') : ''
},
getInfo (player) {
let ret = {
...(player.info || {}),
chestMap: [
{ key: 'commonChest', title: '普通宝箱', max: 2521 },
{ key: 'exquisiteChest', title: '精致宝箱', max: 1585 },
{ key: 'preciousChest', title: '珍贵宝箱', max: 482 },
{ key: 'luxuriousChest', title: '豪华宝箱', max: 184 },
{ key: 'magicChest', title: '奇馈宝箱', max: 140 }
]
}
let stats = ret.stats || {}
if (stats?.activeDay) {
let num = stats?.activeDay
let year = Math.floor(num / 365)
let month = Math.floor((num % 365) / 30.41)
let day = Math.floor((num % 365) % 30.41)
let msg = ''
if (year > 0) {
msg += year + '年'
}
if (month > 0) {
msg += month + '个月'
}
if (day > 0) {
msg += day + '天'
}
ret.activeDay = msg
}
let avatarCount = 0
let avatar5Count = 0
let goldCount = 0
player.forEachAvatar((avatar) => {
avatarCount++
if (avatar.star === 5) {
avatar5Count++
goldCount += (avatar.cons || 0) + 1
}
let w = avatar.weapon
if (w && w.star === 5) {
goldCount += w.affix * 1
}
})
stats.avatar = Math.max(stats.avatar, avatarCount)
stats.goldCount = goldCount
stats.avatar5 = avatar5Count
ret.stats = stats
return ret
}
}
export default MysAvatar

View File

@ -34,7 +34,7 @@ const Profile = {
* @param force
* @returns {Promise<boolean|number>}
*/
async refreshProfile (player, force = true) {
async refreshProfile (player, force = 1) {
player._update = []
let { uid, e } = player
if (uid.toString().length !== 9 || !e) {

View File

@ -5,7 +5,7 @@
.head-box {
margin-top: 0;
}
#banner {
.user-banner {
height: 90px;
background-size: auto 100%;
background-position: right center;
@ -18,7 +18,7 @@
white-space: nowrap;
position: relative;
}
#banner .face {
.user-banner .face {
width: 70px;
height: 70px;
margin: 10px;
@ -29,33 +29,33 @@
background: url('../common/item/bg5.png');
background-size: cover;
}
#banner .face span {
.user-banner .face span {
display: block;
width: 64px;
height: 64px;
background-size: auto 100%;
background-repeat: no-repeat;
}
#banner .user-info {
.user-banner .user-info {
padding: 15px 5px;
color: #414e64;
}
#banner .user-info .name {
.user-banner .user-info .name {
height: 34px;
line-height: 34px;
}
#banner .user-info .name strong {
font-size: 26px;
.user-banner .user-info .name strong {
font-size: 24px;
}
#banner .user-info .name span {
.user-banner .user-info .name span {
padding-left: 5px;
}
#banner .user-info .uid {
.user-banner .user-info .uid {
height: 22px;
line-height: 22px;
font-size: 16px;
}
#banner .stat {
.user-banner .stat {
position: absolute;
right: 0;
top: 0;
@ -66,42 +66,38 @@
height: 58px;
box-shadow: 0 0 5px 0 rgba(0, 0, 0, 0.4);
}
#banner .stat-li {
.user-banner .stat-li {
padding: 7px;
width: 70px;
height: 58px;
text-align: center;
position: relative;
}
#banner .stat-li:nth-child(even) {
.user-banner .stat-li:nth-child(even) {
background: rgba(225, 225, 225, 0.8);
}
#banner .stat-li:first-child {
width: 78px;
padding-left: 15px;
.user-banner .stat-li:first-child {
width: 80px;
padding-left: 17px;
}
#banner .stat-li:last-child {
width: 78px;
padding-right: 15px;
.user-banner .stat-li:last-child {
width: 80px;
padding-right: 17px;
}
#banner .stat-li strong {
.user-banner .stat-li strong {
font-size: 22px;
display: block;
}
#banner .stat-li span {
.user-banner .stat-li span {
display: block;
font-size: 14px;
color: #414e64;
}
#avatar-list {
width: calc(100% + 30px);
margin: 0 -15px -5px;
overflow: hidden;
}
.exploration {
display: flex;
flex-wrap: wrap;
padding: 16px;
margin: 10px 0;
justify-content: center;
}
.exploration .item {
width: 93px;
@ -112,6 +108,7 @@
margin: 3px;
text-align: center;
color: #fff;
align-items: center;
}
.exploration .item strong {
font-size: 24px;
@ -128,12 +125,70 @@
display: block;
text-shadow: 0 0 1px rgba(0, 0, 0, 0.5);
}
.chest-list {
margin: 10px 0;
overflow: hidden;
background: rgba(0, 0, 0, 0.6);
padding: 0 15px;
display: flex;
justify-content: center;
}
.chest-list .chest {
width: 20%;
display: flex;
padding: 15px 0;
}
.chest-list .chest:nth-child(even) {
background: rgba(50, 50, 50, 0.5);
}
.chest-list .chest .value {
font-size: 24px;
line-height: 40px;
height: 40px;
padding-right: 8px;
text-align: right;
width: 70px;
text-shadow: 0 0 1px #000, 1px 1px 3px rgba(0, 0, 0, 0.5);
}
.chest-list .chest .detail {
width: 60px;
height: 40px;
font-size: 13px;
}
.chest-list .chest .info {
display: flex;
height: 20px;
line-height: 20px;
}
.chest-list .chest .icon {
display: inline-block;
width: 18px;
height: 18px;
margin: 1px;
background: url('./imgs/chest.webp') no-repeat;
background-size: auto 100%;
vertical-align: center;
}
.chest-list .chest .max {
font-size: 12px;
padding-left: 3px;
color: #aaa;
}
.chest-list .chest .title {
height: 20px;
display: flex;
color: #d3bc8e;
}
.cont-title {
padding: 8px 15px;
}
.avatar-cont-main {
overflow: hidden;
}
.avatar-cont {
background: rgba(0, 0, 0, 0.5);
padding: 0;
margin: 10px 0;
}
.avatar-list {
display: flex;

View File

@ -7,7 +7,7 @@
{{block 'main'}}
<div id="banner" style="background-image:url({{_res_path}}{{face?.banner}})">
<div class="user-banner" style="background-image:url({{_res_path}}{{face?.banner}})">
<div class="face">
<span style="background-image:url({{_res_path}}{{face?.face}})"></span>
</div>
@ -22,6 +22,7 @@
{{ if info.activeDay}}{{info.activeDay}} {{/if}}
</div>
</div>
{{if info && info.stats}}
<div class="stat">
{{each info?.statMap title key}}
{{if info.stats[key] }}
@ -32,39 +33,67 @@
{{/if}}
{{/each}}
</div>
{{/if}}
</div>
{{if !isSelfCookie}}
<div class="ck-notice">未绑定CK或CK失效信息可能不完全。发送<strong>#体力帮助</strong>查看CK绑定方法发送<strong>#更新面板</strong>更新游戏内角色展柜信息</div>
{{/if}}
<div id="avatar-list">
{{if info && info?.exploration['蒙德']}}
{{set citys = ['蒙德','龙脊雪山','璃月','层岩巨渊','稻妻','渊下宫','须弥'] }}
<div class="exploration">
{{each citys city idx}}
<div class="item city-{{idx+1}}" style="background-position:{{idx}}0% 0">
<span>{{city}}</span>
<strong>{{ (info.exploration[city]||0)/10 || '0'}}%</strong>
{{if info && info.exploration && info.exploration['蒙德']}}
{{set citys = ['蒙德','龙脊雪山','璃月','层岩巨渊','稻妻','渊下宫','须弥'] }}
<div class="exploration">
{{each citys city idx}}
<div class="item city-{{idx+1}}" style="background-position:{{idx}}0% 0">
<span>{{city}}</span>
<strong>{{ (info.exploration[city]||0)/10 || '0'}}%</strong>
</div>
{{/each}}
</div>
{{/if}}
{{if info?.stats?.commonChest}}
{{set ds = info?.stats}}
<div class="cont chest-list">
{{each info?.chestMap cfg idx}}
<div class="chest">
<div class="value">{{ds[cfg.key]}}</div>
<div class="detail">
<div class="info">
<div class="icon" style="background-position:{{idx*2}}0% 0"></div>
<div class="max">{{cfg.max>ds[cfg.key]?cfg.max:ds[cfg.key]}}</div>
</div>
<div class="title">{{cfg.title}}</div>
</div>
</div>
{{/each}}
</div>
{{/if}}
<div class="cont avatar-cont">
<div class="cont-title">角色列表</div>
<div class="avatar-list">
{{each avatars avatar idx}}
<% include(_layout_path+'../tpl/avatar-card.html', [avatar,{_res_path, cardType:'mini'}]) %>
{{/each}}
</div>
{{/if}}
<div class="cont avatar-cont">
<div class="cont-title">角色列表</div>
<div class="avatar-list">
{{each avatars avatar idx}}
<% include(_layout_path+'../tpl/avatar-card.html', [avatar,{_res_path, cardType:'mini'}]) %>
{{/each}}
</div>
<div class="cont-footer cont-notice">
<strong>数据更新时间</strong>
{{if updateTime.profile}}
<span>面板:{{updateTime.profile}}</span>
{{/if}}
{{if updateTime.mys}}
<span>米游社:{{updateTime.mys}}</span>
{{/if}}
</div>
<div class="cont-footer cont-notice">
{{set ut = updateTime }}
{{if ut.profile || ut.mys}}
<strong>数据更新时间</strong>
{{if ut.profile}}
<span>#更新面板:{{ut.profile}}</span>
{{/if}}
{{if ut.mys}}
<span>米游社:{{ut.mys}}</span>
{{/if}}
{{else}}
未绑定CK或CK失效信息可能不完全。发送<strong>#体力帮助</strong>查看CK绑定方法发送<strong>#更新面板</strong>更新游戏内角色展柜信息
{{/if}}
</div>
</div>

View File

@ -8,7 +8,8 @@
margin-top: 0;
}
#banner {
.user-banner {
height: 90px;
background-size: auto 100%;
background-position: right center;
@ -50,7 +51,7 @@
line-height: 34px;
strong {
font-size: 26px;
font-size: 24px;
}
span {
@ -79,7 +80,7 @@
.stat-li {
@width: 70px;
@padding: 8px;
@padding: 10px;
padding: 7px;
width: @width;
@ -116,16 +117,12 @@
}
}
#avatar-list {
width: calc(100% + 30px);
margin: 0 -15px -5px;
overflow: hidden;
}
.exploration {
display: flex;
flex-wrap: wrap;
padding: 16px;
margin: 10px 0;
justify-content: center;
.item {
width: 93px;
@ -136,6 +133,7 @@
margin: 3px;
text-align: center;
color: #fff;
align-items: center;
strong {
font-size: 24px;
@ -154,17 +152,85 @@
text-shadow: 0 0 1px rgba(0, 0, 0, .5);
}
}
}
.chest-list {
margin: 10px 0;
overflow: hidden;
background: rgba(0, 0, 0, .6);
padding: 0 15px;
display: flex;
justify-content: center;
.chest {
width: 20%;
display: flex;
padding: 15px 0;
&:nth-child(even) {
background: rgba(50, 50, 50, .5);
}
.value {
font-size: 24px;
line-height: 40px;
height: 40px;
padding-right: 8px;
text-align: right;
width: 70px;
text-shadow: 0 0 1px #000, 1px 1px 3px rgba(0, 0, 0, .5);
}
.detail {
width: 60px;
height: 40px;
font-size: 13px;
}
.info {
display: flex;
height: 20px;
line-height: 20px;
}
.icon {
display: inline-block;
width: 18px;
height: 18px;
margin: 1px;
background: url('./imgs/chest.webp') no-repeat;
background-size: auto 100%;
vertical-align: center;
}
.max {
font-size: 12px;
padding-left: 3px;
color: #aaa;
}
.title {
height: 20px;
display: flex;
color: #d3bc8e;
}
}
}
.cont-title {
padding: 8px 15px;
}
.avatar-cont-main {
overflow: hidden;
}
.avatar-cont {
background: rgba(0, 0, 0, .5);
padding: 0;
margin: 10px 0;
}
.avatar-list {

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB