This commit is contained in:
2026-04-20 00:00:48 +08:00
parent dbf33477d9
commit cda93965e3
33 changed files with 677 additions and 317 deletions
@@ -11,6 +11,7 @@ import {
renderList,
watch,
} from 'vue'
import { getElementZoom } from '@/utils/position'
type HandleChangeFunction = (value: string | number) => string[] | Promise<string[]>
@@ -55,10 +56,12 @@ export default defineComponent({
function onResize() {
if (triggerRef.value) {
const { width, height, left, top } = triggerRef.value.getBoundingClientRect()
const zoom = getElementZoom('body')
dropdownPosition.value = {
w: width,
x: left,
y: top + height + 2,
w: width / zoom,
x: left / zoom,
y: (top + height + 2) / zoom,
}
}
}
@@ -4,6 +4,7 @@ import type { CSSProperties, PropType } from 'vue'
import { Teleport, Transition, computed, defineComponent, onDeactivated, ref, watch } from 'vue'
import { onClickOutside, useVModel } from '@vueuse/core'
import { getElementZoom } from '@/utils/position'
interface ICascaderItem {
label: string
id?: string | number
@@ -74,18 +75,19 @@ export default defineComponent({
function onResize() {
if (triggerRef.value) {
const { width, height, left, top } = triggerRef.value.getBoundingClientRect()
const zoom = getElementZoom('body')
if (window.innerHeight - top > 160) {
dropdownPosition.value = {
w: width,
x: left,
y: top + height + 2,
w: width / zoom,
x: left / zoom,
y: (top + height + 2) / zoom,
z: 0,
}
} else {
dropdownPosition.value = {
w: width,
x: left,
z: window.innerHeight - top + 2,
w: width / zoom,
x: left / zoom,
z: (window.innerHeight - top + 2) / zoom,
y: 0,
}
}
@@ -13,6 +13,7 @@ import {
} from 'vue'
import { onClickOutside } from '@vueuse/core'
import { getElementZoom } from '@/utils/position'
export default defineComponent({
name: 'IIconselect',
@@ -72,20 +73,24 @@ export default defineComponent({
const dropdownPosition = ref({ x: 0, y: 0, w: 0 })
// 下拉框位置
const dropdownStyle = computed<CSSProperties>(() => {
const zoom = getElementZoom(appendToRef.value)
return {
left: `${dropdownPosition.value.x}px`,
top: `${dropdownPosition.value.y}px`,
width: `${columnNum.value * 32 + 11}px`,
width: `${(columnNum.value * 32 + 11) / zoom}px`,
}
})
function onResize() {
if (triggerRef.value) {
const { width, height, left, top } = triggerRef.value.getBoundingClientRect()
const zoom = getElementZoom(appendToRef.value)
dropdownPosition.value = {
w: width,
x: left - 2,
y: (top + height + 2),
w: width / zoom,
x: (left - 2) / zoom,
y: (top + height + 2) / zoom,
}
}
}
@@ -15,6 +15,7 @@ import {
import { onClickOutside, useVModel } from '@vueuse/core'
import { classPropType, labelPropType } from '@/components/hooks/types'
import { getElementZoom } from '@/utils/position'
export default defineComponent({
name: 'ISelect',
@@ -98,18 +99,19 @@ export default defineComponent({
function onResize() {
if (triggerRef.value) {
const { width, height, left, top } = triggerRef.value.getBoundingClientRect()
const zoom = getElementZoom(appendToRef.value)
if (window.innerHeight - top > 160) {
dropdownPosition.value = {
w: width,
x: left,
y: (top + height + 2),
w: width / zoom,
x: left / zoom,
y: (top + height + 2) / zoom,
z: 0,
}
} else {
dropdownPosition.value = {
w: width,
x: left,
z: (window.innerHeight - top + 2),
w: width / zoom,
x: left / zoom,
z: (window.innerHeight - top + 2) / zoom,
y: 0,
}
}
@@ -3,7 +3,9 @@
<div class="relative" :class="{ inactive: props.inactive }">
<div
class="w-28px h-28px"
:style="{ backgroundImage: `url(${getImageURL(props.equipment?.imageUrl)})` }"
:style="{
backgroundImage: `url(${getImageURL((useDisplayUrl ? props.equipment?.displayUrl : props.equipment?.imageUrl) || '')})`,
}"
>
<img :src="getLocalImageURL(rarity)" />
</div>
@@ -21,6 +23,7 @@ import { getImageURL } from '@/utils/images'
const props = defineProps<{
equipment?: IEquipment
inactive?: boolean
useDisplayUrl?: boolean
}>()
const rarity = computed(() => {
@@ -38,16 +38,12 @@
</div>
<!-- 装备属性 -->
<div class="divide"></div>
<div
class="flex flex-col items-start my-1px whitespace-pre-wrap leading-15px"
>
<div class="flex flex-col items-start my-1px whitespace-pre-wrap leading-15px">
<div class="text-#DED29A py-4px whitespace-pre-wrap" v-html="detail"></div>
</div>
<template v-if="bufferDetail">
<div class="divide"></div>
<div
class="flex flex-col items-start my-1px whitespace-pre-wrap leading-15px"
>
<div class="flex flex-col items-start my-1px whitespace-pre-wrap leading-15px">
<div class="text-#A48B2E mb-10px pt-4px">辅助职业专属属性</div>
<div class="text-#DED29A pb-10px whitespace-pre-wrap" v-html="bufferDetail"></div>
</div>
@@ -95,16 +91,18 @@ const mainAttr = computed(() => {
// a.match(/\[(?!.*?技能).*?]/g)
const detail = computed(() =>
props.equipment?.detail.replace(
/\[(?![^\]]*技能)[^\[\]]+\]/g, match => `<span style="color:#3d9147">${match}</span>`
)
props.equipment?.detail?.replace(
/\[(?![^\]]*技能)[^\[\]]+\]/g,
(match) => `<span style="color:#3d9147">${match}</span>`,
),
)
const bufferDetail = computed(() => {
const detail = props.equipment?.bufferDetail
if (!detail || detail == '-') return undefined
return props.equipment?.bufferDetail.replace(
/\[(?![^\]]*技能)[^\[\]]+\]/g, match => `<span style="color:#3d9147">${match}</span>`
/\[(?![^\]]*技能)[^\[\]]+\]/g,
(match) => `<span style="color:#3d9147">${match}</span>`,
)
})
</script>
@@ -96,7 +96,7 @@ const equ = (id: string) => {
const infoStyle = (part: string) => {
let x = 10
let y = 5
let y = 10
let index = infoStore.parts.findIndex((p) => p == part)
if (index == 13) {
index -= 7
@@ -0,0 +1,182 @@
<template>
<div
class="pos-relative w-264px h-full"
:style="{ backgroundImage: withBg ? `url(${getImageURL('/common/oath/head.png')})` : 'none' }"
>
<template v-for="part in parts" :key="part">
<div
class="pos-absolute text-white/50 w-26px h-26px border-1px border-solid border-#7a7a7a/50 flex items-center justify-center"
:style="infoStyle(part)"
@click="choosePart(part)"
>
<template v-if="detail?.[part]?.id">
<EquipmentIcon :equipment="equ(detail[part].id, part)" useDisplayUrl />
</template>
<template v-else-if="!withBg">
{{ part != '11' ? '星蕴' : '誓约' }}
</template>
</div>
<!-- <div v-if="detail?.[part]?.fusion" class="pos-absolute" :style="fusionStyle(part)">
<EquipmentIcon :equipment="oaths(detail[part].fusion)" />
</div> -->
</template>
<!-- <img
v-if="props.avatar"
:src="props.avatar"
alt="Avatar"
class="pos-absolute w-70% left-1/2 translate-x--1/2 -bottom-10px"
/> -->
</div>
</template>
<script lang="ts" setup name="EquList">
import { getImageURL } from '@/utils/images'
import EquipmentIcon from '@/components/dnf/Equipment/Icon/index.vue'
import { useInfoStore, type IConfigOath } from '@/stores'
const props = defineProps({
withBg: {
type: Boolean,
default: true,
},
detail: {
type: Object as PropType<Record<string, IConfigOath>>,
},
})
const partModelValue = defineModel('part', { default: '0' })
const infoStore = useInfoStore()
const parts = computed(() => {
const parts = infoStore.oathParts
return parts
})
const equ = (id: string, part: string) => {
return infoStore.oaths.find((e) => e.id == id && e.oathPos == part)
}
const position = [
{
x: 30,
y: 12,
},
{
x: 30,
y: 46,
},
{
x: 30,
y: 80.5,
},
{
x: 30,
y: 114,
},
{
x: 206,
y: 12,
},
{
x: 206,
y: 46,
},
{
x: 206,
y: 80.5,
},
{
x: 206,
y: 114,
},
{
x: 74,
y: 131.5,
},
{
x: 118,
y: 145.5,
},
{
x: 162,
y: 131.5,
},
{
x: 118,
y: 111,
},
]
const positionSimple = [
{
x: 30,
y: 12,
},
{
x: 30,
y: 46,
},
{
x: 30,
y: 80.5,
},
{
x: 30,
y: 114,
},
{
x: 206,
y: 12,
},
{
x: 206,
y: 46,
},
{
x: 206,
y: 80.5,
},
{
x: 206,
y: 114,
},
{
x: 74,
y: 114,
},
{
x: 118,
y: 114,
},
{
x: 162,
y: 114,
},
{
x: 118,
y: 80.5,
},
]
const infoStyle = (part: string) => {
if (props.withBg)
return {
left: `${position[parseInt(part)].x}px`,
top: `${position[parseInt(part)].y}px`,
zIndex: 6,
// fontWeight: 900,
}
else
return {
left: `${positionSimple[parseInt(part)].x}px`,
top: `${positionSimple[parseInt(part)].y}px`,
zIndex: 6,
// fontWeight: 900,
}
}
const choosePart = (part: string) => {
partModelValue.value = part
}
</script>
<style lang="scss" scoped></style>