This commit is contained in:
2025-03-12 09:36:26 +08:00
parent b98464d8b5
commit 6053fba1da
22 changed files with 286 additions and 228 deletions
+7 -19
View File
@@ -34,7 +34,7 @@ def dict2obj(dictObj):
return d return d
async def createToken(alter: str, equVersion: str, expire=86400 / 24 * 2, redis=None, env=''): def createToken(alter: str, equVersion: str, redis = None, expire=86400 / 24 * 2)->str:
ts_str = str(time.time() + expire) ts_str = str(time.time() + expire)
ts_byte = ts_str.encode('utf-8') ts_byte = ts_str.encode('utf-8')
sha1_tshex_str = hmac.new(alter.encode('utf-8'), ts_byte, 'sha1').hexdigest() sha1_tshex_str = hmac.new(alter.encode('utf-8'), ts_byte, 'sha1').hexdigest()
@@ -42,15 +42,16 @@ async def createToken(alter: str, equVersion: str, expire=86400 / 24 * 2, redis=
token = base64.urlsafe_b64encode(token.encode('utf-8')).decode('utf-8') token = base64.urlsafe_b64encode(token.encode('utf-8')).decode('utf-8')
# character = createCharacter(alter) # character = createCharacter(alter)
character = {} character = {}
await redis.set(f'token:{token}', json.dumps(AlterState(alter, token, character, equVersion).to_dict()), int(expire)) redis.set(f'token:{token}', json.dumps(AlterState(alter, token, character, equVersion).to_dict()), int(expire))
return token return token
async def readToken(token: str, redis, env) -> AlterState: def readToken(token: str, redis) -> AlterState:
info = None info = None
try: try:
info = dict2obj(json.loads(await redis.get(f'token:{token}'))) info = dict2obj(json.loads(redis.get(f'token:{token}')))
except Exception: except Exception as ex:
print(ex)
ResponseException('登录过期或无效Token,请刷新后重试') ResponseException('登录过期或无效Token,请刷新后重试')
if info is None: if info is None:
raise ResponseException('登录过期或无效Token,请刷新后重试') raise ResponseException('登录过期或无效Token,请刷新后重试')
@@ -62,20 +63,7 @@ def deleteToken(token, redis, env):
return token return token
async def authorize(request: Request, access_token: Optional[str] = Header(None)): def uid(access_uid: Optional[str] = Header(None)):
if access_token is not None:
info = await readToken(access_token, request.app.state.redis, request.app.state.env)
return info
else:
raise ResponseException('登录过期或无效Token,请刷新后重试')
def unauthorize(request: Request, access_token: Optional[str] = Header(None)):
if access_token is not None:
return deleteToken(access_token, request.app.state.redis, request.app.state.env)
async def uid(request: Request, access_uid: Optional[str] = Header(None)):
try: try:
return int(access_uid) return int(access_uid)
except Exception: except Exception:
+19 -2
View File
@@ -1,9 +1,26 @@
from typing import Annotated from typing import Annotated, Optional
from redis import Redis from redis import Redis
from sqlalchemy.orm import Session from sqlalchemy.orm import Session
from fastapi import Depends from fastapi import Depends, Header
from api.core.exception import ResponseException
from database.connect import get_db,get_redis from database.connect import get_db,get_redis
from api.core.Auth import AlterState, deleteToken, readToken
SessionDep = Annotated[Session, Depends(get_db)] SessionDep = Annotated[Session, Depends(get_db)]
RedisDep = Annotated[Redis, Depends(get_redis)] RedisDep = Annotated[Redis, Depends(get_redis)]
def authorize(redis:RedisDep, access_token: Optional[str] = Header(None)):
if access_token is not None:
info = readToken(access_token, redis)
return info
else:
raise ResponseException('登录过期或无效Token,请刷新后重试')
def unauthorize(redis:RedisDep, access_token: Optional[str] = Header(None)):
if access_token is not None:
return deleteToken(access_token, redis)
AltersDep = Annotated[AlterState, Depends(authorize)]
+17 -18
View File
@@ -4,7 +4,8 @@ import json
from fastapi import APIRouter,Request from fastapi import APIRouter,Request
from api.core.Response import Return, response from api.core.Response import Return, response
from api.core.Redis import get_redis_info from api.core.Redis import get_redis_info
from api.dp import RedisDep from api.dp import RedisDep,AltersDep
from core.basic.character import createCharacter
router = APIRouter() router = APIRouter()
@@ -20,22 +21,20 @@ async def get_adventure_info(request: Request,redis:RedisDep):
return response(data=adventure_info) return response(data=adventure_info)
@router.get('/equipment/list') @router.get("/token/get/{alter}")
async def get_equipment_list(request: Request,redis:RedisDep): async def getToken(redis:RedisDep,
def get_equipment_list(): alter: str, request: Request, version: str = None, equVersion: str = "0"
with open('./dataFiles/equipment-list.json', encoding='utf-8') as fp:
return json.load(fp)
equipment_list = get_redis_info(redis, 'dcalc:equipment', get_equipment_list)
return response(data=equipment_list)
@router.get("/token/get/{alter}", response_model=Return[str])
async def getToken(
alter: str, request: Request, version: str = None, equVersion: str = ""
): ):
if version is not None and version != "default" and version != "": token = createToken(alter, equVersion, redis)
alter = version + "." + alter
token = createToken(
alter, equVersion, redis=request.app.state.redis, env=request.app.state.env
)
return response(data=token) return response(data=token)
@router.get("/character")
async def get_character_info(
request: Request, state: AltersDep ,redis:RedisDep
):
character = createCharacter(state.alter, state.equVersion)
def get_character():
return character.getInfo()
info = get_redis_info(redis, f"dcalc:character:{state.alter}", get_character)
return response(data=info)
+3 -1
View File
@@ -569,7 +569,9 @@ class Character:
def createCharacter(alter: str, equVersion: str = '0'): def createCharacter(alter: str, equVersion: str = '0'):
character: Character = None character: Character = None
module_name = 'core.characters.' + alter module_name = 'core.character.' + alter
if equVersion is None or equVersion == '':
equVersion = '0'
try: try:
character = importlib.import_module(module_name).classChange(equVersion) character = importlib.import_module(module_name).classChange(equVersion)
except Exception as ex: except Exception as ex:
+1 -1
View File
@@ -77,7 +77,7 @@ class Skill:
icon = icon.replace('$common', '/characters/common') icon = icon.replace('$common', '/characters/common')
icon = icon.replace('$name', f'{self.name}') icon = icon.replace('$name', f'{self.name}')
icon = icon.replace('$id', f'{self.id}') icon = icon.replace('$id', f'{self.id}')
return icon return f'{icon}.png'
def _calculate_lv(self): def _calculate_lv(self):
return min(int((characterLv - self.learnLv) / self.rangeLv + 1), self.masterLv) if self._lv == 0 else self._lv return min(int((characterLv - self.learnLv) / self.rangeLv + 1), self.masterLv) if self._lv == 0 else self._lv
+68 -68
View File
@@ -3,32 +3,32 @@
"name": "swordman_male", "name": "swordman_male",
"title": "鬼剑士(男)", "title": "鬼剑士(男)",
"children": [ "children": [
{ "title": "极诣·剑魂", "name": "weapon_master", "open": true }, { "title": "极诣·剑魂", "name": "weapon_master", "open": false },
{ "name": "soul_bender", "title": "极诣·鬼泣", "open": true }, { "name": "soul_bender", "title": "极诣·鬼泣", "open": false },
{ "name": "berserker", "title": "极诣·狂战士", "open": true }, { "name": "berserker", "title": "极诣·狂战士", "open": false },
{ "name": "asura", "title": "极诣·阿修罗", "open": true }, { "name": "asura", "title": "极诣·阿修罗", "open": false },
{ "name": "ghostblade", "title": "极诣·剑影", "open": true } { "name": "ghostblade", "title": "极诣·剑影", "open": false }
] ]
}, },
{ {
"name": "swordman_female", "name": "swordman_female",
"title": "鬼剑士(女)", "title": "鬼剑士(女)",
"children": [ "children": [
{ "name": "sword_master", "title": "极诣·驭剑士", "open": true }, { "name": "sword_master", "title": "极诣·驭剑士", "open": false },
{ "name": "dark_templar", "title": "极诣·暗殿骑士", "open": true }, { "name": "dark_templar", "title": "极诣·暗殿骑士", "open": false },
{ "name": "demon_slayer", "title": "极诣·契魔者", "open": true }, { "name": "demon_slayer", "title": "极诣·契魔者", "open": false },
{ "name": "vegabond", "title": "极诣·流浪武士", "open": true }, { "name": "vegabond", "title": "极诣·流浪武士", "open": false },
{ "name": "spectre", "title": "极诣·刃影", "open": true } { "name": "spectre", "title": "极诣·刃影", "open": false }
] ]
}, },
{ {
"name": "fighter_male", "name": "fighter_male",
"title": "格斗家(男)", "title": "格斗家(男)",
"children": [ "children": [
{ "name": "nenmaster_male", "title": "归元·气功师", "open": true }, { "name": "nenmaster_male", "title": "归元·气功师", "open": false },
{ "name": "striker_male", "title": "归元·散打", "open": true }, { "name": "striker_male", "title": "归元·散打", "open": false },
{ "name": "brawler_male", "title": "归元·街霸", "open": true }, { "name": "brawler_male", "title": "归元·街霸", "open": false },
{ "name": "grappler_male", "title": "归元·柔道家", "open": true }, { "name": "grappler_male", "title": "归元·柔道家", "open": false },
{ "name": "empty", "title": "", "comment": "首页" } { "name": "empty", "title": "", "comment": "首页" }
] ]
}, },
@@ -36,10 +36,10 @@
"name": "fighter_female", "name": "fighter_female",
"title": "格斗家(女)", "title": "格斗家(女)",
"children": [ "children": [
{ "name": "nenmaster_female", "title": "归元·气功师", "open": true }, { "name": "nenmaster_female", "title": "归元·气功师", "open": false },
{ "name": "striker_female", "title": "归元·散打", "open": true }, { "name": "striker_female", "title": "归元·散打", "open": false },
{ "name": "brawler_female", "title": "归元·街霸", "open": true }, { "name": "brawler_female", "title": "归元·街霸", "open": false },
{ "name": "grappler_female", "title": "归元·柔道家", "open": true }, { "name": "grappler_female", "title": "归元·柔道家", "open": false },
{ "name": "empty", "title": "", "comment": "设置" } { "name": "empty", "title": "", "comment": "设置" }
] ]
}, },
@@ -47,26 +47,26 @@
"name": "gunner_male", "name": "gunner_male",
"title": "神枪手(男)", "title": "神枪手(男)",
"children": [ "children": [
{ "name": "ranger_male", "title": "重霄·漫游枪手", "open": true }, { "name": "ranger_male", "title": "重霄·漫游枪手", "open": false },
{ "name": "launcher_male", "title": "重霄·枪炮师", "open": true }, { "name": "launcher_male", "title": "重霄·枪炮师", "open": false },
{ "name": "mechanic_male", "title": "重霄·机械师", "open": true }, { "name": "mechanic_male", "title": "重霄·机械师", "open": false },
{ "name": "spitfire_male", "title": "重霄·弹药专家", "open": true }, { "name": "spitfire_male", "title": "重霄·弹药专家", "open": false },
{ "name": "assault", "title": "重霄·合金战士", "open": true } { "name": "assault", "title": "重霄·合金战士", "open": false }
] ]
}, },
{ {
"name": "gunner_female", "name": "gunner_female",
"title": "神枪手(女)", "title": "神枪手(女)",
"children": [ "children": [
{ "name": "ranger_female", "title": "重霄·漫游枪手", "open": true }, { "name": "ranger_female", "title": "重霄·漫游枪手", "open": false },
{ "name": "launcher_female", "title": "重霄·枪炮师", "open": true }, { "name": "launcher_female", "title": "重霄·枪炮师", "open": false },
{ "name": "mechanic_female", "title": "重霄·机械师", "open": true }, { "name": "mechanic_female", "title": "重霄·机械师", "open": false },
{ "name": "spitfire_female", "title": "重霄·弹药专家", "open": true }, { "name": "spitfire_female", "title": "重霄·弹药专家", "open": true, "class": "GF.gunner_female.spitfire_female" },
{ {
"name": "sponsor", "name": "sponsor",
"url": "https://bbs.colg.cn", "url": "https://bbs.colg.cn",
"title": "", "title": "",
"open": true "open": false
} }
] ]
}, },
@@ -74,25 +74,25 @@
"name": "mage_male", "name": "mage_male",
"title": "魔法师(男)", "title": "魔法师(男)",
"children": [ "children": [
{ "name": "elemental_bomber", "title": "知源·元素爆破师", "open": true }, { "name": "elemental_bomber", "title": "知源·元素爆破师", "open": false },
{ "name": "glacial_master", "title": "知源·冰结师", "open": true }, { "name": "glacial_master", "title": "知源·冰结师", "open": false },
{ "name": "blood_mage", "title": "知源·血法师", "open": true }, { "name": "blood_mage", "title": "知源·血法师", "open": false },
{ "name": "swift_master", "title": "知源·逐风者", "open": true }, { "name": "swift_master", "title": "知源·逐风者", "open": false },
{ "name": "dimension_walker", "title": "知源·次元行者", "open": true } { "name": "dimension_walker", "title": "知源·次元行者", "open": false }
] ]
}, },
{ {
"name": "mage_female", "name": "mage_female",
"title": "魔法师(女)", "title": "魔法师(女)",
"children": [ "children": [
{ "name": "elementalist", "title": "知源·元素师", "open": true }, { "name": "elementalist", "title": "知源·元素师", "open": false },
{ "name": "summoner", "title": "知源·召唤师", "open": true }, { "name": "summoner", "title": "知源·召唤师", "open": false },
{ "name": "battle_mage", "title": "知源·战斗法师", "open": true }, { "name": "battle_mage", "title": "知源·战斗法师", "open": false },
{ "name": "witch", "title": "知源·魔道学者", "open": true }, { "name": "witch", "title": "知源·魔道学者", "open": false },
{ {
"name": "enchantress", "name": "enchantress",
"title": "知源·小魔女", "title": "知源·小魔女",
"open": true, "open": false,
"options": [ "options": [
{ "name": "default", "title": "奶", "class": "enchantress" }, { "name": "default", "title": "奶", "class": "enchantress" },
{ "name": "default", "title": "输出", "class": "enchantress_carry" } { "name": "default", "title": "输出", "class": "enchantress_carry" }
@@ -107,15 +107,15 @@
{ {
"name": "crusader_male", "name": "crusader_male",
"title": "神启·圣骑士", "title": "神启·圣骑士",
"open": true, "open": false,
"options": [ "options": [
{ "name": "default", "title": "奶", "class": "crusader_male" }, { "name": "default", "title": "奶", "class": "crusader_male" },
{ "name": "default", "title": "审判", "class": "crusader_male_carry" } { "name": "default", "title": "审判", "class": "crusader_male_carry" }
] ]
}, },
{ "name": "infighter", "title": "神启·蓝拳圣使", "open": true }, { "name": "infighter", "title": "神启·蓝拳圣使", "open": false },
{ "name": "exorcist", "title": "神启·驱魔师", "open": true }, { "name": "exorcist", "title": "神启·驱魔师", "open": false },
{ "name": "avenger", "title": "神启·复仇者", "open": true }, { "name": "avenger", "title": "神启·复仇者", "open": false },
{ "name": "empty", "title": "" } { "name": "empty", "title": "" }
] ]
}, },
@@ -126,7 +126,7 @@
{ {
"name": "crusader_female", "name": "crusader_female",
"title": "神启·圣骑士", "title": "神启·圣骑士",
"open": true, "open": false,
"options": [ "options": [
{ "name": "default", "title": "奶", "class": "crusader_female" }, { "name": "default", "title": "奶", "class": "crusader_female" },
{ {
@@ -136,9 +136,9 @@
} }
] ]
}, },
{ "name": "inquistor", "title": "神启·异端审判者", "open": true }, { "name": "inquistor", "title": "神启·异端审判者", "open": false },
{ "name": "sorceress", "title": "神启·巫女", "open": true }, { "name": "sorceress", "title": "神启·巫女", "open": false },
{ "name": "mistress", "title": "神启·诱魔者", "open": true }, { "name": "mistress", "title": "神启·诱魔者", "open": false },
{ "name": "empty", "title": "" } { "name": "empty", "title": "" }
] ]
}, },
@@ -146,10 +146,10 @@
"name": "thief", "name": "thief",
"title": "暗夜使者", "title": "暗夜使者",
"children": [ "children": [
{ "name": "rogue", "title": "隐夜·刺客", "open": true }, { "name": "rogue", "title": "隐夜·刺客", "open": false },
{ "name": "necro", "title": "隐夜·死灵术士", "open": true }, { "name": "necro", "title": "隐夜·死灵术士", "open": false },
{ "name": "kunoichi", "title": "隐夜·忍者", "open": true }, { "name": "kunoichi", "title": "隐夜·忍者", "open": false },
{ "name": "shadow_dancer", "title": "隐夜·影舞者", "open": true }, { "name": "shadow_dancer", "title": "隐夜·影舞者", "open": false },
{ "name": "empty", "title": "" } { "name": "empty", "title": "" }
] ]
}, },
@@ -157,10 +157,10 @@
"name": "knight", "name": "knight",
"title": "守护者", "title": "守护者",
"children": [ "children": [
{ "name": "elven_knight", "title": "皓曦·精灵骑士", "open": true }, { "name": "elven_knight", "title": "皓曦·精灵骑士", "open": false },
{ "name": "chaos", "title": "皓曦·混沌魔灵", "open": true }, { "name": "chaos", "title": "皓曦·混沌魔灵", "open": false },
{ "name": "paladin", "title": "皓曦·帕拉丁", "open": true }, { "name": "paladin", "title": "皓曦·帕拉丁", "open": false },
{ "name": "dragon_knight", "title": "皓曦·龙骑士", "open": true }, { "name": "dragon_knight", "title": "皓曦·龙骑士", "open": false },
{ "name": "empty", "title": "" } { "name": "empty", "title": "" }
] ]
}, },
@@ -168,10 +168,10 @@
"name": "demonic_lancer", "name": "demonic_lancer",
"title": "魔枪士", "title": "魔枪士",
"children": [ "children": [
{ "name": "vanguard", "title": "千魂·征战者", "open": true }, { "name": "vanguard", "title": "千魂·征战者", "open": false },
{ "name": "skirmisher", "title": "千魂·决战者", "open": true }, { "name": "skirmisher", "title": "千魂·决战者", "open": false },
{ "name": "dragoon", "title": "千魂·狩猎者", "open": true }, { "name": "dragoon", "title": "千魂·狩猎者", "open": false },
{ "name": "impaler", "title": "千魂·暗枪士", "open": true }, { "name": "impaler", "title": "千魂·暗枪士", "open": false },
{ "name": "empty", "title": "" } { "name": "empty", "title": "" }
] ]
}, },
@@ -179,10 +179,10 @@
"name": "gunblader", "name": "gunblader",
"title": "枪剑士", "title": "枪剑士",
"children": [ "children": [
{ "name": "hitman", "title": "苍暮·暗刃", "open": true }, { "name": "hitman", "title": "苍暮·暗刃", "open": false },
{ "name": "agent", "title": "苍暮·特工", "open": true }, { "name": "agent", "title": "苍暮·特工", "open": false },
{ "name": "trouble_shooter", "title": "苍暮·战线佣兵", "open": true }, { "name": "trouble_shooter", "title": "苍暮·战线佣兵", "open": false },
{ "name": "specialist", "title": "苍暮·源能专家", "open": true }, { "name": "specialist", "title": "苍暮·源能专家", "open": false },
{ "name": "empty", "title": "" } { "name": "empty", "title": "" }
] ]
}, },
@@ -190,10 +190,10 @@
"name": "archer", "name": "archer",
"title": "弓箭手", "title": "弓箭手",
"children": [ "children": [
{ "name": "muse", "title": "聆风·缪斯", "open": true }, { "name": "muse", "title": "聆风·缪斯", "open": false },
{ "name": "traveler", "title": "聆风·旅人", "open": true }, { "name": "traveler", "title": "聆风·旅人", "open": false },
{ "name": "hunter", "title": "聆风·猎人", "open": true }, { "name": "hunter", "title": "聆风·猎人", "open": false },
{ "name": "vigilante", "title": "聆风·妖护使", "open": true }, { "name": "vigilante", "title": "聆风·妖护使", "open": false },
{ "name": "empty", "title": "" } { "name": "empty", "title": "" }
] ]
}, },
@@ -201,8 +201,8 @@
"name": "extra", "name": "extra",
"title": "外传", "title": "外传",
"children": [ "children": [
{ "name": "creator", "title": "知源·缔造者", "open": true }, { "name": "creator", "title": "知源·缔造者", "open": false },
{ "name": "dark_knight", "title": "极诣·黑暗武士", "open": true }, { "name": "dark_knight", "title": "极诣·黑暗武士", "open": false },
{ "name": "empty", "title": "" }, { "name": "empty", "title": "" },
{ "name": "empty", "title": "" }, { "name": "empty", "title": "" },
{ "name": "empty", "title": "" } { "name": "empty", "title": "" }
+1 -1
View File
@@ -20,6 +20,6 @@ if __name__ == '__main__':
application.include_router(api_router) application.include_router(api_router)
uvicorn.run(application, host='127.0.0.1', port=config.PORT) uvicorn.run(app = application, host='127.0.0.1', port=config.PORT)
+2 -8
View File
@@ -2,6 +2,7 @@ import type { AxiosInstance, AxiosResponse } from 'axios'
import axios from 'axios' import axios from 'axios'
import { h } from 'vue' import { h } from 'vue'
import { gzip, ungzip } from 'pako' import { gzip, ungzip } from 'pako'
import { useInfoStore } from '@/stores'
// import { useAppStore, useConfigStore } from '@/store' // import { useAppStore, useConfigStore } from '@/store'
// import { useDialog } from '@/components/hooks/dialog' // import { useDialog } from '@/components/hooks/dialog'
@@ -58,19 +59,12 @@ export function defineRequest<T>(fn: (ax: AxiosInstance) => T) {
// const token = configStore.token // const token = configStore.token
// const uid = useAppStore().uid // const uid = useAppStore().uid
const token = 'test' const token = useInfoStore().token
if (token) { if (token) {
request.headers['Access-Token'] = token request.headers['Access-Token'] = token
} }
// 在网页端,会添加token
const accessToken = localStorage.getItem('dcalc/access_token')
if (accessToken) {
request.headers.Authorization = `Bearer ${accessToken}`
}
return request return request
}, },
(error) => { (error) => {
+12 -3
View File
@@ -1,10 +1,19 @@
import { defineRequest } from '../common' import { defineRequest } from '../common'
import type { IAdventureInfo } from './type' import type { IAdventureInfo, ICharacterInfo } from './type'
export default defineRequest((request) => { export default defineRequest((request) => {
return { return {
adventures() { async adventures() {
return request.get<IAdventureInfo[]>('/adventure').then((res) => res.data) const res = await request.get<IAdventureInfo[]>('/adventure')
return res.data
},
async createToken(alter: string, equVersion?: string) {
const res = await request.get<string>(`/token/get/${alter}`, { params: { equVersion } })
return res.data
},
async characterInfo() {
const res = await request.get<ICharacterInfo>('/character')
return res.data
}, },
} }
}) })
+23 -14
View File
@@ -3,20 +3,6 @@ export interface IAdventureInfo {
name: string name: string
children: IAlterInfo[] children: IAlterInfo[]
} }
export interface ITools {
name: string
tooltips: string
link: string
end?: Date
target: '_blank' | '_self'
}
export interface IMonster {
id: number
name: string
}
export interface IAlterOption { export interface IAlterOption {
name: string name: string
title: string title: string
@@ -31,4 +17,27 @@ export interface IAlterInfo {
options?: IAlterOption[] options?: IAlterOption[]
open?: boolean open?: boolean
comment?: string comment?: string
class?:string
} }
export interface ICharacterInfo {
alter: string
name: string
equVersion: string
equips: IEquipment[]
weapons: string[]
skills: ISkill[]
suits: ISuit[]
}
export interface IEquipment {}
export interface ISkill {
icon: string
name: string
id: number
learnLv:number
positon:number
}
export interface ISuit {}
+3 -2
View File
@@ -1,7 +1,8 @@
import '@/style/index.scss' import '@/style/index.scss'
import { createApp } from 'vue' import { createApp } from 'vue'
import { createPinia } from 'pinia' import { pinia } from "@/stores"
import App from '@/pages/IndexView.vue' import App from '@/pages/IndexView.vue'
import router from './router' import router from './router'
@@ -13,7 +14,7 @@ document.body.appendChild(appContainer)
const app = createApp(App) const app = createApp(App)
app.use(createPinia()) app.use(pinia)
app.use(router) app.use(router)
app.mount(appContainer) app.mount(appContainer)
+19
View File
@@ -0,0 +1,19 @@
<template>
<div class="h-90vh w-560px overflow-y-auto overflow-x-hidden">
<SkillTree></SkillTree>
</div>
</template>
<script lang="ts" setup name="Index">
import { useInfoStore } from '@/stores/info'
import { getImageURL } from '@/utils/images'
import SkillTree from './Skill/SkillTree.vue';
const props = defineProps<{
alter: string
}>()
const infoStore = useInfoStore()
onMounted(() => {
infoStore.createCharacter(props.alter, '0')
})
</script>
@@ -0,0 +1,47 @@
<template>
<div class="relative w-550px h-auto">
<template v-for="item in infoStore.skills" :key="item.id">
<div
class="absolute w-34px h-auto flex flex-col gap-2px py-2px items-center bg-#2c2d2c rounded-2px"
:style="skillPositon(item.learnLv, item.positon)"
>
<img class="w-30px h-30px" :src="getImageURL(item.icon)" :alt="item.name" />
<div class="flex-1 bg-black text-white">100级</div>
</div>
</template>
<template v-for="lv of 21" :key="lv">
<div class="skill-tree-line flex items-center px-20px text-#373837">
{{ lv % 2 === 1 ? Math.max(1, (lv - 1) * 5) :'' }}
</div>
</template>
</div>
</template>
<script lang="ts" setup>
import { useInfoStore } from '@/stores'
import { getImageURL } from '@/utils/images'
const infoStore = useInfoStore()
const skillPositon = (learnLv: number, positon: number) => {
return {
positon: 'absolute',
left: `${positon * 50 + 50}px`,
top: `${Math.floor(learnLv / 5) * 80 + 8}px`,
}
}
</script>
<style lang="scss" scoped>
.skill-tree-line {
height: 80px;
width: auto;
&:nth-child(n + 1) {
background-color: #000000;
}
&:nth-child(2n + 1) {
background-color: #202020;
backdrop-filter: blur(1px);
}
}
</style>
@@ -24,82 +24,22 @@ export default defineComponent(async () => {
// 获取角色相关信息,判定是否开放 // 获取角色相关信息,判定是否开放
function choose_job(child: IAlterInfo) { function choose_job(child: IAlterInfo) {
return async () => { return async () => {
// if (child.comment == '首页') { if (child.comment == '首页') {
// return openUrl('https://dnftools.com/') return window.open("https://dnftools.com","_blank")
// } }
// if (child.comment == '设置') { if (child.name == 'sponsor') {
// return openUrl('/set', { width: 600, height: 500, scale: zoom.value }) return window.open((child.url ?? ''),"_blank")
// } }
// if (ignores.includes(child.name)) { if (child.open) {
// return const options = child.options ?? []
// } if (options.length > 0) {
// if (child.name == 'sponsor') { return
// return openUrl(child.url ?? '') }
// } else{
// if (child.open || import.meta.env.DEV) { return window.open("/character/" + (child.class || child.name),"_self")
// const options = child.options ?? [] }
// if (options.length > 0) {
// const id = randomId()
// return await show({
// // id,
// scale: zoom.value,
// content: '请选择职业平衡版本',
// action: () => {
// return (
// <>
// <div class="flex items-center justify-around flex-wrap" style="width:200px">
// {renderList(options, (option) =>
// !option.class ? (
// <calc-button
// class="!w-40% !mb-2"
// onClick={() => {
// openUrl('/character', {
// query: { alter: child.name },
// width: 1100,
// height: 775,
// scale: zoom.value,
// })
// close(id, 'ok')
// }}
// >
// {option.title}
// </calc-button>
// ) : (
// <calc-button
// class="!w-40% !mb-2"
// onClick={() => {
// openUrl('/character', {
// query: { alter: option.class ?? '' },
// width: 1100,
// height: 775,
// scale: zoom.value,
// })
// close(id, 'ok')
// }}
// >
// {option.title}
// </calc-button>
// ),
// )}
// </div>
// </>
// )
// },
// })
// }
// return openUrl('/character', {
// query: { alter: child.name },
// width: 1100,
// height: 775,
// title: child.title,
// scale: zoom.value,
// })
// } else {
// return alert({
// content: '未开放的角色!',
// })
// }
} }
}
// router.push("/character/" + alter) // router.push("/character/" + alter)
} }
+7 -1
View File
@@ -7,8 +7,14 @@ const routes: RouteRecordRaw[] = [
{ {
path: '/', path: '/',
name: 'home', name: 'home',
component: defineAsyncComponent(() => import('@/pages/Home/HomeView.vue')), component: defineAsyncComponent(() => import('@/pages/Home/Index.vue')),
}, },
{
path:'/character/:alter',
name:'character',
props: true,
component: defineAsyncComponent(() => import('@/pages/Character/Index.vue')),
}
] ]
const router = createRouter({ const router = createRouter({
+4
View File
@@ -0,0 +1,4 @@
import {defineStore} from 'pinia'
const config = defineStore('config', ()=>{
})
-12
View File
@@ -1,12 +0,0 @@
import { ref, computed } from 'vue'
import { defineStore } from 'pinia'
export const useCounterStore = defineStore('counter', () => {
const count = ref(0)
const doubleCount = computed(() => count.value * 2)
function increment() {
count.value++
}
return { count, doubleCount, increment }
})
+5
View File
@@ -0,0 +1,5 @@
import { createPinia } from "pinia"
export * from "./info"
export const pinia = createPinia()
+29
View File
@@ -0,0 +1,29 @@
import api from "@/api"
import type { ICharacterInfo } from "@/api/info/type"
import { defineStore } from "pinia"
export const useInfoStore = defineStore("infoStore", ()=>{
const token = ref<string>("")
const infos = ref<ICharacterInfo | null>(null)
const skills = computed(()=>infos.value?.skills ?? [])
const equips = computed(()=>infos.value?.equips ?? [])
const suits = computed(()=>infos.value?.suits ?? [])
const createCharacter = async (alter: string, equVersion?: string) => {
token.value = await api.createToken(alter, equVersion)
infos.value = await api.characterInfo()
}
return {
token,
infos,
skills,
equips,
suits,
createCharacter,
}
})
+3 -2
View File
@@ -1,4 +1,4 @@
let baseURL = '/img' let baseURL = 'https://image.dnftools.com'
// 避免远程开发的时候冲突 // 避免远程开发的时候冲突
if (process.env.NODE_ENV == 'development') { if (process.env.NODE_ENV == 'development') {
@@ -10,5 +10,6 @@ if (import.meta.env.MODE == 'web' || import.meta.env.MODE == 'show') {
} }
export const getImageURL = (image: string) => { export const getImageURL = (image: string) => {
return `${baseURL}/${image}` image = image.startsWith('/') ? image : `/${image}`
return `${baseURL}${image}`
} }
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

+1 -1
View File
@@ -9,7 +9,7 @@ const ImageServer = http.createServer((req, res) => {
// 图片存储的文件夹路径 // 图片存储的文件夹路径
const directoryPath = path.join(__dirname, '../images'); const directoryPath = path.join(__dirname, '../images');
// 请求的图片文件名 // 请求的图片文件名
const filePath = path.join(directoryPath, req.url); const filePath = path.join(directoryPath, decodeURIComponent(req.url));
// 确保文件存在且是文件,不是目录 // 确保文件存在且是文件,不是目录
fs.access(filePath, fs.constants.F_OK | fs.constants.R_OK, (err) => { fs.access(filePath, fs.constants.F_OK | fs.constants.R_OK, (err) => {
if (err) { if (err) {