Files
space/src/views/ForeverMC.vue
2025-07-16 16:41:21 +08:00

263 lines
6.2 KiB
Vue

<template>
<div class="forever-mc">
<loading v-if="doFetching" :show-on="doFetching" />
<template v-else>
<markdown-view :content="computedBindTips" />
<t-table
class="table"
row-key="id"
:data="playerList"
:columns="columns"
>
<template #lastLoginAt="{ row }">
<span v-text="Time.toDateTime(row.lastLoginAt)"></span>
</template>
<template #action="{ row }">
<icon
class="cur-pointer"
name="FAIL"
fill="RED"
@click="doDelete(row.id)"
v-popup="`解除绑定`"
/>
</template>
</t-table>
<t-form class="bind-form" :disabled="computedBoundMax">
<p
v-if="computedBoundMax"
class="bound-max-tips red"
v-text="`已达到最大绑定数量:${maxBind}`"
></p>
<t-form-item label="添加绑定" name="name">
<t-input class="short" v-model="newBind" placeholder="请输入玩家昵称" />
<template #statusIcon>
<t-button
class="submit"
theme="success"
:disabled="doSubmittingBind || computedBoundMax"
@click="doSubmitBind"
>提交</t-button>
</template>
</t-form-item>
</t-form>
</template>
</div>
<t-dialog
class="unbind-confirm-dialog"
v-model:visible="visibleUnbindConfirmDialog"
attach="body"
:close-btn="false"
header="注意: "
>
<template #body>
<markdown-view :content="computedUnbindTips" />
</template>
<template #footer>
<div class="footer">
<t-button
class="submit"
theme="default"
@click="doSubmitUnbind"
:loading="doSubmittingUnbind"
:disabled="doSubmittingUnbind || delayConfirm"
:content="confirmBtnText"
/>
<t-button
@click="visibleUnbindConfirmDialog = false"
:disabled="doSubmittingUnbind"
content="取消"
/>
</div>
</template>
</t-dialog>
</template>
<script lang="ts" setup>
import {
CommonAPI,
Icon,
Loading,
MarkdownView,
SettingKey,
SettingMapper,
TemplateBizType,
Time,
Toolkit
} from "timi-web";
import MinecraftAPI from "@/api/MinecraftAPI.ts";
import { useVisitUserStore } from "@/store/visitUser.ts";
import { MinecraftPlayer } from "@/types/MinecraftPlayer.ts";
import { MessagePlugin } from "tdesign-vue-next";
defineOptions({
name: "ForeverMC"
});
const visitUserStore = useVisitUserStore();
const columns = computed(() => [
{
title: "昵称",
colKey: "name",
width: "40%"
},
{
title: "上次登录",
colKey: "lastLoginAt",
align: "center"
},
{
align: "right",
width: "3rem",
colKey: "id",
cell: "action"
}
]);
const tipsBind = ref();
const tipsUnbind = ref();
const computedBindTips = computed(() => {
if (tipsBind.value) {
return Toolkit.format(tipsBind.value, {
maxBind: SettingMapper.getValue(SettingKey.FMC_MAX_BIND)
});
}
return "";
});
onMounted(() => {
Toolkit.async(async () => {
tipsBind.value = await CommonAPI.getTemplate(TemplateBizType.FOREVER_MC, "PLAYER_BIND");
tipsUnbind.value = await CommonAPI.getTemplate(TemplateBizType.FOREVER_MC, "PLAYER_UNBIND");
});
});
const playerList = ref<MinecraftPlayer[]>([]);
const doFetching = ref<boolean>(false);
async function doFetch() {
if (!doFetching.value) {
doFetching.value = true;
playerList.value.length = 0;
playerList.value.push(...(await MinecraftAPI.list()));
}
doFetching.value = false;
}
watch(() => visitUserStore.visitUserView, doFetch);
onMounted(() => Toolkit.async(async () => await doFetch()));
const newBind = ref();
const maxBind = SettingMapper.getValueRef(SettingKey.FMC_MAX_BIND);
const doSubmittingBind = ref<boolean>(false);
async function doSubmitBind() {
doSubmittingBind.value = true;
await Toolkit.sleep(1E3);
MinecraftAPI.bind(newBind.value).then(async () => {
await MessagePlugin.success("添加绑定成功");
await doFetch();
newBind.value = "";
doSubmittingBind.value = false;
}).catch(async (msg: string) => {
await MessagePlugin.error(msg);
doSubmittingBind.value = false;
});
}
const doSubmittingUnbind = ref<boolean>(false);
const visibleUnbindConfirmDialog = ref<boolean>(false);
const unbindId = ref<number>();
const delayConfirm = ref<boolean>(false);
const delaySeconds = ref<number>(8);
const delayTimer = ref();
watch(visibleUnbindConfirmDialog, () => delayConfirm.value = visibleUnbindConfirmDialog.value);
watch(delayConfirm, () => {
if (delayTimer.value) {
clearInterval(delayTimer.value);
}
delaySeconds.value = 8;
delayTimer.value = setInterval(() => {
delaySeconds.value--;
if (delaySeconds.value === 0) {
delayConfirm.value = false;
clearInterval(delayTimer.value);
}
}, 1E3);
});
const computedBoundMax = computed(() => SettingMapper.getValue(SettingKey.FMC_MAX_BIND) as any as number <= playerList.value.length);
const computedUnbindTips = computed(() => {
if (unbindId.value) {
return Toolkit.format(tipsUnbind.value, {
name: playerList.value.find(i => i.id === unbindId.value)?.name
});
}
return "";
});
const confirmBtnText = computed(() => {
if (delayConfirm.value) {
return `确认 (${delaySeconds.value})`;
}
if (doSubmittingUnbind.value) {
return "正在保存..";
}
return "确认";
});
async function doSubmitUnbind() {
if (unbindId.value) {
doSubmittingUnbind.value = true;
await Toolkit.sleep(1E3);
MinecraftAPI.unbind(unbindId.value).then(async () => {
await MessagePlugin.success("解除绑定成功");
await doFetch();
visibleUnbindConfirmDialog.value = doSubmittingUnbind.value = false;
}).catch(async (msg: string) => {
await MessagePlugin.error(msg);
visibleUnbindConfirmDialog.value = doSubmittingUnbind.value = false;
});
}
}
async function doDelete(id: number) {
unbindId.value = id;
visibleUnbindConfirmDialog.value = true;
}
</script>
<style lang="less" scoped>
.forever-mc {
padding: 2rem 4rem;
display: flex;
transition: padding 500ms var(--tui-bezier);
align-items: center;
flex-direction: column;
justify-content: center;
.table {
max-width: 26rem;
margin-top: 2rem;
}
.bind-form {
margin: 1rem 0;
.bound-max-tips {
text-align: center;
}
.submit {
width: 4rem;
display: block;
}
}
}
@media screen and (max-width: 720px) {
.forever-mc {
padding: 2rem;
transition: padding 500ms var(--tui-bezier);
}
}
:global(.update-confirm-dialog .footer) {
display: flex;
justify-content: center;
}
</style>