2.4.4 更改主播上限

This commit is contained in:
2026-03-26 13:38:35 +08:00
parent 1c67cbc5ea
commit b81a0377b8
7 changed files with 562 additions and 78 deletions

View File

@@ -6,5 +6,7 @@ VITE_REGISTER_API_URL=http://192.168.2.22:48080
# VITE_REGISTER_API_URL=https://backstageapi.yolozs.com # VITE_REGISTER_API_URL=https://backstageapi.yolozs.com
# pk api地址 # pk api地址
VITE_PK_MINI_API_URL=http://192.168.2.22:8086 VITE_PK_MINI_API_URL=http://192.168.2.22:8086
# VITE_PK_MINI_API_URL=https://pk.yolozs.com
# 商店地址 # 商店地址
VITE_SHOP_URL=https://www.tkzyw.com VITE_SHOP_URL=https://www.tkzyw.com

View File

@@ -1,13 +1,16 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="zh-CN"> <html lang="zh-CN">
<head> <head>
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>YoloAI助手Web版</title> <title>Yolo终端</title>
</head> </head>
<body> <body>
<div id="root"></div> <div id="root"></div>
<script type="module" src="/src/main.js"></script> <script type="module" src="/src/main.js"></script>
<script src="https://challenges.cloudflare.com/turnstile/v0/api.js?render=explicit" async defer></script> <script src="https://challenges.cloudflare.com/turnstile/v0/api.js?render=explicit" async defer></script>
</body> </body>
</html> </html>

View File

@@ -20,15 +20,9 @@
<!-- 浏览器页面 --> <!-- 浏览器页面 -->
<div class="h-full w-full animate-fadeIn" v-show="currentPage === 'browser'"> <div class="h-full w-full animate-fadeIn" v-show="currentPage === 'browser'">
<WorkbenchLayout <WorkbenchLayout :account-groups="accountGroups" :rotation-status="rotationStatus"
:account-groups="accountGroups" :greeting-stats="greetingStats" :automation-logs="automationLogs" @go-back="handleGoToConfig"
:rotation-status="rotationStatus" @stop-all="handleStopAll" @logout="handleLogout" />
:greeting-stats="greetingStats"
:automation-logs="automationLogs"
@go-back="handleGoToConfig"
@stop-all="handleStopAll"
@logout="handleLogout"
/>
</div> </div>
</template> </template>
</template> </template>
@@ -71,9 +65,9 @@ noticeStore.fetchNotices()
onMounted(() => { onMounted(() => {
// Set Title // Set Title
getAppVersion().then(version => { getAppVersion().then(version => {
document.title = `YoloAI助手Web版v${version}` document.title = `Yolo终端v${version}`
}).catch(() => { }).catch(() => {
document.title = 'YoloAI助手Web版' document.title = 'Yolo终端'
}) })
console.log('[App]', !isDev, isElectronEnv, !updateReady.value) console.log('[App]', !isDev, isElectronEnv, !updateReady.value)
// Check Login // Check Login

View File

@@ -72,10 +72,8 @@
<div class="space-y-2 max-h-60 overflow-auto"> <div class="space-y-2 max-h-60 overflow-auto">
<div v-for="parent in LEVEL_OPTIONS" :key="parent.value" <div v-for="parent in LEVEL_OPTIONS" :key="parent.value"
class="border border-gray-100 rounded p-2"> class="border border-gray-100 rounded p-2">
<label <label class="flex items-center gap-2 cursor-pointer font-medium text-gray-700">
class="flex items-center gap-2 cursor-pointer font-medium text-gray-700"> <input type="checkbox" :checked="isParentSelected(parent).allSelected"
<input type="checkbox"
:checked="isParentSelected(parent).allSelected"
:indeterminate="isParentSelected(parent).partialSelected" :indeterminate="isParentSelected(parent).partialSelected"
@change="toggleParentLevel(parent.value)" class="w-4 h-4" /> @change="toggleParentLevel(parent.value)" class="w-4 h-4" />
{{ parent.label }} {{ parent.label }}
@@ -120,8 +118,7 @@
<!-- 主播列表 --> <!-- 主播列表 -->
<div class="flex-1 overflow-auto p-4"> <div class="flex-1 overflow-auto p-4">
<div class="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-3"> <div class="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-3">
<div v-for="host in filteredHosts" :key="host.id" @click="toggleSelect(host.id)" <div v-for="host in filteredHosts" :key="host.id" @click="toggleSelect(host.id)" :class="[
:class="[
'p-3 rounded-lg border cursor-pointer transition-all', 'p-3 rounded-lg border cursor-pointer transition-all',
selected.has(host.id) ? 'border-blue-500 bg-blue-50 shadow' : 'border-gray-200 hover:border-gray-300 hover:shadow-sm' selected.has(host.id) ? 'border-blue-500 bg-blue-50 shadow' : 'border-gray-200 hover:border-gray-300 hover:shadow-sm'
]"> ]">
@@ -182,7 +179,8 @@
<!-- 主播ID输入 --> <!-- 主播ID输入 -->
<div> <div>
<label class="block text-sm font-medium text-gray-700 mb-1">主播ID每行一个支持批量粘贴</label> <label class="block text-sm font-medium text-gray-700 mb-1">主播ID每行一个支持批量粘贴</label>
<textarea v-model="addForm.idsText" rows="6" placeholder="粘贴主播ID每行一个&#10;例如:&#10;anchor_001&#10;anchor_002&#10;anchor_003" <textarea v-model="addForm.idsText" rows="6"
placeholder="粘贴主播ID每行一个&#10;例如:&#10;anchor_001&#10;anchor_002&#10;anchor_003"
class="w-full px-3 py-2 border border-gray-300 rounded-lg text-sm focus:border-blue-500 focus:outline-none resize-none font-mono"></textarea> class="w-full px-3 py-2 border border-gray-300 rounded-lg text-sm focus:border-blue-500 focus:outline-none resize-none font-mono"></textarea>
<div class="text-xs text-gray-400 mt-1"> <div class="text-xs text-gray-400 mt-1">
已输入 {{ parsedIds.length }} 个ID 已输入 {{ parsedIds.length }} 个ID
@@ -229,7 +227,8 @@
<!-- 底部按钮 --> <!-- 底部按钮 -->
<div class="p-4 border-t border-gray-200 flex justify-between items-center"> <div class="p-4 border-t border-gray-200 flex justify-between items-center">
<span v-if="addStatus" :class="['text-sm', addStatus.type === 'success' ? 'text-green-600' : 'text-red-600']"> <span v-if="addStatus"
:class="['text-sm', addStatus.type === 'success' ? 'text-green-600' : 'text-red-600']">
{{ addStatus.message }} {{ addStatus.message }}
</span> </span>
<span v-else></span> <span v-else></span>
@@ -418,8 +417,8 @@ const loadConfig = async () => {
if (!isElectron()) return if (!isElectron()) return
try { try {
const config = await window.electronAPI.getAutomationConfig() const config = await window.electronAPI.getAutomationConfig()
if (config?.maxAnchorCount !== undefined) { if (config?.filters?.maxAnchorCount !== undefined) {
maxCount.value = config.maxAnchorCount maxCount.value = config.filters.maxAnchorCount
} }
if (config?.filters?.hostsLevelList) { if (config?.filters?.hostsLevelList) {
selectedLevels.value = new Set(config.filters.hostsLevelList) selectedLevels.value = new Set(config.filters.hostsLevelList)
@@ -498,7 +497,9 @@ const updateMaxCount = async (value) => {
// value is already updated via v-model // value is already updated via v-model
if (!isElectron()) return if (!isElectron()) return
try { try {
await window.electronAPI.updateAutomationConfig({ maxAnchorCount: value }) await window.electronAPI.updateAutomationConfig({
filters: { maxAnchorCount: value }
})
console.log('[HostListDialog] 主播数据上限已更新:', value) console.log('[HostListDialog] 主播数据上限已更新:', value)
} catch (e) { } catch (e) {
console.error('更新配置失败:', e) console.error('更新配置失败:', e)

View File

@@ -59,8 +59,7 @@
<!-- 卡片头部 --> <!-- 卡片头部 -->
<div class="flex items-center justify-between mb-6"> <div class="flex items-center justify-between mb-6">
<div class="flex items-center gap-2"> <div class="flex items-center gap-2">
<span <span class="w-1 h-4 rounded-full bg-gradient-to-b from-blue-500 to-green-500" />
class="w-1 h-4 rounded-full bg-gradient-to-b from-blue-500 to-green-500" />
<span class="font-medium text-gray-900">运行配置</span> <span class="font-medium text-gray-900">运行配置</span>
</div> </div>
@@ -86,8 +85,7 @@
@click="handleStart(config.accountGroups.indexOf(group))" @click="handleStart(config.accountGroups.indexOf(group))"
class="w-full text-left px-4 py-2 text-sm text-gray-700 hover:bg-blue-50 hover:text-blue-600 transition-colors flex items-center justify-between group/item"> class="w-full text-left px-4 py-2 text-sm text-gray-700 hover:bg-blue-50 hover:text-blue-600 transition-colors flex items-center justify-between group/item">
<span>运行 {{ group.name }}</span> <span>运行 {{ group.name }}</span>
<span <span class="text-xs text-gray-400 group-hover/item:text-blue-400">
class="text-xs text-gray-400 group-hover/item:text-blue-400">
{{ config.accountGroups.indexOf(group) + 1 }} {{ config.accountGroups.indexOf(group) + 1 }}
</span> </span>
</button> </button>
@@ -152,15 +150,16 @@
class="absolute right-2 top-1/2 -translate-y-1/2 text-gray-400 hover:text-gray-600 focus:outline-none p-1"> class="absolute right-2 top-1/2 -translate-y-1/2 text-gray-400 hover:text-gray-600 focus:outline-none p-1">
<svg v-if="showPasswordMap[`${gIndex}-${aIndex}`]" class="w-4 h-4" <svg v-if="showPasswordMap[`${gIndex}-${aIndex}`]" class="w-4 h-4"
fill="none" viewBox="0 0 24 24" stroke="currentColor"> fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" <path stroke-linecap="round" stroke-linejoin="round"
d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" /> stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
<path stroke-linecap="round" stroke-linejoin="round" <path stroke-linecap="round" stroke-linejoin="round"
stroke-width="2" stroke-width="2"
d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z" /> d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z" />
</svg> </svg>
<svg v-else class="w-4 h-4" fill="none" viewBox="0 0 24 24" <svg v-else class="w-4 h-4" fill="none" viewBox="0 0 24 24"
stroke="currentColor"> stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" <path stroke-linecap="round" stroke-linejoin="round"
stroke-width="2"
d="M13.875 18.825A10.05 10.05 0 0112 19c-4.478 0-8.268-2.943-9.543-7a9.97 9.97 0 011.563-3.029m5.858.908a3 3 0 114.243 4.243M9.878 9.878l4.242 4.242M9.88 9.88l-3.29-3.29m7.532 7.532l3.29 3.29M3 3l3.59 3.59m0 0A9.953 9.953 0 0112 5c4.478 0 8.268 2.943 9.543 7a10.025 10.025 0 01-4.132 5.411m0 0L21 21" /> d="M13.875 18.825A10.05 10.05 0 0112 19c-4.478 0-8.268-2.943-9.543-7a9.97 9.97 0 011.563-3.029m5.858.908a3 3 0 114.243 4.243M9.878 9.878l4.242 4.242M9.88 9.88l-3.29-3.29m7.532 7.532l3.29 3.29M3 3l3.59 3.59m0 0A9.953 9.953 0 0112 5c4.478 0 8.268 2.943 9.543 7a10.025 10.025 0 01-4.132 5.411m0 0L21 21" />
</svg> </svg>
</button> </button>
@@ -324,7 +323,8 @@
<HostListDialog :visible="showHostDialog" @close="showHostDialog = false" @save="() => { }" /> <HostListDialog :visible="showHostDialog" @close="showHostDialog = false" @save="() => { }" />
<!-- 打招呼内容弹窗 --> <!-- 打招呼内容弹窗 -->
<GreetingDialog :visible="showGreetingDialog" @close="showGreetingDialog = false" @confirm="handleGreetingConfirm" /> <GreetingDialog :visible="showGreetingDialog" @close="showGreetingDialog = false"
@confirm="handleGreetingConfirm" />
<!-- 预热 Loading 遮罩 --> <!-- 预热 Loading 遮罩 -->
<transition name="fade"> <transition name="fade">
@@ -383,7 +383,9 @@ const defaultConfig = {
switchMinutes: 60, switchMinutes: 60,
prologueList: {}, prologueList: {},
needTranslate: false, needTranslate: false,
maxAnchorCount: 100, filters: {
maxAnchorCount: 100
},
lang: 'en' lang: 'en'
} }
@@ -702,7 +704,9 @@ const handleStart = async (specificGroupIndex) => {
inviteThreshold: config.value.inviteThreshold, inviteThreshold: config.value.inviteThreshold,
prologueList, prologueList,
needTranslate: config.value.needTranslate, // 添加翻译开关配置 needTranslate: config.value.needTranslate, // 添加翻译开关配置
maxAnchorCount: config.value.maxAnchorCount, filters: {
maxAnchorCount: config.value.filters?.maxAnchorCount || 100
},
rotationEnabled: config.value.rotateEnabled, rotationEnabled: config.value.rotateEnabled,
rotationIntervalMinutes: config.value.switchMinutes, rotationIntervalMinutes: config.value.switchMinutes,
currentActiveGroup: activeGroupName, currentActiveGroup: activeGroupName,

View File

@@ -1,4 +1,4 @@
// 国家数据 - 简化版本,直接内嵌数据 // 国家数据 - 完整补全版本
const zhCountries = { const zhCountries = {
"CN": "中国", "CN": "中国",
"US": "美国", "US": "美国",
@@ -23,6 +23,7 @@ const zhCountries = {
"PH": "菲律宾", "PH": "菲律宾",
"TW": "中国台湾", "TW": "中国台湾",
"HK": "中国香港", "HK": "中国香港",
"MO": "中国澳门",
"AE": "阿联酋", "AE": "阿联酋",
"SA": "沙特阿拉伯", "SA": "沙特阿拉伯",
"TR": "土耳其", "TR": "土耳其",
@@ -52,7 +53,199 @@ const zhCountries = {
"PK": "巴基斯坦", "PK": "巴基斯坦",
"BD": "孟加拉国", "BD": "孟加拉国",
"NZ": "新西兰", "NZ": "新西兰",
"BK": "保加利亚", "HR": "克罗地亚",
"BG": "保加利亚",
// --- 新增补全 ---
"KP": "朝鲜",
"IE": "爱尔兰",
"AG": "安提瓜和巴布达",
"BS": "巴哈马",
"BB": "巴巴多斯",
"BZ": "伯利兹",
"BW": "博茨瓦纳",
"KY": "开曼群岛",
"CX": "圣诞岛",
"CC": "科科斯群岛",
"CK": "库克群岛",
"DM": "多米尼克",
"SZ": "埃斯瓦蒂尼",
"FK": "福克兰群岛",
"FJ": "斐济",
"GM": "冈比亚",
"GH": "加纳",
"GI": "直布罗陀",
"GD": "格林纳达",
"GU": "关岛",
"GG": "根西岛",
"GY": "圭亚那",
"HM": "赫德岛和麦克唐纳群岛",
"IM": "曼岛",
"JM": "牙买加",
"JE": "泽西岛",
"KE": "肯尼亚",
"KI": "基里巴斯",
"LS": "莱索托",
"LR": "利比里亚",
"MW": "马拉维",
"MH": "马绍尔群岛",
"MU": "毛里求斯",
"FM": "密克罗尼西亚",
"MS": "蒙特塞拉特",
"NA": "纳米比亚",
"NR": "瑙鲁",
"NU": "纽埃",
"NF": "诺福克岛",
"MP": "北马里亚纳群岛",
"PW": "帕劳",
"PG": "巴布亚新几内亚",
"PN": "皮特凯恩群岛",
"SH": "圣赫勒拿",
"KN": "圣基茨和尼维斯",
"LC": "圣卢西亚",
"VC": "圣文森特和格林纳丁斯",
"SL": "塞拉利昂",
"SB": "所罗门群岛",
"GS": "南乔治亚岛和南桑威奇群岛",
"SS": "南苏丹",
"TK": "托克劳",
"TT": "特立尼达和多巴哥",
"TC": "特克斯和凯科斯群岛",
"TV": "图瓦卢",
"UG": "乌干达",
"UM": "美国本土外小岛屿",
"VG": "英属维尔京群岛",
"VI": "美属维尔京群岛",
"ZM": "赞比亚",
"ZW": "津巴布韦",
"AS": "美属萨摩亚",
"AI": "安圭拉",
"AQ": "南极洲",
"BM": "百幕大",
"IO": "英属印度洋领地",
"BJ": "贝宁",
"BF": "布基纳法索",
"BI": "布隆迪",
"CM": "喀麦隆",
"CF": "中非共和国",
"TD": "乍得",
"CD": "刚果民主共和国",
"CI": "科特迪瓦",
"DJ": "吉布提",
"GF": "法属圭亚那",
"PF": "法属波利尼西亚",
"TF": "法属南部领地",
"GA": "加蓬",
"GP": "瓜德罗普",
"GN": "几内亚",
"HT": "海地",
"LU": "卢森堡",
"MG": "马达加斯加",
"ML": "马里",
"MQ": "马提尼克",
"YT": "马约特",
"MC": "摩纳哥",
"NC": "新喀里多尼亚",
"NE": "尼日尔",
"RE": "留尼汪",
"BL": "圣巴泰勒米",
"MF": "法属圣马丁",
"PM": "圣皮埃尔和密克隆",
"SN": "塞内加尔",
"SC": "塞舌尔",
"TG": "多哥",
"WF": "瓦利斯和富图纳",
"LI": "列支敦士登",
"VA": "梵蒂冈",
"SM": "圣马力诺",
"BO": "玻利维亚",
"CR": "哥斯达黎加",
"CU": "古巴",
"DO": "多米尼加共和国",
"EC": "厄瓜多尔",
"SV": "萨尔瓦多",
"GQ": "赤道几内亚",
"GT": "危地马拉",
"HN": "洪都拉斯",
"NI": "尼加拉瓜",
"PA": "巴拿马",
"PY": "巴拉圭",
"PR": "波多黎各",
"UY": "乌拉圭",
"VE": "委内瑞拉",
"CV": "佛得角",
"GW": "几内亚比绍",
"MZ": "莫桑比克",
"ST": "圣多美和普林西比",
"AO": "安哥拉",
"BN": "文莱",
"BH": "巴林",
"KM": "科摩罗",
"IQ": "伊拉克",
"JO": "约旦",
"KW": "科威特",
"LB": "黎巴嫩",
"LY": "利比亚",
"MR": "毛里塔尼亚",
"MA": "摩洛哥",
"OM": "阿曼",
"PS": "巴勒斯坦",
"QA": "卡塔尔",
"SD": "苏丹",
"SY": "叙利亚",
"TN": "突尼斯",
"EH": "西撒哈拉",
"YE": "也门",
"DZ": "阿尔及利亚",
"MM": "缅甸",
"LK": "斯里兰卡",
"CW": "库拉索",
"SX": "荷属圣马丁",
"SR": "苏里南",
"BQ": "荷属加勒比区",
"MD": "摩尔多瓦",
"LA": "老挝",
"AL": "阿尔巴尼亚",
"AD": "安道尔",
"AM": "亚美尼亚",
"AZ": "阿塞拜疆",
"BY": "白俄罗斯",
"BT": "不丹",
"BA": "波斯尼亚和黑塞哥维那",
"KH": "柬埔寨",
"CY": "塞浦路斯",
"ER": "厄立特里亚",
"EE": "爱沙尼亚",
"ET": "埃塞俄比亚",
"GE": "格鲁吉亚",
"GL": "格陵兰",
"IS": "冰岛",
"IR": "伊朗",
"AF": "阿富汗",
"KZ": "哈萨克斯坦",
"KG": "吉尔吉斯斯坦",
"LV": "拉脱维亚",
"LT": "立陶宛",
"MV": "马尔代夫",
"MT": "马耳他",
"MN": "蒙古",
"ME": "黑山",
"RS": "塞尔维亚",
"NP": "尼泊尔",
"MK": "北马其顿",
"SJ": "斯瓦尔巴群岛和扬马延岛",
"BV": "布韦岛",
"RW": "卢旺达",
"WS": "萨摩亚",
"SK": "斯洛伐克",
"SI": "斯洛文尼亚",
"SO": "索马里",
"TJ": "塔吉克斯坦",
"TZ": "坦桑尼亚",
"TL": "东帝汶",
"TO": "汤加",
"TM": "土库曼斯坦",
"UZ": "乌兹别克斯坦",
"VU": "瓦努阿图"
} }
const enCountries = { const enCountries = {
@@ -79,6 +272,7 @@ const enCountries = {
"PH": "Philippines", "PH": "Philippines",
"TW": "Taiwan", "TW": "Taiwan",
"HK": "Hong Kong", "HK": "Hong Kong",
"MO": "Macao",
"AE": "UAE", "AE": "UAE",
"SA": "Saudi Arabia", "SA": "Saudi Arabia",
"TR": "Turkey", "TR": "Turkey",
@@ -107,7 +301,200 @@ const enCountries = {
"IL": "Israel", "IL": "Israel",
"PK": "Pakistan", "PK": "Pakistan",
"BD": "Bangladesh", "BD": "Bangladesh",
"NZ": "New Zealand" "NZ": "New Zealand",
"HR": "Croatia",
"BG": "Bulgaria",
// --- 新增补全 ---
"KP": "North Korea",
"IE": "Ireland",
"AG": "Antigua and Barbuda",
"BS": "Bahamas",
"BB": "Barbados",
"BZ": "Belize",
"BW": "Botswana",
"KY": "Cayman Islands",
"CX": "Christmas Island",
"CC": "Cocos Islands",
"CK": "Cook Islands",
"DM": "Dominica",
"SZ": "Eswatini",
"FK": "Falkland Islands",
"FJ": "Fiji",
"GM": "Gambia",
"GH": "Ghana",
"GI": "Gibraltar",
"GD": "Grenada",
"GU": "Guam",
"GG": "Guernsey",
"GY": "Guyana",
"HM": "Heard Island and McDonald Islands",
"IM": "Isle of Man",
"JM": "Jamaica",
"JE": "Jersey",
"KE": "Kenya",
"KI": "Kiribati",
"LS": "Lesotho",
"LR": "Liberia",
"MW": "Malawi",
"MH": "Marshall Islands",
"MU": "Mauritius",
"FM": "Micronesia",
"MS": "Montserrat",
"NA": "Namibia",
"NR": "Nauru",
"NU": "Niue",
"NF": "Norfolk Island",
"MP": "Northern Mariana Islands",
"PW": "Palau",
"PG": "Papua New Guinea",
"PN": "Pitcairn Islands",
"SH": "Saint Helena",
"KN": "Saint Kitts and Nevis",
"LC": "Saint Lucia",
"VC": "Saint Vincent and the Grenadines",
"SL": "Sierra Leone",
"SB": "Solomon Islands",
"GS": "South Georgia and the South Sandwich Islands",
"SS": "South Sudan",
"TK": "Tokelau",
"TT": "Trinidad and Tobago",
"TC": "Turks and Caicos Islands",
"TV": "Tuvalu",
"UG": "Uganda",
"UM": "U.S. Minor Outlying Islands",
"VG": "British Virgin Islands",
"VI": "U.S. Virgin Islands",
"ZM": "Zambia",
"ZW": "Zimbabwe",
"AS": "American Samoa",
"AI": "Anguilla",
"AQ": "Antarctica",
"BM": "Bermuda",
"IO": "British Indian Ocean Territory",
"BJ": "Benin",
"BF": "Burkina Faso",
"BI": "Burundi",
"CM": "Cameroon",
"CF": "Central African Republic",
"TD": "Chad",
"CD": "DR Congo",
"CI": "Ivory Coast",
"DJ": "Djibouti",
"GF": "French Guiana",
"PF": "French Polynesia",
"TF": "French Southern Territories",
"GA": "Gabon",
"GP": "Guadeloupe",
"GN": "Guinea",
"HT": "Haiti",
"LU": "Luxembourg",
"MG": "Madagascar",
"ML": "Mali",
"MQ": "Martinique",
"YT": "Mayotte",
"MC": "Monaco",
"NC": "New Caledonia",
"NE": "Niger",
"RE": "Réunion",
"BL": "Saint Barthélemy",
"MF": "Saint Martin",
"PM": "Saint Pierre and Miquelon",
"SN": "Senegal",
"SC": "Seychelles",
"TG": "Togo",
"WF": "Wallis and Futuna",
"LI": "Liechtenstein",
"VA": "Vatican City",
"SM": "San Marino",
"BO": "Bolivia",
"CR": "Costa Rica",
"CU": "Cuba",
"DO": "Dominican Republic",
"EC": "Ecuador",
"SV": "El Salvador",
"GQ": "Equatorial Guinea",
"GT": "Guatemala",
"HN": "Honduras",
"NI": "Nicaragua",
"PA": "Panama",
"PY": "Paraguay",
"PR": "Puerto Rico",
"UY": "Uruguay",
"VE": "Venezuela",
"CV": "Cape Verde",
"GW": "Guinea-Bissau",
"MZ": "Mozambique",
"ST": "São Tomé and Príncipe",
"AO": "Angola",
"BN": "Brunei",
"BH": "Bahrain",
"KM": "Comoros",
"IQ": "Iraq",
"JO": "Jordan",
"KW": "Kuwait",
"LB": "Lebanon",
"LY": "Libya",
"MR": "Mauritania",
"MA": "Morocco",
"OM": "Oman",
"PS": "Palestine",
"QA": "Qatar",
"SD": "Sudan",
"SY": "Syria",
"TN": "Tunisia",
"EH": "Western Sahara",
"YE": "Yemen",
"DZ": "Algeria",
"MM": "Myanmar",
"LK": "Sri Lanka",
"CW": "Curaçao",
"SX": "Sint Maarten",
"SR": "Suriname",
"BQ": "Caribbean Netherlands",
"MD": "Moldova",
"LA": "Laos",
"AL": "Albania",
"AD": "Andorra",
"AM": "Armenia",
"AZ": "Azerbaijan",
"BY": "Belarus",
"BT": "Bhutan",
"BA": "Bosnia and Herzegovina",
"KH": "Cambodia",
"CY": "Cyprus",
"ER": "Eritrea",
"EE": "Estonia",
"ET": "Ethiopia",
"GE": "Georgia",
"GL": "Greenland",
"IS": "Iceland",
"IR": "Iran",
"AF": "Afghanistan",
"KZ": "Kazakhstan",
"KG": "Kyrgyzstan",
"LV": "Latvia",
"LT": "Lithuania",
"MV": "Maldives",
"MT": "Malta",
"MN": "Mongolia",
"ME": "Montenegro",
"RS": "Serbia",
"NP": "Nepal",
"MK": "North Macedonia",
"SJ": "Svalbard and Jan Mayen",
"BV": "Bouvet Island",
"RW": "Rwanda",
"WS": "Samoa",
"SK": "Slovakia",
"SI": "Slovenia",
"SO": "Somalia",
"TJ": "Tajikistan",
"TZ": "Tanzania",
"TL": "Timor-Leste",
"TO": "Tonga",
"TM": "Turkmenistan",
"UZ": "Uzbekistan",
"VU": "Vanuatu"
} }
// 创建中文名称到国家代码的映射 // 创建中文名称到国家代码的映射

View File

@@ -55,10 +55,10 @@
<div class="content-area"> <div class="content-area">
<!-- 列表面板 --> <!-- 列表面板 -->
<div class="list-panel"> <div class="list-panel">
<div v-infinite-scroll="loadMore" :infinite-scroll-distance="100" :infinite-scroll-disabled="loading || noMore" <div v-infinite-scroll="loadMore" :infinite-scroll-distance="50" :infinite-scroll-disabled="loading || noMore"
class="pk-list"> :infinite-scroll-immediate="true" class="pk-list">
<div v-for="(item, index) in pkList" :key="index" class="pk-card" :class="{ selected: selectedItem === item }" <div v-for="item in pkList" :key="item.id || item.anchorId" class="pk-card"
@click="handleItemClick(item)"> :class="{ selected: selectedItem === item }" @click="handleItemClick(item)">
<!-- 头像 --> <!-- 头像 -->
<div class="pk-avatar"> <div class="pk-avatar">
<img :src="item.anchorIcon" alt="" /> <img :src="item.anchorIcon" alt="" />
@@ -67,8 +67,8 @@
<!-- 个人信息 --> <!-- 个人信息 -->
<div class="pk-personal"> <div class="pk-personal">
<span class="pk-name">{{ item.disPlayId }}</span> <span class="pk-name">{{ item.disPlayId }}</span>
<span class="pk-gender" :class="item.sex === 1 ? 'male' : 'female'"> <span class="pk-gender" :class="item.sex === '1' ? 'male' : 'female'">
{{ item.sex === 1 ? '男' : '女' }} {{ item.sex === '1' ? '男' : '女' }}
</span> </span>
<span class="pk-country">{{ item.country }}</span> <span class="pk-country">{{ item.country }}</span>
</div> </div>
@@ -89,6 +89,14 @@
</div> </div>
<div v-if="pkList.length === 0" class="empty-tip">暂无数据</div> <div v-if="pkList.length === 0" class="empty-tip">暂无数据</div>
<!-- 加载状态提示 -->
<div v-if="loading" class="loading-tip">
<span class="loading-spinner"></span>
<span>加载中...</span>
</div>
<div v-else-if="noMore && pkList.length > 0" class="no-more-tip">
已加载全部数据
</div>
</div> </div>
</div> </div>
@@ -152,8 +160,8 @@
<div class="anchor-info"> <div class="anchor-info">
<div class="anchor-name">{{ anchor.anchorId }}</div> <div class="anchor-name">{{ anchor.anchorId }}</div>
<div class="anchor-detail"> <div class="anchor-detail">
<span class="anchor-gender" :class="anchor.sex === 1 ? 'male' : 'female'"> <span class="anchor-gender" :class="anchor.sex === '1' ? 'male' : 'female'">
{{ anchor.sex === 1 ? '男' : '女' }} {{ anchor.sex === '1' ? '男' : '女' }}
</span> </span>
<span class="anchor-coin">{{ anchor.coin }}K</span> <span class="anchor-coin">{{ anchor.coin }}K</span>
</div> </div>
@@ -249,11 +257,20 @@ const formatTime = TimestamptolocalTime
function switchMode() { function switchMode() {
isHallMode.value = !isHallMode.value isHallMode.value = !isHallMode.value
selectedItem.value = null selectedItem.value = null
// 重置分页和加载状态
page.value = 0
loading.value = false
noMore.value = false
// 清空当前模式的数据
if (isHallMode.value) { if (isHallMode.value) {
hallList.value = []
pkList.value = hallList.value pkList.value = hallList.value
} else { } else {
todayList.value = []
pkList.value = todayList.value pkList.value = todayList.value
} }
// 重新加载数据
loadPkList()
} }
// 搜索 // 搜索
@@ -281,6 +298,7 @@ function handleReset() {
// 加载更多 // 加载更多
function loadMore() { function loadMore() {
console.log('[PkHall] loadMore 被调用')
loadPkList() loadPkList()
} }
@@ -341,9 +359,27 @@ async function loadPkList() {
} }
} catch (e) { } catch (e) {
console.error('加载 PK 列表失败', e) console.error('加载 PK 列表失败', e)
noMore.value = true ElMessage.error('加载失败,请稍后重试')
} finally { } finally {
loading.value = false loading.value = false
// 数据加载完成后,使用 nextTick 强制重新计算滚动位置
nextTick(() => {
const pkListEl = document.querySelector('.pk-list')
if (pkListEl) {
// 触发一次滚动事件,确保无限滚动指令能够正确检测滚动位置
pkListEl.dispatchEvent(new Event('scroll'))
// 手动检查是否已经滚动到底部,如果是,则直接调用 loadMore
const { scrollTop, scrollHeight, clientHeight } = pkListEl
const isAtBottom = scrollTop + clientHeight >= scrollHeight - 10
if (isAtBottom && !loading.value && !noMore.value) {
console.log('[PkHall] 检测到已滚动到底部,手动调用 loadMore')
setTimeout(() => {
loadMore()
}, 100)
}
}
})
} }
} }
@@ -546,7 +582,7 @@ async function confirmInvite() {
} }
} }
onMounted(() => { onMounted(async () => {
countryOptions.value = getCountryNamesArray() countryOptions.value = getCountryNamesArray()
currentUser.value = getMainUserData() || {} currentUser.value = getMainUserData() || {}
const userId = getUserId(currentUser.value) const userId = getUserId(currentUser.value)
@@ -556,7 +592,27 @@ onMounted(() => {
// 初始加载 PK 大厅数据(通过 loadPkList 统一管理 page/loading/noMore 状态) // 初始加载 PK 大厅数据(通过 loadPkList 统一管理 page/loading/noMore 状态)
if (userId) { if (userId) {
loadPkList() await loadPkList()
// 延迟一段时间,确保无限滚动指令已经完全初始化
setTimeout(() => {
const pkListEl = document.querySelector('.pk-list')
if (pkListEl) {
const { scrollTop, scrollHeight, clientHeight } = pkListEl
console.log('[PkHall] pk-list 元素信息:', {
scrollTop,
scrollHeight,
clientHeight,
isAtBottom: scrollTop + clientHeight >= scrollHeight - 10
})
// 手动滚动到底部,然后触发滚动事件
pkListEl.scrollTop = scrollHeight - clientHeight
setTimeout(() => {
pkListEl.dispatchEvent(new Event('scroll'))
console.log('[PkHall] 手动滚动到底部并触发滚动事件')
}, 100)
}
}, 500)
} else { } else {
console.warn('[PkHall] 未找到用户 ID无法加载数据') console.warn('[PkHall] 未找到用户 ID无法加载数据')
} }
@@ -860,6 +916,43 @@ onUnmounted(() => {
font-size: 16px; font-size: 16px;
} }
// 加载状态提示
.loading-tip {
display: flex;
align-items: center;
justify-content: center;
gap: 10px;
padding: 20px;
color: #2563eb; // blue-600
font-size: 14px;
}
.loading-spinner {
width: 16px;
height: 16px;
border: 2px solid #e2e8f0;
border-top: 2px solid #2563eb;
border-radius: 50%;
animation: spin 1s linear infinite;
}
@keyframes spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
.no-more-tip {
text-align: center;
padding: 20px;
color: #94a3b8; // slate-400
font-size: 14px;
}
// 聊天面板 // 聊天面板
.chat-panel { .chat-panel {
width: 350px; width: 350px;