mirror of
https://github.com/BTMuli/TeyvatGuide.git
synced 2025-12-15 09:48:14 +08:00
♻️ showConfirm重构
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
@@ -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>
|
||||
113
src/components/func/dialog.ts
Normal file
113
src/components/func/dialog.ts
Normal 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;
|
||||
294
src/components/func/dialog.vue
Normal file
294
src/components/func/dialog.vue
Normal 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>
|
||||
@@ -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,
|
||||
|
||||
@@ -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%);
|
||||
}
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user