♻️ showConfirm重构

This commit is contained in:
目棃
2024-11-15 15:47:40 +08:00
parent 76f8bc3c16
commit 36b0d198a9
30 changed files with 650 additions and 804 deletions

View File

@@ -21,7 +21,7 @@ import { useRouter } from "vue-router";
import TBackTop from "./components/app/t-backTop.vue";
import TSidebar from "./components/app/t-sidebar.vue";
import showConfirm from "./components/func/confirm.js";
import showDialog from "./components/func/dialog.js";
import showSnackbar from "./components/func/snackbar.js";
import TGSqlite from "./plugins/Sqlite/index.js";
import TSUserAccount from "./plugins/Sqlite/modules/userAccount.js";
@@ -247,11 +247,8 @@ async function checkUpdate(): Promise<void> {
const needUpdate = await TGSqlite.checkUpdate();
if (needUpdate && isProdEnv) {
await TGLogger.Info("[App][checkUpdate] 检测到版本更新!");
const confirm = await showConfirm({
title: "检测到版本更新",
text: "是否更新数据库数据?(请确保成就数据已导出)",
});
if (!confirm) {
const updateCheck = await showDialog.check("检测到版本更新", "是否更新数据库数据?");
if (!updateCheck) {
showSnackbar.error("请到设置页手动更新数据库!", 3000);
return;
}

View File

@@ -75,7 +75,7 @@ import TGSqlite from "../../plugins/Sqlite/index.js";
import { useAppStore } from "../../store/modules/app.js";
import { backUpUserData } from "../../utils/dataBS.js";
import TGShell from "../../utils/TGShell.js";
import showConfirm from "../func/confirm.js";
import showDialog from "../func/dialog.js";
import showSnackbar from "../func/snackbar.js";
const appStore = storeToRefs(useAppStore());
@@ -100,8 +100,8 @@ onMounted(async () => {
async function confirmCUD(): Promise<void> {
const oriDir = appStore.userDir.value;
const check = await showConfirm({ title: "确认修改用户数据路径吗?" });
if (!check) {
const changeCheck = await showDialog.check("确认修改用户数据路径吗?");
if (!changeCheck) {
showSnackbar.cancel("已取消修改");
return;
}
@@ -122,8 +122,8 @@ async function confirmCUD(): Promise<void> {
await TGSqlite.saveAppData("userDir", dir);
await backUpUserData(dir);
showSnackbar.success("已修改用户数据路径!");
const confirm = await showConfirm({ title: "是否删除原用户数据目录?", text: "删除后不可恢复!" });
if (confirm) {
const delCheck = await showDialog.check("是否删除原用户数据目录?");
if (delCheck) {
await remove(oriDir, { recursive: true });
showSnackbar.success("已删除原用户数据目录!");
}
@@ -136,11 +136,11 @@ async function confirmCGD(): Promise<void> {
return;
}
const oriEmpty = appStore.gameDir.value === "未设置";
const editConfirm = await showConfirm({
title: oriEmpty ? "确认设置目录?" : "确认修改目录?",
text: oriEmpty ? "请选择启动器所在目录" : `当前:${appStore.gameDir.value}`,
});
if (!editConfirm) {
const editCheck = await showDialog.check(
oriEmpty ? "确认设置游戏目录?" : "确认修改游戏目录?",
oriEmpty ? "请选择启动器所在目录" : `当前:${appStore.gameDir.value}`,
);
if (!editCheck) {
showSnackbar.cancel(oriEmpty ? "已取消设置" : "已取消修改");
return;
}
@@ -175,11 +175,8 @@ function isOverWeek(date: string): boolean {
}
async function confirmCLD(): Promise<void> {
const check = await showConfirm({
title: "确认清理日志文件吗?",
text: "将保留一周内的日志文件",
});
if (!check) {
const delCheck = await showDialog.check("确认清理日志文件吗?", "将保留一周内的日志文件");
if (!delCheck) {
showSnackbar.cancel("已取消清理");
return;
}

View File

@@ -112,7 +112,7 @@ import { useAppStore } from "../../store/modules/app.js";
import { useUserStore } from "../../store/modules/user.js";
import TGLogger from "../../utils/TGLogger.js";
import TGRequest from "../../web/request/TGRequest.js";
import showConfirm from "../func/confirm.js";
import showDialog from "../func/dialog.js";
import showGeetest from "../func/geetest.js";
import showSnackbar from "../func/snackbar.js";
@@ -139,7 +139,7 @@ const userInfo = computed<TGApp.App.Account.BriefInfo>(() => {
});
async function tryCaptchaLogin(): Promise<void> {
const phone = await showConfirm({ mode: "input", title: "请输入手机号", text: "+86" });
const phone = await showDialog.input("请输入手机号", "+86");
if (!phone) {
showSnackbar.cancel("已取消验证码登录");
return;
@@ -152,12 +152,7 @@ async function tryCaptchaLogin(): Promise<void> {
const actionType = await tryGetCaptcha(phone);
if (!actionType) return;
showSnackbar.success(`已发送验证码到 ${phone}`);
const captcha = await showConfirm({
mode: "input",
title: "请输入验证码",
text: "验证码:",
otcancel: false,
});
const captcha = await showDialog.input("请输入验证码", "验证码:", undefined, false);
if (!captcha) {
showSnackbar.warn("输入验证码为空");
return;
@@ -365,31 +360,28 @@ async function loadAccount(uid: string): Promise<void> {
}
async function confirmRefreshUser(uid: string): Promise<void> {
const res = await showConfirm({ title: "确认刷新用户信息吗?", text: "将会重新获取用户信息" });
if (!res) {
const freshCheck = await showDialog.check("确认刷新用户信息吗?", "将会重新获取用户信息");
if (!freshCheck) {
showSnackbar.cancel("已取消刷新用户信息");
return;
}
await refreshUser(uid);
if (userStore.uid.value === uid) showSnackbar.success("成功刷新用户信息");
const confirm = await showConfirm({ title: "是否切换用户?", text: `将切换到用户${uid}` });
if (!confirm) return;
const switchCheck = await showDialog.check("是否切换用户?", `将切换到用户${uid}`);
if (!switchCheck) return;
await loadAccount(uid);
}
async function confirmCopyCookie(): Promise<void> {
const res = await showConfirm({
title: "确认复制 Cookie 吗?",
text: "将会复制当前登录的 Cookie",
});
if (!res) {
showSnackbar.cancel("已取消复制 Cookie");
return;
}
if (!userStore.cookie.value) {
showSnackbar.warn("请先登录");
return;
}
const copyCheck = await showDialog.check("确认复制 Cookie 吗?", "将会复制当前登录的 Cookie");
if (!copyCheck) {
showSnackbar.cancel("已取消复制 Cookie");
return;
}
const ckText = TSUserAccount.account.copy(userStore.cookie.value);
await navigator.clipboard.writeText(ckText);
showSnackbar.success("已复制 Cookie!");
@@ -447,11 +439,7 @@ async function showAccounts(): Promise<void> {
}
async function addByCookie(): Promise<void> {
const ckInput = await showConfirm({
mode: "input",
title: "请输入cookie",
text: "Cookie:",
});
const ckInput = await showDialog.input("请输入Cookie", "Cookie:");
if (!ckInput) {
showSnackbar.cancel("已取消Cookie输入");
return;
@@ -553,8 +541,8 @@ async function clearUser(user: TGApp.App.Account.User): Promise<void> {
showSnackbar.warn("当前登录用户不许删除!");
return;
}
const confirm = await showConfirm({ title: "确认删除", text: "将删除账号及其游戏账号数据" });
if (!confirm) {
const delCheck = await showDialog.check("确认删除用户吗?", "将删除账号及其游戏账号数据");
if (!delCheck) {
showSnackbar.cancel("已取消删除用户数据");
return;
}

View File

@@ -1,66 +0,0 @@
/**
* @file component/func/confirm.ts
* @description 封装自定义 confirm 组件,通过函数调用的方式,简化 confirm 的使用
* @since Beta v0.3.9
*/
import { h, render } from "vue";
import type { ComponentInternalInstance, VNode } from "vue";
import confirm from "./confirm.vue";
const confirmId = "tg-func-confirm";
/**
* @description 自定义 confirm 组件
* @since Beta v0.3.4
* @extends ComponentInternalInstance
* @property {Function} exposeProxy.displayBox 显示 confirm
* @return ConfirmInstance
*/
interface ConfirmInstance extends ComponentInternalInstance {
exposeProxy: {
displayBox: (props: TGApp.Component.Confirm.Params) => Promise<string | boolean>;
};
}
const renderBox = (props: TGApp.Component.Confirm.Params): VNode => {
const container = document.createElement("div");
container.id = confirmId;
const boxVNode: VNode = h(confirm, props);
render(boxVNode, container);
document.body.appendChild(container);
return boxVNode;
};
let confirmInstance: VNode;
/**
* @function showConfirm
* @since Beta v0.3.9
* @description 弹出 confirm
* @param {TGApp.Component.Confirm.Params} props confirm 的参数
* @return {Promise<string | boolean | undefined>} 点击确认返回 true点击取消返回 false点击外部返回 undefined
*/
async function showConfirm(
props: TGApp.Component.Confirm.ParamsConfirm,
): Promise<boolean | undefined>;
async function showConfirm(
props: TGApp.Component.Confirm.ParamsInput,
): Promise<string | false | undefined>;
async function showConfirm(
props: TGApp.Component.Confirm.Params,
): Promise<string | boolean | undefined>;
async function showConfirm(
props: TGApp.Component.Confirm.Params,
): Promise<string | boolean | undefined> {
if (confirmInstance !== undefined) {
const boxVue = <ConfirmInstance>confirmInstance.component;
return await boxVue.exposeProxy.displayBox(props);
} else {
confirmInstance = renderBox(props);
return await showConfirm(props);
}
}
export default showConfirm;

View File

@@ -1,270 +0,0 @@
<template>
<transition name="func-confirm-outer">
<div v-show="show || showOuter" class="confirm-overlay" @click.self.prevent="handleOuter">
<transition name="func-confirm-inner">
<div v-show="showInner" class="confirm-box">
<div class="confirm-title">{{ data.title }}</div>
<div
v-show="data?.text !== '' && data.mode === 'confirm'"
class="confirm-subtitle"
:title="data.text"
>
{{ data.text }}
</div>
<div v-show="data?.text !== '' && data.mode === 'input'" class="confirm-input">
<div class="confirm-input-label">{{ data.text }}</div>
<input
v-model="inputVal"
class="confirm-input-box"
ref="inputRef"
@keydown.enter="handleConfirm"
/>
</div>
<div class="confirm-btn-box">
<button class="confirm-btn no-btn" @click="handleCancel">取消</button>
<button class="confirm-btn ok-btn" @click="handleConfirm">确定</button>
</div>
</div>
</transition>
</div>
</transition>
</template>
<script lang="ts" setup>
import { nextTick, onMounted, reactive, ref, watch, useTemplateRef } from "vue";
interface ConfirmProps {
title: string;
text?: string;
mode?: "confirm" | "input";
otcancel?: boolean;
}
const defaultProp: ConfirmProps = { title: "", text: "", mode: "confirm", otcancel: false };
const props = withDefaults(defineProps<ConfirmProps>(), {
title: "",
text: "",
mode: "confirm",
otcancel: false,
});
// 组件参数
const data = reactive<TGApp.Component.Confirm.Params>(defaultProp);
const show = ref<boolean>(false);
const showOuter = ref<boolean>(false);
const showInner = ref<boolean>(false);
const confirmVal = ref<boolean | string | undefined>();
const inputVal = ref<string>("");
const inputEl = useTemplateRef<HTMLInputElement>("inputRef");
watch(
() => show.value,
() => {
if (show.value) {
showOuter.value = true;
setTimeout(() => (showInner.value = true), 100);
return;
}
setTimeout(() => (showInner.value = false), 100);
setTimeout(() => (showOuter.value = false), 300);
},
);
onMounted(async () => await displayBox(props));
async function displayBox(
params: TGApp.Component.Confirm.Params,
): Promise<string | boolean | undefined> {
data.title = params.title;
data.text = params.text ?? "";
data.mode = params.mode ?? "confirm";
data.otcancel = params.otcancel ?? true;
if (params.mode === "input" && params.input) inputVal.value = params.input;
show.value = true;
// 等待确认框关闭返回关闭后的confirmVal
return await new Promise<string | boolean | undefined>((resolve) => {
nextTick(() => {
if (data.mode === "input") {
// 等待确认框打开,聚焦输入框
setTimeout(() => inputEl.value?.focus(), 100);
}
});
watch(
() => show.value,
() => setTimeout(() => resolve(confirmVal.value), 500),
);
});
}
// 确认
function handleConfirm(): void {
if (data.mode === "input") {
confirmVal.value = inputVal.value;
inputVal.value = "";
} else {
confirmVal.value = true;
}
show.value = false;
}
// 取消
function handleCancel(): void {
confirmVal.value = false;
show.value = false;
}
// 点击外部事件
function handleOuter(): void {
if (data.otcancel) {
confirmVal.value = undefined;
show.value = false;
}
}
defineExpose({ displayBox });
</script>
<style scoped>
.func-confirm-outer-enter-active,
.func-confirm-outer-leave-active,
.func-confirm-inner-enter-active {
transition: all 0.3s;
}
.func-confirm-inner-leave-active {
transition: all 0.5s ease-in-out;
}
.func-confirm-inner-enter-from {
opacity: 0;
transform: scale(1.5);
}
.func-confirm-inner-enter-to,
.func-confirm-inner-leave-from {
opacity: 1;
transform: scale(1);
}
.func-confirm-outer-enter-to,
.func-confirm-outer-leave-from {
opacity: 1;
}
.func-confirm-outer-enter-from,
.func-confirm-outer-leave-to {
opacity: 0;
}
.func-confirm-inner-leave-to {
opacity: 0;
transform: scale(0);
}
.confirm-overlay {
position: fixed;
z-index: 100;
top: 0;
left: 0;
display: flex;
width: 100%;
height: 100%;
align-items: center;
justify-content: center;
-webkit-backdrop-filter: blur(10px);
backdrop-filter: blur(10px);
/* 颜色变量 */
--confirm-title: var(--tgc-dark-7);
--confirm-bg: var(--tgc-white-1);
}
/* 深色模式 */
.dark .confirm-overlay {
--confirm-title: var(--tgc-white-1);
--confirm-bg: var(--tgc-dark-7);
}
.confirm-box {
display: flex;
width: 520px;
height: 240px;
flex-direction: column;
align-items: center;
justify-content: space-between;
padding: 10px;
border: 1px solid var(--common-shadow-1);
border-radius: 15px;
background: var(--confirm-bg);
box-shadow: 0 0 10px var(--common-shadow-t-1);
color: var(--tgc-yellow-3);
}
.confirm-title {
width: 100%;
border-bottom: 1px solid var(--confirm-title);
color: var(--confirm-title);
font-family: var(--font-title);
font-size: 30px;
text-align: center;
}
.confirm-subtitle {
overflow: hidden;
width: 100%;
font-family: var(--font-text);
font-size: 20px;
text-align: center;
text-overflow: ellipsis;
white-space: normal;
word-break: break-all;
}
.confirm-input {
display: flex;
width: 100%;
align-items: center;
justify-content: center;
font-family: var(--font-text);
font-size: 16px;
gap: 10px;
}
.confirm-input-box {
width: 50%;
height: 100%;
padding: 5px;
border: 1px solid var(--confirm-title);
border-radius: 5px;
background: inherit;
color: var(--confirm-title);
}
.confirm-btn-box {
display: flex;
width: 100%;
align-items: flex-end;
justify-content: space-around;
}
.confirm-btn {
position: relative;
display: flex;
width: 180px;
height: 60px;
align-items: center;
justify-content: center;
border-radius: 15px;
cursor: pointer;
font-family: var(--font-title);
font-size: 20px;
}
.no-btn {
border: 1px solid var(--tgc-yellow-1);
}
.ok-btn {
background: var(--confirm-title);
}
</style>

View File

@@ -0,0 +1,113 @@
/**
* @file component/func/dialog.ts
* @description dialog 组件封装,函数式调用
* @since Beta v0.6.3
*/
import { h, render } from "vue";
import type { ComponentInternalInstance, VNode } from "vue";
import dialog from "./dialog.vue";
const dialogId = "tg-func-dialog";
export type DialogParams = DialogCheckParams | DialogInputParams;
export type DialogCheckParams = {
mode: "check";
title: string;
text?: string;
otcancel?: boolean;
};
export type DialogInputParams = {
mode: "input";
title: string;
text?: string;
otcancel?: boolean;
input?: string;
};
/**
* @description 自定义 confirm 组件
* @since Beta v0.6.3
* @extends ComponentInternalInstance
* @property {Function} exposeProxy.displayBox 显示 confirm
* @return DialogInstance
*/
interface DialogInstance extends ComponentInternalInstance {
exposeProxy: {
displayCheckBox: (props: DialogCheckParams) => Promise<boolean | undefined>;
displayInputBox: (props: DialogInputParams) => Promise<string | false | undefined>;
};
}
function renderBox(props: DialogParams): VNode {
const container = document.createElement("div");
container.id = dialogId;
const boxVNode: VNode = h(dialog, props);
render(boxVNode, container);
document.body.appendChild(container);
return boxVNode;
}
let dialogInstance: VNode;
async function showDialogFull(
mode: "check" | "input",
title: string,
text?: string,
input?: string,
otcancel?: boolean,
): Promise<boolean | string | undefined> {
if (mode === "check") return await showDialogCheck(title, text, otcancel);
return await showDialogInput(title, text, input, otcancel);
}
async function showDialogCheck(
title: string,
text?: string,
otcancel?: boolean,
): Promise<boolean | undefined> {
const params: DialogCheckParams = {
mode: "check",
title: title,
text: text,
otcancel: otcancel,
};
if (dialogInstance !== undefined) {
const boxVue = <DialogInstance>dialogInstance.component;
return await boxVue.exposeProxy.displayCheckBox(params);
} else {
dialogInstance = renderBox(params);
return await showDialogCheck(title, text, otcancel);
}
}
async function showDialogInput(
title: string,
text?: string,
input?: string,
otcancel?: boolean,
): Promise<string | false | undefined> {
const params: DialogInputParams = {
mode: "input",
title: title,
text: text,
input: input,
otcancel: otcancel,
};
if (dialogInstance !== undefined) {
const boxVue = <DialogInstance>dialogInstance.component;
return await boxVue.exposeProxy.displayInputBox(params);
} else {
dialogInstance = renderBox(params);
return await showDialogInput(title, text, input, otcancel);
}
}
const showDialog = {
_: showDialogFull,
check: showDialogCheck,
input: showDialogInput,
};
export default showDialog;

View File

@@ -0,0 +1,294 @@
<template>
<transition name="func-dialog-outer">
<div v-show="show || showOuter" class="dialog-overlay" @click.self.prevent="handleOuter">
<transition name="func-dialog-inner">
<div v-show="showInner" class="dialog-box">
<div class="dialog-title">{{ data.title }}</div>
<div
v-show="data?.text !== '' && data.mode === 'check'"
class="dialog-subtitle"
:title="data.text"
>
{{ data.text }}
</div>
<div v-show="data?.text !== '' && data.mode === 'input'" class="dialog-input">
<div class="dialog-input-label">{{ data.text }}</div>
<input
v-model="inputDefault"
class="dialog-input-box"
ref="inputRef"
@keydown.enter="handleConfirm"
/>
</div>
<div class="dialog-btn-box">
<button class="dialog-btn no-btn" @click="handleCancel">取消</button>
<button class="dialog-btn ok-btn" @click="handleConfirm">确定</button>
</div>
</div>
</transition>
</div>
</transition>
</template>
<script lang="ts" setup>
import { nextTick, onMounted, reactive, ref, watch, useTemplateRef, computed } from "vue";
import { DialogCheckParams, DialogInputParams, DialogParams } from "./dialog.js";
const defaultProp: DialogParams = { title: "", text: "", mode: "check", otcancel: false };
const props = defineProps<DialogParams>();
// 组件参数
const data = reactive<DialogParams>(defaultProp);
const show = ref<boolean>(false);
const showOuter = ref<boolean>(false);
const showInner = ref<boolean>(false);
const dialogVal = ref<boolean | string | undefined>();
const inputDefault = ref<string>("");
const inputEl = useTemplateRef<HTMLInputElement>("inputRef");
const checkVal = computed<boolean | undefined>(() => {
if (typeof dialogVal.value === "string") return dialogVal.value !== "";
return dialogVal.value;
});
const inputVal = computed<string | false | undefined>(() => {
if (typeof dialogVal.value === "string") return dialogVal.value;
if (dialogVal.value === undefined) return undefined;
return false;
});
watch(
() => show.value,
() => {
if (show.value) {
showOuter.value = true;
setTimeout(() => (showInner.value = true), 100);
return;
}
setTimeout(() => (showInner.value = false), 100);
setTimeout(() => (showOuter.value = false), 300);
},
);
onMounted(async () => {
if (props.mode === "input") {
const param: DialogInputParams = {
mode: "input",
title: props.title,
text: props.text,
input: props.input,
otcancel: props.otcancel,
};
await displayInputBox(param);
} else {
const param: DialogCheckParams = {
mode: "check",
title: props.title,
text: props.text,
otcancel: props.otcancel,
};
await displayCheckBox(param);
}
});
async function displayCheckBox(params: DialogCheckParams): Promise<boolean | undefined> {
data.title = params.title;
data.text = params.text ?? "";
data.mode = "check";
data.otcancel = params.otcancel ?? true;
show.value = true;
return await new Promise<boolean | undefined>((resolve) => {
watch(
() => show.value,
() => setTimeout(() => resolve(checkVal.value), 500),
);
});
}
async function displayInputBox(params: DialogInputParams): Promise<string | false | undefined> {
data.title = params.title;
data.text = params.text ?? "";
data.mode = "input";
data.otcancel = params.otcancel ?? true;
show.value = true;
return await new Promise<string | false | undefined>((resolve) => {
nextTick(() => setTimeout(() => inputEl.value?.focus(), 100));
watch(
() => show.value,
() => setTimeout(() => resolve(inputVal.value), 500),
);
});
}
// 确认
function handleConfirm(): void {
if (data.mode === "input") {
dialogVal.value = inputDefault.value;
inputDefault.value = "";
} else {
dialogVal.value = true;
}
show.value = false;
}
// 取消
function handleCancel(): void {
dialogVal.value = false;
show.value = false;
}
// 点击外部事件
function handleOuter(): void {
if (data.otcancel) {
dialogVal.value = undefined;
show.value = false;
}
}
defineExpose({ displayInputBox, displayCheckBox });
</script>
<style scoped>
.func-dialog-outer-enter-active,
.func-dialog-outer-leave-active,
.func-dialog-inner-enter-active {
transition: all 0.3s;
}
.func-dialog-inner-leave-active {
transition: all 0.5s ease-in-out;
}
.func-dialog-inner-enter-from {
opacity: 0;
transform: scale(1.5);
}
.func-dialog-inner-enter-to,
.func-dialog-inner-leave-from {
opacity: 1;
transform: scale(1);
}
.func-dialog-outer-enter-to,
.func-dialog-outer-leave-from {
opacity: 1;
}
.func-dialog-outer-enter-from,
.func-dialog-outer-leave-to {
opacity: 0;
}
.func-dialog-inner-leave-to {
opacity: 0;
transform: scale(0);
}
.dialog-overlay {
position: fixed;
z-index: 100;
top: 0;
left: 0;
display: flex;
width: 100%;
height: 100%;
align-items: center;
justify-content: center;
-webkit-backdrop-filter: blur(10px);
backdrop-filter: blur(10px);
/* 颜色变量 */
--dialog-title: var(--tgc-dark-7);
--dialog-bg: var(--tgc-white-1);
}
/* 深色模式 */
.dark .dialog-overlay {
--dialog-title: var(--tgc-white-1);
--dialog-bg: var(--tgc-dark-7);
}
.dialog-box {
display: flex;
width: 520px;
height: 240px;
flex-direction: column;
align-items: center;
justify-content: space-between;
padding: 10px;
border: 1px solid var(--common-shadow-1);
border-radius: 15px;
background: var(--dialog-bg);
box-shadow: 0 0 10px var(--common-shadow-t-1);
color: var(--tgc-yellow-3);
}
.dialog-title {
width: 100%;
border-bottom: 1px solid var(--dialog-title);
color: var(--dialog-title);
font-family: var(--font-title);
font-size: 30px;
text-align: center;
}
.dialog-subtitle {
overflow: hidden;
width: 100%;
font-family: var(--font-text);
font-size: 20px;
text-align: center;
text-overflow: ellipsis;
white-space: normal;
word-break: break-all;
}
.dialog-input {
display: flex;
width: 100%;
align-items: center;
justify-content: center;
font-family: var(--font-text);
font-size: 16px;
gap: 10px;
}
.dialog-input-box {
width: 50%;
height: 100%;
padding: 5px;
border: 1px solid var(--dialog-title);
border-radius: 5px;
background: inherit;
color: var(--dialog-title);
}
.dialog-btn-box {
display: flex;
width: 100%;
align-items: flex-end;
justify-content: space-around;
}
.dialog-btn {
position: relative;
display: flex;
width: 180px;
height: 60px;
align-items: center;
justify-content: center;
border-radius: 15px;
cursor: pointer;
font-family: var(--font-title);
font-size: 20px;
}
.no-btn {
border: 1px solid var(--tgc-yellow-1);
}
.ok-btn {
background: var(--dialog-title);
}
</style>

View File

@@ -1,6 +1,6 @@
/**
* @file component func snackbar.ts
* @description 封装 vuetify 的 snackbar 组件,通过函数调用的方式,简化 snackbar 的使用
* @file component/func/snackbar.ts
* @description snackbar 组件封装,函数调用
* @since Beta v0.6.3
*/
@@ -11,32 +11,32 @@ import snackbar from "./snackbar.vue";
const snackbarId = "tg-func-snackbar";
export type SnackbarParams = { text: string; color: string; timeout: number };
/**
* @description 自定义 snackbar 组件
* @since Beta v0.3.3
* @extends ComponentInternalInstance
* @property {Function} exposeProxy.displayBox 显示 snackbar
* @since Beta v0.6.3
* @return SnackbarInstance
*/
interface SnackbarInstance extends ComponentInternalInstance {
exposeProxy: {
displayBox: (props: TGApp.Component.Snackbar.Params) => void;
displayBox: (props: SnackbarParams) => void;
};
}
const renderBox = (props: TGApp.Component.Snackbar.Params): VNode => {
function renderBox(props: SnackbarParams): VNode {
const container = document.createElement("div");
container.id = snackbarId;
const boxVNode: VNode = h(snackbar, props);
render(boxVNode, container);
document.body.appendChild(container);
return boxVNode;
};
}
let snackbarInstance: VNode;
function showSnackbarFull(text: string, color?: string, timeout?: number): void {
const params: TGApp.Component.Snackbar.Params = {
const params: SnackbarParams = {
text: text,
color: color ?? "success",
timeout: timeout ?? 1500,

View File

@@ -1,7 +1,7 @@
<template>
<transition name="func-snackbar">
<div class="func-snackbar-container" v-show="show">
<div class="func-snackbar" :style="{ backgroundColor: data.color }">
<div class="func-snackbar">
<slot name="text">
<span class="func-snackbar-text">{{ data.text }}</span>
</slot>
@@ -10,18 +10,14 @@
</transition>
</template>
<script lang="ts" setup>
import { onMounted, ref, toRaw } from "vue";
import { computed, onMounted, ref, toRaw } from "vue";
interface SnackbarProps {
text: string;
color: string;
timeout: number;
}
import { SnackbarParams } from "./snackbar.js";
const props = defineProps<SnackbarProps>();
const data = ref<TGApp.Component.Snackbar.Params>(toRaw(props));
// 组件参数
const props = defineProps<SnackbarParams>();
const data = ref<SnackbarParams>(toRaw(props));
const show = ref<boolean>(false);
const bgColor = computed(() => data.value.color);
// eslint-disable-next-line no-undef
let timer: NodeJS.Timeout | undefined = undefined;
@@ -99,6 +95,7 @@ defineExpose({ displayBox });
justify-content: center;
padding: 10px 20px;
border-radius: 5px;
background-color: v-bind(bgColor);
box-shadow: 0 0 10px rgb(0 0 0 / 20%);
}

View File

@@ -57,7 +57,7 @@ import { useRouter } from "vue-router";
import { AppGachaData, AppCharacterData, AppWeaponData } from "../../data/index.js";
import { createPost } from "../../utils/TGWindow.js";
import { timestampToDate } from "../../utils/toolFunc.js";
import showConfirm from "../func/confirm.js";
import showDialog from "../func/dialog.js";
import showSnackbar from "../func/snackbar.js";
import TItembox, { TItemBoxData } from "../main/t-itembox.vue";
@@ -90,20 +90,20 @@ onMounted(() => {
async function toWiki(id: number): Promise<void> {
const cFind = AppCharacterData.find((item) => item.id === id);
const wFind = AppWeaponData.find((item) => item.id === id);
const confirm = await showConfirm({
title: "是否跳转到对应图鉴界面?",
});
if (confirm === undefined || confirm === false) {
const jumpCheck = await showDialog.check("是否跳转到对应图鉴界面?");
if (!jumpCheck) {
showSnackbar.cancel("已取消");
return;
}
if (cFind) {
await router.push({ name: "角色图鉴", params: { id: id.toString() } });
} else if (wFind) {
await router.push({ name: "武器图鉴", params: { id: id.toString() } });
} else {
showSnackbar.warn("未找到对应角色或武器");
return;
}
if (wFind) {
await router.push({ name: "武器图鉴", params: { id: id.toString() } });
return;
}
showSnackbar.warn("未找到对应角色或武器");
}
function getType(type: TGApp.App.Gacha.WishType): string {

View File

@@ -20,7 +20,7 @@ import TGClient from "../../utils/TGClient.js";
import TGLogger from "../../utils/TGLogger.js";
import { createPost } from "../../utils/TGWindow.js";
import TGRequest from "../../web/request/TGRequest.js";
import showConfirm from "../func/confirm.js";
import showDialog from "../func/dialog.js";
import showSnackbar from "../func/snackbar.js";
import ToLivecode from "../overlay/to-livecode.vue";
@@ -103,16 +103,13 @@ async function toNav(item: TGApp.BBS.Navigator.Navigator): Promise<void> {
await TGClient.open("web_act_thin", item.app_path);
return;
}
const modeConfirm = await showConfirm({
title: "是否采用宽屏模式打开?",
text: "取消则采用竖屏模式打开",
});
if (modeConfirm === undefined) {
const modeCheck = await showDialog.check("是否采用宽屏模式打开?", "取消则采用竖屏模式打开");
if (modeCheck === undefined) {
showSnackbar.cancel("已取消打开");
return;
}
if (modeConfirm) await TGClient.open("web_act", item.app_path);
else await TGClient.open("web_act_thin", item.app_path);
if (!modeCheck) await TGClient.open("web_act_thin", item.app_path);
else await TGClient.open("web_act", item.app_path);
}
// 处理 protocol

View File

@@ -25,7 +25,7 @@
import { computed, ref, watch } from "vue";
import TSUserCollection from "../../plugins/Sqlite/modules/userCollect.js";
import showConfirm from "../func/confirm.js";
import showDialog from "../func/dialog.js";
import showSnackbar from "../func/snackbar.js";
import TOverlay from "../main/t-overlay.vue";
@@ -73,10 +73,7 @@ async function onSubmit(): Promise<void> {
}
submit.value = true;
let force = false;
const forceCheck = await showConfirm({
title: "是否保留原分类",
text: "若否则仅保留新分类",
});
const forceCheck = await showDialog.check("是否保留原分类", "若否则仅保留新分类");
if (forceCheck === false) force = true;
const check = await TSUserCollection.updatePostsCollect(props.post, select.value, force);
if (!check) {
@@ -92,11 +89,7 @@ async function onSubmit(): Promise<void> {
async function newCollect(): Promise<void> {
let title, desc;
const titleC = await showConfirm({
mode: "input",
title: "新建分类",
text: "请输入分类名称",
});
const titleC = await showDialog.input("新建分类", "请输入分类名称");
if (titleC === undefined || titleC === false) return;
if (titleC === "未分类") {
showSnackbar.warn("分类名不可为未分类");
@@ -107,11 +100,7 @@ async function newCollect(): Promise<void> {
return;
}
title = titleC;
const descC = await showConfirm({
mode: "input",
title: "新建分类",
text: "请输入分类描述",
});
const descC = await showDialog.input("新建分类", "请输入分类描述");
if (descC === false) return;
if (descC === undefined) desc = title;
else desc = descC;

View File

@@ -37,7 +37,7 @@
import { computed, ref, watch } from "vue";
import TSUserCollection from "../../plugins/Sqlite/modules/userCollect.js";
import showConfirm from "../func/confirm.js";
import showDialog from "../func/dialog.js";
import showSnackbar from "../func/snackbar.js";
import TOverlay from "../main/t-overlay.vue";
@@ -89,11 +89,8 @@ const visible = computed({
});
async function deleteCollect(item: TGApp.Sqlite.UserCollection.UFCollection): Promise<void> {
const res = await showConfirm({
title: "确定删除分类?",
text: "该分类若有帖子,则会变为未分类",
});
if (!res) {
const delCheck = await showDialog.check("确定删除分类?", "该分类若有帖子,则会变为未分类");
if (!delCheck) {
showSnackbar.cancel("取消删除");
return;
}
@@ -108,11 +105,7 @@ async function deleteCollect(item: TGApp.Sqlite.UserCollection.UFCollection): Pr
async function newCollect(): Promise<void> {
let title, desc;
const titleC = await showConfirm({
mode: "input",
title: "新建分类",
text: "请输入分类名称",
});
const titleC = await showDialog.input("新建分类", "请输入分类名称");
if (titleC === undefined || titleC === false) return;
if (titleC === "未分类") {
showSnackbar.warn("分类名不可为未分类");
@@ -123,11 +116,7 @@ async function newCollect(): Promise<void> {
return;
}
title = titleC;
const descC = await showConfirm({
mode: "input",
title: "新建分类",
text: "请输入分类描述",
});
const descC = await showDialog.input("新建分类", "请输入分类描述");
if (descC === false) return;
if (descC === undefined) desc = title;
else desc = descC;

View File

@@ -17,7 +17,7 @@ import { onBeforeMount, ref, watch } from "vue";
import TSUserCollection from "../../plugins/Sqlite/modules/userCollect.js";
import TGLogger from "../../utils/TGLogger.js";
import showConfirm from "../func/confirm.js";
import showDialog from "../func/dialog.js";
import showSnackbar from "../func/snackbar.js";
import ToPostCollect from "../overlay/to-postCollect.vue";
@@ -82,13 +82,8 @@ async function switchCollect(): Promise<void> {
return;
}
if (collect.value.length > 1) {
const check = await showConfirm({
title: "确定取消收藏?",
text: "该帖子有多个收藏分类,是否全部取消?",
});
if (!check) {
return;
}
const check = await showDialog.check("确定取消收藏?", "该帖子有多个收藏分类,是否全部取消?");
if (!check) return;
}
await TSUserCollection.deletePostCollect(props.modelValue.toString(), true);
await event.emit("refreshCollect");

View File

@@ -108,7 +108,7 @@ import { toRaw, ref, watch, computed, onMounted, onUnmounted } from "vue";
import Mys from "../../plugins/Mys/index.js";
import { generateShareImg } from "../../utils/TGShare.js";
import showConfirm from "../func/confirm.js";
import showDialog from "../func/dialog.js";
import showSnackbar from "../func/snackbar.js";
import TpParser from "../post/tp-parser.vue";
@@ -226,12 +226,9 @@ async function loadSub(): Promise<void> {
}
async function exportData(): Promise<void> {
const confirm = await showConfirm({
title: "导出数据?",
text: "将回复对应的JSON数据导出到文件",
});
if (!confirm) {
showSnackbar.cancel("已取消");
const exportCheck = await showDialog.check("导出数据", "是否导出回复数据?");
if (!exportCheck) {
showSnackbar.cancel("已取消导出该回复数据");
return;
}
const data = JSON.stringify(toRaw(props.modelValue), null, 2);

View File

@@ -36,7 +36,7 @@ import { toRaw, ref, watch } from "vue";
import { AppAchievementSeriesData } from "../../data/index.js";
import TSUserAchi from "../../plugins/Sqlite/modules/userAchi.js";
import { timestampToDate } from "../../utils/toolFunc.js";
import showConfirm from "../func/confirm.js";
import showDialog from "../func/dialog.js";
import showSnackbar from "../func/snackbar.js";
interface TuaAchiProps {
@@ -81,12 +81,7 @@ async function setAchiStat(stat: boolean): Promise<void> {
showSnackbar.success(`已将成就 ${data.value.name}(${data.value.id}) 状态设为未完成`);
return;
}
let progress: boolean | undefined | string = await showConfirm({
mode: "input",
title: "请输入成就进度",
text: "进度",
input: data.value.progress,
});
let progress = await showDialog.input("请输入成就进度", "进度", data.value.progress.toString());
if (progress === false) {
showSnackbar.cancel("已取消成就编辑");
return;

View File

@@ -115,7 +115,7 @@ import { storeToRefs } from "pinia";
import { onMounted, ref, watch, computed } from "vue";
import { useRouter } from "vue-router";
import showConfirm from "../../components/func/confirm.js";
import showDialog from "../../components/func/dialog.js";
import showSnackbar from "../../components/func/snackbar.js";
import TSubLine from "../../components/main/t-subline.vue";
import ToLoading from "../../components/overlay/to-loading.vue";
@@ -196,20 +196,20 @@ async function refreshAbyss(): Promise<void> {
return;
}
if (uidCur.value && uidCur.value !== user.value.gameUid) {
const confirmSwitch = await showConfirm({
title: "是否切换游戏账户",
text: `确认则尝试切换至 ${uidCur.value}`,
});
if (confirmSwitch) {
const switchCheck = await showDialog.check(
"是否切换游戏账户",
`确认则尝试切换至 ${uidCur.value}`,
);
if (switchCheck) {
await useUserStore().switchGameAccount(uidCur.value);
await refreshAbyss();
return;
}
const confirm = await showConfirm({
title: "确定刷新?",
text: `用户${user.value.gameUid}与当前UID${uidCur.value}不一致`,
});
if (!confirm) {
const freshCheck = await showDialog.check(
"确定刷新?",
`用户${user.value.gameUid}与当前UID${uidCur.value}不一致`,
);
if (!freshCheck) {
showSnackbar.cancel("已取消深渊数据刷新");
return;
}
@@ -321,11 +321,8 @@ async function deleteAbyss(): Promise<void> {
showSnackbar.warn("未选择游戏UID");
return;
}
const confirm = await showConfirm({
title: "确定删除数据?",
text: `将清除${uidCur.value}的所有深渊数据`,
});
if (!confirm) {
const delCheck = await showDialog.check("确定删除数据?", `将清除${uidCur.value}的所有深渊数据`);
if (!delCheck) {
showSnackbar.cancel("已取消删除");
return;
}

View File

@@ -103,7 +103,7 @@ import { getVersion } from "@tauri-apps/api/app";
import { storeToRefs } from "pinia";
import { onMounted, ref, watch, computed } from "vue";
import showConfirm from "../../components/func/confirm.js";
import showDialog from "../../components/func/dialog.js";
import showSnackbar from "../../components/func/snackbar.js";
import ToLoading from "../../components/overlay/to-loading.vue";
import TuaAvatarBox from "../../components/userAvatar/tua-avatar-box.vue";
@@ -252,20 +252,20 @@ async function refresh(): Promise<void> {
await new Promise((resolve) => setTimeout(resolve, 500));
}
if (uidCur.value && uidCur.value !== user.value.gameUid) {
const switchConfirm = await showConfirm({
title: "是否切换游戏账户",
text: `确认则尝试切换至${uidCur.value}`,
});
if (switchConfirm) {
const switchCheck = await showDialog.check(
"是否切换游戏账户",
`确认则尝试切换至${uidCur.value}`,
);
if (switchCheck) {
await useUserStore().switchGameAccount(uidCur.value);
await refresh();
return;
}
const confirm = await showConfirm({
title: "确定刷新?",
text: `用户${user.value.gameUid}与当前UID${uidCur.value}不一致`,
});
if (!confirm) {
const freshCheck = await showDialog.check(
"是否刷新角色数据",
`用户${user.value.gameUid}与当前UID${uidCur.value}不一致`,
);
if (!freshCheck) {
showSnackbar.cancel("已取消角色数据刷新");
return;
}
@@ -353,11 +353,8 @@ async function deleteUid(): Promise<void> {
showSnackbar.warn("未找到当前UID");
return;
}
const confirm = await showConfirm({
title: "确定删除?",
text: `将删除${uidCur.value}对应的角色数据`,
});
if (!confirm) {
const delCheck = await showDialog.check("确定删除?", `将删除${uidCur.value}对应的角色数据`);
if (!delCheck) {
showSnackbar.cancel("已取消删除");
return;
}

View File

@@ -96,7 +96,7 @@ import { storeToRefs } from "pinia";
import { onMounted, ref, watch, computed } from "vue";
import { useRouter } from "vue-router";
import showConfirm from "../../components/func/confirm.js";
import showDialog from "../../components/func/dialog.js";
import showSnackbar from "../../components/func/snackbar.js";
import TSubLine from "../../components/main/t-subline.vue";
import ToLoading from "../../components/overlay/to-loading.vue";
@@ -167,20 +167,20 @@ async function refreshCombat(): Promise<void> {
return;
}
if (uidCur.value && uidCur.value !== user.value.gameUid) {
const confirmSwitch = await showConfirm({
title: "是否切换游戏账户",
text: `确认则尝试切换至 ${uidCur.value}`,
});
if (confirmSwitch) {
const switchCheck = await showDialog.check(
"是否切换游戏账户",
`确认则尝试切换至 ${uidCur.value}`,
);
if (switchCheck) {
await useUserStore().switchGameAccount(uidCur.value);
await refreshCombat();
return;
}
const confirm = await showConfirm({
title: "确定刷新?",
text: `用户${user.value.gameUid}与当前UID${uidCur.value}不一致`,
});
if (!confirm) {
const freshCheck = await showDialog.check(
"确定刷新?",
`用户${user.value.gameUid}与当前UID${uidCur.value}不一致`,
);
if (!freshCheck) {
showSnackbar.cancel("已取消剧诗数据刷新");
return;
}
@@ -279,11 +279,8 @@ async function deleteCombat(): Promise<void> {
showSnackbar.error("未找到符合条件的数据!");
return;
}
const confirm = await showConfirm({
title: "确定删除数据?",
text: `将清除${uidCur.value}的所有剧诗数据`,
});
if (!confirm) {
const delCheck = await showDialog.check("确定删除数据?", `将清除${uidCur.value}的所有剧诗数据`);
if (!delCheck) {
showSnackbar.cancel("已取消删除");
return;
}

View File

@@ -55,7 +55,7 @@ import { open, save } from "@tauri-apps/plugin-dialog";
import { storeToRefs } from "pinia";
import { onMounted, ref, watch, computed } from "vue";
import showConfirm from "../../components/func/confirm.js";
import showDialog from "../../components/func/dialog.js";
import showSnackbar from "../../components/func/snackbar.js";
import GroEcharts from "../../components/gachaRecord/gro-echarts.vue";
import GroHistory from "../../components/gachaRecord/gro-history.vue";
@@ -129,20 +129,20 @@ onMounted(async () => {
async function confirmRefresh(force: boolean): Promise<void> {
await TGLogger.Info(`[UserGacha][${account.value.gameUid}][confirmRefresh] 刷新祈愿数据`);
if (uidCur.value && uidCur.value !== account.value.gameUid) {
const confirmSwitch = await showConfirm({
title: "是否切换游戏账户",
text: `确认则尝试切换至 ${uidCur.value}`,
});
if (confirmSwitch) {
const switchCheck = await showDialog.check(
"是否切换游戏账户",
`确认则尝试切换至 ${uidCur.value}`,
);
if (switchCheck) {
await useUserStore().switchGameAccount(uidCur.value);
await confirmRefresh(force);
return;
}
const confirm = await showConfirm({
title: "确定刷新",
text: `用户${account.value.gameUid}与当前UID${uidCur.value}不一致`,
});
if (!confirm) {
const freshCheck = await showDialog.check(
"确定刷新?",
`用户${account.value.gameUid}与当前UID${uidCur.value}不一致`,
);
if (!freshCheck) {
showSnackbar.cancel("已取消祈愿数据刷新");
return;
}
@@ -297,11 +297,11 @@ async function importUigf4(filePath: string): Promise<void> {
const remoteData = await readUigf4Data(filePath);
const uidCount = remoteData.hk4e.length;
const dataCount = remoteData.hk4e.reduce((acc, cur) => acc + cur.list.length, 0);
const res = await showConfirm({
title: "是否导入祈愿数据?",
text: `${uidCount} 个 UID${dataCount} 条数据`,
});
if (!res) {
const importCheck = await showDialog.check(
"是否导入祈愿数据?",
`${uidCount} 个 UID${dataCount} 条数据`,
);
if (!importCheck) {
showSnackbar.cancel("已取消祈愿数据导入");
return;
}
@@ -321,11 +321,11 @@ async function importUigf4(filePath: string): Promise<void> {
async function importUigf(filePath: string): Promise<void> {
const remoteData = await readUigfData(filePath);
const confirm = await showConfirm({
title: "是否导入祈愿数据?",
text: `UID${remoteData.info.uid},共 ${remoteData.list.length} 条数据`,
});
if (!confirm) {
const importCheck = await showDialog.check(
"是否导入祈愿数据?",
`UID${remoteData.info.uid},共 ${remoteData.list.length} 条数据`,
);
if (!importCheck) {
showSnackbar.cancel("已取消祈愿数据导入");
return;
}
@@ -354,11 +354,11 @@ async function exportUigf(): Promise<void> {
showSnackbar.error(`UID ${uidCur.value} 暂无祈愿数据`);
return;
}
const res = await showConfirm({
title: "是否导出祈愿数据?",
text: `UID${uidCur.value},共 ${gachaList.length} 条数据`,
});
if (!res) {
const exportCheck = await showDialog.check(
"是否导出祈愿数据?",
`UID${uidCur.value},共 ${gachaList.length} 条数据`,
);
if (!exportCheck) {
showSnackbar.cancel(`已取消 UID ${uidCur.value} 的祈愿数据导出`);
return;
}
@@ -385,22 +385,22 @@ async function exportUigf(): Promise<void> {
// 导出 UIGF v4 版本的祈愿数据
async function exportUigf4(): Promise<void> {
if (!uidCur.value) return;
const checkConfirm = await showConfirm({ title: "确定导出UIGFv4格式的祈愿数据" });
if (!checkConfirm) {
const exportCheck = await showDialog.check("确定导出UIGFv4格式的祈愿数据");
if (!exportCheck) {
showSnackbar.cancel("已取消 UIGF v4 格式导出");
return;
}
await TGLogger.Info(`[UserGacha][${uidCur.value}][exportUigf4] 导出祈愿数据(v4)`);
// todo 单开一个overlay用于选取导出的UID
const allConfirm = await showConfirm({
title: "是否导出所有 UID 的祈愿数据?",
text: "取消则只导出当前 UID 的祈愿数据",
});
if (allConfirm === undefined) {
const exportAllCheck = await showDialog.check(
"是否导出所有 UID 的祈愿数据?",
"取消则只导出当前 UID 的祈愿数据",
);
if (exportAllCheck === undefined) {
showSnackbar.cancel("已取消 UIGF v4 格式导出");
return;
}
if (!allConfirm) {
if (!exportAllCheck) {
const gachaList = await TSUserGacha.getGachaRecords(uidCur.value);
if (gachaList.length === 0) {
showSnackbar.error(`UID ${uidCur.value} 暂无祈愿数据`);
@@ -418,7 +418,7 @@ async function exportUigf4(): Promise<void> {
}
loadingTitle.value = "正在导出祈愿数据";
loading.value = true;
if (!allConfirm) {
if (!exportAllCheck) {
await exportUigf4Data(file, uidCur.value);
} else {
await exportUigf4Data(file);
@@ -435,25 +435,20 @@ async function deleteGacha(): Promise<void> {
return;
}
await TGLogger.Info(`[UserGacha][${uidCur.value}][deleteGacha] 删除祈愿数据`);
const firstConfirm = await showConfirm({
title: "是否删除祈愿数据?",
text: `UID${uidCur.value},共 ${gachaListCur.value.length} 条数据`,
});
if (!firstConfirm) {
const delCheck = await showDialog.check(
"确定删除祈愿数据?",
`UID${uidCur.value},共 ${gachaListCur.value.length} 条数据`,
);
if (!delCheck) {
showSnackbar.cancel("已取消祈愿数据删除");
await TGLogger.Info(`[UserGacha][${uidCur.value}][deleteGacha] 已取消祈愿数据删除`);
return;
}
const uidList = await TSUserGacha.getUidList();
let secondConfirm: string | boolean | undefined;
if (uidList.length <= 1) {
secondConfirm = await showConfirm({
title: "删除后数据库将为空,确定删除?",
text: `UID${uidCur.value},共 ${gachaListCur.value.length} 条数据`,
});
if (!secondConfirm) {
const forceCheck = await showDialog.check("删除后数据库将为空,确定删除?");
if (!forceCheck) {
showSnackbar.cancel("已取消祈愿数据删除");
await TGLogger.Info(`[UserGacha][${uidCur.value}][deleteGacha] 已取消祈愿数据删除`);
return;
}
}

View File

@@ -60,7 +60,7 @@ import { getVersion } from "@tauri-apps/api/app";
import { storeToRefs } from "pinia";
import { computed, onMounted, ref, watch } from "vue";
import showConfirm from "../../components/func/confirm.js";
import showDialog from "../../components/func/dialog.js";
import showSnackbar from "../../components/func/snackbar.js";
import TSubLine from "../../components/main/t-subline.vue";
import ToLoading from "../../components/overlay/to-loading.vue";
@@ -125,20 +125,20 @@ async function loadRecord(): Promise<void> {
async function refreshRecord(): Promise<void> {
if (!user.value) return;
if (uidCur.value && uidCur.value.toString() !== user.value.gameUid) {
const switchConfirm = await showConfirm({
title: "是否切换游戏账户",
text: `确认则尝试切换至${uidCur.value}`,
});
if (switchConfirm) {
const switchCheck = await showDialog.check(
"是否切换游戏账户",
`确认则尝试切换至${uidCur.value}`,
);
if (switchCheck) {
await useUserStore().switchGameAccount(uidCur.value.toString());
await refreshRecord();
return;
}
const confirm = await showConfirm({
title: "确定刷新?",
text: `用户${user.value.gameUid}与当前UID${uidCur.value}不一致`,
});
if (!confirm) {
const freshCheck = await showDialog.check(
"是否刷新战绩数据",
`用户${user.value.gameUid}与当前UID${uidCur.value}不一致`,
);
if (!freshCheck) {
showSnackbar.cancel("已取消战绩数据刷新");
return;
}
@@ -198,11 +198,8 @@ async function deleteRecord(): Promise<void> {
showSnackbar.warn("未找到当前UID");
return;
}
const confirm = await showConfirm({
title: "确定删除?",
text: `将删除${uidCur.value}对应的战绩数据`,
});
if (!confirm) {
const delCheck = await showDialog.check("确定删除?", `将删除${uidCur.value}对应的战绩数据`);
if (!delCheck) {
showSnackbar.cancel("已取消删除战绩数据");
return;
}

View File

@@ -26,7 +26,7 @@
import { onBeforeMount, ref, watch } from "vue";
import { useRoute } from "vue-router";
import showConfirm from "../../components/func/confirm.js";
import showDialog from "../../components/func/dialog.js";
import showSnackbar from "../../components/func/snackbar.js";
import TwcCharacter from "../../components/wiki/twc-character.vue";
import TwcListItem from "../../components/wiki/twc-list-item.vue";
@@ -99,11 +99,8 @@ async function toOuter(item?: TGApp.App.Character.WikiBriefInfo): Promise<void>
showSnackbar.warn(`角色 ${item.name} 暂无观测枢页面`);
return;
}
const confirm = await showConfirm({
title: `角色 ${item.name} 暂无数据`,
text: "是否打开观测枢页面?",
});
if (!confirm) {
const openCheck = await showDialog.check(`角色 ${item.name} 暂无数据`, "是否打开观测枢页面?");
if (!openCheck) {
showSnackbar.cancel("已取消打开观测枢页面");
return;
}

View File

@@ -29,7 +29,7 @@
import { onBeforeMount, ref } from "vue";
import { useRoute } from "vue-router";
import showConfirm from "../../components/func/confirm.js";
import showDialog from "../../components/func/dialog.js";
import showSnackbar from "../../components/func/snackbar.js";
import TwcListItem from "../../components/wiki/twc-list-item.vue";
import TwcWeapon from "../../components/wiki/twc-weapon.vue";
@@ -92,11 +92,8 @@ async function toOuter(item?: TGApp.App.Weapon.WikiBriefInfo): Promise<void> {
showSnackbar.warn(`武器 ${item.name} 暂无观测枢页面`);
return;
}
const confirm = await showConfirm({
title: `武器 ${item.name} 暂无数据`,
text: "是否打开观测枢页面?",
});
if (!confirm) {
const check = await showDialog.check(`武器 ${item.name} 暂无数据`, "是否打开观测枢页面?");
if (!check) {
showSnackbar.cancel("已取消打开观测枢页面");
return;
}

View File

@@ -59,7 +59,7 @@ import { writeTextFile } from "@tauri-apps/plugin-fs";
import { onMounted, ref, watch, computed, onUnmounted } from "vue";
import { useRoute, useRouter } from "vue-router";
import showConfirm from "../../components/func/confirm.js";
import showDialog from "../../components/func/dialog.js";
import showSnackbar from "../../components/func/snackbar.js";
import ToLoading from "../../components/overlay/to-loading.vue";
import TuaAchiList from "../../components/userAchi/tua-achi-list.vue";
@@ -151,12 +151,7 @@ async function importJson(): Promise<void> {
}
const check = await verifyUiafData(selectedFile);
if (!check) return;
let uidInput = await showConfirm({
mode: "input",
title: "请输入存档UID",
text: "UID:",
input: uidCur.value.toString(),
});
let uidInput = await showDialog.input("请输入存档UID", "UID:", uidCur.value.toString());
if (uidInput === false) {
showSnackbar.cancel("已取消存档导入");
return;
@@ -211,25 +206,16 @@ async function exportJson(): Promise<void> {
async function handleImportOuter(app: string): Promise<void> {
await TGLogger.Info(`[Achievements][handleImportOuter] 导入来源:${app}`);
const confirm = await showConfirm({
title: "是否导入祈愿数据?",
text: `来源APP${app}`,
});
if (!confirm) {
const importCheck = await showDialog.check("是否导入祈愿数据?", `来源APP${app}`);
if (!importCheck) {
showSnackbar.cancel("已取消导入");
await TGLogger.Info("[Achievements][handleImportOuter] 已取消导入");
return;
}
// 读取 剪贴板
const clipboard = await window.navigator.clipboard.readText();
const check = await verifyUiafDataClipboard();
if (!check) return;
let uidInput = await showConfirm({
mode: "input",
title: "请输入存档UID",
text: "UID:",
input: uidCur.value.toString(),
});
let uidInput = await showDialog.input("请输入存档UID", "UID:", uidCur.value.toString());
if (uidInput === false) {
showSnackbar.cancel("已取消存档导入");
return;
@@ -250,11 +236,7 @@ async function handleImportOuter(app: string): Promise<void> {
}
async function createUid(): Promise<void> {
const uidInput = await showConfirm({
mode: "input",
title: "请输入新存档UID",
text: "UID:",
});
const uidInput = await showDialog.input("请输入新存档UID", "UID:");
if (uidInput === undefined || uidInput === false) {
showSnackbar.cancel("已取消");
return;
@@ -273,11 +255,11 @@ async function createUid(): Promise<void> {
}
async function deleteUid(): Promise<void> {
const uidInput = await showConfirm({
title: "确定删除该存档?",
text: `确认则清空存档-${uidCur.value}对应数据`,
});
if (uidInput === undefined || !uidInput) {
const delCheck = await showDialog.check(
"确定删除该存档?",
`确认则清空存档-${uidCur.value}对应数据`,
);
if (!delCheck) {
showSnackbar.cancel("已取消删除存档");
return;
}

View File

@@ -120,7 +120,7 @@ import TcDataDir from "../../components/config/tc-dataDir.vue";
import TcGameBadge from "../../components/config/tc-gameBadge.vue";
import TcInfo from "../../components/config/tc-info.vue";
import TcUserBadge from "../../components/config/tc-userBadge.vue";
import showConfirm from "../../components/func/confirm.js";
import showDialog from "../../components/func/dialog.js";
import showSnackbar from "../../components/func/snackbar.js";
import ToLoading from "../../components/overlay/to-loading.vue";
import TGSqlite from "../../plugins/Sqlite/index.js";
@@ -162,16 +162,13 @@ onMounted(async () => {
// 备份数据
async function confirmBackup(): Promise<void> {
const res = await showConfirm({
title: "是否备份到默认路径",
text: "取消则自选路径,点击外部不做处理",
});
if (res === undefined) {
const bcCheck = await showDialog.check("是否备份到默认路径", "取消则自选路径,点击外部不做处理");
if (bcCheck === undefined) {
showSnackbar.cancel("已取消备份");
return;
}
let saveDir = appStore.userDir;
if (!res) {
if (!bcCheck) {
const dir: string | null = await open({
directory: true,
defaultPath: saveDir,
@@ -196,16 +193,13 @@ async function confirmBackup(): Promise<void> {
// 恢复数据
async function confirmRestore(): Promise<void> {
const resConfirm = await showConfirm({
title: "是否从默认路径恢复",
text: "取消则自选路径,点击外部不做处理",
});
if (resConfirm === undefined) {
const rsCheck = await showDialog.check("是否从默认路径恢复", "取消则自选路径,点击外部不做处理");
if (rsCheck === undefined) {
showSnackbar.cancel("已取消恢复");
return;
}
let saveDir = appStore.userDir;
if (!resConfirm) {
if (!rsCheck) {
const dir: string | null = await open({
directory: true,
defaultPath: saveDir,
@@ -231,8 +225,8 @@ async function confirmRestore(): Promise<void> {
// 更新数据
async function confirmUpdate(title?: string): Promise<void> {
const res = await showConfirm({ title: title ?? "确认更新数据吗?", text: "请确保存在备份数据" });
if (!res) {
const updateCheck = await showDialog.check(title ?? "确认更新数据吗?");
if (!updateCheck) {
showSnackbar.cancel("已取消更新数据库");
return;
}
@@ -250,11 +244,11 @@ async function confirmUpdate(title?: string): Promise<void> {
async function confirmUpdateDevice(force?: boolean): Promise<void> {
if (force !== undefined && force) {
await TGLogger.Info("[Config][confirmUpdateDevice][force] 开始强制更新设备信息");
const resF = await showConfirm({
title: "确认强制更新设备信息吗?",
text: `DeviceFp:${appStore.deviceInfo.device_fp}`,
});
if (!resF) {
const forceCheck = await showDialog.check(
"确认强制更新设备信息吗?",
`DeviceFp:${appStore.deviceInfo.device_fp}`,
);
if (!forceCheck) {
showSnackbar.cancel("已取消强制更新设备信息");
await TGLogger.Info("[Config][confirmUpdateDevice][force] 取消强制更新设备信息");
return;
@@ -274,8 +268,8 @@ async function confirmUpdateDevice(force?: boolean): Promise<void> {
await TGLogger.Info("[Config][confirmUpdateDevice] 开始更新设备信息");
const localFp = getDeviceInfo("device_fp");
if (localFp !== "0000000000000") {
const res = await showConfirm({ title: "确认更新设备信息吗?", text: `DeviceFp:${localFp}` });
if (!res) {
const updateCheck = await showDialog.check("确认更新设备信息吗?", `DeviceFp:${localFp}`);
if (!updateCheck) {
showSnackbar.cancel("已取消更新设备信息");
await TGLogger.Info("[Config][confirmUpdateDevice] 取消更新设备信息");
return;
@@ -312,11 +306,11 @@ async function confirmDelCache(): Promise<void> {
}
cacheSize.value = cacheBSize;
loading.value = false;
const res = await showConfirm({
title: "确认清除缓存吗?",
text: `当前缓存大小为 ${bytesToSize(cacheBSize)}`,
});
if (!res) {
const delCheck = await showDialog.check(
"确认清除缓存吗?",
`当前缓存大小为 ${bytesToSize(cacheBSize)}`,
);
if (!delCheck) {
showSnackbar.cancel("已取消清除缓存");
await TGLogger.Info("[Config][confirmDelCache] 取消清除缓存");
return;
@@ -335,8 +329,8 @@ async function confirmDelCache(): Promise<void> {
// 恢复默认设置
async function confirmResetApp(): Promise<void> {
await TGLogger.Info("[Config][confirmResetApp] 开始恢复默认设置");
const res = await showConfirm({ title: "确认恢复默认设置吗?" });
if (!res) {
const resetCheck = await showDialog.check("确认恢复默认设置吗?");
if (!resetCheck) {
showSnackbar.cancel("已取消恢复默认设置");
await TGLogger.Info("[Config][confirmResetApp] 取消恢复默认设置");
return;
@@ -350,18 +344,14 @@ async function confirmResetApp(): Promise<void> {
// 前置
async function tryShowReset(): Promise<void> {
const res = await showConfirm({
title: "请输入验证 Code",
text: "请联系开发者获取",
mode: "input",
});
if (!res) {
const codeInput = await showDialog.input("请输入验证 Code", "请联系开发者获取");
if (!codeInput) {
showSnackbar.cancel("已取消");
return;
}
const time = getBuildTime();
const code = time.startsWith("dev.") ? "dev" : time;
if (res === code || res === "reset1128") {
if (codeInput === code || codeInput === "reset1128") {
showReset.value = true;
showSnackbar.success("已开启重置数据库选项");
return;
@@ -372,11 +362,11 @@ async function tryShowReset(): Promise<void> {
// 重置数据库
async function confirmResetDB(title?: string): Promise<void> {
await TGLogger.Info("[Config][confirmResetDB] 开始重置数据库");
const res = await showConfirm({
title: title ?? "确认重置数据库吗?",
text: "请确认已经备份关键数据",
});
if (!res) {
const resetCheck = await showDialog.check(
title ?? "确认重置数据库吗?",
"请确认已经备份关键数据",
);
if (!resetCheck) {
showSnackbar.cancel("已取消重置数据库");
await TGLogger.Info("[Config][confirmResetDB] 取消重置数据库");
return;

View File

@@ -95,7 +95,7 @@ import { UnlistenFn } from "@tauri-apps/api/event";
import { storeToRefs } from "pinia";
import { computed, onMounted, onUnmounted, ref, watch } from "vue";
import showConfirm from "../../components/func/confirm.js";
import showDialog from "../../components/func/dialog.js";
import showSnackbar from "../../components/func/snackbar.js";
import TPostCard from "../../components/main/t-postcard.vue";
import ToCollectPost from "../../components/overlay/to-collectPost.vue";
@@ -188,11 +188,7 @@ function toSelect() {
async function addCollect(): Promise<void> {
let title, desc;
const titleC = await showConfirm({
mode: "input",
title: "新建分类",
text: "请输入分类名称",
});
const titleC = await showDialog.input("新建分类", "分类名称:");
if (titleC === undefined || titleC === false) return;
if (titleC === "未分类") {
showSnackbar.warn("分类名不可为未分类");
@@ -203,11 +199,7 @@ async function addCollect(): Promise<void> {
return;
}
title = titleC;
const descC = await showConfirm({
mode: "input",
title: "新建分类",
text: "请输入分类描述",
});
const descC = await showDialog.input("新建分类", "分类描述:");
if (descC === false) return;
if (descC === undefined) desc = title;
else desc = descC;
@@ -226,12 +218,7 @@ async function toEdit(): Promise<void> {
showSnackbar.warn("未找到合集信息");
return;
}
let cTc = await showConfirm({
title: "修改分类标题",
mode: "input",
text: "请输入分类标题",
input: collect.title,
});
let cTc = await showDialog.input("修改分类标题", "分类标题:", collect.title);
if (cTc === false) {
showSnackbar.cancel("取消修改分类信息");
return;
@@ -245,14 +232,9 @@ async function toEdit(): Promise<void> {
showSnackbar.warn("分类名称重复");
return;
}
let cTd = await showConfirm({
title: "修改分类描述",
mode: "input",
text: "请输入分类描述",
input: collect.desc,
});
let cTd = await showDialog.input("修改分类描述", "分类描述:", collect.desc);
if (typeof cTd !== "string") cTd = collect.desc;
const cc = await showConfirm({ title: "确定修改?", text: `[${cTc}] ${cTd}` });
const cc = await showDialog.check("确定修改?", `[${cTc}] ${cTd}`);
if (!cc) {
showSnackbar.cancel("取消修改分类信息");
return;
@@ -280,11 +262,8 @@ async function deletePost(force: boolean = false): Promise<void> {
return;
}
const title = force ? "删除帖子" : "移除帖子分类";
const res = await showConfirm({
title: `确定${title}?`,
text: `${selectedPost.value.length} 条帖子`,
});
if (!res) {
const check = await showDialog.check(`确定${title}?`, `${selectedPost.value.length} 条帖子`);
if (!check) {
showSnackbar.cancel("取消操作");
return;
}
@@ -311,11 +290,11 @@ async function deleteCollect(force: boolean): Promise<void> {
return;
}
const title = force ? "删除分类" : "清空分类";
const res = await showConfirm({
title: `确定${title}?`,
text: `该分类下${selected.value.length}条帖子将被${force ? "删除" : "移除分类(未分类将被删除)"}`,
});
if (!res) {
const check = await showDialog.check(
`确定${title}?`,
`该分类下 ${selected.value.length} 条帖子将被${force ? "删除" : "移除分类(未分类将被删除)"}`,
);
if (!check) {
showSnackbar.cancel("取消操作");
return;
}
@@ -377,17 +356,13 @@ watch(
);
async function freshOther(): Promise<void> {
const input = await showConfirm({
mode: "input",
title: "导入其他用户收藏",
text: "请输入用户米游社UID",
});
if (typeof input === "string") {
if (isNaN(Number(input))) {
const uidInput = await showDialog.input("导入其他用户收藏", "米游社UID");
if (typeof uidInput === "string") {
if (isNaN(Number(uidInput))) {
showSnackbar.warn("UID 格式错误,请输入数字");
return;
}
await freshUser(input);
await freshUser(uidInput);
return;
}
showSnackbar.cancel("取消导入");

View File

@@ -1,58 +0,0 @@
/**
* @file types Component Confirm.d.ts
* @description Component Confirm 类型声明文件
* @since Beta v0.3.4
*/
declare namespace TGApp.Component.Confirm {
/**
* @description Confirm 参数
* @interface ParamsBase
* @since Beta v0.3.3
* @property {string} title 标题
* @property {string} text 文本
* @property {string} mode 模式 // normal: 正常(默认),input: 输入框
* @property {boolean} otcancel 点击外部取消 // true: 取消(默认),false: 不取消
* @return ParamsBase
*/
interface ParamsBase {
title: string;
text?: string;
mode?: "confirm" | "input";
otcancel?: boolean;
}
/**
* @description Confirm 参数- confirm mode
* @interface ParamsConfirm
* @since Beta v0.3.3
* @extends ParamsBase
* @property {"confirm"|undefined} mode
* @return ParamsConfirm
*/
interface ParamsConfirm extends ParamsBase {
mode?: "confirm";
}
/**
* @description Confirm 参数 - input mode
* @interface ParamsInput
* @since Beta v0.4.5
* @extends ParamsBase
* @property {"input"} mode
* @property {string} input 可选的配置默认输入值
* @return ParamsInput
*/
interface ParamsInput extends ParamsBase {
mode: "input";
input?: string;
}
/**
* @description Confirm 参数
* @since Beta v0.3.3
* @type Params
* @return Params
*/
type Params = ParamsConfirm | ParamsInput;
}

View File

@@ -1,23 +0,0 @@
/**
* @file types Component Snackbar.d.ts
* @description Component Snackbar 类型声明文件
* @since Beta v0.6.3
*/
declare namespace TGApp.Component.Snackbar {
/**
* @description Snackbar 参数
* @interface Params
* @since Beta v0.6.3
* @property {string} text 文本
* @property {string} color 颜色
* @property {number} timeout 超时时间
* @property {boolean} show 是否显示
* @return Params
*/
interface Params {
text: string;
color: string;
timeout: number;
}
}

View File

@@ -9,7 +9,7 @@ import { save } from "@tauri-apps/plugin-dialog";
import { writeFile } from "@tauri-apps/plugin-fs";
import html2canvas from "html2canvas";
import showConfirm from "../components/func/confirm.js";
import showDialog from "../components/func/dialog.js";
import showSnackbar from "../components/func/snackbar.js";
import TGHttp from "./TGHttp.js";
@@ -137,11 +137,8 @@ export async function generateShareImg(
}
if (size > 20000000) {
const sizeStr = bytesToSize(size);
const saveFile = await showConfirm({
title: "图像过大",
text: `图像大小为 ${sizeStr},是否保存到文件?`,
});
if (saveFile === true) {
const saveCheck = await showDialog.check("图像过大", `图像大小为 ${sizeStr},是否保存到文件?`);
if (saveCheck === true) {
await saveCanvasImg(buffer, fileName);
return;
}

View File

@@ -6,7 +6,7 @@
import { emit } from "@tauri-apps/api/event";
import showConfirm from "../components/func/confirm.js";
import showDialog from "../components/func/dialog.js";
import showSnackbar from "../components/func/snackbar.js";
import TGClient from "./TGClient.js";
@@ -143,19 +143,13 @@ export async function parseLink(
"mihoyo.genshinnet.com",
];
if (prefix.includes(url.hostname) && !useInner) {
const openCheck = await showConfirm({
title: "采用内置 JSBridge",
text: "取消则使用外部浏览器打开",
});
const openCheck = await showDialog.check("采用内置 JSBridge", "取消则使用外部浏览器打开");
if (openCheck === undefined) {
showSnackbar.cancel("已取消打开");
return true;
}
if (!openCheck) return url.href;
const typeCheck = await showConfirm({
title: "采用宽屏模式?",
text: "取消则使用默认竖屏",
});
const typeCheck = await showDialog.check("采用宽屏模式?", "取消则使用默认竖屏");
if (!typeCheck) await TGClient.open("web_act_thin", link);
else await TGClient.open("web_act", link);
return true;