fix:修复若干bug

This commit is contained in:
steve
2025-09-04 01:44:05 +08:00
parent 29ce1d4683
commit 223619501a
7 changed files with 388 additions and 64 deletions

View File

@@ -22,12 +22,18 @@
{{ teamId }} {{ teamId }}
</button> </button>
<button <button
class="team-button refresh-button" class="refresh-button"
:disabled="loading" :disabled="loading"
title="刷新队伍数据" title="刷新队伍数据"
@click="refreshTeamData(true)" @click="refreshTeamData(true)"
> >
🔄 <svg class="refresh-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8"/>
<path d="M21 3v5h-5"/>
<path d="M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16"/>
<path d="M3 21v-5h5"/>
</svg>
<span class="refresh-text">刷新</span>
</button> </button>
</div> </div>
</div> </div>
@@ -84,7 +90,7 @@ import { useMessage, NTag } from 'naive-ui'
* 集成英雄字典游戏ID -> { name, type } * 集成英雄字典游戏ID -> { name, type }
* 你也可以独立出一个 heroDict.ts 后 import按你的要求这里整合到同一文件。 * 你也可以独立出一个 heroDict.ts 后 import按你的要求这里整合到同一文件。
*/ */
const HERO_DICT: Record<number, { name: string; type: string }> = { const HERO_DICT = {
101: { name: '司马懿', type: '魏国' }, 102: { name: '郭嘉', type: '魏国' }, 103: { name: '关羽', type: '蜀国' }, 101: { name: '司马懿', type: '魏国' }, 102: { name: '郭嘉', type: '魏国' }, 103: { name: '关羽', type: '蜀国' },
104: { name: '诸葛亮', type: '蜀国' }, 105: { name: '周瑜', type: '吴国' }, 106: { name: '太史慈', type: '吴国' }, 104: { name: '诸葛亮', type: '蜀国' }, 105: { name: '周瑜', type: '吴国' }, 106: { name: '太史慈', type: '吴国' },
107: { name: '吕布', type: '群雄' }, 108: { name: '华佗', type: '群雄' }, 109: { name: '甄姬', type: '魏国' }, 107: { name: '吕布', type: '群雄' }, 108: { name: '华佗', type: '群雄' }, 109: { name: '甄姬', type: '魏国' },
@@ -115,16 +121,22 @@ const message = useMessage()
const loading = ref(false) const loading = ref(false)
const switching = ref(false) const switching = ref(false)
const currentTeam = ref(1) const currentTeam = ref(1)
const availableTeams = ref<number[]>([1, 2, 3, 4]) const availableTeams = ref([1, 2, 3, 4])
// WebSocket连接状态
const wsStatus = computed(() => {
if (!tokenStore.selectedToken) return 'disconnected'
return tokenStore.getWebSocketStatus(tokenStore.selectedToken.id)
})
// —— 缓存优先的 presetTeam 原始数据 —— // —— 缓存优先的 presetTeam 原始数据 ——
const presetTeamRaw = computed(() => tokenStore.gameData?.presetTeam ?? null) const presetTeamRaw = computed(() => tokenStore.gameData?.presetTeam ?? null)
// 统一结构:输出 { useTeamId, teams } // 统一结构:输出 { useTeamId, teams }
function normalizePresetTeam(raw: any): { useTeamId: number; teams: Record<number, { teamInfo: Record<string, any> }> } { function normalizePresetTeam(raw) {
if (!raw) return { useTeamId: 1, teams: {} } if (!raw) return { useTeamId: 1, teams: {} }
const root = raw.presetTeamInfo ?? raw const root = raw.presetTeamInfo ?? raw
const findUseIdRec = (obj: any): number | null => { const findUseIdRec = (obj) => {
if (!obj || typeof obj !== 'object') return null if (!obj || typeof obj !== 'object') return null
if (typeof obj.useTeamId === 'number') return obj.useTeamId if (typeof obj.useTeamId === 'number') return obj.useTeamId
for (const k of Object.keys(obj)) { for (const k of Object.keys(obj)) {
@@ -136,7 +148,7 @@ function normalizePresetTeam(raw: any): { useTeamId: number; teams: Record<numbe
const useTeamId = root.useTeamId ?? root.presetTeamInfo?.useTeamId ?? findUseIdRec(root) ?? 1 const useTeamId = root.useTeamId ?? root.presetTeamInfo?.useTeamId ?? findUseIdRec(root) ?? 1
const dict = root.presetTeamInfo ?? root const dict = root.presetTeamInfo ?? root
const teams: Record<number, { teamInfo: Record<string, any> }> = {} const teams = {}
const ids = Object.keys(dict || {}).filter(k => /^\d+$/.test(k)) const ids = Object.keys(dict || {}).filter(k => /^\d+$/.test(k))
for (const idStr of ids) { for (const idStr of ids) {
const id = Number(idStr) const id = Number(idStr)
@@ -146,10 +158,10 @@ function normalizePresetTeam(raw: any): { useTeamId: number; teams: Record<numbe
teams[id] = { teamInfo: node.teamInfo } teams[id] = { teamInfo: node.teamInfo }
} else if (node.heroes) { } else if (node.heroes) {
const ti: Record<string, any> = {} const ti: Record<string, any> = {}
node.heroes.forEach((h: any, idx: number) => { ti[String(idx + 1)] = h }) node.heroes.forEach((h, idx) => { ti[String(idx + 1)] = h })
teams[id] = { teamInfo: ti } teams[id] = { teamInfo: ti }
} else if (typeof node === 'object') { } else if (typeof node === 'object') {
const hasHero = Object.values(node).some((v: any) => v && typeof v === 'object' && 'heroId' in v) const hasHero = Object.values(node).some((v) => v && typeof v === 'object' && 'heroId' in v)
teams[id] = { teamInfo: hasHero ? node : {} } teams[id] = { teamInfo: hasHero ? node : {} }
} else { } else {
teams[id] = { teamInfo: {} } teams[id] = { teamInfo: {} }
@@ -164,7 +176,7 @@ const presetTeam = computed(() => normalizePresetTeam(presetTeamRaw.value))
const currentTeamHeroes = computed(() => { const currentTeamHeroes = computed(() => {
const team = presetTeam.value.teams[currentTeam.value]?.teamInfo const team = presetTeam.value.teams[currentTeam.value]?.teamInfo
if (!team) return [] if (!team) return []
const heroes: Array<{ id: number; name: string; type: string; position: number; level?: number; avatar?: string }> = [] const heroes = []
for (const [pos, hero] of Object.entries(team)) { for (const [pos, hero] of Object.entries(team)) {
const hid = (hero as any)?.heroId ?? (hero as any)?.id const hid = (hero as any)?.heroId ?? (hero as any)?.id
if (!hid) continue if (!hid) continue
@@ -183,10 +195,10 @@ const currentTeamHeroes = computed(() => {
}) })
// —— 命令封装 —— // —— 命令封装 ——
const executeGameCommand = async (tokenId: string | number, cmd: string, params: any = {}, description = '', timeout = 8000) => { const executeGameCommand = async (tokenId, cmd, params = {}, description = '', timeout = 8000) => {
try { try {
return await tokenStore.sendMessageWithPromise(tokenId, cmd, params, timeout) return await tokenStore.sendMessageWithPromise(tokenId, cmd, params, timeout)
} catch (error: any) { } catch (error) {
const msg = error?.message ?? String(error) const msg = error?.message ?? String(error)
if (description) message.error(`${description}失败:${msg}`) if (description) message.error(`${description}失败:${msg}`)
throw error throw error
@@ -213,6 +225,9 @@ const getTeamInfoWithCache = async (force = false) => {
state.gameData = { ...(state.gameData ?? {}), presetTeam: result } state.gameData = { ...(state.gameData ?? {}), presetTeam: result }
}) })
return result?.presetTeamInfo ?? null return result?.presetTeamInfo ?? null
} catch (error) {
console.error('获取阵容信息失败:', error)
return null
} finally { } finally {
loading.value = false loading.value = false
} }
@@ -226,7 +241,7 @@ const updateAvailableTeams = () => {
const updateCurrentTeam = () => { currentTeam.value = presetTeam.value.useTeamId || 1 } const updateCurrentTeam = () => { currentTeam.value = presetTeam.value.useTeamId || 1 }
// —— 交互 —— // —— 交互 ——
const selectTeam = async (teamId: number) => { const selectTeam = async (teamId) => {
if (switching.value || loading.value) return if (switching.value || loading.value) return
if (!tokenStore.selectedToken) { message.warning('请先选择Token'); return } if (!tokenStore.selectedToken) { message.warning('请先选择Token'); return }
const prev = currentTeam.value const prev = currentTeam.value
@@ -245,14 +260,53 @@ const selectTeam = async (teamId: number) => {
const refreshTeamData = async (force = false) => { await getTeamInfoWithCache(force) } const refreshTeamData = async (force = false) => { await getTeamInfoWithCache(force) }
// —— 首次挂载:先查缓存,再兜底拉接口 —— // —— 首次挂载:检查连接状态后获取数据 ——
onMounted(async () => { onMounted(async () => {
// 组件挂载时获取队伍信息
if (tokenStore.selectedToken && wsStatus.value === 'connected') {
await refreshTeamData(false) await refreshTeamData(false)
updateAvailableTeams(); updateCurrentTeam() updateAvailableTeams(); updateCurrentTeam()
if (!presetTeamRaw.value) { if (!presetTeamRaw.value) {
await refreshTeamData(true) await refreshTeamData(true)
updateAvailableTeams(); updateCurrentTeam() updateAvailableTeams(); updateCurrentTeam()
} }
} else if (!tokenStore.selectedToken) {
console.log('🛡️ 没有选中的Token无法获取队伍信息')
} else {
console.log('🛡️ WebSocket未连接等待连接后自动获取队伍信息')
}
})
// —— 监听WebSocket连接状态变化 ——
watch(wsStatus, (newStatus, oldStatus) => {
console.log(`🛡️ WebSocket状态变化: ${oldStatus} -> ${newStatus}`)
if (newStatus === 'connected' && oldStatus !== 'connected' && tokenStore.selectedToken) {
console.log('🛡️ WebSocket已连接自动获取队伍信息')
// 延迟一点时间让WebSocket完全就绪
setTimeout(async () => {
await refreshTeamData(false)
updateAvailableTeams(); updateCurrentTeam()
if (!presetTeamRaw.value) {
await refreshTeamData(true)
updateAvailableTeams(); updateCurrentTeam()
}
}, 1000)
}
})
// —— 监听Token变化 ——
watch(() => tokenStore.selectedToken, async (newToken, oldToken) => {
if (newToken && newToken.id !== oldToken?.id) {
console.log('🛡️ Token已切换重新获取队伍信息')
// 检查WebSocket是否已连接
const status = tokenStore.getWebSocketStatus(newToken.id)
if (status === 'connected') {
await refreshTeamData(true) // 切换Token时强制刷新
updateAvailableTeams(); updateCurrentTeam()
}
}
}) })
// —— 监听缓存变化(其他地方写入也能联动) —— // —— 监听缓存变化(其他地方写入也能联动) ——
@@ -282,9 +336,76 @@ watch(() => presetTeamRaw.value, () => { updateAvailableTeams(); updateCurrentTe
cursor: pointer; transition: all var(--transition-fast); cursor: pointer; transition: all var(--transition-fast);
&:hover { background: var(--bg-secondary); } &:hover { background: var(--bg-secondary); }
&.active { background: var(--primary-color); color: white; } &.active { background: var(--primary-color); color: white; }
&.refresh-button { background: var(--success-color, #10b981); color: white; &:hover { background: var(--success-color-dark, #059669); } }
&:disabled { opacity: .6; cursor: not-allowed; } &:disabled { opacity: .6; cursor: not-allowed; }
} }
.refresh-button {
display: flex;
align-items: center;
gap: 6px;
height: 32px;
padding: 0 12px;
border: 1px solid var(--border-color, #e5e7eb);
border-radius: 8px;
background: var(--bg-primary, #ffffff);
color: var(--text-secondary, #6b7280);
font-size: 13px;
font-weight: 500;
cursor: pointer;
transition: all var(--transition-fast, 0.15s ease);
&:hover {
background: var(--bg-secondary, #f9fafb);
border-color: var(--border-hover, #d1d5db);
color: var(--text-primary, #374151);
transform: translateY(-1px);
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
}
&:active {
transform: translateY(0);
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
}
&:disabled {
opacity: 0.5;
cursor: not-allowed;
transform: none;
box-shadow: none;
&:hover {
background: var(--bg-primary, #ffffff);
border-color: var(--border-color, #e5e7eb);
color: var(--text-secondary, #6b7280);
transform: none;
box-shadow: none;
}
}
.refresh-icon {
width: 14px;
height: 14px;
transition: transform var(--transition-fast, 0.15s ease);
}
&:not(:disabled):hover .refresh-icon {
transform: rotate(180deg);
}
&:disabled .refresh-icon {
animation: spin 1s linear infinite;
}
.refresh-text {
font-size: 13px;
line-height: 1;
}
}
@keyframes spin {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
.card-content .current-team-info { .card-content .current-team-info {
display: flex; justify-content: space-between; align-items: center; margin-bottom: var(--spacing-lg); display: flex; justify-content: space-between; align-items: center; margin-bottom: var(--spacing-lg);
.label { font-size: var(--font-size-sm); color: var(--text-secondary); } .label { font-size: var(--font-size-sm); color: var(--text-secondary); }

View File

@@ -89,20 +89,18 @@
> >
{{ getWSStatus(roleId) === 'connected' ? '断开WS' : '连接WS' }} {{ getWSStatus(roleId) === 'connected' ? '断开WS' : '连接WS' }}
</n-button> </n-button>
<n-button
size="tiny" <n-dropdown
type="warning" :options="getTokenMenuOptions(tokenData)"
@click="regenerateToken(roleId)" @select="handleTokenAction($event, roleId, tokenData)"
trigger="click"
> >
刷新Token <n-button size="tiny" type="tertiary">
</n-button> <template #icon>
<n-button <n-icon><EllipsisHorizontal /></n-icon>
size="tiny" </template>
type="error"
@click="removeToken(roleId)"
>
删除
</n-button> </n-button>
</n-dropdown>
</div> </div>
</div> </div>
@@ -156,14 +154,19 @@
</template> </template>
<script setup> <script setup>
import { ref } from 'vue' import { ref, h } from 'vue'
import { useMessage, useDialog } from 'naive-ui' import { useMessage, useDialog, NIcon } from 'naive-ui'
import { useLocalTokenStore } from '@/stores/localTokenManager' import { useLocalTokenStore } from '@/stores/localTokenManager'
import { useGameRolesStore } from '@/stores/gameRoles' import { useGameRolesStore } from '@/stores/gameRoles'
import { import {
Refresh, Refresh,
Download, Download,
CloudUpload CloudUpload,
EllipsisHorizontal,
Create,
TrashBin,
SyncCircle,
CopyOutline
} from '@vicons/ionicons5' } from '@vicons/ionicons5'
const message = useMessage() const message = useMessage()
@@ -205,6 +208,70 @@ const getWSStatusText = (status) => {
} }
} }
// 获取Token菜单选项
const getTokenMenuOptions = (tokenData) => {
const options = [
{
label: '编辑',
key: 'edit',
icon: () => h(NIcon, null, { default: () => h(Create) })
},
{
label: '复制Token',
key: 'copy',
icon: () => h(NIcon, null, { default: () => h(CopyOutline) })
}
]
// 如果是URL获取的Token显示刷新选项
if (tokenData.importMethod === 'url' && tokenData.sourceUrl) {
options.unshift({
label: '从URL刷新',
key: 'refresh-url',
icon: () => h(NIcon, null, { default: () => h(SyncCircle) })
})
} else {
// 手动添加的Token显示重新生成选项
options.unshift({
label: '刷新Token',
key: 'refresh',
icon: () => h(NIcon, null, { default: () => h(Refresh) })
})
}
options.push(
{ type: 'divider' },
{
label: '删除',
key: 'delete',
icon: () => h(NIcon, null, { default: () => h(TrashBin) })
}
)
return options
}
// 处理Token菜单操作
const handleTokenAction = (action, roleId, tokenData) => {
switch (action) {
case 'edit':
editToken(roleId, tokenData)
break
case 'copy':
copyToken(tokenData.token)
break
case 'refresh':
regenerateToken(roleId)
break
case 'refresh-url':
refreshTokenFromUrl(roleId, tokenData)
break
case 'delete':
removeToken(roleId)
break
}
}
const refreshTokens = () => { const refreshTokens = () => {
localTokenStore.initTokenManager() localTokenStore.initTokenManager()
message.success('Token数据已刷新') message.success('Token数据已刷新')
@@ -337,6 +404,84 @@ const removeToken = (roleId) => {
}) })
} }
// 编辑Token暂时显示提示信息后续可以实现编辑功能
const editToken = (roleId, tokenData) => {
message.info('编辑功能正在开发中')
}
// 复制Token到剪贴板
const copyToken = async (token) => {
try {
await navigator.clipboard.writeText(token)
message.success('Token已复制到剪贴板')
} catch (error) {
// 降级方案
const textArea = document.createElement('textarea')
textArea.value = token
document.body.appendChild(textArea)
textArea.select()
document.execCommand('copy')
document.body.removeChild(textArea)
message.success('Token已复制到剪贴板')
}
}
// 从URL刷新Token
const refreshTokenFromUrl = async (roleId, tokenData) => {
if (!tokenData.sourceUrl) {
message.warning('该Token没有配置源URL')
return
}
dialog.info({
title: '从URL刷新Token',
content: `确定要从源URL重新获取Token吗\n源地址${tokenData.sourceUrl}`,
positiveText: '确定',
negativeText: '取消',
onPositiveClick: async () => {
try {
const loadingMsg = message.loading('正在从URL获取新Token...', { duration: 0 })
// 使用与TokenImport相同的逻辑获取Token
let response
const isLocalUrl = tokenData.sourceUrl.startsWith(window.location.origin) ||
tokenData.sourceUrl.startsWith('/') ||
tokenData.sourceUrl.startsWith('http://localhost') ||
tokenData.sourceUrl.startsWith('http://127.0.0.1')
if (isLocalUrl) {
response = await fetch(tokenData.sourceUrl)
} else {
// 跨域请求,使用代理
const proxyUrl = `/api/proxy?url=${encodeURIComponent(tokenData.sourceUrl)}`
response = await fetch(proxyUrl)
}
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`)
}
const data = await response.json()
if (!data.token) {
throw new Error('返回数据中未找到token字段')
}
// 更新Token
localTokenStore.updateGameToken(roleId, {
token: data.token,
lastUsed: new Date().toISOString()
})
loadingMsg.destroy()
message.success('Token刷新成功')
} catch (error) {
console.error('URL刷新Token失败:', error)
message.error('刷新失败: ' + error.message)
}
}
})
}
const exportTokens = () => { const exportTokens = () => {
try { try {
const tokenData = localTokenStore.exportTokens() const tokenData = localTokenStore.exportTokens()

View File

@@ -44,7 +44,10 @@ export const useTokenStore = defineStore('tokens', () => {
profession: tokenData.profession || '', profession: tokenData.profession || '',
createdAt: new Date().toISOString(), createdAt: new Date().toISOString(),
lastUsed: new Date().toISOString(), lastUsed: new Date().toISOString(),
isActive: true isActive: true,
// URL获取相关信息
sourceUrl: tokenData.sourceUrl || null, // Token来源URL用于刷新
importMethod: tokenData.importMethod || 'manual' // 导入方式manual 或 url
} }
gameTokens.value.push(newToken) gameTokens.value.push(newToken)
@@ -221,7 +224,7 @@ export const useTokenStore = defineStore('tokens', () => {
} }
// 处理队伍信息 - 支持多种队伍相关响应 // 处理队伍信息 - 支持多种队伍相关响应
else if (cmd === 'presetteam_getteam' || cmd === 'presetteam_getteamresp' || else if (cmd === 'presetteam_getinfo' || cmd === 'presetteam_getinforesp' ||
cmd === 'presetteam_setteam' || cmd === 'presetteam_setteamresp' || cmd === 'presetteam_setteam' || cmd === 'presetteam_setteamresp' ||
cmd === 'presetteam_saveteam' || cmd === 'presetteam_saveteamresp' || cmd === 'presetteam_saveteam' || cmd === 'presetteam_saveteamresp' ||
cmd === 'role_gettargetteam' || cmd === 'role_gettargetteamresp' || cmd === 'role_gettargetteam' || cmd === 'role_gettargetteamresp' ||
@@ -696,15 +699,19 @@ export const useTokenStore = defineStore('tokens', () => {
const sendMessageWithPromise = async (tokenId, cmd, params = {}, timeout = 5000) => { const sendMessageWithPromise = async (tokenId, cmd, params = {}, timeout = 5000) => {
const connection = wsConnections.value[tokenId] const connection = wsConnections.value[tokenId]
if (!connection || connection.status !== 'connected') { if (!connection || connection.status !== 'connected') {
throw new Error(`WebSocket未连接 [${tokenId}]`) return Promise.reject(new Error(`WebSocket未连接 [${tokenId}]`))
} }
const client = connection.client const client = connection.client
if (!client) { if (!client) {
throw new Error(`WebSocket客户端不存在 [${tokenId}]`) return Promise.reject(new Error(`WebSocket客户端不存在 [${tokenId}]`))
} }
try {
return await client.sendWithPromise(cmd, params, timeout) return await client.sendWithPromise(cmd, params, timeout)
} catch (error) {
return Promise.reject(error)
}
} }
// 发送心跳消息 // 发送心跳消息
@@ -748,7 +755,7 @@ export const useTokenStore = defineStore('tokens', () => {
// 发送获取队伍信息 // 发送获取队伍信息
const sendGetTeamInfo = (tokenId, params = {}) => { const sendGetTeamInfo = (tokenId, params = {}) => {
return sendMessageWithPromise(tokenId, 'presetteam_getteam', params) return sendMessageWithPromise(tokenId, 'presetteam_getinfo', params)
} }
// 发送自定义游戏消息 // 发送自定义游戏消息

View File

@@ -158,7 +158,7 @@ export function registerDefaultCommands(reg) {
// 队伍相关 // 队伍相关
.register("presetteam_getinfo") .register("presetteam_getinfo")
.register("presetteam_getteam") .register("presetteam_getinfo")
.register("presetteam_setteam") .register("presetteam_setteam")
.register("presetteam_saveteam", { teamId: 1 }) .register("presetteam_saveteam", { teamId: 1 })
.register("role_gettargetteam") .register("role_gettargetteam")
@@ -532,7 +532,7 @@ export class XyzwWebSocketClient {
'arena_getareatargetresp': 'arena_getareatarget', 'arena_getareatargetresp': 'arena_getareatarget',
'presetteam_getinforesp': 'presetteam_getinfo', 'presetteam_getinforesp': 'presetteam_getinfo',
'presetteam_saveteamresp': 'presetteam_saveteam', 'presetteam_saveteamresp': 'presetteam_saveteam',
'presetteam_getteamresp': 'presetteam_getteam', 'presetteam_getinforesp': 'presetteam_getinfo',
'mail_claimallattachmentresp': 'mail_claimallattachment', 'mail_claimallattachmentresp': 'mail_claimallattachment',
'store_buyresp': 'store_purchase', 'store_buyresp': 'store_purchase',
'system_getdatabundleverresp': 'system_getdatabundlever', 'system_getdatabundleverresp': 'system_getdatabundlever',

View File

@@ -111,6 +111,10 @@ const connectionClass = computed(() => {
return connectionStatus.value === 'connected' ? 'status-connected' : 'status-disconnected' return connectionStatus.value === 'connected' ? 'status-connected' : 'status-disconnected'
}) })
const isConnected = computed(() => {
return connectionStatus.value === 'connected'
})
// 方法 // 方法
const handleFeatureAction = (featureType) => { const handleFeatureAction = (featureType) => {
if (!tokenStore.selectedToken) { if (!tokenStore.selectedToken) {
@@ -255,7 +259,7 @@ const initializeGameData = async () => {
// 获取队伍信息 // 获取队伍信息
console.log('🎮 正在获取队伍信息...') console.log('🎮 正在获取队伍信息...')
const teamResult = tokenStore.sendMessage(tokenId, 'presetteam_getteam') const teamResult = tokenStore.sendMessage(tokenId, 'presetteam_getinfo')
console.log('🎮 队伍信息请求结果:', teamResult) console.log('🎮 队伍信息请求结果:', teamResult)
console.log('🎮 游戏数据初始化请求已发送') console.log('🎮 游戏数据初始化请求已发送')

View File

@@ -451,9 +451,9 @@
</template> </template>
<script setup> <script setup>
import { ref, reactive, onMounted, computed } from 'vue' import { ref, reactive, onMounted, computed, h } from 'vue'
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
import { useMessage, useDialog } from 'naive-ui' import { useMessage, useDialog, NIcon } from 'naive-ui'
import { useTokenStore } from '@/stores/tokenStore' import { useTokenStore } from '@/stores/tokenStore'
import { import {
Add, Add,
@@ -464,7 +464,12 @@ import {
Refresh, Refresh,
Sunny, Sunny,
Moon, Moon,
Home Home,
Create,
Copy,
SyncCircle,
Link,
TrashBin
} from '@vicons/ionicons5' } from '@vicons/ionicons5'
const router = useRouter() const router = useRouter()
@@ -573,7 +578,8 @@ const handleImport = async () => {
importForm.base64Token, importForm.base64Token,
{ {
server: importForm.server, server: importForm.server,
wsUrl: importForm.wsUrl wsUrl: importForm.wsUrl,
importMethod: 'manual'
} }
) )
@@ -654,7 +660,8 @@ const handleUrlImport = async () => {
{ {
server: urlForm.server || data.server, server: urlForm.server || data.server,
wsUrl: urlForm.wsUrl, wsUrl: urlForm.wsUrl,
sourceUrl: urlForm.url // 保存源URL用于刷新 sourceUrl: urlForm.url, // 保存源URL用于刷新
importMethod: 'url'
} }
) )
@@ -795,13 +802,52 @@ const toggleConnection = (token) => {
} }
} }
const getTokenActions = (token) => [ const getTokenActions = (token) => {
{ label: '编辑', key: 'edit' }, const actions = [
{ label: '复制Token', key: 'copy' }, {
{ label: '重新连接', key: 'reconnect' }, label: '编辑',
key: 'edit',
icon: () => h(NIcon, null, { default: () => h(Create) })
},
{
label: '复制Token',
key: 'copy',
icon: () => h(NIcon, null, { default: () => h(Copy) })
}
]
// 根据Token类型添加不同的刷新选项
if (token.importMethod === 'url' && token.sourceUrl) {
actions.push({
label: '从URL刷新',
key: 'refresh-url',
icon: () => h(NIcon, null, { default: () => h(SyncCircle) })
})
} else {
actions.push({
label: '刷新Token',
key: 'refresh',
icon: () => h(NIcon, null, { default: () => h(Refresh) })
})
}
actions.push(
{
label: '重新连接',
key: 'reconnect',
icon: () => h(NIcon, null, { default: () => h(Link) })
},
{ type: 'divider' }, { type: 'divider' },
{ label: '删除', key: 'delete' } {
] label: '删除',
key: 'delete',
icon: () => h(NIcon, null, { default: () => h(TrashBin) }),
props: { style: { color: '#e74c3c' } }
}
)
return actions
}
const handleTokenAction = async (key, token) => { const handleTokenAction = async (key, token) => {
switch (key) { switch (key) {
@@ -811,6 +857,14 @@ const handleTokenAction = async (key, token) => {
case 'copy': case 'copy':
copyToken(token) copyToken(token)
break break
case 'refresh':
// 手动添加的Token的刷新逻辑暂时提示
message.info('手动添加的Token暂不支持刷新请重新导入')
break
case 'refresh-url':
// URL获取的Token刷新
refreshToken(token)
break
case 'reconnect': case 'reconnect':
reconnectToken(token) reconnectToken(token)
break break

View File

@@ -18,13 +18,6 @@ export default defineConfig({
server: { server: {
port: 3000, port: 3000,
open: true, open: true,
proxy: {
'/api': {
target: 'http://xyzw.my',
changeOrigin: true,
rewrite: (path) => path
}
}
}, },
css: { css: {
preprocessorOptions: { preprocessorOptions: {