|
|
|
<template>
|
|
|
|
<Tooltip :infos="[t('archive.0')]" width="12rem">
|
|
|
|
<img class="menu-img" :src="menu_icons.exportGame" @click="showMenu">
|
|
|
|
</Tooltip>
|
|
|
|
|
|
|
|
<Dialog :title="t('archive.0')" v-model="showArchive" top="4rem" left='8%' @close="state.curMenu = null">
|
|
|
|
<div class="archive">
|
|
|
|
<span class="tip">* {{ t('archive.1') }}</span>
|
|
|
|
<textarea class="textarea" v-model="archive"></textarea>
|
|
|
|
</div>
|
|
|
|
<div class="footer">
|
|
|
|
<button class="button" @click="copyArchive(archive)">{{ t('copyArchive.0') }}</button>
|
|
|
|
<button class="button" @click="pasteArchive">{{ t('pasteArchive.0') }}</button>
|
|
|
|
<button class="button" @click="importArchive">{{ t('importArchive.0') }}</button>
|
|
|
|
</div>
|
|
|
|
<div class="footer">
|
|
|
|
<button class="button" @click="uploadArchive">{{ t('uploadArchive') }}</button>
|
|
|
|
<button class="button" @click="downArchive">{{ t('downArchive') }}</button>
|
|
|
|
</div>
|
|
|
|
</Dialog>
|
|
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
<script lang="ts" setup>
|
|
|
|
import { useStore } from "vuex";
|
|
|
|
import { computed, onMounted, ref, onBeforeUnmount } from "vue";
|
|
|
|
import { useI18n } from "vue3-i18n";
|
|
|
|
import { Tooltip, Dialog } from "@/components"
|
|
|
|
import { menu_icons } from "@/config";
|
|
|
|
import { getArchive, AES_CBC_ENCRYPT, AES_CBC_DECRYPT, checkImportArchive, saveArchive, replace, archive_version, MD5 } from "@/tool";
|
|
|
|
import * as API from "@/api";
|
|
|
|
|
|
|
|
const { t } = useI18n();
|
|
|
|
const { state, commit, dispatch } = useStore();
|
|
|
|
const showArchive = computed(() => {
|
|
|
|
return state.curMenu == 'archive';
|
|
|
|
});
|
|
|
|
const archive = ref('');
|
|
|
|
const key = 'KUf4hM5rThssysJhcRFCfxLR8Imihjl0eMsyhh1M7Wk';
|
|
|
|
let timeOut = 0;
|
|
|
|
const strengthenLv = computed(() => {
|
|
|
|
const player = state.playerAttribute;
|
|
|
|
const equips = [player.weapon, player.armor, player.neck, player.ring, player.jewelry, player.pants, player.shoes, player.bracers];
|
|
|
|
let lv = 0;
|
|
|
|
equips.forEach(equip => {
|
|
|
|
equip && (lv += equip.strengthenLv)
|
|
|
|
})
|
|
|
|
return lv;
|
|
|
|
});
|
|
|
|
|
|
|
|
const showMenu = () => {
|
|
|
|
if (showArchive.value) {
|
|
|
|
state.curMenu = null;
|
|
|
|
} else {
|
|
|
|
state.curMenu = 'archive';
|
|
|
|
getArchive().then((rsp: any) => {
|
|
|
|
archive.value = AES_CBC_ENCRYPT(JSON.stringify(rsp), key);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const copyArchive = (archive) => {
|
|
|
|
if (navigator.clipboard && window.isSecureContext) {
|
|
|
|
navigator.clipboard.writeText(archive).then(() => {
|
|
|
|
commit('set_sys_info', { msg: t('copyArchive.1'), type: 'win' })
|
|
|
|
showMenu();
|
|
|
|
}).catch(() => {
|
|
|
|
commit('set_sys_info', { msg: t('copyArchive.2'), type: 'waring' })
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
const textField = document.createElement("textarea");
|
|
|
|
textField.innerText = archive;
|
|
|
|
document.body.appendChild(textField);
|
|
|
|
textField.select();
|
|
|
|
document.execCommand("copy");
|
|
|
|
textField.remove();
|
|
|
|
commit('set_sys_info', { msg: t('copyArchive.1'), type: 'win' })
|
|
|
|
showMenu();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const uploadArchive = () => {
|
|
|
|
API.getUser().then(user => {
|
|
|
|
if (user) {
|
|
|
|
const palyer = state.playerAttribute;
|
|
|
|
const data = { version: archive_version, lv: palyer.lv, coins: palyer.coins, strengthenLv: strengthenLv.value, archive: archive.value }
|
|
|
|
API.uploadArchive(data).then(rsp => rsp && showMenu());
|
|
|
|
} else {
|
|
|
|
state.showLogin = true;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
const downArchive = () => {
|
|
|
|
API.getUser().then(user => {
|
|
|
|
if (user) {
|
|
|
|
API.downArchive({ version: archive_version }).then((rsp: any) => {
|
|
|
|
if (rsp) {
|
|
|
|
archive.value = rsp;
|
|
|
|
importArchive();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
state.showLogin = true;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
const pasteArchive = () => {
|
|
|
|
const name: any = 'clipboard-read';
|
|
|
|
navigator.permissions.query({ name: name }).then(result => {
|
|
|
|
if (result.state === 'granted') {
|
|
|
|
navigator.clipboard.readText().then(text => {
|
|
|
|
archive.value = text;
|
|
|
|
commit('set_sys_info', { msg: t('pasteArchive.1'), type: 'win' })
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
commit('set_sys_info', { msg: t('pasteArchive.2'), type: 'waring' })
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
const importArchive = async () => {
|
|
|
|
try {
|
|
|
|
const data = JSON.parse(AES_CBC_DECRYPT(archive.value, key));
|
|
|
|
if (!data || data == 'undfind') {
|
|
|
|
commit('set_sys_info', { msg: t('loadEmpty'), type: 'warning' });
|
|
|
|
}
|
|
|
|
if (data.version != archive_version) {
|
|
|
|
commit('set_sys_info', { msg: t('importArchive.3'), type: 'warning' });
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
await checkImportArchive(data);
|
|
|
|
await dispatch('loadGame', data);
|
|
|
|
if (state.experiential) {
|
|
|
|
commit('set_sys_info', { msg: replace(t('experiential.0'), [data.experientialTime]), type: 'win' });
|
|
|
|
const time = data.experientialTime || 10;
|
|
|
|
clearTimeout(timeOut);
|
|
|
|
timeOut = setTimeout(() => {
|
|
|
|
commit('set_sys_info', { msg: replace(t('experiential.2'), [data.experientialTime]), type: 'warning' });
|
|
|
|
dispatch('loadGame');
|
|
|
|
}, time * 60 * 100);
|
|
|
|
} else {
|
|
|
|
saveArchive(state);
|
|
|
|
}
|
|
|
|
showMenu();
|
|
|
|
} catch (error) {
|
|
|
|
console.log(error);
|
|
|
|
commit('set_sys_info', { msg: t('loadError'), type: 'warning' });
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const keydown = (e) => {
|
|
|
|
if (e.keyCode == 65 && !e.ctrlKey) {
|
|
|
|
showMenu();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
onMounted(() => {
|
|
|
|
document.addEventListener('keydown', keydown);
|
|
|
|
});
|
|
|
|
onBeforeUnmount(() => {
|
|
|
|
document.removeEventListener('keydown', keydown);
|
|
|
|
clearTimeout(timeOut);
|
|
|
|
})
|
|
|
|
|
|
|
|
onMounted(() => { });
|
|
|
|
</script>
|
|
|
|
<style lang="scss" scoped>
|
|
|
|
.archive {
|
|
|
|
padding: 0.7rem;
|
|
|
|
display: flex;
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
|
|
.tip {
|
|
|
|
color: white;
|
|
|
|
font-size: 0.8rem;
|
|
|
|
margin: 0.25rem 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
.textarea {
|
|
|
|
width: 25rem;
|
|
|
|
height: 15rem;
|
|
|
|
user-select: text;
|
|
|
|
background: rgba($color: #ffffff, $alpha: 0.8);
|
|
|
|
}
|
|
|
|
|
|
|
|
.footer {
|
|
|
|
border-top: 1px solid #ccc;
|
|
|
|
padding: 0.4rem;
|
|
|
|
display: flex;
|
|
|
|
align-items: center;
|
|
|
|
justify-content: center;
|
|
|
|
}
|
|
|
|
|
|
|
|
@media only screen and (max-width: 768px) {
|
|
|
|
.archive {
|
|
|
|
padding: 0.3rem;
|
|
|
|
|
|
|
|
.tip {
|
|
|
|
color: white;
|
|
|
|
font-size: 0.8rem;
|
|
|
|
margin: 0.25rem 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
.textarea {
|
|
|
|
width: 22rem;
|
|
|
|
height: 20rem;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
</style>
|