new:新增技能导出
This commit is contained in:
@@ -28,6 +28,13 @@
|
||||
class="ml-1"
|
||||
icon="exchange"
|
||||
></calc-button>
|
||||
<calc-button
|
||||
title="技能加点导出"
|
||||
@click="exportSkillTree"
|
||||
:disabled="exportingSkillTree || !infoStore.infos"
|
||||
class="ml-1"
|
||||
icon="share"
|
||||
></calc-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -51,8 +58,16 @@ import ImportVue from './Config/import.vue'
|
||||
import ImportSkillVue from './Config/importSkill.vue'
|
||||
import ImportDnfhelper from './Config/importDnfhelper.vue'
|
||||
import Result from './Result/Index.vue'
|
||||
import SkillTree from './Skill/components/SkillTree'
|
||||
import { useDnfHelperStore } from '@/stores/dnfhelper.ts'
|
||||
import { type IHelperRoleInfo } from '@/api/info/type'
|
||||
import { useDialog } from '@/components/hooks/dialog'
|
||||
import { toPng } from 'html-to-image'
|
||||
import { h, nextTick, render } from 'vue'
|
||||
|
||||
const skillTreeExportWidth = 550
|
||||
const skillTreeExportPixelRatio = 2
|
||||
|
||||
const props = defineProps<{
|
||||
alter: string
|
||||
}>()
|
||||
@@ -63,6 +78,8 @@ const importVisible = ref(false)
|
||||
const importSkillVisible = ref(false)
|
||||
const helperStore = useDnfHelperStore()
|
||||
const toImport = ref<IHelperRoleInfo>()
|
||||
const exportingSkillTree = ref(false)
|
||||
const { alert } = useDialog()
|
||||
|
||||
// const shouldWatch = ref(true)
|
||||
|
||||
@@ -92,6 +109,79 @@ const showImportSkill = () => {
|
||||
importSkillVisible.value = true
|
||||
}
|
||||
|
||||
const waitForSkillImages = async (root: HTMLElement) => {
|
||||
const pendingImages = Array.from(root.querySelectorAll('img')).filter((image) => !image.complete)
|
||||
if (pendingImages.length === 0) return
|
||||
|
||||
await Promise.race([
|
||||
Promise.all(
|
||||
pendingImages.map(
|
||||
(image) =>
|
||||
new Promise<void>((resolve) => {
|
||||
image.addEventListener('load', () => resolve(), { once: true })
|
||||
image.addEventListener('error', () => resolve(), { once: true })
|
||||
}),
|
||||
),
|
||||
),
|
||||
new Promise<void>((resolve) => window.setTimeout(resolve, 3000)),
|
||||
])
|
||||
}
|
||||
|
||||
const exportSkillTree = async () => {
|
||||
if (exportingSkillTree.value || !infoStore.infos) return
|
||||
|
||||
exportingSkillTree.value = true
|
||||
const exportHost = document.createElement('div')
|
||||
exportHost.className = 'skill-tree-export-host'
|
||||
const exportRoot = document.createElement('div')
|
||||
exportRoot.className = 'skill-tree-export-root'
|
||||
exportHost.appendChild(exportRoot)
|
||||
document.body.appendChild(exportHost)
|
||||
|
||||
try {
|
||||
render(
|
||||
h(SkillTree, {
|
||||
skills: infoStore.skills,
|
||||
lvInfo: configStore.config.skills,
|
||||
bindAwake: configStore.config.bindAwake,
|
||||
alter: infoStore.infos.alter,
|
||||
}),
|
||||
exportRoot,
|
||||
)
|
||||
|
||||
await nextTick()
|
||||
await document.fonts.ready
|
||||
await waitForSkillImages(exportRoot)
|
||||
|
||||
const exportHeight = exportRoot.scrollHeight
|
||||
const dataUrl = await toPng(exportRoot, {
|
||||
width: skillTreeExportWidth,
|
||||
height: exportHeight,
|
||||
canvasWidth: skillTreeExportWidth,
|
||||
canvasHeight: exportHeight,
|
||||
pixelRatio: skillTreeExportPixelRatio,
|
||||
backgroundColor: '#101012',
|
||||
cacheBust: true,
|
||||
})
|
||||
|
||||
const fileName = `${infoStore.infos.name || props.alter}-技能加点.png`.replace(
|
||||
/[\\/:*?"<>|]/g,
|
||||
'-',
|
||||
)
|
||||
const downloadLink = document.createElement('a')
|
||||
downloadLink.download = fileName
|
||||
downloadLink.href = dataUrl
|
||||
downloadLink.click()
|
||||
} catch (error) {
|
||||
console.error('技能加点导出失败', error)
|
||||
await alert({ content: '技能加点导出失败,请稍后重试' })
|
||||
} finally {
|
||||
render(null, exportRoot)
|
||||
exportHost.remove()
|
||||
exportingSkillTree.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const route = useRoute()
|
||||
|
||||
onMounted(async () => {
|
||||
@@ -163,4 +253,19 @@ onUnmounted(() => {
|
||||
left: 0;
|
||||
background-color: rgba(50, 50, 50, 0.75);
|
||||
}
|
||||
|
||||
.skill-tree-export-host {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: -10000px;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.skill-tree-export-root {
|
||||
width: 550px;
|
||||
min-width: 550px;
|
||||
overflow: visible;
|
||||
color: #e9c558;
|
||||
background: #101012;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -4,7 +4,7 @@ import { useVModel } from '@vueuse/core'
|
||||
import CalcButton from '@/components/calc/button/index.vue'
|
||||
import './style.scss'
|
||||
|
||||
const rowPrefixes = ['通用', 1, '', 10, '', 20, '', 30, '', 40, 50, 60, 70, 80, 90, 100]
|
||||
const rowPrefixes = ['通用', 1, '', 10, '', 20, '', 30, '', 40, '', 50, 60, 70, 80, 90, 100]
|
||||
const defaultColumnCount = 11
|
||||
const altersWithoutRowPrefix = new Set(['creator', 'dark_knight'])
|
||||
|
||||
|
||||
Reference in New Issue
Block a user