feat: huge change

This commit is contained in:
HK560 2025-05-13 22:35:18 +08:00
parent 444112f6a0
commit 88866f3bfa
37 changed files with 333 additions and 145 deletions

24
nginx.conf Normal file
View file

@ -0,0 +1,24 @@
server {
listen 80;
server_name localhost;
location / {
proxy_pass http://ms.r1delta.net;
proxy_set_header Host ms.r1delta.net;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# 设置超时时间
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
# 允许较大的请求体
client_max_body_size 50M;
# 启用压缩
gzip on;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
}
}

View file

@ -8,17 +8,19 @@
"preview": "vite preview"
},
"dependencies": {
"vue": "^3.3.4",
"vue-i18n": "^9.2.2",
"vue-router": "^4.2.4",
"@heroicons/vue": "^2.0.18",
"axios": "^1.4.0",
"@heroicons/vue": "^2.0.18"
"vue": "^3.3.4",
"vue-i18n": "12.0.0-alpha.2",
"vue-router": "^4.2.4"
},
"devDependencies": {
"@types/node": "^22.15.17",
"@vitejs/plugin-vue": "^4.2.3",
"autoprefixer": "^10.4.14",
"postcss": "^8.4.27",
"tailwindcss": "^3.3.3",
"typescript": "^5.8.3",
"vite": "^4.4.9"
}
}
}

116
pnpm-lock.yaml generated
View file

@ -10,23 +10,26 @@ importers:
dependencies:
'@heroicons/vue':
specifier: ^2.0.18
version: 2.2.0(vue@3.5.13)
version: 2.2.0(vue@3.5.13(typescript@5.8.3))
axios:
specifier: ^1.4.0
version: 1.9.0
vue:
specifier: ^3.3.4
version: 3.5.13
version: 3.5.13(typescript@5.8.3)
vue-i18n:
specifier: ^9.2.2
version: 9.14.4(vue@3.5.13)
specifier: 12.0.0-alpha.2
version: 12.0.0-alpha.2(vue@3.5.13(typescript@5.8.3))
vue-router:
specifier: ^4.2.4
version: 4.5.1(vue@3.5.13)
version: 4.5.1(vue@3.5.13(typescript@5.8.3))
devDependencies:
'@types/node':
specifier: ^22.15.17
version: 22.15.17
'@vitejs/plugin-vue':
specifier: ^4.2.3
version: 4.6.2(vite@4.5.14)(vue@3.5.13)
version: 4.6.2(vite@4.5.14(@types/node@22.15.17))(vue@3.5.13(typescript@5.8.3))
autoprefixer:
specifier: ^10.4.14
version: 10.4.21(postcss@8.5.3)
@ -36,9 +39,12 @@ importers:
tailwindcss:
specifier: ^3.3.3
version: 3.4.17
typescript:
specifier: ^5.8.3
version: 5.8.3
vite:
specifier: ^4.4.9
version: 4.5.14
version: 4.5.14(@types/node@22.15.17)
packages:
@ -200,18 +206,24 @@ packages:
peerDependencies:
vue: '>= 3'
'@intlify/core-base@9.14.4':
resolution: {integrity: sha512-vtZCt7NqWhKEtHa3SD/322DlgP5uR9MqWxnE0y8Q0tjDs9H5Lxhss+b5wv8rmuXRoHKLESNgw9d+EN9ybBbj9g==}
'@intlify/core-base@12.0.0-alpha.2':
resolution: {integrity: sha512-sPWvQ1Z4Wyw9Kp8xqjAk2sMOeZ4pO7p/NL3Eol8l9a7iPyMTuHyJ2DZVbOBG6zDnCupvLAqnRMAT1LAgvx0QRQ==}
engines: {node: '>= 16'}
'@intlify/message-compiler@9.14.4':
resolution: {integrity: sha512-vcyCLiVRN628U38c3PbahrhbbXrckrM9zpy0KZVlDk2Z0OnGwv8uQNNXP3twwGtfLsCf4gu3ci6FMIZnPaqZsw==}
'@intlify/message-compiler@12.0.0-alpha.2':
resolution: {integrity: sha512-PD9C+oQbb7BF52hec0+vLnScaFkvnfX+R7zSbODYuRo/E2niAtGmHd0wPvEMsDhf9Z9b8f/qyDsVeZnD/ya9Ug==}
engines: {node: '>= 16'}
'@intlify/shared@9.14.4':
resolution: {integrity: sha512-P9zv6i1WvMc9qDBWvIgKkymjY2ptIiQ065PjDv7z7fDqH3J/HBRBN5IoiR46r/ujRcU7hCuSIZWvCAFCyuOYZA==}
'@intlify/shared@12.0.0-alpha.2':
resolution: {integrity: sha512-P2DULVX9nz3y8zKNqLw9Es1aAgQ1JGC+kgpx5q7yLmrnAKkPR5MybQWoEhxanefNJgUY5ehsgo+GKif59SrncA==}
engines: {node: '>= 16'}
'@intlify/vue-i18n-core@12.0.0-alpha.2':
resolution: {integrity: sha512-y1NPEcPbD8xqWGiaEREkA9WxxWbxmd8IurN176w39MenZKEf5P20rYyk0w4r718+w/9jjm0m5zR1ed6uMaZT2Q==}
engines: {node: '>= 16'}
peerDependencies:
vue: ^3.0.0
'@isaacs/cliui@8.0.2':
resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==}
engines: {node: '>=12'}
@ -250,6 +262,9 @@ packages:
resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==}
engines: {node: '>=14'}
'@types/node@22.15.17':
resolution: {integrity: sha512-wIX2aSZL5FE+MR0JlvF87BNVrtFWf6AE6rxSE9X7OwnVvoyCQjpzSRJ+M87se/4QCkCiebQAqrJ0y6fwIyi7nw==}
'@vitejs/plugin-vue@4.6.2':
resolution: {integrity: sha512-kqf7SGFoG+80aZG6Pf+gsZIVvGSCKE98JbiWqcCV9cThtg91Jav0yvYFC9Zb+jKetNGF6ZKeoaxgZfND21fWKw==}
engines: {node: ^14.18.0 || >=16.0.0}
@ -784,6 +799,14 @@ packages:
ts-interface-checker@0.1.13:
resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==}
typescript@5.8.3:
resolution: {integrity: sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==}
engines: {node: '>=14.17'}
hasBin: true
undici-types@6.21.0:
resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==}
update-browserslist-db@1.1.3:
resolution: {integrity: sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==}
hasBin: true
@ -821,8 +844,8 @@ packages:
terser:
optional: true
vue-i18n@9.14.4:
resolution: {integrity: sha512-B934C8yUyWLT0EMud3DySrwSUJI7ZNiWYsEEz2gknTthqKiG4dzWE/WSa8AzCuSQzwBEv4HtG1jZDhgzPfWSKQ==}
vue-i18n@12.0.0-alpha.2:
resolution: {integrity: sha512-ZSaZrDV/PhD4hLVybo84bkaNRnkGDF7GpI0Fcmn9Yj+2Kq5C3nE7I5iRbo+DiHyRGrwZ/IV1VP3naFAhcNJGsg==}
engines: {node: '>= 16'}
peerDependencies:
vue: ^3.0.0
@ -941,21 +964,28 @@ snapshots:
'@esbuild/win32-x64@0.18.20':
optional: true
'@heroicons/vue@2.2.0(vue@3.5.13)':
'@heroicons/vue@2.2.0(vue@3.5.13(typescript@5.8.3))':
dependencies:
vue: 3.5.13
vue: 3.5.13(typescript@5.8.3)
'@intlify/core-base@9.14.4':
'@intlify/core-base@12.0.0-alpha.2':
dependencies:
'@intlify/message-compiler': 9.14.4
'@intlify/shared': 9.14.4
'@intlify/message-compiler': 12.0.0-alpha.2
'@intlify/shared': 12.0.0-alpha.2
'@intlify/message-compiler@9.14.4':
'@intlify/message-compiler@12.0.0-alpha.2':
dependencies:
'@intlify/shared': 9.14.4
'@intlify/shared': 12.0.0-alpha.2
source-map-js: 1.2.1
'@intlify/shared@9.14.4': {}
'@intlify/shared@12.0.0-alpha.2': {}
'@intlify/vue-i18n-core@12.0.0-alpha.2(vue@3.5.13(typescript@5.8.3))':
dependencies:
'@intlify/core-base': 12.0.0-alpha.2
'@intlify/shared': 12.0.0-alpha.2
'@vue/devtools-api': 6.6.4
vue: 3.5.13(typescript@5.8.3)
'@isaacs/cliui@8.0.2':
dependencies:
@ -998,10 +1028,14 @@ snapshots:
'@pkgjs/parseargs@0.11.0':
optional: true
'@vitejs/plugin-vue@4.6.2(vite@4.5.14)(vue@3.5.13)':
'@types/node@22.15.17':
dependencies:
vite: 4.5.14
vue: 3.5.13
undici-types: 6.21.0
'@vitejs/plugin-vue@4.6.2(vite@4.5.14(@types/node@22.15.17))(vue@3.5.13(typescript@5.8.3))':
dependencies:
vite: 4.5.14(@types/node@22.15.17)
vue: 3.5.13(typescript@5.8.3)
'@vue/compiler-core@3.5.13':
dependencies:
@ -1051,11 +1085,11 @@ snapshots:
'@vue/shared': 3.5.13
csstype: 3.1.3
'@vue/server-renderer@3.5.13(vue@3.5.13)':
'@vue/server-renderer@3.5.13(vue@3.5.13(typescript@5.8.3))':
dependencies:
'@vue/compiler-ssr': 3.5.13
'@vue/shared': 3.5.13
vue: 3.5.13
vue: 3.5.13(typescript@5.8.3)
'@vue/shared@3.5.13': {}
@ -1554,6 +1588,10 @@ snapshots:
ts-interface-checker@0.1.13: {}
typescript@5.8.3: {}
undici-types@6.21.0: {}
update-browserslist-db@1.1.3(browserslist@4.24.5):
dependencies:
browserslist: 4.24.5
@ -1562,33 +1600,37 @@ snapshots:
util-deprecate@1.0.2: {}
vite@4.5.14:
vite@4.5.14(@types/node@22.15.17):
dependencies:
esbuild: 0.18.20
postcss: 8.5.3
rollup: 3.29.5
optionalDependencies:
'@types/node': 22.15.17
fsevents: 2.3.3
vue-i18n@9.14.4(vue@3.5.13):
vue-i18n@12.0.0-alpha.2(vue@3.5.13(typescript@5.8.3)):
dependencies:
'@intlify/core-base': 9.14.4
'@intlify/shared': 9.14.4
'@intlify/core-base': 12.0.0-alpha.2
'@intlify/shared': 12.0.0-alpha.2
'@intlify/vue-i18n-core': 12.0.0-alpha.2(vue@3.5.13(typescript@5.8.3))
'@vue/devtools-api': 6.6.4
vue: 3.5.13
vue: 3.5.13(typescript@5.8.3)
vue-router@4.5.1(vue@3.5.13):
vue-router@4.5.1(vue@3.5.13(typescript@5.8.3)):
dependencies:
'@vue/devtools-api': 6.6.4
vue: 3.5.13
vue: 3.5.13(typescript@5.8.3)
vue@3.5.13:
vue@3.5.13(typescript@5.8.3):
dependencies:
'@vue/compiler-dom': 3.5.13
'@vue/compiler-sfc': 3.5.13
'@vue/runtime-dom': 3.5.13
'@vue/server-renderer': 3.5.13(vue@3.5.13)
'@vue/server-renderer': 3.5.13(vue@3.5.13(typescript@5.8.3))
'@vue/shared': 3.5.13
optionalDependencies:
typescript: 5.8.3
which@2.0.2:
dependencies:

Binary file not shown.

After

Width:  |  Height:  |  Size: 816 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 94 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 79 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 81 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 91 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 119 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 124 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 94 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 99 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 98 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 94 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 101 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 94 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 106 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

View file

@ -3,7 +3,7 @@
<header class="bg-titanfall-secondary shadow-lg">
<div class="container mx-auto px-4 py-6">
<h1 class="text-3xl font-bold text-titanfall-accent">
{{ $t('serverList.title') }}
{{ t('serverList.title') }}
</h1>
</div>
</header>
@ -15,7 +15,7 @@
<input
v-model="searchQuery"
type="text"
:placeholder="$t('serverList.search')"
:placeholder="t('serverList.search')"
class="w-full px-4 py-2 rounded-lg bg-titanfall-secondary border border-gray-700 focus:border-titanfall-accent focus:outline-none"
/>
</div>
@ -31,7 +31,7 @@
: 'bg-titanfall-secondary hover:bg-gray-700'
]"
>
{{ $t(`serverList.filter.${mode.value}`) }}
{{ t(`serverList.filter.${mode.value}`) }}
</button>
</div>
</div>
@ -57,19 +57,19 @@
<div class="p-6 space-y-4 flex-grow flex flex-col">
<div class="space-y-2">
<p class="flex justify-between">
<span class="text-gray-400">{{ $t('serverList.status.players') }}:</span>
<span class="text-gray-400">{{ t('serverList.status.players') }}:</span>
<span>{{ server.total_players }}/{{ server.max_players }}</span>
</p>
<p class="flex justify-between">
<span class="text-gray-400">{{ $t('serverList.status.map') }}:</span>
<span>{{ server.map_name }}</span>
<span class="text-gray-400">{{ t('serverList.status.map') }}:</span>
<span>{{ t(`serverList.map.${server.map_name}`) }}</span>
</p>
<p class="flex justify-between">
<span class="text-gray-400">{{ $t('serverList.status.mode') }}:</span>
<span>{{ $t(`serverList.filter.${server.game_mode}`) }}</span>
<span class="text-gray-400">{{ t('serverList.status.mode') }}:</span>
<span>{{ t(`serverList.filter.${server.game_mode}`) }}</span>
</p>
<p class="flex justify-between">
<span class="text-gray-400">{{ $t('serverList.status.version') }}:</span>
<span class="text-gray-400">{{ t('serverList.status.version') }}:</span>
<span>{{ server.version }}</span>
</p>
<div class="flex items-center justify-between mb-2">
@ -86,11 +86,9 @@
</div>
</div>
<div class="overflow-y-auto flex-grow border-t border-gray-700 py-2">
<p class="text-sm text-gray-400">{{ server.description }}</p>
</div>
<div class="overflow-y-auto flex-grow border-t border-gray-700 py-2">
<p class="text-sm text-gray-400">{{ server.description }}</p>
</div>
</div>
</div>
</div>
@ -98,18 +96,23 @@
</div>
</template>
<script setup>
<script setup lang="ts">
import { ref, computed, onMounted } from 'vue'
import { useI18n } from 'vue-i18n'
import axios from 'axios'
import type { Server, GameMode, GameModeOption } from './types'
import { mapImageMapping } from './data/data'
const servers = ref([])
const { t } = useI18n()
const servers = ref<Server[]>([])
const searchQuery = ref('')
const selectedMode = ref('all')
const selectedMode = ref<GameMode>('all')
const copiedServer = ref('')
const gameModes = [
const gameModes: GameModeOption[] = [
{ value: 'all', label: 'All' },
{ value: 'attrition', label: 'Attrition' },
{ value: 'at', label: 'Attrition' },
{ value: 'campaign', label: 'Campaign' },
{ value: 'coop', label: 'Co-op' },
{ value: 'ctf', label: 'Capture the Flag' },
@ -128,45 +131,20 @@ const filteredServers = computed(() => {
})
})
const fetchServers = async () => {
const fetchServers = async (): Promise<void> => {
try {
const response = await axios.get('/api/servers')
const response = await axios.get<Server[]>('/api/servers')
servers.value = response.data
} catch (error) {
console.error('Error fetching servers:', error)
}
}
const mapImageMapping = {
'mp_angel_city': '/image/maps/TF_AngelCity_Loadscreen.jpg',
'mp_black_water_canal': '/image/maps/TF_BlackWaterCanal_Loadscreen.jpg',
'mp_coliseum': '/image/maps/TF_Coliseum_Loadscreen.jpg',
'mp_colony02': '/image/maps/TF_Colony_Loadscreen.jpg',
'mp_complex3': '/image/maps/TF_Complex_Loadscreen.jpg',
'mp_crashsite3': '/image/maps/TF_Crashsite_Loadscreen.jpg',
'mp_drydock': '/image/maps/TF_Drydock_Loadscreen.jpg',
'mp_eden': '/image/maps/TF_Eden_Loadscreen.jpg',
'mp_forwardbase_kodai': '/image/maps/TF_ForwardBaseKodai_Loadscreen.jpg',
'mp_glitch': '/image/maps/TF_Glitch_Loadscreen.jpg',
'mp_grave': '/image/maps/TF_Grave_Loadscreen.jpg',
'mp_homestead': '/image/maps/TF_Homestead_Loadscreen.jpg',
'mp_lf_deck': '/image/maps/TF_LFDeck_Loadscreen.jpg',
'mp_lf_meadow': '/image/maps/TF_LFMeadow_Loadscreen.jpg',
'mp_lf_stacks': '/image/maps/TF_LFStacks_Loadscreen.jpg',
'mp_lf_township': '/image/maps/TF_LFTownship_Loadscreen.jpg',
'mp_lf_traffic': '/image/maps/TF_LFTraffic_Loadscreen.jpg',
'mp_lf_uma': '/image/maps/TF_LFUMA_Loadscreen.jpg',
'mp_relic02': '/image/maps/TF_Relic_Loadscreen.jpg',
'mp_rise': '/image/maps/TF_Rise_Loadscreen.jpg',
'mp_thaw': '/image/maps/TF_Thaw_Loadscreen.jpg',
'mp_wargames': '/image/maps/TF_Wargames_Loadscreen.jpg'
}
const getMapImage = (mapName) => {
const getMapImage = (mapName: string): string => {
return mapImageMapping[mapName.toLowerCase()] || '/image/maps/default_map.jpg'
}
const copyConnectCommand = async (server) => {
const copyConnectCommand = async (server: Server): Promise<void> => {
const command = `${server.ip}:${server.port}`
try {
await navigator.clipboard.writeText(command)

27
src/data/data.ts Normal file
View file

@ -0,0 +1,27 @@
export const mapImageMapping: Record<string, string> = {
'mp_airbase': '/image/maps/TF_Airbase_Loadscreen.jpg',
'mp_angel_city': '/image/maps/TF_AngelCity_Loadscreen.jpg',
'mp_boneyard': '/image/maps/TF_Boneyard_Loadscreen.jpg',
'mp_colony': '/image/maps/TF_Colony_Loadscreen.jpg',
'mp_corporate': '/image/maps/TF_Corporate_Loadscreen.jpg',
'mp_fracture': '/image/maps/TF_Fracture_Loadscreen.jpg',
'mp_lagoon': '/image/maps/TF_Lagoon_Loadscreen.jpg',
'mp_nexus': '/image/maps/TF_Nexus_Loadscreen.jpg',
'mp_o2': '/image/maps/TF_Demeter_Loadscreen.jpg',
'mp_outpost_207': '/image/maps/TF_Outpost207_Loadscreen.jpg',
'mp_overlook': '/image/maps/TF_Overlook_Loadscreen.jpg',
'mp_relic': '/image/maps/TF_Relic_Loadscreen.jpg',
'mp_rise': '/image/maps/TF_Rise_Loadscreen.jpg',
'mp_smugglers_cove': '/image/maps/TF_Smuggler_Cove_Loadscreen.jpg',
'mp_training_ground': '/image/maps/TF_TrainingGround_Loadscreen.jpg',
'mp_wargames': '/image/maps/TF_War_Games_Loadscreen.jpg',
'mp_runoff': '/image/maps/TF_Runoff_Loadscreen.jpg',
'mp_swampland': '/image/maps/TF_Swampland_Loadscreen.jpg',
'mp_haven': '/image/maps/TF_Haven_Loadscreen.jpg',
'mp_harmony_mines': '/image/maps/TF_Dig_Site_Loadscreen.jpg',
'mp_switchback': '/image/maps/TF_Export_Loadscreen.jpg',
'mp_backwater': '/image/maps/TF_Backwater_Loadscreen.jpg',
'mp_sandtrap': '/image/maps/TF_Sand_Trap_Loadscreen.jpg',
'mp_zone_18': '/image/maps/TF_Zone_18_Loadscreen.jpg',
'mp_lobby': '/image/maps/Menu_Background.png',
}

51
src/lang/en.js Normal file
View file

@ -0,0 +1,51 @@
export default {
serverList: {
title: 'Titanfall Server List',
search: 'Search servers...',
filter: {
all: 'All',
at: 'Attrition',
campaign: 'Campaign',
coop: 'Co-op',
ctf: 'Capture the Flag',
lts: 'Last Titan Standing',
mfdp: 'Marked for Death Pro',
ps: 'Pilot Skirmish',
tdm: 'Team Deathmatch'
},
map:{
mp_airbase: 'AirBase',
mp_angel_city: 'Angel City',
mp_boneyard: 'Boneyard',
mp_colony: 'Colony',
mp_corporate: 'Corporate',
mp_fracture: 'Fracture',
mp_lagoon: 'Lagoon',
mp_nexus: 'Nexus',
mp_o2: 'Demeter',
mp_outpost_207: 'Outpost 207',
mp_overlook: 'Overlook',
mp_relic: 'Relic',
mp_rise: 'Rise',
mp_smugglers_cove: 'Smugglers Cove',
mp_training_ground: 'Training Ground',
mp_wargames: 'War Games',
mp_runoff: 'Runoff',
mp_swampland: 'Swampland',
mp_haven: 'Haven',
mp_harmony_mines: 'Dig Site',
mp_switchback: 'Export',
mp_backwater: 'Backwater',
mp_sandtrap: 'SandTrap',
mp_zone_18: 'Zone18',
mp_lobby: 'Lobby',
},
status: {
players: 'Players',
maxPlayers: 'Max Players',
map: 'Map',
mode: 'Mode',
version: 'Version'
}
}
}

14
src/lang/i18n.js Normal file
View file

@ -0,0 +1,14 @@
import { createI18n } from 'vue-i18n'
import zh from './zh'
import en from './en'
const i18n = createI18n({
locale: 'zh',
fallbackLocale: 'en',
messages: {
zh,
en
}
})
export default i18n

51
src/lang/zh.js Normal file
View file

@ -0,0 +1,51 @@
export default {
serverList: {
title: 'R1Delta 服务器列表(本页面开发中)',
search: '搜索服务器...',
filter: {
all: '全部',
at: '消耗战',
campaign: '战役',
coop: '边境防御',
ctf: '夺旗',
lts: '泰坦殊死战',
mfdp: '标记死亡',
ps: '铁驭对铁驭',
tdm: '团队死斗'
},
map:{
mp_airbase: '空军基地',
mp_angel_city: '天使城',
mp_boneyard: '墓地',
mp_colony: '殖民地',
mp_corporate: '总部',
mp_fracture: '摧残之地',
mp_lagoon: '泻湖',
mp_nexus: '中枢',
mp_o2: '穀神星',
mp_outpost_207: '207号哨站',
mp_overlook: '瞭望台',
mp_relic: '遗迹',
mp_rise: '崛起',
mp_smugglers_cove: '走私巢穴',
mp_training_ground: '训练场地',
mp_wargames: '战争游戏',
mp_runoff: '径流',
mp_swampland: '沼泽地',
mp_haven: '避难所',
mp_harmony_mines: '挖掘场',
mp_switchback: '输出港',
mp_backwater: '荒僻之地',
mp_sandtrap: '飞沙陷阱',
mp_zone_18: '第18区',
mp_lobby: '大厅',
},
status: {
players: '玩家数',
maxPlayers: '最大玩家数',
map: '地图',
mode: '模式',
version: '版本'
}
}
}

View file

@ -1,61 +1,7 @@
import { createApp } from 'vue'
import { createI18n } from 'vue-i18n'
import App from './App.vue'
import './assets/main.css'
const i18n = createI18n({
locale: 'zh',
messages: {
zh: {
serverList: {
title: 'R1Delta 服务器列表(本页面开发中)',
search: '搜索服务器...',
filter: {
all: '全部',
attrition: '消耗战',
campaign: '战役',
coop: '合作',
ctf: '夺旗',
lts: '泰坦死斗',
mfdp: '标记死亡',
ps: '飞行员对战',
tdm: '团队死斗'
},
status: {
players: '玩家数',
maxPlayers: '最大玩家数',
map: '地图',
mode: '模式',
version: '版本'
}
}
},
en: {
serverList: {
title: 'Titanfall Server List',
search: 'Search servers...',
filter: {
all: 'All',
attrition: 'Attrition',
campaign: 'Campaign',
coop: 'Co-op',
ctf: 'Capture the Flag',
lts: 'Last Titan Standing',
mfdp: 'Marked for Death Pro',
ps: 'Pilot Skirmish',
tdm: 'Team Deathmatch'
},
status: {
players: 'Players',
maxPlayers: 'Max Players',
map: 'Map',
mode: 'Mode',
version: 'Version'
}
}
}
}
})
import i18n from './lang/i18n'
const app = createApp(App)
app.use(i18n)

18
src/types/index.ts Normal file
View file

@ -0,0 +1,18 @@
export interface Server {
ip: string;
port: number;
host_name: string;
description: string;
map_name: string;
game_mode: GameMode;
total_players: number;
max_players: number;
version: string;
}
export type GameMode = 'all' | 'at' | 'campaign' | 'coop' | 'ctf' | 'lts' | 'mfdp' | 'ps' | 'tdm';
export interface GameModeOption {
value: GameMode;
label: string;
}

25
tsconfig.json Normal file
View file

@ -0,0 +1,25 @@
{
"compilerOptions": {
"target": "ES2020",
"useDefineForClassFields": true,
"module": "ESNext",
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"skipLibCheck": true,
/* Bundler mode */
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "preserve",
/* Linting */
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true
},
"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"],
"references": [{ "path": "./tsconfig.node.json" }]
}

10
tsconfig.node.json Normal file
View file

@ -0,0 +1,10 @@
{
"compilerOptions": {
"composite": true,
"skipLibCheck": true,
"module": "ESNext",
"moduleResolution": "bundler",
"allowSyntheticDefaultImports": true
},
"include": ["vite.config.ts"]
}