mirror of
https://github.com/BTMuli/TeyvatGuide.git
synced 2026-05-02 23:39:38 +08:00
🎨 规范化代码
This commit is contained in:
@@ -36,8 +36,8 @@ const model = defineModel<number>({ default: 2 });
|
||||
|
||||
const actId = ref<string>();
|
||||
const showOverlay = ref<boolean>(false);
|
||||
const nav = shallowRef<TGApp.BBS.Navigator.Navigator[]>([]);
|
||||
const codeData = shallowRef<TGApp.BBS.Navigator.CodeData[]>([]);
|
||||
const nav = shallowRef<Array<TGApp.BBS.Navigator.Navigator>>([]);
|
||||
const codeData = shallowRef<Array<TGApp.BBS.Navigator.CodeData>>([]);
|
||||
const hasNav = computed<TGApp.BBS.Navigator.Navigator | undefined>(() => {
|
||||
const liveNames = ["前瞻直播", "前瞻节目", "直播兑换码", "特别节目"];
|
||||
const find = nav.value.find((item) => liveNames.includes(item.name));
|
||||
|
||||
@@ -81,7 +81,7 @@ function parseNameCard(desc: string): string {
|
||||
return res;
|
||||
}
|
||||
|
||||
function parseDesc(desc: string, inQuote: boolean = false): string[] {
|
||||
function parseDesc(desc: string, inQuote: boolean = false): Array<string> {
|
||||
let res = desc.replace(/。/g, "。\n");
|
||||
res = res.replace(/;/g, ";\n");
|
||||
/* 闲云·鹤云 */
|
||||
@@ -113,7 +113,7 @@ function parseDesc(desc: string, inQuote: boolean = false): string[] {
|
||||
res = res.replace(/\n」/g, "」\n");
|
||||
}
|
||||
const match = res.split("\n");
|
||||
let array: string[] = [];
|
||||
let array: Array<string> = [];
|
||||
for (const item of match) {
|
||||
if (item.length > 0 && item.length <= 32) {
|
||||
array.push(item);
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
/**
|
||||
* @file component/func/dialog.ts
|
||||
* @description dialog 组件封装,函数式调用
|
||||
* dialog 组件封装,函数式调用
|
||||
* @since Beta v0.6.3
|
||||
*/
|
||||
|
||||
@@ -27,18 +26,15 @@ export type DialogInputParams = {
|
||||
};
|
||||
|
||||
/**
|
||||
* @description 自定义 confirm 组件
|
||||
* 自定义 confirm 组件
|
||||
* @since Beta v0.6.3
|
||||
* @extends ComponentInternalInstance
|
||||
* @property {Function} exposeProxy.displayBox 显示 confirm
|
||||
* @return DialogInstance
|
||||
*/
|
||||
interface DialogInstance extends ComponentInternalInstance {
|
||||
type DialogInstance = {
|
||||
exposeProxy: {
|
||||
displayCheckBox: (props: DialogCheckParams) => Promise<boolean | undefined>;
|
||||
displayInputBox: (props: DialogInputParams) => Promise<string | false | undefined>;
|
||||
};
|
||||
}
|
||||
} & ComponentInternalInstance;
|
||||
|
||||
function renderBox(props: DialogParams): VNode {
|
||||
const container = document.createElement("div");
|
||||
|
||||
@@ -13,18 +13,15 @@ const geetestId = "tg-func-geetest";
|
||||
/**
|
||||
* 自定义 geetest 组件
|
||||
* @since Beta v0.8.7
|
||||
* @extends ComponentInternalInstance
|
||||
* @property {Function} exposeProxy.displayBox 弹出 geetest 验证
|
||||
* @return GeetestInstance
|
||||
*/
|
||||
interface GeetestInstance extends ComponentInternalInstance {
|
||||
type GeetestInstance = {
|
||||
exposeProxy: {
|
||||
displayBox: (
|
||||
props: TGApp.BBS.Geetest.CreateRes,
|
||||
raw?: TGApp.BBS.CaptchaLogin.CaptchaAigis,
|
||||
) => Promise<TGApp.BBS.Geetest.GeetestVerifyRes | false>;
|
||||
};
|
||||
}
|
||||
} & ComponentInternalInstance;
|
||||
|
||||
function renderBox(props: TGApp.BBS.Geetest.CreateRes): VNode {
|
||||
const container = document.createElement("div");
|
||||
@@ -40,9 +37,9 @@ let geetestInstance: VNode;
|
||||
/**
|
||||
* 弹出 geetest 验证
|
||||
* @since Beta v0.8.7
|
||||
* @param {TGApp.BBS.Geetest.CreateRes} props geetest 验证的参数
|
||||
* @param {TGApp.BBS.CaptchaLogin.CaptchaAigis} raw 原始数据,一般用于 Gt4 验证
|
||||
* @return {Promise<TGApp.BBS.Geetest.GeetestVerifyRes|false>} 验证成功返回验证数据
|
||||
* @param props - geetest 验证的参数
|
||||
* @param raw - 原始数据,一般用于 Gt4 验证
|
||||
* @returns 验证数据
|
||||
*/
|
||||
async function showGeetest(
|
||||
props: TGApp.BBS.Geetest.CreateRes,
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
/**
|
||||
* @file component/func/loading.ts
|
||||
* @description loading 组件封装,函数式调用
|
||||
* loading 组件封装,函数式调用
|
||||
* @since Beta v0.6.7
|
||||
*/
|
||||
|
||||
@@ -17,9 +16,9 @@ type LoadingUpdateParams = Omit<LoadingParams, "show" | "subtitle"> & { timeout?
|
||||
const TIMEOUT: Readonly<number> = 150;
|
||||
|
||||
/**
|
||||
* @description 自定义 loading 组件
|
||||
* 自定义 loading 组件
|
||||
* @since Beta v0.6.7
|
||||
* @return LoadingInstance
|
||||
* @returns LoadingInstance
|
||||
*/
|
||||
type LoadingInstance = ComponentInternalInstance & {
|
||||
exposeProxy: { displayBox: (props: LoadingParams) => Promise<void> };
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
/**
|
||||
* @file component/func/snackbar.ts
|
||||
* @description snackbar 组件封装,函数式调用
|
||||
* snackbar 组件封装,函数式调用
|
||||
* @since Beta v0.6.3
|
||||
*/
|
||||
|
||||
@@ -14,15 +13,14 @@ const snackbarId = "tg-func-snackbar";
|
||||
export type SnackbarParams = { text: string; color: string; timeout: number };
|
||||
|
||||
/**
|
||||
* @description 自定义 snackbar 组件
|
||||
* 自定义 snackbar 组件
|
||||
* @since Beta v0.6.3
|
||||
* @return SnackbarInstance
|
||||
*/
|
||||
interface SnackbarInstance extends ComponentInternalInstance {
|
||||
type SnackbarInstance = {
|
||||
exposeProxy: {
|
||||
displayBox: (props: SnackbarParams) => void;
|
||||
};
|
||||
}
|
||||
} & ComponentInternalInstance;
|
||||
|
||||
function renderBox(props: SnackbarParams): VNode {
|
||||
const container = document.createElement("div");
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div :id="`anno_card_${model.id}`" class="anno-card">
|
||||
<div :title="model.title" class="anno-cover" @click="createAnno">
|
||||
<TMiImg v-if="model.banner !== ''" :ori="true" :src="model.banner" alt="cover" />
|
||||
<div :id="`anno_card_${props.anno.ann_id}`" class="anno-card">
|
||||
<div :title="props.anno.title" class="anno-cover" @click="createAnno">
|
||||
<TMiImg v-if="props.anno.banner !== ''" :ori="true" :src="props.anno.banner" alt="cover" />
|
||||
<img v-else alt="cover" src="/source/UI/defaultCover.webp" />
|
||||
<div class="anno-info">
|
||||
<div class="anno-time">
|
||||
@@ -10,26 +10,19 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div :title="model.title" class="anno-title" @click="shareAnno">
|
||||
{{ parseTitle(model.subtitle) }}
|
||||
<div :title="props.anno.title" class="anno-title" @click="shareAnno">
|
||||
{{ parseTitle(props.anno.subtitle) }}
|
||||
</div>
|
||||
<div
|
||||
:style="{ background: str2Color(`${model.tagIcon}${model.tagLabel}`, 40) }"
|
||||
:title="`标签:${model.tagLabel}`"
|
||||
class="anno-label"
|
||||
>
|
||||
<TMiImg :ori="true" :src="model.tagIcon" alt="tag" />
|
||||
<span>{{ model.tagLabel }}</span>
|
||||
</div>
|
||||
<div :style="{ background: str2Color(`${model.id}`, 0) }" class="anno-id">
|
||||
ID:{{ model.id }}
|
||||
<div :title="`标签:${props.anno.tag_label}`" class="anno-label">
|
||||
<TMiImg :ori="true" :src="props.anno.tag_icon" alt="tag" />
|
||||
<span>{{ props.anno.tag_label }}</span>
|
||||
</div>
|
||||
<div class="anno-id">ID:{{ props.anno.ann_id }}</div>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import TMiImg from "@comp/app/t-mi-img.vue";
|
||||
import showSnackbar from "@comp/func/snackbar.js";
|
||||
import { AnnoTypeEnum } from "@enum/anno.js";
|
||||
import useAppStore from "@store/app.js";
|
||||
import { str2Color } from "@utils/colorFunc.js";
|
||||
import TGLogger from "@utils/TGLogger.js";
|
||||
@@ -37,19 +30,26 @@ import { generateShareImg } from "@utils/TGShare.js";
|
||||
import { createTGWindow } from "@utils/TGWindow.js";
|
||||
import { decodeRegExp } from "@utils/toolFunc.js";
|
||||
import { storeToRefs } from "pinia";
|
||||
import { onMounted, ref, watch } from "vue";
|
||||
import { computed, onMounted, ref, watch } from "vue";
|
||||
|
||||
import type { AnnoCard } from "@/pages/common/PageAnno.vue";
|
||||
type TaCardProps = { anno: TGApp.Game.Anno.ListAnno; detail?: TGApp.Game.Anno.AnnoDetail };
|
||||
|
||||
const { server, lang } = storeToRefs(useAppStore());
|
||||
const model = defineModel<AnnoCard>({ required: true });
|
||||
const timeStr = ref<string>(model.value.timeStr);
|
||||
|
||||
const props = defineProps<TaCardProps>();
|
||||
const timeStr = ref<string>("");
|
||||
|
||||
const idColor = computed<string>(() => str2Color(`${props.anno.ann_id}`, 0));
|
||||
const tagColor = computed<string>(() =>
|
||||
str2Color(`${props.anno.tag_icon}${props.anno.tag_label}`, 40),
|
||||
);
|
||||
|
||||
onMounted(() => refreshAnnoTime());
|
||||
|
||||
watch(
|
||||
() => model.value,
|
||||
() => props.anno,
|
||||
(newVal, oldVal) => {
|
||||
if (newVal.id !== oldVal.id) refreshAnnoTime();
|
||||
if (newVal.ann_id !== oldVal.ann_id) refreshAnnoTime();
|
||||
},
|
||||
);
|
||||
|
||||
@@ -59,15 +59,15 @@ function parseTitle(title: string): string {
|
||||
}
|
||||
|
||||
async function createAnno(): Promise<void> {
|
||||
const annoPath = `/anno_detail/${server.value}/${model.value.id}/${lang.value}`;
|
||||
const annoTitle = `Anno_${model.value.id} ${model.value.title}`;
|
||||
await TGLogger.Info(`[Announcements][createAnno][${model.value.id}] 打开公告窗口`);
|
||||
const annoPath = `/anno_detail/${server.value}/${props.anno.ann_id}/${lang.value}`;
|
||||
const annoTitle = `Anno_${props.anno.ann_id} ${props.anno.title}`;
|
||||
await TGLogger.Info(`[Announcements][createAnno][${props.anno.ann_id}] 打开公告窗口`);
|
||||
await createTGWindow(annoPath, "Sub_window", annoTitle, 960, 720, false, false);
|
||||
}
|
||||
|
||||
async function shareAnno(): Promise<void> {
|
||||
const fileName = `AnnoCard_${model.value.id}_${model.value.subtitle}`;
|
||||
const element = document.querySelector<HTMLElement>(`#anno_card_${model.value.id}`);
|
||||
const fileName = `AnnoCard_${props.anno.ann_id}_${props.anno.subtitle}`;
|
||||
const element = document.querySelector<HTMLElement>(`#anno_card_${props.anno.ann_id}`);
|
||||
if (element === null) {
|
||||
showSnackbar.error("分享失败,未找到分享元素");
|
||||
return;
|
||||
@@ -76,18 +76,19 @@ async function shareAnno(): Promise<void> {
|
||||
}
|
||||
|
||||
async function refreshAnnoTime(): Promise<void> {
|
||||
if (model.value.typeLabel === AnnoTypeEnum.GAME) timeStr.value = model.value.timeStr;
|
||||
const strGet = getAnnoTime(model.value.detail.content);
|
||||
// MAGIC ANNO TYPE
|
||||
if (props.anno.type !== 1) timeStr.value = `${props.anno.start_time} ~ ${props.anno.end_time}`;
|
||||
const strGet = getAnnoTime(props.detail?.content ?? "");
|
||||
if (strGet !== false) timeStr.value = strGet;
|
||||
else timeStr.value = `${props.anno.start_time} ~ ${props.anno.end_time}`;
|
||||
}
|
||||
|
||||
function getAnnoTime(content: string): string | false {
|
||||
const regexes = [
|
||||
/〓活动时间〓.*?(\d\.\d|「月之[一二三四五六七八九]」)版本期间持续开放/,
|
||||
/(?:〓活动时间〓|〓任务开放时间〓).*?(?:(\d\.\d|「月之[一二三四五六七八九]」)版本更新(?:完成|)|<t class="t_(?:gl|lc)".*?>(.*?)<\/t> *?)后永久开放/s,
|
||||
/(?:〓活动时间〓|〓(任务|玩法)开放时间〓).*?(?:(\d\.\d|「月之[一二三四五六七八九]」)版本更新(?:完成|)|<t class="t_(?:gl|lc)".*?>(.*?)<\/t> *?)后永久开放/s,
|
||||
/(?:〓活动时间〓|祈愿时间|【上架时间】|〓折扣时间〓|〓获取奖励时限〓).*?(\d\.\d|「月之[一二三四五六七八九]」)版本更新后.*?~.*?<t class="t_(?:gl|lc)".*?>(.*?)<\/t>/s,
|
||||
/(?:〓(?:活动|折扣)时间〓|祈愿时间|【上架时间】).*?<t class="t_(?:gl|lc)".*?>(.*?)<\/t>.*?~.*?<t class="t_(?:gl|lc)".*?>(.*?)<\/t>/s,
|
||||
// /〓活动时间〓.*?(\d{4}\/\d{2}\/\d{2} \d{2}:\d{2}:\d{2}).*?(\d\.\d版本结束)/
|
||||
/〓活动时间〓.*?(\d{4}\/\d{2}\/\d{2} \d{2}:\d{2}).*?((\d\.\d|「月之[一二三四五六七八九]」)版本结束)/s,
|
||||
];
|
||||
if (content.match(regexes[0])) {
|
||||
@@ -224,6 +225,7 @@ function getAnnoTime(content: string): string | false {
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
padding: 4px;
|
||||
background: v-bind(tagColor); /* stylelint-disable-line value-keyword-case */
|
||||
border-bottom-left-radius: 6px;
|
||||
box-shadow: 0 0 10px var(--tgc-dark-1);
|
||||
color: var(--tgc-white-1);
|
||||
@@ -244,7 +246,7 @@ function getAnnoTime(content: string): string | false {
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 0 4px;
|
||||
background: var(--tgc-od-orange);
|
||||
background: v-bind(idColor); /* stylelint-disable-line value-keyword-case */
|
||||
border-bottom-right-radius: 4px;
|
||||
box-shadow: 0 0 8px var(--tgc-dark-1);
|
||||
color: var(--tgc-white-1);
|
||||
|
||||
@@ -24,7 +24,7 @@ import type { MaterialInfo } from "@/pages/common/PageBagMaterial.vue";
|
||||
/** 组件参数 */
|
||||
type PbMaterialItemProps = {
|
||||
/** 数据库数据 */
|
||||
tb: TGApp.Sqlite.UserBag.TableMaterial;
|
||||
tb: TGApp.Sqlite.UserBag.MaterialTable;
|
||||
/** WIKI 数据 */
|
||||
info: TGApp.App.Material.WikiItem;
|
||||
/** 当前选中材料 */
|
||||
@@ -36,7 +36,7 @@ type PbMaterialItemEmits = (e: "select", v: MaterialInfo) => void;
|
||||
const props = defineProps<PbMaterialItemProps>();
|
||||
const emits = defineEmits<PbMaterialItemEmits>();
|
||||
|
||||
const item = shallowRef<TGApp.Sqlite.UserBag.TableMaterial>(props.tb);
|
||||
const item = shallowRef<TGApp.Sqlite.UserBag.MaterialTable>(props.tb);
|
||||
|
||||
function toMaterial(): void {
|
||||
emits("select", { tb: item.value, info: props.info });
|
||||
|
||||
@@ -37,7 +37,7 @@ async function loadData(): Promise<void> {
|
||||
const tmp: Array<PboConvertSource> = [];
|
||||
for (const item of props.data.source) {
|
||||
let cnt: number = 0;
|
||||
const dbGet = await TSUserBagMaterial.getMaterial(props.uid, item.id);
|
||||
const dbGet = await TSUserBagMaterial.getMaterial(props.uid, Number(item.id));
|
||||
if (dbGet.length > 0) cnt = dbGet[0].count;
|
||||
tmp.push({ ...item, local: cnt });
|
||||
}
|
||||
|
||||
@@ -78,7 +78,7 @@ const showRecord = computed<boolean>(() => !SKIP_BAG_TYPES.includes(props.data.i
|
||||
|
||||
onMounted(async () => (version.value = await getVersion()));
|
||||
|
||||
const dbInfo = shallowRef<TGApp.Sqlite.UserBag.TableMaterial>(props.data.tb);
|
||||
const dbInfo = shallowRef<TGApp.Sqlite.UserBag.MaterialTable>(props.data.tb);
|
||||
|
||||
watch(
|
||||
() => props.data.info,
|
||||
|
||||
@@ -36,7 +36,7 @@ const emits = defineEmits<ToPostCollectEmits>();
|
||||
const visible = defineModel<boolean>();
|
||||
const select = ref<string>();
|
||||
const submit = ref<boolean>(false);
|
||||
const collectList = shallowRef<Array<TGApp.Sqlite.UserCollection.UFCollection>>([]);
|
||||
const collectList = shallowRef<Array<TGApp.Sqlite.Collection.Collection>>([]);
|
||||
|
||||
watch(
|
||||
() => visible.value,
|
||||
|
||||
@@ -194,7 +194,7 @@ async function cycleGetDataGame(): Promise<void> {
|
||||
model.value = false;
|
||||
return;
|
||||
}
|
||||
const statusRaw: TGApp.Game.Login.StatusPayloadRaw = JSON.parse(res.payload.raw);
|
||||
const statusRaw: TGApp.Game.Login.StatPayloadRaw = JSON.parse(res.payload.raw);
|
||||
await showLoading.start("正在获取SToken");
|
||||
const stResp = await takumiReq.game.stoken(statusRaw);
|
||||
await showLoading.end();
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import TMiImg from "@comp/app/t-mi-img.vue";
|
||||
import bbsEnum from "@enum/bbs.js";
|
||||
import TSAvatarBirth from "@Sqlm/avatarBirth.js";
|
||||
import useAppStore from "@store/app.js";
|
||||
import { parseHtmlText } from "@utils/toolFunc.js";
|
||||
@@ -90,8 +91,8 @@ async function toBirth(data: TGApp.Archive.Birth.CalendarItem): Promise<void> {
|
||||
}
|
||||
|
||||
async function toNews(): Promise<void> {
|
||||
recentNewsType.value = "news";
|
||||
await router.push({ name: "资讯", params: { gid: 2, type: "news" } });
|
||||
recentNewsType.value = bbsEnum.post.newsType.NEWS;
|
||||
await router.push({ name: "资讯", params: { gid: 2 } });
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
|
||||
@@ -62,8 +62,8 @@ const { isLogin } = storeToRefs(useAppStore());
|
||||
const loading = ref<boolean>(false);
|
||||
const loadingProgress = ref<number>(0);
|
||||
const loadingText = ref<string>("");
|
||||
const gameAccounts = ref<TGApp.Sqlite.Account.Game[]>([]);
|
||||
const signAccounts = ref<SignAccount[]>([]);
|
||||
const gameAccounts = ref<Array<TGApp.Sqlite.Account.Game>>([]);
|
||||
const signAccounts = ref<Array<SignAccount>>([]);
|
||||
|
||||
watch(
|
||||
() => uid.value,
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
</div>
|
||||
<div class="subtitle">
|
||||
<!-- 处理幽境危战 -->
|
||||
<template v-if="props.pos.type === ActCalendarTypeEnum.HardChallenge">
|
||||
<template v-if="props.pos.type === gameEnum.actCalendarType.HardChallenge">
|
||||
<div class="challenge-append" title="点击前往幽境页面" @click="toChallenge()">
|
||||
<template v-if="!props.pos.hard_challenge_detail.is_unlock">
|
||||
<span>未解锁</span>
|
||||
@@ -37,13 +37,13 @@
|
||||
</div>
|
||||
</template>
|
||||
<!-- 处理真境剧诗 -->
|
||||
<template v-else-if="props.pos.type === ActCalendarTypeEnum.RoleCombat">
|
||||
<template v-else-if="props.pos.type === gameEnum.actCalendarType.RoleCombat">
|
||||
<div class="combat-append" title="点击前往剧诗页面" @click="toCombat()">
|
||||
<span>{{ getCombatStat(props.pos.role_combat_detail) }}</span>
|
||||
</div>
|
||||
</template>
|
||||
<!-- 处理深境螺旋 -->
|
||||
<template v-else-if="props.pos.type === ActCalendarTypeEnum.Tower">
|
||||
<template v-else-if="props.pos.type === gameEnum.actCalendarType.Tower">
|
||||
<div class="abyss-append" title="点击前往深渊页面" @click="toAbyss()">
|
||||
<template v-if="!props.pos.tower_detail.is_unlock">
|
||||
<span>未解锁</span>
|
||||
@@ -60,17 +60,17 @@
|
||||
</div>
|
||||
</template>
|
||||
<!-- 处理区域探索 -->
|
||||
<template v-else-if="props.pos.type === ActCalendarTypeEnum.Explore">
|
||||
<template v-else-if="props.pos.type === gameEnum.actCalendarType.Explore">
|
||||
<span>当前区域探索度: {{ props.pos.explore_detail.explore_percent }}%</span>
|
||||
</template>
|
||||
<!-- 处理双倍经验 -->
|
||||
<template v-else-if="props.pos.type === ActCalendarTypeEnum.Double">
|
||||
<template v-else-if="props.pos.type === gameEnum.actCalendarType.Double">
|
||||
<span>
|
||||
剩余双倍次数: {{ props.pos.double_detail.left }}/{{ props.pos.double_detail.total }}
|
||||
</span>
|
||||
</template>
|
||||
<!-- 处理立本活动 TODO:待完善 -->
|
||||
<template v-else-if="props.pos.type === ActCalendarTypeEnum.LiBen">
|
||||
<template v-else-if="props.pos.type === gameEnum.actCalendarType.LiBen">
|
||||
<span>当天{{ props.pos.liben_detail.status === 1 ? "未" : "已" }}兑换</span>
|
||||
<span>{{ props.pos.liben_detail.progress }}/{{ props.pos.liben_detail.total }}</span>
|
||||
<span>
|
||||
@@ -78,7 +78,7 @@
|
||||
</span>
|
||||
</template>
|
||||
<!-- 处理累登活动 TODO:待完善 -->
|
||||
<template v-else-if="props.pos.type === ActCalendarTypeEnum.SignIn">
|
||||
<template v-else-if="props.pos.type === gameEnum.actCalendarType.SignIn">
|
||||
<span>{{ props.pos.sign_in_detail.progress }}/{{ props.pos.sign_in_detail.total }}</span>
|
||||
<span>当天{{ props.pos.sign_in_detail.status === 1 ? "未领取" : "已领取" }}</span>
|
||||
</template>
|
||||
@@ -114,7 +114,7 @@
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import TMiImg from "@comp/app/t-mi-img.vue";
|
||||
import { ActCalendarTypeEnum } from "@enum/game.js";
|
||||
import gameEnum from "@enum/game.js";
|
||||
import { getHardChallengeDesc } from "@Sql/utils/transUserRecord.js";
|
||||
import { generateShareImg } from "@utils/TGShare.js";
|
||||
import { parseHtmlText, stamp2LastTime, timestampToDate } from "@utils/toolFunc.js";
|
||||
|
||||
@@ -6,11 +6,11 @@
|
||||
<div
|
||||
v-for="(item, index) in channelList"
|
||||
:key="index"
|
||||
class="toc-list-item"
|
||||
:class="props.gid === item.gid.toString() ? 'active' : ''"
|
||||
class="toc-list-item"
|
||||
@click="toChannel(item)"
|
||||
>
|
||||
<TMiImg :src="item.icon" alt="icon" :ori="true" />
|
||||
<TMiImg :ori="true" :src="item.icon" alt="icon" />
|
||||
<span class="toc-list-title">{{ item.title }}</span>
|
||||
<span class="toc-list-id">GID:{{ item.gid }}</span>
|
||||
</div>
|
||||
@@ -22,7 +22,8 @@
|
||||
import TMiImg from "@comp/app/t-mi-img.vue";
|
||||
import TOverlay from "@comp/app/t-overlay.vue";
|
||||
import showSnackbar from "@comp/func/snackbar.js";
|
||||
import useAppStore, { type NewsType } from "@store/app.js";
|
||||
import bbsEnum from "@enum/bbs.js";
|
||||
import useAppStore from "@store/app.js";
|
||||
import useBBSStore from "@store/bbs.js";
|
||||
import { storeToRefs } from "pinia";
|
||||
import { onMounted, shallowRef } from "vue";
|
||||
@@ -49,11 +50,11 @@ async function toChannel(item: ChannelItem): Promise<void> {
|
||||
}
|
||||
visible.value = false;
|
||||
let link = `/news/${item.gid}/{type}`;
|
||||
if (recentNewsType.value satisfies NewsType) {
|
||||
link = link.replace("{type}", recentNewsType.value);
|
||||
if (recentNewsType.value satisfies TGApp.BBS.Post.NewsTypeEnum) {
|
||||
link = link.replace("{type}", recentNewsType.value.toString());
|
||||
} else {
|
||||
link = link.replace("{type}", "notice");
|
||||
recentNewsType.value = "notice";
|
||||
link = link.replace("{type}", bbsEnum.post.newsType.NOTICE.toString());
|
||||
recentNewsType.value = bbsEnum.post.newsType.NOTICE;
|
||||
}
|
||||
window.location.href = link;
|
||||
}
|
||||
|
||||
@@ -61,10 +61,10 @@ const showOverlay = ref<boolean>(false);
|
||||
const isFinish = ref<boolean>(false);
|
||||
|
||||
const ncData = shallowRef<TGApp.App.NameCard.Item>();
|
||||
const achievements = shallowRef<Array<TGApp.Sqlite.Achievement.RenderAchi>>([]);
|
||||
const selectedAchi = shallowRef<TGApp.Sqlite.Achievement.RenderAchi>();
|
||||
const achievements = shallowRef<Array<TGApp.App.Achievement.RenderItem>>([]);
|
||||
const selectedAchi = shallowRef<TGApp.App.Achievement.RenderItem>();
|
||||
|
||||
const renderAchi = computed<Array<TGApp.Sqlite.Achievement.RenderAchi>>(() => {
|
||||
const renderAchi = computed<Array<TGApp.App.Achievement.RenderItem>>(() => {
|
||||
if (props.hideFin) return achievements.value.filter((a) => !a.isCompleted);
|
||||
return achievements.value;
|
||||
});
|
||||
@@ -116,7 +116,7 @@ async function loadAchi(): Promise<void> {
|
||||
showSnackbar.success(`已获取 ${achievements.value.length} 条成就数据`);
|
||||
}
|
||||
|
||||
function selectAchi(data: TGApp.Sqlite.Achievement.RenderAchi): void {
|
||||
function selectAchi(data: TGApp.App.Achievement.RenderItem): void {
|
||||
selectedAchi.value = data;
|
||||
showOverlay.value = true;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<TOverlay v-model="visible" blur-val="5px">
|
||||
<div class="tua-ao-container" v-if="props.data">
|
||||
<div v-if="props.data" class="tua-ao-container">
|
||||
<slot name="left"></slot>
|
||||
<div class="tua-ao-box">
|
||||
<div class="tua-ao-top">
|
||||
@@ -23,13 +23,13 @@
|
||||
<div class="tua-ao-mid-title">
|
||||
<span>原石奖励:</span>
|
||||
<span>{{ props.data.reward }}</span>
|
||||
<img src="/icon/material/201.webp" alt="原石" />
|
||||
<img alt="原石" src="/icon/material/201.webp" />
|
||||
</div>
|
||||
<div class="tua-ao-mid-title">
|
||||
<span>触发方式:</span>
|
||||
<span>{{ parseTriggerType() }}</span>
|
||||
</div>
|
||||
<div class="tua-ao-mid-item" v-for="item in props.data.trigger.task" :key="item.questId">
|
||||
<div v-for="item in props.data.trigger.task" :key="item.questId" class="tua-ao-mid-item">
|
||||
<v-icon size="16">mdi-alert-decagram</v-icon>
|
||||
<span class="tua-ao-click" @click="searchDirect(item.name)">{{ item.name }}</span>
|
||||
<span>({{ item.type }})</span>
|
||||
@@ -40,11 +40,11 @@
|
||||
<span>是否完成:</span>
|
||||
<span>{{ props.data.isCompleted ? "是" : "否" }}</span>
|
||||
</div>
|
||||
<div class="tua-ao-bottom-title" v-if="props.data.isCompleted">
|
||||
<div v-if="props.data.isCompleted" class="tua-ao-bottom-title">
|
||||
<span>完成时间:</span>
|
||||
<span>{{ props.data.completedTime }}</span>
|
||||
</div>
|
||||
<div class="tua-ao-bottom-title" v-if="props.data.progress > 0">
|
||||
<div v-if="props.data.progress > 0" class="tua-ao-bottom-title">
|
||||
<span>当前进度:</span>
|
||||
<span>{{ props.data.progress }}</span>
|
||||
</div>
|
||||
@@ -56,7 +56,7 @@
|
||||
<slot name="right"></slot>
|
||||
</div>
|
||||
</TOverlay>
|
||||
<VpOverlaySearch gid="2" v-model="showSearch" :keyword="search" />
|
||||
<VpOverlaySearch v-model="showSearch" :keyword="search" gid="2" />
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import TOverlay from "@comp/app/t-overlay.vue";
|
||||
@@ -68,7 +68,7 @@ import { ref } from "vue";
|
||||
|
||||
import { AppAchievementSeriesData } from "@/data/index.js";
|
||||
|
||||
type ToAchiInfoProps = { data: TGApp.Sqlite.Achievement.RenderAchi };
|
||||
type ToAchiInfoProps = { data: TGApp.App.Achievement.RenderItem };
|
||||
type ToAchiInfoEmits = (e: "select-series", v: number) => void;
|
||||
|
||||
const props = defineProps<ToAchiInfoProps>();
|
||||
|
||||
@@ -39,17 +39,17 @@ import { ref, toRaw, watch } from "vue";
|
||||
|
||||
import { AppAchievementSeriesData } from "@/data/index.js";
|
||||
|
||||
type TuaAchiProps = { modelValue: TGApp.Sqlite.Achievement.RenderAchi };
|
||||
type TuaAchiEmits = (e: "select-achi", data: TGApp.Sqlite.Achievement.RenderAchi) => void;
|
||||
type TuaAchiProps = { modelValue: TGApp.App.Achievement.RenderItem };
|
||||
type TuaAchiEmits = (e: "select-achi", data: TGApp.App.Achievement.RenderItem) => void;
|
||||
|
||||
const props = defineProps<TuaAchiProps>();
|
||||
const emits = defineEmits<TuaAchiEmits>();
|
||||
const model = defineModel<TGApp.Sqlite.Achievement.RenderAchi>();
|
||||
const data = ref<TGApp.Sqlite.Achievement.RenderAchi>(toRaw(props.modelValue));
|
||||
const model = defineModel<TGApp.App.Achievement.RenderItem>();
|
||||
const data = ref<TGApp.App.Achievement.RenderItem>(toRaw(props.modelValue));
|
||||
|
||||
watch(
|
||||
() => props.modelValue,
|
||||
(newVal: TGApp.Sqlite.Achievement.RenderAchi) => {
|
||||
(newVal: TGApp.App.Achievement.RenderItem) => {
|
||||
data.value = toRaw(newVal);
|
||||
},
|
||||
);
|
||||
|
||||
@@ -1,29 +1,30 @@
|
||||
<!-- 成就系列 -->
|
||||
<template>
|
||||
<div
|
||||
class="tuas-card"
|
||||
@click="selectSeries"
|
||||
v-if="data"
|
||||
:title="data.name"
|
||||
:class="{
|
||||
'tuas-selected': props.cur === props.series,
|
||||
'tuas-radius': showCard,
|
||||
}"
|
||||
:title="data.name"
|
||||
class="tuas-card"
|
||||
@click="selectSeries"
|
||||
>
|
||||
<div class="tuas-version">v{{ data.version }}</div>
|
||||
<div class="tuas-reward" v-if="showCard">
|
||||
<div v-if="showCard" class="tuas-reward">
|
||||
<img
|
||||
:class="{ finish: progress === 100 }"
|
||||
alt="card"
|
||||
:src="`/WIKI/nameCard/bg/${data.card}.webp`"
|
||||
alt="card"
|
||||
/>
|
||||
</div>
|
||||
<div class="tuas-icon">
|
||||
<img alt="icon" :src="`/icon/achievement/${data.icon}.webp`" />
|
||||
<img :src="`/icon/achievement/${data.icon}.webp`" alt="icon" />
|
||||
<v-progress-circular
|
||||
class="progress"
|
||||
bg-color="var(--tgc-od-white)"
|
||||
color="var(--tgc-yellow-2)"
|
||||
:model-value="progress"
|
||||
bg-color="var(--tgc-od-white)"
|
||||
class="progress"
|
||||
color="var(--tgc-yellow-2)"
|
||||
/>
|
||||
</div>
|
||||
<div class="tuas-content">
|
||||
@@ -47,7 +48,7 @@ let achiListener: UnlistenFn | null = null;
|
||||
const props = defineProps<TuaSeriesProps>();
|
||||
const emits = defineEmits<TuaSeriesEmits>();
|
||||
|
||||
const overview = shallowRef<TGApp.Sqlite.Achievement.Overview>({ fin: 0, total: 0 });
|
||||
const overview = shallowRef<TGApp.App.Achievement.Overview>({ fin: 0, total: 0 });
|
||||
const data = computed<TGApp.App.Achievement.Series | undefined>(() =>
|
||||
AppAchievementSeriesData.find((s) => s.id === props.series),
|
||||
);
|
||||
@@ -109,6 +110,7 @@ function selectSeries(): void {
|
||||
justify-content: flex-start;
|
||||
padding: 8px;
|
||||
border-radius: 4px;
|
||||
background: var(--app-page-bg);
|
||||
color: var(--box-text-1);
|
||||
column-gap: 8px;
|
||||
cursor: pointer;
|
||||
|
||||
@@ -63,7 +63,7 @@ import TuaRelicBox from "./tua-relic-box.vue";
|
||||
|
||||
type fixedLenArr<T, N extends number> = [T, ...Array<T>] & { length: N };
|
||||
type AvatarRelics = fixedLenArr<TGApp.Game.Avatar.Relic | false, 5>;
|
||||
type TuaAvatarBoxProps = { modelValue: TGApp.Sqlite.Character.UserRole };
|
||||
type TuaAvatarBoxProps = { modelValue: TGApp.Sqlite.Character.TableTrans };
|
||||
|
||||
const props = defineProps<TuaAvatarBoxProps>();
|
||||
const userStore = useUserStore();
|
||||
@@ -121,7 +121,7 @@ const nameCard = computed<string>(() => {
|
||||
|
||||
function getWeaponTitle(): string {
|
||||
const weapon = props.modelValue.weapon;
|
||||
const title: string[] = [];
|
||||
const title: Array<string> = [];
|
||||
title.push(`${weapon.type_name} - ${weapon.name}`);
|
||||
title.push(`${weapon.rarity}星 精炼${weapon.affix_level} Lv.${weapon.level}`);
|
||||
const propMain = userStore.getProp(weapon.main_property.property_type);
|
||||
|
||||
@@ -90,7 +90,7 @@ import TuaDcWeapon from "./tua-dc-weapon.vue";
|
||||
|
||||
type fixedLenArr<T, N extends number> = [T, ...Array<T>] & { length: N };
|
||||
type RelicList = fixedLenArr<TGApp.Game.Avatar.Relic | false, 5>;
|
||||
type TuaDetailCardProps = { modelValue: TGApp.Sqlite.Character.UserRole };
|
||||
type TuaDetailCardProps = { modelValue: TGApp.Sqlite.Character.TableTrans };
|
||||
|
||||
const props = defineProps<TuaDetailCardProps>();
|
||||
const userStore = useUserStore();
|
||||
|
||||
@@ -55,12 +55,12 @@ import { computed, ref, watch } from "vue";
|
||||
import TuaDetailCard from "./tua-detail-card.vue";
|
||||
|
||||
type TuaDetailOverlayProps = {
|
||||
avatar: TGApp.Sqlite.Character.UserRole;
|
||||
avatars: Array<TGApp.Sqlite.Character.UserRole>;
|
||||
avatar: TGApp.Sqlite.Character.TableTrans;
|
||||
avatars: Array<TGApp.Sqlite.Character.TableTrans>;
|
||||
};
|
||||
type TuaDetailOverlayEmits = {
|
||||
(e: "toNext", val: boolean): void;
|
||||
(e: "toAvatar", val: TGApp.Sqlite.Character.UserRole): void;
|
||||
(e: "toAvatar", val: TGApp.Sqlite.Character.TableTrans): void;
|
||||
};
|
||||
|
||||
const props = defineProps<TuaDetailOverlayProps>();
|
||||
|
||||
@@ -46,7 +46,7 @@ function getRelicPosName(): string {
|
||||
function getRelicTitle(): string {
|
||||
const posName = getRelicPosName();
|
||||
if (props.modelValue === false) return `${posName}:未装备`;
|
||||
const relicProps: string[] = [];
|
||||
const relicProps: Array<string> = [];
|
||||
const mainProp = userStore.getProp(props.modelValue.main_property.property_type);
|
||||
relicProps.push(
|
||||
`主词条:${mainProp === false ? "未知属性" : mainProp.name} ${props.modelValue.main_property.value}`,
|
||||
|
||||
@@ -51,7 +51,7 @@ import DucDetailOlt from "./duc-detail-olt.vue";
|
||||
import DucDetailOrt from "./duc-detail-ort.vue";
|
||||
import DucDetailRelic from "./duc-detail-relic.vue";
|
||||
|
||||
type DucDetailOverlayProps = { modelValue: TGApp.Sqlite.Character.UserRole };
|
||||
type DucDetailOverlayProps = { modelValue: TGApp.Sqlite.Character.TableTrans };
|
||||
type fixedLenArr<T, N extends number> = [T, ...Array<T>] & { length: N };
|
||||
type RelicList = fixedLenArr<TGApp.Game.Avatar.Relic | false, 5>;
|
||||
|
||||
|
||||
@@ -84,7 +84,7 @@ import TucDetailDescWeapon from "./tuc-detail-desc-weapon.vue";
|
||||
import TucDetailItemBox from "./tuc-detail-itembox.vue";
|
||||
import TucDetailRelic from "./tuc-detail-relic.vue";
|
||||
|
||||
type ToUcDetailProps = { modelValue: TGApp.Sqlite.Character.UserRole };
|
||||
type ToUcDetailProps = { modelValue: TGApp.Sqlite.Character.TableTrans };
|
||||
type ToUcDetailSelect = { type: "命座" | "武器" | "圣遗物"; pos: number };
|
||||
type fixedLenArr<T, N extends number> = [T, ...Array<T>] & { length: N };
|
||||
type RelicList = fixedLenArr<TGApp.Game.Avatar.Relic | false, 5>;
|
||||
|
||||
@@ -21,7 +21,7 @@ import { computed } from "vue";
|
||||
|
||||
import { AppGachaBData } from "@/data/index.js";
|
||||
|
||||
export type GbrDataLineProps = { data: TGApp.Sqlite.GachaRecords.TableGachaB; count: number };
|
||||
export type GbrDataLineProps = { data: TGApp.Sqlite.Gacha.GachaB; count: number };
|
||||
|
||||
const props = defineProps<GbrDataLineProps>();
|
||||
const hint = getEndHint();
|
||||
@@ -47,7 +47,7 @@ const progressColor = computed<string>(() => {
|
||||
const progressWidth = computed<string>(() => {
|
||||
let final = 10;
|
||||
if (props.data.rank === "5") {
|
||||
if (props.data.gachaType === "302") final = 80;
|
||||
if (props.data.gachaType === "2000") final = 80;
|
||||
else final = 90;
|
||||
} else if (props.data.rank === "4") final = 10;
|
||||
else return "0%";
|
||||
|
||||
@@ -117,7 +117,7 @@ import GbrDataLine, { type GbrDataLineProps } from "./gbr-data-line.vue";
|
||||
|
||||
type GachaDataViewProps = {
|
||||
dataType: "normal" | "boy" | "girl";
|
||||
dataVal: Array<TGApp.Sqlite.GachaRecords.TableGachaB>;
|
||||
dataVal: Array<TGApp.Sqlite.Gacha.GachaB>;
|
||||
};
|
||||
|
||||
const props = defineProps<GachaDataViewProps>();
|
||||
@@ -248,7 +248,7 @@ function loadData(): void {
|
||||
reset3count.value = currentReset3;
|
||||
|
||||
// Helper function to check if item should be displayed based on dataType
|
||||
function shouldDisplay(item: TGApp.Sqlite.GachaRecords.TableGachaB): boolean {
|
||||
function shouldDisplay(item: TGApp.Sqlite.Gacha.GachaB): boolean {
|
||||
if (props.dataType === "normal") return true;
|
||||
if (props.dataType === "boy") {
|
||||
return item.opGachaType === "20011" || item.opGachaType === "20012";
|
||||
|
||||
@@ -10,13 +10,13 @@ import { computed } from "vue";
|
||||
|
||||
import GbrDataView from "./gbr-data-view.vue";
|
||||
|
||||
type GachaOverviewProps = { modelValue: Array<TGApp.Sqlite.GachaRecords.TableGachaB> };
|
||||
type GachaOverviewProps = { modelValue: Array<TGApp.Sqlite.Gacha.GachaB> };
|
||||
|
||||
const props = defineProps<GachaOverviewProps>();
|
||||
const normalData = computed<Array<TGApp.Sqlite.GachaRecords.TableGachaB>>(() =>
|
||||
const normalData = computed<Array<TGApp.Sqlite.Gacha.GachaB>>(() =>
|
||||
props.modelValue.filter((item) => item.gachaType === "1000"),
|
||||
);
|
||||
const eventData = computed<Array<TGApp.Sqlite.GachaRecords.TableGachaB>>(() =>
|
||||
const eventData = computed<Array<TGApp.Sqlite.Gacha.GachaB>>(() =>
|
||||
props.modelValue.filter((item) => item.gachaType === "2000"),
|
||||
);
|
||||
</script>
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
<script lang="ts" setup>
|
||||
import { AppGachaBData } from "@/data/index.js";
|
||||
|
||||
type GroTableProps = { modelValue: Array<TGApp.Sqlite.GachaRecords.TableGachaB> };
|
||||
type GroTableProps = { modelValue: Array<TGApp.Sqlite.Gacha.GachaB> };
|
||||
|
||||
const props = defineProps<GroTableProps>();
|
||||
|
||||
@@ -40,6 +40,7 @@ const headers = <const>[
|
||||
{ title: "星级", align: "center", key: "rank" },
|
||||
];
|
||||
|
||||
// TODO: 枚举类
|
||||
function getPool(type: string) {
|
||||
switch (type) {
|
||||
case "1000":
|
||||
|
||||
@@ -85,8 +85,8 @@ async function getCalendarOptions(): Promise<EChartsOption> {
|
||||
// 获取年份
|
||||
const yearsSet = new Set(Object.keys(records).map((v) => v.split("-")[0]));
|
||||
|
||||
function getYearData(year: string): [string, number][] {
|
||||
const res: [string, number][] = [];
|
||||
function getYearData(year: string): Array<[string, number]> {
|
||||
const res: Array<[string, number]> = [];
|
||||
for (const key in records) {
|
||||
if (key.startsWith(year)) res.push([key, records[key].length]);
|
||||
}
|
||||
|
||||
@@ -99,7 +99,7 @@ async function getStackBarOptions(): Promise<EChartsOption> {
|
||||
temp4.push(star4);
|
||||
temp3.push(star3);
|
||||
}
|
||||
const series: BarSeriesOption[] = [
|
||||
const series: Array<BarSeriesOption> = [
|
||||
{ data: temp5, type: "bar", stack: "a", name: "五星数量" },
|
||||
{ data: temp4, type: "bar", stack: "a", name: "四星数量" },
|
||||
{ data: temp3, type: "bar", stack: "a", name: "三星数量" },
|
||||
|
||||
@@ -24,7 +24,7 @@ import { computed } from "vue";
|
||||
*/
|
||||
export type GroDataLineProps = {
|
||||
/* 原始数据 */
|
||||
data: TGApp.Sqlite.GachaRecords.TableGacha;
|
||||
data: TGApp.Sqlite.Gacha.Gacha;
|
||||
/* 抽数 */
|
||||
count: number;
|
||||
/* 是否是 Up */
|
||||
|
||||
@@ -112,7 +112,7 @@ import { AppGachaData } from "@/data/index.js";
|
||||
|
||||
type GachaDataViewProps = {
|
||||
dataType: "new" | "avatar" | "weapon" | "normal" | "mix";
|
||||
dataVal: Array<TGApp.Sqlite.GachaRecords.TableGacha>;
|
||||
dataVal: Array<TGApp.Sqlite.Gacha.Gacha>;
|
||||
};
|
||||
|
||||
const props = defineProps<GachaDataViewProps>();
|
||||
@@ -240,10 +240,10 @@ function getStar5Avg(): string {
|
||||
|
||||
/**
|
||||
* 判断是否是Up物品
|
||||
* @param {TGApp.Sqlite.GachaRecords.TableGacha} item 原始数据
|
||||
* @param {TGApp.Sqlite.Gacha.Gacha} item 原始数据
|
||||
* @returns {boolean|undefined}
|
||||
*/
|
||||
function checkIsUp(item: TGApp.Sqlite.GachaRecords.TableGacha): boolean | undefined {
|
||||
function checkIsUp(item: TGApp.Sqlite.Gacha.Gacha): boolean | undefined {
|
||||
// 新手池和常驻池不存在UP概念
|
||||
if (item.gachaType === "100" || item.gachaType === "200") return undefined;
|
||||
const itemTime = new Date(item.time).getTime();
|
||||
|
||||
@@ -37,24 +37,24 @@ import { computed } from "vue";
|
||||
|
||||
import GroDataView from "./gro-data-view.vue";
|
||||
|
||||
type GachaOverviewProps = { modelValue: Array<TGApp.Sqlite.GachaRecords.TableGacha> };
|
||||
type GachaOverviewProps = { modelValue: Array<TGApp.Sqlite.Gacha.Gacha> };
|
||||
|
||||
const props = defineProps<GachaOverviewProps>();
|
||||
const swiperModules = [Autoplay, A11y, Pagination];
|
||||
|
||||
const newData = computed<Array<TGApp.Sqlite.GachaRecords.TableGacha>>(() =>
|
||||
const newData = computed<Array<TGApp.Sqlite.Gacha.Gacha>>(() =>
|
||||
props.modelValue.filter((item) => item.uigfType === "100"),
|
||||
);
|
||||
const normalData = computed<Array<TGApp.Sqlite.GachaRecords.TableGacha>>(() =>
|
||||
const normalData = computed<Array<TGApp.Sqlite.Gacha.Gacha>>(() =>
|
||||
props.modelValue.filter((item) => item.uigfType === "200"),
|
||||
);
|
||||
const avatarData = computed<Array<TGApp.Sqlite.GachaRecords.TableGacha>>(() =>
|
||||
const avatarData = computed<Array<TGApp.Sqlite.Gacha.Gacha>>(() =>
|
||||
props.modelValue.filter((item) => item.uigfType === "301"),
|
||||
);
|
||||
const weaponData = computed<Array<TGApp.Sqlite.GachaRecords.TableGacha>>(() =>
|
||||
const weaponData = computed<Array<TGApp.Sqlite.Gacha.Gacha>>(() =>
|
||||
props.modelValue.filter((item) => item.uigfType === "302"),
|
||||
);
|
||||
const mixData = computed<Array<TGApp.Sqlite.GachaRecords.TableGacha>>(() =>
|
||||
const mixData = computed<Array<TGApp.Sqlite.Gacha.Gacha>>(() =>
|
||||
props.modelValue.filter((item) => item.uigfType === "500"),
|
||||
);
|
||||
</script>
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
</v-data-table>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
type GroTableProps = { modelValue: Array<TGApp.Sqlite.GachaRecords.TableGacha> };
|
||||
type GroTableProps = { modelValue: Array<TGApp.Sqlite.Gacha.Gacha> };
|
||||
|
||||
const props = defineProps<GroTableProps>();
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<template>
|
||||
<div class="user-gacha-history-card-comp">
|
||||
<img
|
||||
class="ug-his-banner"
|
||||
:src="props.pool.banner"
|
||||
alt="banner"
|
||||
class="ug-his-banner"
|
||||
@click="createPost(pool.postId)"
|
||||
/>
|
||||
<div class="ug-his-info">
|
||||
@@ -37,6 +37,7 @@
|
||||
<script lang="ts" setup>
|
||||
import TItemBox, { type TItemBoxData } from "@comp/app/t-itemBox.vue";
|
||||
import showSnackbar from "@comp/func/snackbar.js";
|
||||
import gameEnum from "@enum/game.js";
|
||||
import { createPost } from "@utils/TGWindow.js";
|
||||
import { getWikiBrief, timestampToDate } from "@utils/toolFunc.js";
|
||||
import { useRouter } from "vue-router";
|
||||
@@ -46,6 +47,17 @@ type UgHisCardProps = { pool: TGApp.App.Gacha.PoolItem };
|
||||
const router = useRouter();
|
||||
const props = defineProps<UgHisCardProps>();
|
||||
|
||||
const gachaTypeList: ReadonlyArray<TGApp.App.Gacha.PoolGachaType> = [
|
||||
TGApp.Game.Gacha.GachaType.AvatarUp,
|
||||
TGApp.Game.Gacha.GachaType.AvatarUp2,
|
||||
TGApp.Game.Gacha.GachaType.WeaponUp,
|
||||
TGApp.Game.Gacha.GachaType.MixUp,
|
||||
];
|
||||
|
||||
function isPoolGachaType(x: string): x is TGApp.App.Gacha.PoolGachaType {
|
||||
return (<ReadonlyArray<string>>gachaTypeList).includes(x);
|
||||
}
|
||||
|
||||
async function toWiki(id: number): Promise<void> {
|
||||
const find = getWikiBrief(id);
|
||||
if (!find) {
|
||||
@@ -59,19 +71,23 @@ async function toWiki(id: number): Promise<void> {
|
||||
await router.push({ name: "武器图鉴", params: { id: id.toString() } });
|
||||
}
|
||||
|
||||
function getType(type: TGApp.App.Gacha.WishType): string {
|
||||
switch (type) {
|
||||
case 301:
|
||||
return "角色活动祈愿";
|
||||
case 400:
|
||||
return "角色活动祈愿2";
|
||||
case 302:
|
||||
return "武器活动祈愿";
|
||||
case 500:
|
||||
return "集录祈愿";
|
||||
default:
|
||||
return `未知类型 ${type}`;
|
||||
function getType(type: number): string {
|
||||
const typeStr = type.toString();
|
||||
if (isPoolGachaType(typeStr)) {
|
||||
switch (typeStr) {
|
||||
case gameEnum.gachaType.AvatarUp:
|
||||
return "角色活动祈愿";
|
||||
case gameEnum.gachaType.AvatarUp2:
|
||||
return "角色活动祈愿2";
|
||||
case gameEnum.gachaType.WeaponUp:
|
||||
return "武器活动祈愿";
|
||||
case gameEnum.gachaType.MixUp:
|
||||
return "集录祈愿";
|
||||
default:
|
||||
return `未知类型 ${type}`;
|
||||
}
|
||||
}
|
||||
return `未知类型 ${type}`;
|
||||
}
|
||||
|
||||
function getTimeStr(pool: TGApp.App.Gacha.PoolItem): string {
|
||||
|
||||
@@ -162,7 +162,7 @@ async function handleExportData(): Promise<void> {
|
||||
data.value = tmpData;
|
||||
}
|
||||
|
||||
function parseDataRaw(data: TGApp.Sqlite.GachaRecords.TableGacha[]): UgoUidItem {
|
||||
function parseDataRaw(data: Array<TGApp.Sqlite.Gacha.Gacha>): UgoUidItem {
|
||||
const timeList = data.map((item) => new Date(item.time).getTime());
|
||||
return {
|
||||
uid: data[0].uid,
|
||||
|
||||
@@ -1,19 +1,22 @@
|
||||
<template>
|
||||
<div v-if="modelValue.length === 0">暂无数据</div>
|
||||
<div v-if="worlds.length === 0">暂无数据</div>
|
||||
<div v-else class="tur-wg-box">
|
||||
<TurWorldSub v-for="area in modelValue" :key="area.id" :data="area" />
|
||||
<TurWorldSub v-for="world in worlds" :key="world.id" :world />
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import TurWorldSub from "./tur-world-sub.vue";
|
||||
|
||||
defineProps<{ modelValue: Array<TGApp.Sqlite.Record.WorldExplore> }>();
|
||||
type TurWorldGridProps = { worlds: Array<TGApp.Sqlite.Record.WorldExplore> };
|
||||
|
||||
defineProps<TurWorldGridProps>();
|
||||
</script>
|
||||
<style lang="css" scoped>
|
||||
.tur-wg-box {
|
||||
position: relative;
|
||||
display: grid;
|
||||
width: 100%;
|
||||
gap: 8px;
|
||||
grid-template-columns: repeat(3, 0.33fr);
|
||||
grid-template-columns: repeat(3, 0.34fr);
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,24 +1,25 @@
|
||||
<!-- 单地区探索数据 -->
|
||||
<template>
|
||||
<div class="tur-ws-box">
|
||||
<div class="tur-ws-bg">
|
||||
<TMiImg :ori="true" :src="data.bg" alt="bg" />
|
||||
<TMiImg :ori="true" :src="world.bg" alt="bg" />
|
||||
</div>
|
||||
<div class="tur-ws-icon">
|
||||
<TMiImg :src="icon" :ori="true" alt="icon" />
|
||||
<TMiImg :src="world.iconLight" :ori="true" alt="icon" />
|
||||
</div>
|
||||
<div class="tur-ws-content">
|
||||
<div class="tur-ws-title">
|
||||
<span>{{ data.name }}</span>
|
||||
<span v-if="data.offerings?.length === 1" class="tur-ws-sub">
|
||||
<img :src="data.offerings[0].icon" alt="offer" />
|
||||
<span>{{ data.offerings[0].name }}-</span>
|
||||
<span>{{ data.offerings[0].level }}</span>
|
||||
<span>{{ world.name }}</span>
|
||||
<span v-if="world.offerings?.length === 1" class="tur-ws-sub">
|
||||
<img :src="world.offerings[0].icon" alt="offer" />
|
||||
<span>{{ world.offerings[0].name }}-</span>
|
||||
<span>{{ world.offerings[0].level }}</span>
|
||||
<span>级</span>
|
||||
</span>
|
||||
</div>
|
||||
<div class="tur-ws-offerings" v-if="data.offerings && data.offerings.length > 1">
|
||||
<div class="tur-ws-offerings" v-if="world.offerings && world.offerings.length > 1">
|
||||
<span
|
||||
v-for="(offer, idx) in data.offerings"
|
||||
v-for="(offer, idx) in world.offerings"
|
||||
:key="idx"
|
||||
class="tur-ws-sub"
|
||||
:title="offer.name + '-' + offer.level + '级'"
|
||||
@@ -28,18 +29,18 @@
|
||||
<span>级</span>
|
||||
</span>
|
||||
</div>
|
||||
<div v-if="data.children.length === 0" class="tur-ws-sub">
|
||||
<div v-if="world.children.length === 0" class="tur-ws-sub">
|
||||
<span>探索度:</span>
|
||||
<span>{{ data.exploration / 10 }}</span>
|
||||
<span>{{ world.exploration / 10 }}</span>
|
||||
<span>%</span>
|
||||
</div>
|
||||
<div v-else>
|
||||
<div v-if="data.exploration !== 0" class="tur-ws-sub">
|
||||
<span>{{ data.name }}探索度:</span>
|
||||
<span>{{ data.exploration / 10 }}</span>
|
||||
<div v-if="world.exploration !== 0" class="tur-ws-sub">
|
||||
<span>{{ world.name }}探索度:</span>
|
||||
<span>{{ world.exploration / 10 }}</span>
|
||||
<span>%</span>
|
||||
</div>
|
||||
<div v-for="item in data.children" :key="item.id" class="tur-ws-sub">
|
||||
<div v-for="item in world.children" :key="item.id" class="tur-ws-sub">
|
||||
<span>{{ item.name }}探索度:</span>
|
||||
<span>{{ item.exploration / 10 }}</span>
|
||||
<span>%</span>
|
||||
@@ -47,14 +48,14 @@
|
||||
</div>
|
||||
<div
|
||||
v-if="
|
||||
data.area_exploration_list &&
|
||||
data.area_exploration_list.length > 0 &&
|
||||
data.exploration < 1000
|
||||
world.area_exploration_list &&
|
||||
world.area_exploration_list.length > 0 &&
|
||||
world.exploration < 1000
|
||||
"
|
||||
class="tur-ws-areas"
|
||||
>
|
||||
<span
|
||||
v-for="area in data.area_exploration_list.filter((i) => i.exploration_percentage < 1000)"
|
||||
v-for="area in world.area_exploration_list.filter((i) => i.exploration_percentage < 1000)"
|
||||
:key="area.name"
|
||||
class="tur-ws-sub"
|
||||
>
|
||||
@@ -63,9 +64,9 @@
|
||||
<span>%</span>
|
||||
</span>
|
||||
</div>
|
||||
<div v-if="data.reputation" class="tur-ws-sub">
|
||||
<div v-if="world.reputation" class="tur-ws-sub">
|
||||
<span>声望等级:</span>
|
||||
<span>{{ data.reputation }}</span>
|
||||
<span>{{ world.reputation }}</span>
|
||||
<span>级</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -77,19 +78,16 @@ import useAppStore from "@store/app.js";
|
||||
import { storeToRefs } from "pinia";
|
||||
import { computed } from "vue";
|
||||
|
||||
type TurWorldSubProps = { data: TGApp.Sqlite.Record.WorldExplore };
|
||||
type TurWorldSubProps = { world: TGApp.Sqlite.Record.WorldExplore };
|
||||
|
||||
const { theme } = storeToRefs(useAppStore());
|
||||
const props = defineProps<TurWorldSubProps>();
|
||||
|
||||
defineProps<TurWorldSubProps>();
|
||||
|
||||
const imgFilter = computed<string>(() => {
|
||||
if (theme.value === "dark") return "none";
|
||||
return "invert(0.75)";
|
||||
});
|
||||
const icon = computed<string>(() => {
|
||||
if (props.data.icon) return props.data.icon;
|
||||
return props.data.iconLight;
|
||||
});
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.tur-ws-box {
|
||||
|
||||
@@ -254,7 +254,7 @@ async function refreshState(ck: TGApp.App.Account.Cookie): Promise<void> {
|
||||
}
|
||||
}
|
||||
|
||||
async function trySign(ac: SignAccount[], ck: TGApp.App.Account.Cookie): Promise<void> {
|
||||
async function trySign(ac: Array<SignAccount>, ck: TGApp.App.Account.Cookie): Promise<void> {
|
||||
const cookie = { cookie_token: ck.cookie_token, account_id: ck.account_id };
|
||||
const ckSign = { stoken: ck.stoken, stuid: ck.stuid, mid: ck.mid };
|
||||
for (const item of ac) {
|
||||
|
||||
@@ -103,7 +103,7 @@ function miniImgUrl(): string {
|
||||
}
|
||||
|
||||
function getImageTitle(): string {
|
||||
const res: string[] = [];
|
||||
const res: Array<string> = [];
|
||||
if (props.data.attributes) {
|
||||
res.push(`宽度:${props.data.attributes.width}px`);
|
||||
res.push(`高度:${props.data.attributes.height}px`);
|
||||
|
||||
@@ -57,11 +57,11 @@ type TpVillaCard = {
|
||||
owner_nickname: string;
|
||||
owner_avatar_url: string;
|
||||
villa_introduce?: string;
|
||||
tag_list?: string[];
|
||||
tag_list?: Array<string>;
|
||||
villa_member_num: string;
|
||||
is_official?: boolean;
|
||||
is_available: boolean;
|
||||
hot_member_avatar?: string[];
|
||||
hot_member_avatar?: Array<string>;
|
||||
hot_room?: VillaRoom;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -78,7 +78,7 @@ onMounted(async () => {
|
||||
const voteInfo = await ApiHubReq.vote.info(vote.id, vote.uid);
|
||||
console.log(`[${props.data.insert.vote.id}]voteInfo:`, voteInfo);
|
||||
const voteResult = await ApiHubReq.vote.result(vote.id, vote.uid);
|
||||
console.log("[${props.data.insert.vote.id}]voteResult:", voteResult);
|
||||
console.log(`[${props.data.insert.vote.id}]voteResult:`, voteResult);
|
||||
votes.value = {
|
||||
title: voteInfo.title,
|
||||
count: voteResult.user_cnt,
|
||||
|
||||
@@ -26,7 +26,7 @@ type TbCollectProps = { modelValue: number; data?: TGApp.BBS.Post.FullData };
|
||||
const props = defineProps<TbCollectProps>();
|
||||
const isCollected = ref<boolean>(false);
|
||||
const showEdit = ref<boolean>(false);
|
||||
const collect = shallowRef<Array<TGApp.Sqlite.UserCollection.UFMap>>([]);
|
||||
const collect = shallowRef<Array<TGApp.Sqlite.Collection.PcMap>>([]);
|
||||
|
||||
onBeforeMount(async () => await refresh());
|
||||
|
||||
|
||||
@@ -46,8 +46,8 @@ const props = defineProps<ToPostCollectProps>();
|
||||
const emits = defineEmits<ToPostCollectEmits>();
|
||||
const visible = defineModel<boolean>();
|
||||
const submit = ref<boolean>(false);
|
||||
const collectList = shallowRef<Array<TGApp.Sqlite.UserCollection.UFCollection>>([]);
|
||||
const postCollect = shallowRef<Array<TGApp.Sqlite.UserCollection.UFMap>>([]);
|
||||
const collectList = shallowRef<Array<TGApp.Sqlite.Collection.Collection>>([]);
|
||||
const postCollect = shallowRef<Array<TGApp.Sqlite.Collection.PcMap>>([]);
|
||||
const selectList = shallowRef<Array<string>>([]);
|
||||
|
||||
watch(
|
||||
@@ -72,7 +72,7 @@ async function freshData(): Promise<void> {
|
||||
}
|
||||
}
|
||||
|
||||
async function deleteCollect(item: TGApp.Sqlite.UserCollection.UFCollection): Promise<void> {
|
||||
async function deleteCollect(item: TGApp.Sqlite.Collection.Collection): Promise<void> {
|
||||
const delCheck = await showDialog.check("确定删除分类?", "该分类若有帖子,则会变为未分类");
|
||||
if (!delCheck) {
|
||||
showSnackbar.cancel("取消删除");
|
||||
|
||||
Reference in New Issue
Block a user