1
This commit is contained in:
@@ -208,6 +208,34 @@ async def get_skill_data_summary(
|
|||||||
job (str): 职业名称,必填参数
|
job (str): 职业名称,必填参数
|
||||||
skills (str, optional): 技能列表字符串,逗号拼接技能名称,不传递或者传递为空时,查询所有技能,默认为''
|
skills (str, optional): 技能列表字符串,逗号拼接技能名称,不传递或者传递为空时,查询所有技能,默认为''
|
||||||
weapons (str, optional): 武器类型列表字符串,逗号拼接武器类型名称,不传递或者传递为空时,查询所有武器类型,默认为''
|
weapons (str, optional): 武器类型列表字符串,逗号拼接武器类型名称,不传递或者传递为空时,查询所有武器类型,默认为''
|
||||||
|
|
||||||
|
Response:
|
||||||
|
{
|
||||||
|
"code": int,
|
||||||
|
"message": str,
|
||||||
|
"data": [
|
||||||
|
{
|
||||||
|
"技能名称": str,
|
||||||
|
"武器类型": str,
|
||||||
|
"职业": str,
|
||||||
|
"技能描述": str,
|
||||||
|
"技能等级": int,
|
||||||
|
"冷却时间": float,
|
||||||
|
"消耗": str,
|
||||||
|
"伤害": float,
|
||||||
|
# 已学等级
|
||||||
|
"learnedLevel": int | str,
|
||||||
|
"基础百分比": float | str,
|
||||||
|
"等效百分比": float | str,
|
||||||
|
"原始冷却": float | str,
|
||||||
|
"实际冷却": float | str,
|
||||||
|
"理论秒伤": float | str,
|
||||||
|
"SP": float | None | str,
|
||||||
|
# 所在等级
|
||||||
|
"unlockAtRoleLevel": str | None,
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
"""
|
"""
|
||||||
job = job.replace('(', '(').replace(')', ')')
|
job = job.replace('(', '(').replace(')', ')')
|
||||||
key = f'openapi:skillData:summary:{job}'
|
key = f'openapi:skillData:summary:{job}'
|
||||||
|
|||||||
+1
-1
Submodule backend/openapi updated: 8ec11073e6...20f052e93e
@@ -7,7 +7,7 @@ requires-python = ">=3.10"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"aiohttp>=3.13.3",
|
"aiohttp>=3.13.3",
|
||||||
"fastapi[all]>=0.115.11",
|
"fastapi[all]>=0.115.11",
|
||||||
"fastmcp>=3.1.0",
|
"fastmcp>=3.3.1",
|
||||||
"redis>=5.2.1",
|
"redis>=5.2.1",
|
||||||
"requests>=2.32.3",
|
"requests>=2.32.3",
|
||||||
"sqlalchemy>=2.0.38",
|
"sqlalchemy>=2.0.38",
|
||||||
|
|||||||
Generated
+66
-16
@@ -200,14 +200,15 @@ wheels = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "authlib"
|
name = "authlib"
|
||||||
version = "1.6.9"
|
version = "1.7.2"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "cryptography" },
|
{ name = "cryptography" },
|
||||||
|
{ name = "joserfc" },
|
||||||
]
|
]
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/af/98/00d3dd826d46959ad8e32af2dbb2398868fd9fd0683c26e56d0789bd0e68/authlib-1.6.9.tar.gz", hash = "sha256:d8f2421e7e5980cc1ddb4e32d3f5fa659cfaf60d8eaf3281ebed192e4ab74f04", size = 165134, upload-time = "2026-03-02T07:44:01.998Z" }
|
sdist = { url = "https://files.pythonhosted.org/packages/36/98/7d93f30d029643c0275dbc0bd6d5a6f670661ee6c9a94d93af7ab4887600/authlib-1.7.2.tar.gz", hash = "sha256:2cea25fefcd4e7173bdf1372c0afc265c8034b23a8cd5dcb6a9164b826c64231", size = 176511, upload-time = "2026-05-06T08:10:23.116Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/53/23/b65f568ed0c22f1efacb744d2db1a33c8068f384b8c9b482b52ebdbc3ef6/authlib-1.6.9-py2.py3-none-any.whl", hash = "sha256:f08b4c14e08f0861dc18a32357b33fbcfd2ea86cfe3fe149484b4d764c4a0ac3", size = 244197, upload-time = "2026-03-02T07:44:00.307Z" },
|
{ url = "https://files.pythonhosted.org/packages/fb/95/adcb68e20c34162e9135f370d6e31737719c2b6f94bc953fe7ed1f10fe21/authlib-1.7.2-py2.py3-none-any.whl", hash = "sha256:3e1faedc9d87e7d56a164eca3ccb6ace0d61b94abe83e92242f8dc8bba9b4a9f", size = 259548, upload-time = "2026-05-06T08:10:21.436Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -533,7 +534,7 @@ dependencies = [
|
|||||||
requires-dist = [
|
requires-dist = [
|
||||||
{ name = "aiohttp", specifier = ">=3.13.3" },
|
{ name = "aiohttp", specifier = ">=3.13.3" },
|
||||||
{ name = "fastapi", extras = ["all"], specifier = ">=0.115.11" },
|
{ name = "fastapi", extras = ["all"], specifier = ">=0.115.11" },
|
||||||
{ name = "fastmcp", specifier = ">=3.1.0" },
|
{ name = "fastmcp", specifier = ">=3.3.1" },
|
||||||
{ name = "redis", specifier = ">=5.2.1" },
|
{ name = "redis", specifier = ">=5.2.1" },
|
||||||
{ name = "requests", specifier = ">=2.32.3" },
|
{ name = "requests", specifier = ">=2.32.3" },
|
||||||
{ name = "sqlalchemy", specifier = ">=2.0.38" },
|
{ name = "sqlalchemy", specifier = ">=2.0.38" },
|
||||||
@@ -639,12 +640,47 @@ standard = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fastmcp"
|
name = "fastmcp"
|
||||||
version = "3.1.0"
|
version = "3.3.1"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
{ name = "fastmcp-slim", extra = ["client", "server"] },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/3b/a9/5c5a01b6abd5346bf60b97cfd29e4a86661940c27dd562bfcda07fd03519/fastmcp-3.3.1.tar.gz", hash = "sha256:979362ea557de42a5f40342563c7e4b236bcc8e7cd192715f50030695d1a71cd", size = 28681699, upload-time = "2026-05-15T15:50:39.673Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/9f/11/6b1bdada6ccfe647d615ae63f9106f8136aec17971e9361546af01c7d38e/fastmcp-3.3.1-py3-none-any.whl", hash = "sha256:862440c5c4d281363a5995eee59d77f0f7cac1f18869038729cecf03b02fc522", size = 7903, upload-time = "2026-05-15T15:50:36.424Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fastmcp-slim"
|
||||||
|
version = "3.3.1"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "platformdirs" },
|
||||||
|
{ name = "pydantic", extra = ["email"] },
|
||||||
|
{ name = "pydantic-settings" },
|
||||||
|
{ name = "python-dotenv" },
|
||||||
|
{ name = "rich" },
|
||||||
|
{ name = "typing-extensions" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/d1/a0/627103e517e1d0d6f1eec633d5662d13e776f01b45ad188e4f5f7478b438/fastmcp_slim-3.3.1.tar.gz", hash = "sha256:0957835fc59452e143ab2f4b7836d2d2df9b2d9958408edc79ba8b56232b2a88", size = 567007, upload-time = "2026-05-15T15:50:10.426Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/7a/ee/97047f4cc2d7b1d46670d08d8ad01a96e7a748cc01c0b4b351ad8eddbc7a/fastmcp_slim-3.3.1-py3-none-any.whl", hash = "sha256:6cf1c2d77e3adb0d409d6825ed6b0b2a999062973e00b8eea03bd48bf9b4c043", size = 738644, upload-time = "2026-05-15T15:50:08.336Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.optional-dependencies]
|
||||||
|
client = [
|
||||||
|
{ name = "authlib" },
|
||||||
|
{ name = "exceptiongroup" },
|
||||||
|
{ name = "httpx" },
|
||||||
|
{ name = "mcp" },
|
||||||
|
{ name = "opentelemetry-api" },
|
||||||
|
{ name = "py-key-value-aio", extra = ["filetree", "keyring", "memory"] },
|
||||||
|
]
|
||||||
|
server = [
|
||||||
{ name = "authlib" },
|
{ name = "authlib" },
|
||||||
{ name = "cyclopts" },
|
{ name = "cyclopts" },
|
||||||
{ name = "exceptiongroup" },
|
{ name = "exceptiongroup" },
|
||||||
|
{ name = "griffelib" },
|
||||||
{ name = "httpx" },
|
{ name = "httpx" },
|
||||||
{ name = "jsonref" },
|
{ name = "jsonref" },
|
||||||
{ name = "jsonschema-path" },
|
{ name = "jsonschema-path" },
|
||||||
@@ -652,22 +688,15 @@ dependencies = [
|
|||||||
{ name = "openapi-pydantic" },
|
{ name = "openapi-pydantic" },
|
||||||
{ name = "opentelemetry-api" },
|
{ name = "opentelemetry-api" },
|
||||||
{ name = "packaging" },
|
{ name = "packaging" },
|
||||||
{ name = "platformdirs" },
|
|
||||||
{ name = "py-key-value-aio", extra = ["filetree", "keyring", "memory"] },
|
{ name = "py-key-value-aio", extra = ["filetree", "keyring", "memory"] },
|
||||||
{ name = "pydantic", extra = ["email"] },
|
|
||||||
{ name = "pyperclip" },
|
{ name = "pyperclip" },
|
||||||
{ name = "python-dotenv" },
|
{ name = "python-multipart" },
|
||||||
{ name = "pyyaml" },
|
{ name = "pyyaml" },
|
||||||
{ name = "rich" },
|
|
||||||
{ name = "uncalled-for" },
|
{ name = "uncalled-for" },
|
||||||
{ name = "uvicorn" },
|
{ name = "uvicorn" },
|
||||||
{ name = "watchfiles" },
|
{ name = "watchfiles" },
|
||||||
{ name = "websockets" },
|
{ name = "websockets" },
|
||||||
]
|
]
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/0a/70/862026c4589441f86ad3108f05bfb2f781c6b322ad60a982f40b303b47d7/fastmcp-3.1.0.tar.gz", hash = "sha256:e25264794c734b9977502a51466961eeecff92a0c2f3b49c40c070993628d6d0", size = 17347083, upload-time = "2026-03-03T02:43:11.283Z" }
|
|
||||||
wheels = [
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/17/07/516f5b20d88932e5a466c2216b628e5358a71b3a9f522215607c3281de05/fastmcp-3.1.0-py3-none-any.whl", hash = "sha256:b1f73b56fd3b0cb2bd9e2a144fc650d5cc31587ed129d996db7710e464ae8010", size = 633749, upload-time = "2026-03-03T02:43:09.06Z" },
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "frozenlist"
|
name = "frozenlist"
|
||||||
@@ -841,6 +870,15 @@ wheels = [
|
|||||||
{ url = "https://files.pythonhosted.org/packages/ac/38/08cc303ddddc4b3d7c628c3039a61a3aae36c241ed01393d00c2fd663473/greenlet-3.1.1-cp313-cp313t-musllinux_1_1_x86_64.whl", hash = "sha256:411f015496fec93c1c8cd4e5238da364e1da7a124bcb293f085bf2860c32c6f6", size = 1142112, upload-time = "2024-09-20T17:09:28.753Z" },
|
{ url = "https://files.pythonhosted.org/packages/ac/38/08cc303ddddc4b3d7c628c3039a61a3aae36c241ed01393d00c2fd663473/greenlet-3.1.1-cp313-cp313t-musllinux_1_1_x86_64.whl", hash = "sha256:411f015496fec93c1c8cd4e5238da364e1da7a124bcb293f085bf2860c32c6f6", size = 1142112, upload-time = "2024-09-20T17:09:28.753Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "griffelib"
|
||||||
|
version = "2.0.2"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/9d/82/74f4a3310cdabfbb10da554c3a672847f1ed33c6f61dd472681ce7f1fe67/griffelib-2.0.2.tar.gz", hash = "sha256:3cf20b3bc470e83763ffbf236e0076b1211bac1bc67de13daf494640f2de707e", size = 166461, upload-time = "2026-03-27T11:34:51.091Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/11/8c/c9138d881c79aa0ea9ed83cbd58d5ca75624378b38cee225dcf5c42cc91f/griffelib-2.0.2-py3-none-any.whl", hash = "sha256:925c857658fb1ba40c0772c37acbc2ab650bd794d9c1b9726922e36ea4117ea1", size = 142357, upload-time = "2026-03-27T11:34:46.275Z" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "h11"
|
name = "h11"
|
||||||
version = "0.14.0"
|
version = "0.14.0"
|
||||||
@@ -1010,6 +1048,18 @@ wheels = [
|
|||||||
{ url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899, upload-time = "2025-03-05T20:05:00.369Z" },
|
{ url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899, upload-time = "2025-03-05T20:05:00.369Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "joserfc"
|
||||||
|
version = "1.6.5"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "cryptography" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/3b/dc/5f768c2e391e9afabe5d18e3221346deb5fb6338565f1ccc9e7c6d7befdd/joserfc-1.6.5.tar.gz", hash = "sha256:1482a7db78fb4602e44ed89e51b599d052e091288c7c532c5b694e20149dec48", size = 231881, upload-time = "2026-05-06T04:58:13.408Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/54/3b/ad1cb22e75c963b1f07c8a2329bf47227ce7e4361df5eb2fb101b2ce33ef/joserfc-1.6.5-py3-none-any.whl", hash = "sha256:e9878a0f8243fe7b95e11fdda81374ca9f7a689e302751579d3dfdeec559675e", size = 70464, upload-time = "2026-05-06T04:58:11.668Z" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "jsonref"
|
name = "jsonref"
|
||||||
version = "1.1.0"
|
version = "1.1.0"
|
||||||
@@ -1796,11 +1846,11 @@ wheels = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "python-multipart"
|
name = "python-multipart"
|
||||||
version = "0.0.20"
|
version = "0.0.29"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/f3/87/f44d7c9f274c7ee665a29b885ec97089ec5dc034c7f3fafa03da9e39a09e/python_multipart-0.0.20.tar.gz", hash = "sha256:8dd0cab45b8e23064ae09147625994d090fa46f5b0d1e13af944c331a7fa9d13", size = 37158, upload-time = "2024-12-16T19:45:46.972Z" }
|
sdist = { url = "https://files.pythonhosted.org/packages/4e/fe/70bd71a6738b09a0bdf6480ca6436b167469ca4578b2a0efbe390b4b0e70/python_multipart-0.0.29.tar.gz", hash = "sha256:643e93849196645e2dbdd81a0f8829a23123ad7f797a84a364c6fb3563f18904", size = 45678, upload-time = "2026-05-17T17:29:47.654Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/45/58/38b5afbc1a800eeea951b9285d3912613f2603bdf897a4ab0f4bd7f405fc/python_multipart-0.0.20-py3-none-any.whl", hash = "sha256:8a62d3a8335e06589fe01f2a3e178cdcc632f3fbe0d492ad9ee0ec35aab1f104", size = 24546, upload-time = "2024-12-16T19:45:44.423Z" },
|
{ url = "https://files.pythonhosted.org/packages/8f/cb/769cfc37177252872a45a71f3fbdde9d51b471a3f3c14bfe95dde3407386/python_multipart-0.0.29-py3-none-any.whl", hash = "sha256:2ddcc971cef266225f54f552d8fa10bcfbb1f14446caec199060daac59ff2d69", size = 29640, upload-time = "2026-05-17T17:29:45.69Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import type { AccordionRootEmits, AccordionRootProps } from 'reka-ui'
|
||||||
|
import { AccordionRoot, useForwardPropsEmits } from 'reka-ui'
|
||||||
|
|
||||||
|
const props = defineProps<AccordionRootProps>()
|
||||||
|
const emits = defineEmits<AccordionRootEmits>()
|
||||||
|
|
||||||
|
const forwarded = useForwardPropsEmits(props, emits)
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<AccordionRoot data-slot="accordion" v-bind="forwarded">
|
||||||
|
<slot />
|
||||||
|
</AccordionRoot>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import type { AccordionContentProps } from 'reka-ui'
|
||||||
|
import { AccordionContent } from 'reka-ui'
|
||||||
|
import { cn } from '@/lib/utils'
|
||||||
|
|
||||||
|
const props = defineProps<AccordionContentProps & { class?: string }>()
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<AccordionContent
|
||||||
|
data-slot="accordion-content"
|
||||||
|
v-bind="props"
|
||||||
|
:class="cn('overflow-hidden text-sm data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down', props.class)"
|
||||||
|
>
|
||||||
|
<div class="pb-3 pt-0">
|
||||||
|
<slot />
|
||||||
|
</div>
|
||||||
|
</AccordionContent>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import type { AccordionItemProps } from 'reka-ui'
|
||||||
|
import { AccordionItem } from 'reka-ui'
|
||||||
|
import { cn } from '@/lib/utils'
|
||||||
|
|
||||||
|
const props = defineProps<AccordionItemProps & { class?: string }>()
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<AccordionItem data-slot="accordion-item" v-bind="props" :class="cn('border-b', props.class)">
|
||||||
|
<slot />
|
||||||
|
</AccordionItem>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { ChevronDown } from 'lucide-vue-next'
|
||||||
|
import type { AccordionTriggerProps } from 'reka-ui'
|
||||||
|
import { AccordionHeader, AccordionTrigger } from 'reka-ui'
|
||||||
|
import { cn } from '@/lib/utils'
|
||||||
|
|
||||||
|
const props = defineProps<AccordionTriggerProps & { class?: string }>()
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<AccordionHeader class="flex">
|
||||||
|
<AccordionTrigger
|
||||||
|
data-slot="accordion-trigger"
|
||||||
|
v-bind="props"
|
||||||
|
:class="cn('group/accordion-trigger flex flex-1 items-center justify-between gap-2 py-3 text-left text-sm font-medium transition-all hover:underline [&[data-state=open]>svg]:rotate-180', props.class)"
|
||||||
|
>
|
||||||
|
<slot />
|
||||||
|
<ChevronDown class="size-4 shrink-0 text-muted-foreground transition-transform duration-200" />
|
||||||
|
</AccordionTrigger>
|
||||||
|
</AccordionHeader>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
export { default as Accordion } from './Accordion.vue'
|
||||||
|
export { default as AccordionItem } from './AccordionItem.vue'
|
||||||
|
export { default as AccordionTrigger } from './AccordionTrigger.vue'
|
||||||
|
export { default as AccordionContent } from './AccordionContent.vue'
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import type { ScrollAreaRootProps } from 'reka-ui'
|
||||||
|
import { ScrollAreaRoot, ScrollAreaViewport } from 'reka-ui'
|
||||||
|
import { cn } from '@/lib/utils'
|
||||||
|
|
||||||
|
const props = defineProps<ScrollAreaRootProps & { class?: string }>()
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<ScrollAreaRoot data-slot="scroll-area" :class="cn('relative overflow-hidden', props.class)" v-bind="props">
|
||||||
|
<ScrollAreaViewport class="size-full rounded-[inherit]">
|
||||||
|
<slot />
|
||||||
|
</ScrollAreaViewport>
|
||||||
|
<slot name="scrollbar" />
|
||||||
|
</ScrollAreaRoot>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import type { ScrollAreaScrollbarProps } from 'reka-ui'
|
||||||
|
import { ScrollAreaScrollbar, ScrollAreaThumb } from 'reka-ui'
|
||||||
|
import { cn } from '@/lib/utils'
|
||||||
|
|
||||||
|
const props = withDefaults(defineProps<ScrollAreaScrollbarProps & { class?: string }>(), {
|
||||||
|
orientation: 'vertical',
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<ScrollAreaScrollbar
|
||||||
|
data-slot="scroll-area-scrollbar"
|
||||||
|
v-bind="props"
|
||||||
|
:class="cn(
|
||||||
|
'flex touch-none select-none p-px transition-colors',
|
||||||
|
props.orientation === 'vertical' ? 'h-full w-2.5 border-l border-l-transparent' : 'h-2.5 w-full border-t border-t-transparent',
|
||||||
|
props.class,
|
||||||
|
)"
|
||||||
|
>
|
||||||
|
<ScrollAreaThumb data-slot="scroll-area-thumb" class="relative flex-1 rounded-full bg-border" />
|
||||||
|
</ScrollAreaScrollbar>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
export { default as ScrollArea } from './ScrollArea.vue'
|
||||||
|
export { default as ScrollBar } from './ScrollBar.vue'
|
||||||
@@ -367,13 +367,6 @@ const resetAllForge = () => {
|
|||||||
>
|
>
|
||||||
配置编辑
|
配置编辑
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
|
||||||
size="sm"
|
|
||||||
:variant="forgeViewTab === 'result' ? 'default' : 'ghost'"
|
|
||||||
@click="forgeViewTab = 'result'"
|
|
||||||
>
|
|
||||||
计算结果
|
|
||||||
</Button>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="forgeViewTab === 'config'" class="inline-flex flex-wrap rounded-md border p-1">
|
<div v-if="forgeViewTab === 'config'" class="inline-flex flex-wrap rounded-md border p-1">
|
||||||
|
|||||||
@@ -46,7 +46,8 @@ const activeTab = computed(() => {
|
|||||||
return "equipment";
|
return "equipment";
|
||||||
});
|
});
|
||||||
|
|
||||||
const showGlobalResultPanel = computed(() => activeTab.value !== "equipment");
|
// Result panel is now embedded inside Equipment/Skill/Forge pages to avoid duplicate rendering.
|
||||||
|
const showGlobalResultPanel = computed(() => false);
|
||||||
|
|
||||||
const loadCharacter = async () => {
|
const loadCharacter = async () => {
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
|
|||||||
@@ -5,6 +5,13 @@ import { useConfigStore, useInfoStore } from "@/stores";
|
|||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
|
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
|
||||||
import { Input } from "@/components/ui/input";
|
import { Input } from "@/components/ui/input";
|
||||||
|
import {
|
||||||
|
Accordion,
|
||||||
|
AccordionContent,
|
||||||
|
AccordionItem,
|
||||||
|
AccordionTrigger,
|
||||||
|
} from "@/components/ui/accordion";
|
||||||
|
import { ScrollArea, ScrollBar } from "@/components/ui/scroll-area";
|
||||||
import Tabs from "@/components/ui/tabs/Tabs.vue";
|
import Tabs from "@/components/ui/tabs/Tabs.vue";
|
||||||
import TabsList from "@/components/ui/tabs/TabsList.vue";
|
import TabsList from "@/components/ui/tabs/TabsList.vue";
|
||||||
import TabsTrigger from "@/components/ui/tabs/TabsTrigger.vue";
|
import TabsTrigger from "@/components/ui/tabs/TabsTrigger.vue";
|
||||||
@@ -163,6 +170,8 @@ const diffClass = (current: number, baseline: number) => {
|
|||||||
const hasVisibleResult = computed(() => {
|
const hasVisibleResult = computed(() => {
|
||||||
return (resultState.value?.skills?.length ?? 0) > 0 || (resultState.value?.info?.length ?? 0) > 0;
|
return (resultState.value?.skills?.length ?? 0) > 0 || (resultState.value?.info?.length ?? 0) > 0;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const defaultOpenSections = ["equipped", "changes"];
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -190,55 +199,73 @@ const hasVisibleResult = computed(() => {
|
|||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
<Card>
|
<Card>
|
||||||
<CardHeader class="pb-2">
|
<CardContent class="pt-3">
|
||||||
<CardTitle class="text-sm">穿戴信息</CardTitle>
|
<Accordion type="multiple" :default-value="defaultOpenSections" class="w-full">
|
||||||
</CardHeader>
|
<AccordionItem value="equipped" class="border-border/60">
|
||||||
<CardContent class="space-y-2 text-xs">
|
<AccordionTrigger>穿戴信息</AccordionTrigger>
|
||||||
<Tabs :model-value="displayTab">
|
<AccordionContent>
|
||||||
<TabsList class="grid w-full grid-cols-2">
|
<div class="space-y-2 text-xs">
|
||||||
<TabsTrigger value="equ" @click="displayTab = 'equ'">装备</TabsTrigger>
|
<Tabs :model-value="displayTab">
|
||||||
<TabsTrigger value="oath" @click="displayTab = 'oath'">誓约</TabsTrigger>
|
<TabsList class="grid w-full grid-cols-2">
|
||||||
</TabsList>
|
<TabsTrigger value="equ" @click="displayTab = 'equ'">装备</TabsTrigger>
|
||||||
</Tabs>
|
<TabsTrigger value="oath" @click="displayTab = 'oath'">誓约</TabsTrigger>
|
||||||
|
</TabsList>
|
||||||
|
</Tabs>
|
||||||
|
|
||||||
<div v-if="displayTab === 'equ'" class="rounded-md border p-2">
|
<ScrollArea class="max-h-56 rounded-md border p-2">
|
||||||
<EquList
|
<div v-if="displayTab === 'equ'">
|
||||||
v-model:part="equippedPart"
|
<EquList
|
||||||
:detail="configStore.config.equips"
|
v-model:part="equippedPart"
|
||||||
:with-sub-weapon="(infoStore.infos?.alter?.includes('vegabond') ?? false)"
|
:detail="configStore.config.equips"
|
||||||
:with-pet="true"
|
:with-sub-weapon="(infoStore.infos?.alter?.includes('vegabond') ?? false)"
|
||||||
/>
|
:with-pet="true"
|
||||||
</div>
|
/>
|
||||||
|
</div>
|
||||||
|
<div v-else>
|
||||||
|
<OathList v-model:part="equippedOathPart" :detail="configStore.config.oaths" />
|
||||||
|
</div>
|
||||||
|
<template #scrollbar>
|
||||||
|
<ScrollBar orientation="vertical" />
|
||||||
|
</template>
|
||||||
|
</ScrollArea>
|
||||||
|
</div>
|
||||||
|
</AccordionContent>
|
||||||
|
</AccordionItem>
|
||||||
|
|
||||||
<div v-else class="rounded-md border p-2">
|
<AccordionItem value="changes" class="border-border/60">
|
||||||
<OathList v-model:part="equippedOathPart" :detail="configStore.config.oaths" />
|
<AccordionTrigger>配置变更来源</AccordionTrigger>
|
||||||
</div>
|
<AccordionContent>
|
||||||
</CardContent>
|
<div class="space-y-1 text-xs">
|
||||||
</Card>
|
<div class="flex items-center justify-between pb-1">
|
||||||
|
<span class="text-muted-foreground">用于回归定位最近触发计算的操作来源。</span>
|
||||||
|
<Button size="sm" variant="ghost" @click="clearChangeSources">清空</Button>
|
||||||
|
</div>
|
||||||
|
|
||||||
<Card>
|
<div v-if="changeSources.length === 0" class="text-muted-foreground">
|
||||||
<CardHeader class="pb-2">
|
暂无变更来源记录。
|
||||||
<CardTitle class="text-sm">配置变更来源</CardTitle>
|
</div>
|
||||||
<CardDescription class="flex items-center justify-between">
|
<ScrollArea v-else class="max-h-44 rounded-md border border-border/60 p-2">
|
||||||
<span>用于回归定位最近触发计算的操作来源。</span>
|
<div class="space-y-1">
|
||||||
<Button size="sm" variant="ghost" @click="clearChangeSources">清空</Button>
|
<div
|
||||||
</CardDescription>
|
v-for="item in changeSources"
|
||||||
</CardHeader>
|
:key="item.id"
|
||||||
<CardContent class="space-y-1 text-xs">
|
class="rounded-md border border-border/60 bg-muted/20 px-2 py-1"
|
||||||
<div v-if="changeSources.length === 0" class="text-muted-foreground">
|
>
|
||||||
暂无变更来源记录。
|
<div class="flex items-center justify-between">
|
||||||
</div>
|
<span class="font-medium">{{ item.source }}</span>
|
||||||
<div
|
<span class="text-muted-foreground">{{ item.time }}</span>
|
||||||
v-for="item in changeSources"
|
</div>
|
||||||
:key="item.id"
|
<div class="text-muted-foreground">{{ item.detail }}</div>
|
||||||
class="rounded-md border border-border/60 bg-muted/20 px-2 py-1"
|
</div>
|
||||||
>
|
</div>
|
||||||
<div class="flex items-center justify-between">
|
<template #scrollbar>
|
||||||
<span class="font-medium">{{ item.source }}</span>
|
<ScrollBar orientation="vertical" />
|
||||||
<span class="text-muted-foreground">{{ item.time }}</span>
|
</template>
|
||||||
</div>
|
</ScrollArea>
|
||||||
<div class="text-muted-foreground">{{ item.detail }}</div>
|
</div>
|
||||||
</div>
|
</AccordionContent>
|
||||||
|
</AccordionItem>
|
||||||
|
</Accordion>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
@@ -324,8 +351,9 @@ const hasVisibleResult = computed(() => {
|
|||||||
暂无结果,请先编辑配置。
|
暂无结果,请先编辑配置。
|
||||||
</div>
|
</div>
|
||||||
<div v-else class="flex min-h-0 h-full flex-col">
|
<div v-else class="flex min-h-0 h-full flex-col">
|
||||||
<div class="min-h-0 flex-1 overflow-auto rounded-md border">
|
<div class="min-h-0 flex-1 overflow-hidden rounded-md border">
|
||||||
<table class="w-full table-fixed text-[11px] sm:text-xs">
|
<ScrollArea class="h-full w-full">
|
||||||
|
<table class="w-full table-fixed text-[11px] sm:text-xs">
|
||||||
<colgroup v-if="!isBufferClass">
|
<colgroup v-if="!isBufferClass">
|
||||||
<col class="w-[9.5rem] sm:w-[11rem]" />
|
<col class="w-[9.5rem] sm:w-[11rem]" />
|
||||||
<col class="hidden sm:table-column sm:w-[4.25rem]" />
|
<col class="hidden sm:table-column sm:w-[4.25rem]" />
|
||||||
@@ -482,7 +510,12 @@ const hasVisibleResult = computed(() => {
|
|||||||
</template>
|
</template>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
<template #scrollbar>
|
||||||
|
<ScrollBar orientation="horizontal" />
|
||||||
|
<ScrollBar orientation="vertical" />
|
||||||
|
</template>
|
||||||
|
</ScrollArea>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
v-if="!isBufferClass"
|
v-if="!isBufferClass"
|
||||||
|
|||||||
Reference in New Issue
Block a user