国际化

This commit is contained in:
pengxiaolong
2025-12-02 21:23:21 +08:00
parent 84bab8b8c8
commit 812fade238
15 changed files with 1589 additions and 484 deletions

Binary file not shown.

93
package-lock.json generated
View File

@@ -15,6 +15,7 @@
"pinia": "^3.0.3",
"qwebchannel": "^6.2.0",
"vue": "^3.2.13",
"vue-i18n": "^9.14.5",
"vue-router": "^4.0.3",
"vuex": "^4.0.0"
},
@@ -91,6 +92,7 @@
"integrity": "sha512-vMqyb7XCDMPvJFFOaT9kxtiRh42GwlZEg1/uIgtZshS5a/8OaduUfCi7kynKgc3Tw/6Uo2D+db9qBttghhmxwQ==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@ampproject/remapping": "^2.2.0",
"@babel/code-frame": "^7.26.2",
@@ -1767,6 +1769,7 @@
}
],
"license": "MIT",
"peer": true,
"engines": {
"node": ">=18"
},
@@ -1790,6 +1793,7 @@
}
],
"license": "MIT",
"peer": true,
"engines": {
"node": ">=18"
}
@@ -1874,6 +1878,7 @@
"integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"cssesc": "^3.0.0",
"util-deprecate": "^1.0.2"
@@ -2221,6 +2226,7 @@
"integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"cssesc": "^3.0.0",
"util-deprecate": "^1.0.2"
@@ -2871,6 +2877,50 @@
"@hapi/hoek": "^9.0.0"
}
},
"node_modules/@intlify/core-base": {
"version": "9.14.5",
"resolved": "https://registry.npmjs.org/@intlify/core-base/-/core-base-9.14.5.tgz",
"integrity": "sha512-5ah5FqZG4pOoHjkvs8mjtv+gPKYU0zCISaYNjBNNqYiaITxW8ZtVih3GS/oTOqN8d9/mDLyrjD46GBApNxmlsA==",
"license": "MIT",
"dependencies": {
"@intlify/message-compiler": "9.14.5",
"@intlify/shared": "9.14.5"
},
"engines": {
"node": ">= 16"
},
"funding": {
"url": "https://github.com/sponsors/kazupon"
}
},
"node_modules/@intlify/message-compiler": {
"version": "9.14.5",
"resolved": "https://registry.npmjs.org/@intlify/message-compiler/-/message-compiler-9.14.5.tgz",
"integrity": "sha512-IHzgEu61/YIpQV5Pc3aRWScDcnFKWvQA9kigcINcCBXN8mbW+vk9SK+lDxA6STzKQsVJxUPg9ACC52pKKo3SVQ==",
"license": "MIT",
"dependencies": {
"@intlify/shared": "9.14.5",
"source-map-js": "^1.0.2"
},
"engines": {
"node": ">= 16"
},
"funding": {
"url": "https://github.com/sponsors/kazupon"
}
},
"node_modules/@intlify/shared": {
"version": "9.14.5",
"resolved": "https://registry.npmjs.org/@intlify/shared/-/shared-9.14.5.tgz",
"integrity": "sha512-9gB+E53BYuAEMhbCAxVgG38EZrk59sxBtv3jSizNL2hEWlgjBjAw1AwpLHtNaeda12pe6W20OGEa0TwuMSRbyQ==",
"license": "MIT",
"engines": {
"node": ">= 16"
},
"funding": {
"url": "https://github.com/sponsors/kazupon"
}
},
"node_modules/@jridgewell/gen-mapping": {
"version": "0.3.8",
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz",
@@ -3222,6 +3272,7 @@
"resolved": "https://registry.npmjs.org/@types/lodash-es/-/lodash-es-4.17.12.tgz",
"integrity": "sha512-0NgftHUcV4v34VhXm8QBSftKVXtbkBG3ViCjs6+eJ5a6y6Mi/jiFGPc1sC7QK+9BFhWrURE3EOggmWaSxL9OzQ==",
"license": "MIT",
"peer": true,
"dependencies": {
"@types/lodash": "*"
}
@@ -3648,6 +3699,7 @@
"integrity": "sha512-nV7tYQLe7YsTtzFrfOMIHc5N2hp5lHG2rpYr0aNja9rNljdgcPZLyQRb2YRivTHqTv7lI962UXFURcpStHgyFw==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@babel/helper-compilation-targets": "^7.12.16",
"@soda/friendly-errors-webpack-plugin": "^1.8.0",
@@ -4386,6 +4438,7 @@
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"fast-deep-equal": "^3.1.1",
"fast-json-stable-stringify": "^2.0.0",
@@ -4912,6 +4965,7 @@
}
],
"license": "MIT",
"peer": true,
"dependencies": {
"caniuse-lite": "^1.0.30001688",
"electron-to-chromium": "^1.5.73",
@@ -5718,6 +5772,7 @@
"integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"cssesc": "^3.0.0",
"util-deprecate": "^1.0.2"
@@ -5732,6 +5787,7 @@
"integrity": "sha512-CTJ+AEQJjq5NzLga5pE39qdiSV56F8ywCIsqNIRF0r7BDgWsN25aazToqAFg7ZrtA/U016xudB3ffgweORxX7g==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"icss-utils": "^5.1.0",
"postcss": "^8.4.33",
@@ -5820,6 +5876,7 @@
"integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"fast-deep-equal": "^3.1.3",
"fast-uri": "^3.0.1",
@@ -8467,13 +8524,15 @@
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
"license": "MIT"
"license": "MIT",
"peer": true
},
"node_modules/lodash-es": {
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz",
"integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==",
"license": "MIT"
"license": "MIT",
"peer": true
},
"node_modules/lodash-unified": {
"version": "1.0.3",
@@ -8910,6 +8969,7 @@
"integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"fast-deep-equal": "^3.1.3",
"fast-uri": "^3.0.1",
@@ -9784,6 +9844,7 @@
}
],
"license": "MIT",
"peer": true,
"dependencies": {
"nanoid": "^3.3.8",
"picocolors": "^1.1.1",
@@ -10712,6 +10773,7 @@
"integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"cssesc": "^3.0.0",
"util-deprecate": "^1.0.2"
@@ -12880,6 +12942,7 @@
"integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"fast-deep-equal": "^3.1.3",
"fast-uri": "^3.0.1",
@@ -13269,6 +13332,7 @@
"resolved": "https://registry.npmjs.org/vue/-/vue-3.5.13.tgz",
"integrity": "sha512-wmeiSMxkZCSc+PM2w2VRsOYAZC8GdipNFRTsLSfodVqI9mbejKeXEGr8SckuLnrQPGe3oJN5c3K0vpoU9q/wCQ==",
"license": "MIT",
"peer": true,
"dependencies": {
"@vue/compiler-dom": "3.5.13",
"@vue/compiler-sfc": "3.5.13",
@@ -13292,6 +13356,26 @@
"dev": true,
"license": "MIT"
},
"node_modules/vue-i18n": {
"version": "9.14.5",
"resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-9.14.5.tgz",
"integrity": "sha512-0jQ9Em3ymWngyiIkj0+c/k7WgaPO+TNzjKSNq9BvBQaKJECqn9cd9fL4tkDhB5G1QBskGl9YxxbDAhgbFtpe2g==",
"license": "MIT",
"dependencies": {
"@intlify/core-base": "9.14.5",
"@intlify/shared": "9.14.5",
"@vue/devtools-api": "^6.5.0"
},
"engines": {
"node": ">= 16"
},
"funding": {
"url": "https://github.com/sponsors/kazupon"
},
"peerDependencies": {
"vue": "^3.0.0"
}
},
"node_modules/vue-loader": {
"version": "17.4.2",
"resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-17.4.2.tgz",
@@ -13431,6 +13515,7 @@
"integrity": "sha512-UFynvx+gM44Gv9qFgj0acCQK2VE1CtdfwFdimkapco3hlPCJ/zeq73n2yVKimVbtm+TnApIugGhLJnkU6gjYXA==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@types/eslint-scope": "^3.7.7",
"@types/estree": "^1.0.6",
@@ -13567,6 +13652,7 @@
"integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"fast-deep-equal": "^3.1.3",
"fast-uri": "^3.0.1",
@@ -13684,6 +13770,7 @@
"integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"fast-deep-equal": "^3.1.3",
"fast-uri": "^3.0.1",
@@ -13778,6 +13865,7 @@
"integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==",
"dev": true,
"license": "MIT",
"peer": true,
"engines": {
"node": ">=10.13.0"
}
@@ -13795,6 +13883,7 @@
"integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"fast-deep-equal": "^3.1.3",
"fast-uri": "^3.0.1",

View File

@@ -14,6 +14,7 @@
"pinia": "^3.0.3",
"qwebchannel": "^6.2.0",
"vue": "^3.2.13",
"vue-i18n": "^9.14.5",
"vue-router": "^4.0.3",
"vuex": "^4.0.0"
},

View File

@@ -18,14 +18,16 @@ export function tkaccountuseinfo(accountName) {
return getAxios({ url: `/api/common/accountCount?accountName=${accountName}` })
}
export function tokenVerification() {
return getAxios({ url: `/api/common/health` })
}
export function tkhostdata(data) {
return postAxios({ url: '/api/big-brother/page', data })
}
export function apiGetCart() {
return getAxios({ url: '/cgi-bin/cart/latest' })
}

BIN
src/assets/wifi.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

26
src/i18n/index.js Normal file
View File

@@ -0,0 +1,26 @@
import { createI18n } from 'vue-i18n'
import zhCn from 'element-plus/dist/locale/zh-cn.mjs'
import en from 'element-plus/dist/locale/en.mjs'
// 导入语言文件
import zh from './lang/zh-CN'
import enLang from './lang/en-US'
// 创建 i18n 实例
const i18n = createI18n({
legacy: false, // 使用 Composition API
locale: localStorage.getItem('language') || 'zh-CN', // 默认语言
fallbackLocale: 'zh-CN', // 备用语言
messages: {
'zh-CN': zh,
'en-US': enLang
}
})
// Element Plus 语言配置
export const elementPlusLocale = {
'zh-CN': zhCn,
'en-US': en
}
export default i18n

354
src/i18n/lang/en-US.js Normal file
View File

@@ -0,0 +1,354 @@
export default {
common: {
networkSettings: 'Network Settings',
language: 'Language',
simplifiedChinese: 'Simplified Chinese',
english: 'English',
accountLogin: 'Account Login',
tenantName: 'Tenant Name',
account: 'Account',
password: 'Password',
login: 'Login',
version: 'Version',
expirationtime: 'Expiration Time',
},
hostsList: {
// 顶部筛选
filterPrivateUsers: 'Filter Private Users',
minCoins: 'Min Coins',
maxCoins: 'Max Coins',
minLevel: 'Min Level',
maxLevel: 'Max Level',
specifiedRooms: 'Specified Rooms',
specifyRooms: 'Specify Rooms',
total: 'Total',
valid: 'Valid',
reset: 'Reset',
start: 'Start',
end: 'End',
// 第二行筛选
selectCountry: 'Select Country',
bigBrotherId: 'Big Brother ID',
search: 'Search',
exportExcel: 'Export Excel Data',
moreFilters: 'More Filters',
openTikTok: 'Open TikTok Login',
currentNetwork: 'Current Network',
runningTime: 'Running Time',
// 表格列
id: 'Id',
hostId: 'Host ID',
userId: 'User ID',
level: 'Level',
fansLevel: 'Fan Club Level',
coins: 'Coins',
totalGiftCoins: 'Total Gift Coins',
region: 'Region',
followerCount: 'Followers',
followingCount: 'Following',
createTime: 'Created Time',
// 更多筛选弹窗
time: 'Time',
startTime: 'Start Time',
endTime: 'End Time',
selectTime: 'Select Query Time',
minValue: 'Min Value',
maxValue: 'Max Value',
enterMinValue: 'Enter Min Value',
enterMaxValue: 'Enter Max Value',
sort: 'Sort',
sortType: 'Sort Type',
sortOrder: 'Ascending/Descending',
pleaseSelect: 'Please Select',
ascending: 'Ascending',
descending: 'Descending',
confirm: 'Confirm',
cancel: 'Cancel',
// 指定直播间弹窗
cancelSpecify: 'Cancel Specify Rooms',
specifyReset: 'Reset',
specifyConfirm: 'Confirm',
specifyStart: 'Start',
enterRoomIds: 'Enter room IDs, separate multiple IDs with Enter key',
enterRoomId: 'Please enter room ID',
// 网络问题弹窗
networkFailed:
'Network connection failed, unable to access the network. Please check network settings.',
// 复制提示
noContentToCopy: 'No content to copy',
copySuccess: 'Copied successfully',
copyFailed: 'Copy failed',
// 任务状态 loading
stopping: 'Stopping...',
starting: 'Starting...',
// 获取国家失败弹窗
pleaseEnterCountryName: 'Please enter the country name in Chinese',
getCountryFailed: 'Failed to get country',
},
// ==== 新增:国家名称国际化 ====
countries: {
AD: "Andorra",
AE: "United Arab Emirates",
AF: "Afghanistan",
AG: "Antigua and Barbuda",
AI: "Anguilla",
AL: "Albania",
AM: "Armenia",
AO: "Angola",
AQ: "Antarctica",
AR: "Argentina",
AS: "American Samoa",
AT: "Austria",
AU: "Australia",
AU1: "Australia",
AW: "Aruba",
AX: "Åland Islands",
AZ: "Azerbaijan",
BA: "Bosnia and Herzegovina",
BB: "Barbados",
BD: "Bangladesh",
BE: "Belgium",
BF: "Burkina Faso",
BG: "Bulgaria",
BH: "Bahrain",
BI: "Burundi",
BJ: "Benin",
BL: "Saint Barthélemy",
BM: "Bermuda",
BN: "Brunei Darussalam",
BO: "Bolivia",
BQ: "Bonaire, Sint Eustatius and Saba",
BR: "Brazil",
BS: "Bahamas",
BT: "Bhutan",
BV: "Bouvet Island",
BW: "Botswana",
BY: "Belarus",
BZ: "Belize",
CA: "Canada",
CA1: "Canada",
CC: "Cocos (Keeling) Islands",
CD: "Democratic Republic of the Congo",
CF: "Central African Republic",
CG: "Republic of the Congo",
CH: "Switzerland",
CI: "Côte d'Ivoire",
CK: "Cook Islands",
CL: "Chile",
CM: "Cameroon",
CN: "China",
CO: "Colombia",
CR: "Costa Rica",
CU: "Cuba",
CV: "Cape Verde",
CW: "Curaçao",
CX: "Christmas Island",
CY: "Cyprus",
CZ: "Czech Republic",
DE: "Germany",
DG: "Diego Garcia",
DJ: "Djibouti",
DK: "Denmark",
DM: "Dominica",
DO: "Dominican Republic",
DZ: "Algeria",
EC: "Ecuador",
EE: "Estonia",
EG: "Egypt",
EH: "Western Sahara",
ER: "Eritrea",
ES: "Spain",
ET: "Ethiopia",
FI: "Finland",
FJ: "Fiji",
FK: "Falkland Islands",
FM: "Micronesia",
FO: "Faroe Islands",
FR: "France",
GA: "Gabon",
GB: "United Kingdom",
GD: "Grenada",
GE: "Georgia",
GF: "French Guiana",
GG: "Guernsey",
GH: "Ghana",
GI: "Gibraltar",
GL: "Greenland",
GM: "Gambia",
GN: "Guinea",
GP: "Guadeloupe",
GQ: "Equatorial Guinea",
GR: "Greece",
GS: "South Georgia and the South Sandwich Islands",
GT: "Guatemala",
GU: "Guam",
GW: "Guinea-Bissau",
GY: "Guyana",
HK: "Hong Kong SAR China",
HM: "Heard Island and McDonald Islands",
HN: "Honduras",
HR: "Croatia",
HT: "Haiti",
HU: "Hungary",
ID: "Indonesia",
IE: "Ireland",
IL: "Israel",
IM: "Isle of Man",
IN: "India",
IO: "British Indian Ocean Territory",
IQ: "Iraq",
IR: "Iran",
IS: "Iceland",
IT: "Italy",
JE: "Jersey",
JM: "Jamaica",
JO: "Jordan",
JP: "Japan",
JP1: "Japan",
KE: "Kenya",
KG: "Kyrgyzstan",
KH: "Cambodia",
KI: "Kiribati",
KM: "Comoros",
KN: "Saint Kitts and Nevis",
KP: "North Korea",
KR: "South Korea",
KR1: "South Korea",
KR1_UXWAUDIT: "South Korea",
KW: "Kuwait",
KY: "Cayman Islands",
KZ: "Kazakhstan",
LA: "Laos",
LB: "Lebanon",
LC: "Saint Lucia",
LI: "Liechtenstein",
LK: "Sri Lanka",
LR: "Liberia",
LS: "Lesotho",
LT: "Lithuania",
LU: "Luxembourg",
LV: "Latvia",
LY: "Libya",
MA: "Morocco",
MC: "Monaco",
MD: "Moldova",
ME: "Montenegro",
MF: "Saint Martin",
MG: "Madagascar",
MH: "Marshall Islands",
MK: "North Macedonia",
ML: "Mali",
MM: "Myanmar",
MN: "Mongolia",
MO: "Macao SAR China",
MP: "Northern Mariana Islands",
MQ: "Martinique",
MR: "Mauritania",
MS: "Montserrat",
MT: "Malta",
MU: "Mauritius",
MV: "Maldives",
MW: "Malawi",
MX: "Mexico",
MY: "Malaysia",
MZ: "Mozambique",
NA: "Namibia",
NC: "New Caledonia",
NE: "Niger",
NF: "Norfolk Island",
NG: "Nigeria",
NI: "Nicaragua",
NL: "Netherlands",
NO: "Norway",
NP: "Nepal",
NR: "Nauru",
NU: "Niue",
NZ: "New Zealand",
OM: "Oman",
PA: "Panama",
PE: "Peru",
PF: "French Polynesia",
PG: "Papua New Guinea",
PH: "Philippines",
PK: "Pakistan",
PL: "Poland",
PM: "Saint Pierre and Miquelon",
PN: "Pitcairn Islands",
PR: "Puerto Rico",
PS: "Palestine",
PT: "Portugal",
PW: "Palau",
PY: "Paraguay",
QA: "Qatar",
RE: "Réunion",
RO: "Romania",
RS: "Serbia",
RU: "Russia",
RW: "Rwanda",
SA: "Saudi Arabia",
SB: "Solomon Islands",
SC: "Seychelles",
SD: "Sudan",
SE: "Sweden",
SG: "Singapore",
SI: "Slovenia",
SJ: "Svalbard and Jan Mayen",
SK: "Slovakia",
SL: "Sierra Leone",
SM: "San Marino",
SN: "Senegal",
SO: "Somalia",
SR: "Suriname",
SS: "South Sudan",
ST: "Sao Tome and Principe",
SV: "El Salvador",
SX: "Sint Maarten",
SY: "Syria",
SZ: "Eswatini",
TC: "Turks and Caicos Islands",
TD: "Chad",
TF: "French Southern Territories",
TG: "Togo",
TH: "Thailand",
TJ: "Tajikistan",
TK: "Tokelau",
TL: "Timor-Leste",
TM: "Turkmenistan",
TN: "Tunisia",
TO: "Tonga",
TR: "Turkey",
TT: "Trinidad and Tobago",
TV: "Tuvalu",
TW: "Taiwan",
TZ: "Tanzania",
UA: "Ukraine",
UG: "Uganda",
UM: "United States Minor Outlying Islands",
US: "United States",
UY: "Uruguay",
UZ: "Uzbekistan",
VA: "Vatican City",
VC: "Saint Vincent and the Grenadines",
VE: "Venezuela",
VG: "British Virgin Islands",
VI: "U.S. Virgin Islands",
VN: "Vietnam",
VN1: "Vietnam",
VU: "Vanuatu",
WS: "Samoa",
YE: "Yemen",
YT: "Mayotte",
ZA: "South Africa",
ZM: "Zambia",
ZW: "Zimbabwe"
}
}

347
src/i18n/lang/zh-CN.js Normal file
View File

@@ -0,0 +1,347 @@
export default {
common: {
networkSettings: '网络设置',
language: '语言',
simplifiedChinese: '简体中文',
english: 'English',
accountLogin: '账号登录',
tenantName: '租户名称',
account: '账号',
password: '密码',
login: '登录',
version: '版本号',
expirationtime: '过期时间',
},
hostsList: {
filterPrivateUsers: '过滤隐私用户',
minCoins: '最小金币',
maxCoins: '最大金币',
minLevel: '最小等级',
maxLevel: '最大等级',
specifiedRooms: '已指定直播间',
specifyRooms: '指定直播间',
total: '总数',
valid: '有效数',
reset: '重置',
start: '开始',
end: '结束',
selectCountry: '选择国家',
bigBrotherId: '大哥id',
search: '查询',
exportExcel: '导出Excel数据',
moreFilters: '更多筛选',
openTikTok: '打开 TikTok 登录',
currentNetwork: '当前网络',
runningTime: '运行时间',
id: 'Id',
hostId: '所在直播间主播id',
time: '时间',
startTime: '开始时间',
endTime: '结束时间',
selectTime: '选择查询时间',
minValue: '最小值',
maxValue: '最大值',
enterMinValue: '请输入最小值',
enterMaxValue: '请输入最大值',
sort: '排序',
sortType: '排序类型',
sortOrder: '升序/降序',
pleaseSelect: '请选择',
ascending: '升序',
descending: '降序',
confirm: '确认',
cancel: '取消',
cancelSpecify: '取消指定直播间',
specifyReset: '重置',
specifyConfirm: '确认',
specifyStart: '开始',
networkFailed: '网络连接失败,无法访问网络,请查看网络设置。',
enterRoomIds: '请输入直播间id多个id用回车键隔开',
// ==== 新增:表格列、排序使用 ====
userId: '用户id',
level: '等级',
fansLevel: '粉丝团等级',
coins: '打赏的金币',
totalGiftCoins: '打赏金币总和',
region: '地区',
followerCount: '粉丝数',
followingCount: '关注数',
createTime: '创建时间',
// ==== 新增:复制提示 ====
noContentToCopy: '无内容可复制',
copySuccess: '复制成功',
copyFailed: '复制失败',
// ==== 新增:获取国家失败弹窗 ====
pleaseEnterCountryName: '请输入要获取的国家',
getCountryFailed: '获取国家失败',
// ==== 新增loading 提示 ====
stopping: '正在停止...',
starting: '正在启动...',
// ==== 新增单个直播间id校验提示 ====
enterRoomId: '请输入直播间id',
},
// ==== 新增:国家名称国际化 ====
countries: {
AD: "安道尔",
AE: "阿拉伯联合酋长国",
AF: "阿富汗",
AG: "安提瓜和巴布达",
AI: "安圭拉",
AL: "阿尔巴尼亚",
AM: "亚美尼亚",
AO: "安哥拉",
AQ: "南极洲",
AR: "阿根廷",
AS: "美属萨摩亚",
AT: "奥地利",
AU: "澳大利亚",
AU1: "澳大利亚",
AW: "阿鲁巴",
AX: "奥兰群岛",
AZ: "阿塞拜疆",
BA: "波斯尼亚和黑塞哥维那",
BB: "巴巴多斯",
BD: "孟加拉国",
BE: "比利时",
BF: "布基纳法索",
BG: "保加利亚",
BH: "巴林",
BI: "布隆迪",
BJ: "贝宁",
BL: "圣巴泰勒米",
BM: "百慕大群岛",
BN: "文莱达鲁萨兰国",
BO: "玻利维亚",
BQ: "博奈尔、圣尤斯特歇斯和萨巴",
BR: "巴西",
BS: "巴哈马",
BT: "不丹",
BV: "布韦岛",
BW: "博茨瓦纳",
BY: "白俄罗斯",
BZ: "伯利兹",
CA: "加拿大",
CA1: "加拿大",
CC: "科科斯(基林)群岛",
CD: "刚果民主共和国",
CF: "中非共和国",
CG: "刚果共和国",
CH: "瑞士",
CI: "科特迪瓦",
CK: "库克群岛",
CL: "智利",
CM: "喀麦隆",
CN: "中国",
CO: "哥伦比亚",
CR: "哥斯达黎加",
CU: "古巴",
CV: "佛得角",
CW: "库拉索",
CX: "圣诞岛",
CY: "塞浦路斯",
CZ: "捷克共和国",
DE: "德国",
DG: "迪戈加西亚岛",
DJ: "吉布提",
DK: "丹麦",
DM: "多米尼克",
DO: "多米尼加共和国",
DZ: "阿尔及利亚",
EC: "厄瓜多尔",
EE: "爱沙尼亚",
EG: "埃及",
EH: "西撒哈拉",
ER: "厄立特里亚",
ES: "西班牙",
ET: "埃塞俄比亚",
FI: "芬兰",
FJ: "斐济",
FK: "福克兰群岛",
FM: "密克罗尼西亚",
FO: "法罗群岛",
FR: "法国",
GA: "加蓬",
GB: "英国",
GD: "格林纳达",
GE: "格鲁吉亚",
GF: "法属圭亚那",
GG: "根西岛",
GH: "加纳",
GI: "直布罗陀",
GL: "格陵兰",
GM: "冈比亚",
GN: "几内亚",
GP: "瓜德罗普",
GQ: "赤道几内亚",
GR: "希腊",
GS: "南乔治亚和南桑德威奇群岛",
GT: "危地马拉",
GU: "关岛",
GW: "几内亚比绍",
GY: "圭亚那",
HK: "中国香港特别行政区",
HM: "赫德岛和麦克唐纳群岛",
HN: "洪都拉斯",
HR: "克罗地亚",
HT: "海地",
HU: "匈牙利",
ID: "印度尼西亚",
IE: "爱尔兰",
IL: "以色列",
IM: "马恩岛",
IN: "印度",
IO: "英属印度洋领地",
IQ: "伊拉克",
IR: "伊朗",
IS: "冰岛",
IT: "意大利",
JE: "泽西岛",
JM: "牙买加",
JO: "约旦",
JP: "日本",
JP1: "日本",
KE: "肯尼亚",
KG: "吉尔吉斯斯坦",
KH: "柬埔寨",
KI: "基里巴斯",
KM: "科摩罗",
KN: "圣基茨和尼维斯",
KP: "朝鲜",
KR: "韩国",
KR1: "韩国",
KR1_UXWAUDIT: "韩国",
KW: "科威特",
KY: "开曼群岛",
KZ: "哈萨克斯坦",
LA: "老挝",
LB: "黎巴嫩",
LC: "圣卢西亚",
LI: "列支敦士登",
LK: "斯里兰卡",
LR: "利比里亚",
LS: "莱索托",
LT: "立陶宛",
LU: "卢森堡",
LV: "拉脱维亚",
LY: "利比亚",
MA: "摩洛哥",
MC: "摩纳哥",
MD: "摩尔多瓦",
ME: "黑山",
MF: "圣马丁",
MG: "马达加斯加",
MH: "马绍尔群岛",
MK: "北马其顿",
ML: "马里",
MM: "缅甸",
MN: "蒙古",
MO: "中国澳门特别行政区",
MP: "北马里亚纳群岛",
MQ: "马提尼克",
MR: "毛里塔尼亚",
MS: "蒙特塞拉特",
MT: "马耳他",
MU: "毛里求斯",
MV: "马尔代夫",
MW: "马拉维",
MX: "墨西哥",
MY: "马来西亚",
MZ: "莫桑比克",
NA: "纳米比亚",
NC: "新喀里多尼亚",
NE: "尼日尔",
NF: "诺福克岛",
NG: "尼日利亚",
NI: "尼加拉瓜",
NL: "荷兰",
NO: "挪威",
NP: "尼泊尔",
NR: "瑙鲁",
NU: "纽埃",
NZ: "新西兰",
OM: "阿曼",
PA: "巴拿马",
PE: "秘鲁",
PF: "法属玻利尼西亚",
PG: "巴布亚新几内亚",
PH: "菲律宾",
PK: "巴基斯坦",
PL: "波兰",
PM: "圣皮埃尔和密克隆群岛",
PN: "皮特凯恩群岛",
PR: "波多黎各",
PS: "巴勒斯坦",
PT: "葡萄牙",
PW: "帕劳",
PY: "巴拉圭",
QA: "卡塔尔",
RE: "留尼汪",
RO: "罗马尼亚",
RS: "塞尔维亚",
RU: "俄罗斯",
RW: "卢旺达",
SA: "沙特阿拉伯",
SB: "索罗门群岛",
SC: "塞舌尔",
SD: "苏丹",
SE: "瑞典",
SG: "新加坡",
SI: "斯洛文尼亚",
SJ: "斯瓦尔巴和扬马延",
SK: "斯洛伐克",
SL: "塞拉利昂",
SM: "圣马利诺",
SN: "塞内加尔",
SO: "索马里",
SR: "苏里南",
SS: "南苏丹",
ST: "圣多美和普林西比",
SV: "萨尔瓦多",
SX: "荷属圣马丁",
SY: "叙利亚",
SZ: "斯威士兰",
TC: "特克斯和凯科斯群岛",
TD: "乍得",
TF: "法属南部领地",
TG: "多哥",
TH: "泰国",
TJ: "塔吉克斯坦",
TK: "托克劳群岛",
TL: "东帝汶",
TM: "土库曼斯坦",
TN: "突尼斯",
TO: "汤加",
TR: "土耳其",
TT: "特立尼达和多巴哥",
TV: "图瓦卢",
TW: "台湾",
TZ: "坦桑尼亚",
UA: "乌克兰",
UG: "乌干达",
UM: "美国本土外小岛屿",
US: "美国",
UY: "乌拉圭",
UZ: "乌兹别克斯坦",
VA: "梵蒂冈",
VC: "圣文森特",
VE: "委内瑞拉",
VG: "英属维尔京群岛",
VI: "美属维尔京群岛",
VN: "越南",
VN1: "越南",
VU: "瓦努阿图",
WS: "萨摩亚",
YE: "也门",
YT: "马约特岛",
ZA: "南非",
ZM: "赞比亚",
ZW: "津巴布韦"
}
}

View File

@@ -5,14 +5,18 @@ import store from './store'
import { createPinia } from 'pinia';
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import zhCn from 'element-plus/dist/locale/zh-cn.mjs'; // 引入中文语言包
import i18n, { elementPlusLocale } from './i18n'
const app = createApp(App);
// 获取当前语言
const currentLocale = localStorage.getItem('language') || 'zh-CN'
app.use(ElementPlus, {
locale: zhCn, // 配置中文
locale: elementPlusLocale[currentLocale] // 动态配置Element Plus语言
});
app.use(ElementPlus) // 注册 ElementPlus
app.use(i18n); // 注册 i18n
app.use(createPinia()); // 注册 Pinia
app.use(store); // 注册 store
app.use(router); // 注册 router

View File

@@ -22,16 +22,16 @@ const { stopScript } = usePythonBridge();
let baseURL = ''
if (process.env.NODE_ENV === 'development') {
// 生产环境
// baseURL = "https://api.tkpage.yolozs.com"
baseURL = "http://47.79.98.113:8101"
baseURL = "https://crawlclient.api.yolozs.com"
// baseURL = "http://47.79.98.113:8101"
// baseURL = "http://192.168.0.103:8085/"
// baseURL = "http://192.168.1.144:8101"
} else {
// 测试环境
// baseURL = "http://120.26.251.180:8085/"
// 开发环境
// baseURL = "https://api.tkpage.yolozs.com"
baseURL = "http://47.79.98.113:8101"
baseURL = "https://crawlclient.api.yolozs.com"
// baseURL = "http://47.79.98.113:8101"
// baseURL = "http://192.168.1.144:8101"
// baseURL = "http://api.tkpage.vvtiktok.cn"
}

View File

@@ -1,261 +1,270 @@
// country-utils.js
import i18n from '../i18n'
// 国家代码枚举(只包含代码,不包含名称)
export const CountryCode = {
AD: "安道尔",
AE: "阿拉伯联合酋长国",
AF: "阿富汗",
AG: "安提瓜和巴布达",
AI: "安圭拉",
AL: "阿尔巴尼亚",
AM: "亚美尼亚",
AO: "安哥拉",
AQ: "南极洲",
AR: "阿根廷",
AS: "美属萨摩亚",
AT: "奥地利",
AU: "澳大利亚",
AU1: "澳大利亚",
AW: "阿鲁巴",
AX: "奥兰群岛",
AZ: "阿塞拜疆",
BA: "波斯尼亚和黑塞哥维那",
BB: "巴巴多斯",
BD: "孟加拉国",
BE: "比利时",
BF: "布基纳法索",
BG: "保加利亚",
BH: "巴林",
BI: "布隆迪",
BJ: "贝宁",
BL: "圣巴泰勒米",
BM: "百慕大群岛",
BN: "文莱达鲁萨兰国",
BO: "玻利维亚",
BQ: "博奈尔、圣尤斯特歇斯和萨巴",
BR: "巴西",
BS: "巴哈马",
BT: "不丹",
BV: "布韦岛",
BW: "博茨瓦纳",
BY: "白俄罗斯",
BZ: "伯利兹",
CA: "加拿大",
CA1: "加拿大",
CC: "科科斯(基林)群岛",
CD: "刚果民主共和国",
CF: "中非共和国",
CG: "刚果共和国",
CH: "瑞士",
CI: "科特迪瓦",
CK: "库克群岛",
CL: "智利",
CM: "喀麦隆",
CN: "中国",
CO: "哥伦比亚",
CR: "哥斯达黎加",
CU: "古巴",
CV: "佛得角",
CW: "库拉索",
CX: "圣诞岛",
CY: "塞浦路斯",
CZ: "捷克共和国",
DE: "德国",
DG: "迪戈加西亚岛",
DJ: "吉布提",
DK: "丹麦",
DM: "多米尼克",
DO: "多米尼加共和国",
DZ: "阿尔及利亚",
EC: "厄瓜多尔",
EE: "爱沙尼亚",
EG: "埃及",
EH: "西撒哈拉",
ER: "厄立特里亚",
ES: "西班牙",
ET: "埃塞俄比亚",
FI: "芬兰",
FJ: "斐济",
FK: "福克兰群岛",
FM: "密克罗尼西亚",
FO: "法罗群岛",
FR: "法国",
GA: "加蓬",
GB: "英国",
GD: "格林纳达",
GE: "格鲁吉亚",
GF: "法属圭亚那",
GG: "根西岛",
GH: "加纳",
GI: "直布罗陀",
GL: "格陵兰",
GM: "冈比亚",
GN: "几内亚",
GP: "瓜德罗普",
GQ: "赤道几内亚",
GR: "希腊",
GS: "南乔治亚和南桑德威奇群岛",
GT: "危地马拉",
GU: "关岛",
GW: "几内亚比绍",
GY: "圭亚那",
HK: "中国香港特别行政区",
HM: "赫德岛和麦克唐纳群岛",
HN: "洪都拉斯",
HR: "克罗地亚",
HT: "海地",
HU: "匈牙利",
ID: "印度尼西亚",
IE: "爱尔兰",
IL: "以色列",
IM: "马恩岛",
IN: "印度",
IO: "英属印度洋领地",
IQ: "伊拉克",
IR: "伊朗",
IS: "冰岛",
IT: "意大利",
JE: "泽西岛",
JM: "牙买加",
JO: "约旦",
JP: "日本",
JP1: "日本",
KE: "肯尼亚",
KG: "吉尔吉斯斯坦",
KH: "柬埔寨",
KI: "基里巴斯",
KM: "科摩罗",
KN: "圣基茨和尼维斯",
KP: "朝鲜",
KR: "韩国",
KR1: "韩国",
KR1_UXWAUDIT: "韩国",
KW: "科威特",
KY: "开曼群岛",
KZ: "哈萨克斯坦",
LA: "老挝",
LB: "黎巴嫩",
LC: "圣卢西亚",
LI: "列支敦士登",
LK: "斯里兰卡",
LR: "利比里亚",
LS: "莱索托",
LT: "立陶宛",
LU: "卢森堡",
LV: "拉脱维亚",
LY: "利比亚",
MA: "摩洛哥",
MC: "摩纳哥",
MD: "摩尔多瓦",
ME: "黑山",
MF: "圣马丁",
MG: "马达加斯加",
MH: "马绍尔群岛",
MK: "北马其顿",
ML: "马里",
MM: "缅甸",
MN: "蒙古",
MO: "中国澳门特别行政区",
MP: "北马里亚纳群岛",
MQ: "马提尼克",
MR: "毛里塔尼亚",
MS: "蒙特塞拉特",
MT: "马耳他",
MU: "毛里求斯",
MV: "马尔代夫",
MW: "马拉维",
MX: "墨西哥",
MY: "马来西亚",
MZ: "莫桑比克",
NA: "纳米比亚",
NC: "新喀里多尼亚",
NE: "尼日尔",
NF: "诺福克岛",
NG: "尼日利亚",
NI: "尼加拉瓜",
NL: "荷兰",
NO: "挪威",
NP: "尼泊尔",
NR: "瑙鲁",
NU: "纽埃",
NZ: "新西兰",
OM: "阿曼",
PA: "巴拿马",
PE: "秘鲁",
PF: "法属玻利尼西亚",
PG: "巴布亚新几内亚",
PH: "菲律宾",
PK: "巴基斯坦",
PL: "波兰",
PM: "圣皮埃尔和密克隆群岛",
PN: "皮特凯恩群岛",
PR: "波多黎各",
PS: "巴勒斯坦",
PT: "葡萄牙",
PW: "帕劳",
PY: "巴拉圭",
QA: "卡塔尔",
RE: "留尼汪",
RO: "罗马尼亚",
RS: "塞尔维亚",
RU: "俄罗斯",
RW: "卢旺达",
SA: "沙特阿拉伯",
SB: "索罗门群岛",
SC: "塞舌尔",
SD: "苏丹",
SE: "瑞典",
SG: "新加坡",
SI: "斯洛文尼亚",
SJ: "斯瓦尔巴和扬马延",
SK: "斯洛伐克",
SL: "塞拉利昂",
SM: "圣马利诺",
SN: "塞内加尔",
SO: "索马里",
SR: "苏里南",
SS: "南苏丹",
ST: "圣多美和普林西比",
SV: "萨尔瓦多",
SX: "荷属圣马丁",
SY: "叙利亚",
SZ: "斯威士兰",
TC: "特克斯和凯科斯群岛",
TD: "乍得",
TF: "法属南部领地",
TG: "多哥",
TH: "泰国",
TJ: "塔吉克斯坦",
TK: "托克劳群岛",
TL: "东帝汶",
TM: "土库曼斯坦",
TN: "突尼斯",
TO: "汤加",
TR: "土耳其",
TT: "特立尼达和多巴哥",
TV: "图瓦卢",
TW: "台湾",
TZ: "坦桑尼亚",
UA: "乌克兰",
UG: "乌干达",
UM: "美国本土外小岛屿",
US: "美国",
UY: "乌拉圭",
UZ: "乌兹别克斯坦",
VA: "梵蒂冈",
VC: "圣文森特",
VE: "委内瑞拉",
VG: "英属维尔京群岛",
VI: "美属维尔京群岛",
VN: "越南",
VN1: "越南",
VU: "瓦努阿图",
WS: "萨摩亚",
YE: "也门",
YT: "马约特岛",
ZA: "南非",
ZM: "赞比亚",
ZW: "津巴布韦"
AD: "AD",
AE: "AE",
AF: "AF",
AG: "AG",
AI: "AI",
AL: "AL",
AM: "AM",
AO: "AO",
AQ: "AQ",
AR: "AR",
AS: "AS",
AT: "AT",
AU: "AU",
AU1: "AU1",
AW: "AW",
AX: "AX",
AZ: "AZ",
BA: "BA",
BB: "BB",
BD: "BD",
BE: "BE",
BF: "BF",
BG: "BG",
BH: "BH",
BI: "BI",
BJ: "BJ",
BL: "BL",
BM: "BM",
BN: "BN",
BO: "BO",
BQ: "BQ",
BR: "BR",
BS: "BS",
BT: "BT",
BV: "BV",
BW: "BW",
BY: "BY",
BZ: "BZ",
CA: "CA",
CA1: "CA1",
CC: "CC",
CD: "CD",
CF: "CF",
CG: "CG",
CH: "CH",
CI: "CI",
CK: "CK",
CL: "CL",
CM: "CM",
CN: "CN",
CO: "CO",
CR: "CR",
CU: "CU",
CV: "CV",
CW: "CW",
CX: "CX",
CY: "CY",
CZ: "CZ",
DE: "DE",
DG: "DG",
DJ: "DJ",
DK: "DK",
DM: "DM",
DO: "DO",
DZ: "DZ",
EC: "EC",
EE: "EE",
EG: "EG",
EH: "EH",
ER: "ER",
ES: "ES",
ET: "ET",
FI: "FI",
FJ: "FJ",
FK: "FK",
FM: "FM",
FO: "FO",
FR: "FR",
GA: "GA",
GB: "GB",
GD: "GD",
GE: "GE",
GF: "GF",
GG: "GG",
GH: "GH",
GI: "GI",
GL: "GL",
GM: "GM",
GN: "GN",
GP: "GP",
GQ: "GQ",
GR: "GR",
GS: "GS",
GT: "GT",
GU: "GU",
GW: "GW",
GY: "GY",
HK: "HK",
HM: "HM",
HN: "HN",
HR: "HR",
HT: "HT",
HU: "HU",
ID: "ID",
IE: "IE",
IL: "IL",
IM: "IM",
IN: "IN",
IO: "IO",
IQ: "IQ",
IR: "IR",
IS: "IS",
IT: "IT",
JE: "JE",
JM: "JM",
JO: "JO",
JP: "JP",
JP1: "JP1",
KE: "KE",
KG: "KG",
KH: "KH",
KI: "KI",
KM: "KM",
KN: "KN",
KP: "KP",
KR: "KR",
KR1: "KR1",
KR1_UXWAUDIT: "KR1_UXWAUDIT",
KW: "KW",
KY: "KY",
KZ: "KZ",
LA: "LA",
LB: "LB",
LC: "LC",
LI: "LI",
LK: "LK",
LR: "LR",
LS: "LS",
LT: "LT",
LU: "LU",
LV: "LV",
LY: "LY",
MA: "MA",
MC: "MC",
MD: "MD",
ME: "ME",
MF: "MF",
MG: "MG",
MH: "MH",
MK: "MK",
ML: "ML",
MM: "MM",
MN: "MN",
MO: "MO",
MP: "MP",
MQ: "MQ",
MR: "MR",
MS: "MS",
MT: "MT",
MU: "MU",
MV: "MV",
MW: "MW",
MX: "MX",
MY: "MY",
MZ: "MZ",
NA: "NA",
NC: "NC",
NE: "NE",
NF: "NF",
NG: "NG",
NI: "NI",
NL: "NL",
NO: "NO",
NP: "NP",
NR: "NR",
NU: "NU",
NZ: "NZ",
OM: "OM",
PA: "PA",
PE: "PE",
PF: "PF",
PG: "PG",
PH: "PH",
PK: "PK",
PL: "PL",
PM: "PM",
PN: "PN",
PR: "PR",
PS: "PS",
PT: "PT",
PW: "PW",
PY: "PY",
QA: "QA",
RE: "RE",
RO: "RO",
RS: "RS",
RU: "RU",
RW: "RW",
SA: "SA",
SB: "SB",
SC: "SC",
SD: "SD",
SE: "SE",
SG: "SG",
SI: "SI",
SJ: "SJ",
SK: "SK",
SL: "SL",
SM: "SM",
SN: "SN",
SO: "SO",
SR: "SR",
SS: "SS",
ST: "ST",
SV: "SV",
SX: "SX",
SY: "SY",
SZ: "SZ",
TC: "TC",
TD: "TD",
TF: "TF",
TG: "TG",
TH: "TH",
TJ: "TJ",
TK: "TK",
TL: "TL",
TM: "TM",
TN: "TN",
TO: "TO",
TR: "TR",
TT: "TT",
TV: "TV",
TW: "TW",
TZ: "TZ",
UA: "UA",
UG: "UG",
UM: "UM",
US: "US",
UY: "UY",
UZ: "UZ",
VA: "VA",
VC: "VC",
VE: "VE",
VG: "VG",
VI: "VI",
VN: "VN",
VN1: "VN1",
VU: "VU",
WS: "WS",
YE: "YE",
YT: "YT",
ZA: "ZA",
ZM: "ZM",
ZW: "ZW"
};
export function getCountryName(code) {
return CountryCode[code] || null;
if (!code) return null;
// 使用 i18n 获取国家名称翻译
const countryName = i18n.global.t(`countries.${code}`);
// 如果找不到翻译,返回 null
return countryName === `countries.${code}` ? null : countryName;
}

View File

@@ -48,6 +48,32 @@ export function usePythonBridge() {
});
};
//设置储存数据
const storageSetInfos = (data) => {
return new Promise((resolve, reject) => {
if (pyBridge.value) {
pyBridge.value.storageSetInfo(JSON.stringify(data),function (result) {
resolve(result);
});
}else{
console.log("pyBridge is null未连接上")
}
});
};
//设置储存数据
const readSetInfos = (data) => {
return new Promise((resolve, reject) => {
if (pyBridge.value) {
pyBridge.value.readSetInfo(JSON.stringify(data),function (result) {
resolve(result);
});
}else{
console.log("pyBridge is null未连接上")
}
});
};
// 查询获取大哥的数据
const controlTask = (data) => {
return new Promise((resolve, reject) => {
@@ -120,6 +146,19 @@ export function usePythonBridge() {
}
});
};
const setClipboards = (data) => {
return new Promise((resolve, reject) => {
if (pyBridge.value) {
pyBridge.value.setClipboard(JSON.stringify(data),function (result) {
resolve(result);
});
}else{
console.log("pyBridge is null未连接上")
}
});
};
//跳转到主播页面
const givePyAnchorId = (id) => {
console.log("id",id);
@@ -178,6 +217,9 @@ export function usePythonBridge() {
Specifystreaming,
setStorageStreamId,
getStorageStreamId,
openAnchorIdRooms
openAnchorIdRooms,
storageSetInfos,
readSetInfos,
setClipboards
};
}

View File

@@ -9,11 +9,26 @@
<div class="setup">
<div class="setup-item center-justify">
<div></div>
<span> 网络设置 </span>
<span>{{ $t('common.networkSettings') }}</span>
</div>
<div class="setup-item center-justify">
<div></div>
<span> 简体中文 </span>
<!-- <div class="setup-item center-justify"> -->
<div class="">
<el-select
v-model="currentLanguage"
:placeholder="$t('common.language')"
@change="changeLanguage"
size="small"
style="width: 120px;"
>
<el-option
:label="$t('common.simplifiedChinese')"
value="zh-CN"
/>
<el-option
:label="$t('common.english')"
value="en-US"
/>
</el-select>
</div>
</div>
</div>
@@ -28,7 +43,7 @@
<!-- From -->
<div class="from">
<div class="from-title center-justify">
<div>账号登陆</div>
<div>{{ $t('common.accountLogin') }}</div>
</div>
<div class="from-input">
@@ -38,7 +53,7 @@
<el-input
style="height: 25px"
v-model="formData.tenantName"
placeholder="租户名称"
:placeholder="$t('common.tenantName')"
clearable
@keyup.enter="onSubmit"
/>
@@ -48,7 +63,7 @@
<el-input
style="height: 25px"
v-model="formData.userId"
placeholder="账号"
:placeholder="$t('common.account')"
clearable
@keyup.enter="onSubmit"
/>
@@ -59,7 +74,7 @@
style="height: 25px"
v-model="formData.password"
type="password"
placeholder="密码"
:placeholder="$t('common.password')"
show-password
@keyup.enter="onSubmit"
/>
@@ -71,14 +86,14 @@
color="#8f7ee7"
type="primary"
@click="onSubmit"
>登录</el-button
>{{ $t('common.login') }}</el-button
>
</div>
</el-form>
</div>
</div>
</div>
<div class="version center-justify">版本号{{ version }}</div>
<div class="version center-justify">{{ $t('common.version') }}{{ version }}</div>
</div>
</div>
</div>
@@ -87,6 +102,7 @@
<script setup>
import { ref, reactive, onMounted } from "vue";
import { useRouter } from "vue-router";
import { useI18n } from 'vue-i18n';
import { login, rentgetloginID } from "@/api/account";
import { getToken, setToken, setUser, setUserPass, getUserPass } from "@/utils/storage";
import { ElLoading } from "element-plus";
@@ -94,11 +110,15 @@ import { usePythonBridge } from "@/utils/pythonBridge";
import { ElMessage } from 'element-plus';
import { tokenStore,UserStore } from '@/stores/notice'
const { t, locale } = useI18n();
const tokenCache = tokenStore()
const userCache = UserStore()
const { getVersion } = usePythonBridge();
let version = ref("0.0.0");
// 当前语言
const currentLanguage = ref(localStorage.getItem('language') || 'zh-CN');
onMounted(() => {
setTimeout(() => {
getVersion().then((res) => {
@@ -117,6 +137,14 @@ async function getpassword(){
};
}
// 切换语言
const changeLanguage = (lang) => {
locale.value = lang;
currentLanguage.value = lang;
localStorage.setItem('language', lang);
// 重新加载页面以应用Element Plus语言包
window.location.reload();
};
const router = useRouter();
@@ -213,6 +241,7 @@ const onSubmit = () => {
.setup {
display: flex;
align-items: center;
color: #fff;
.setup-item {

View File

@@ -1,19 +1,19 @@
<template>
<div class="hostList">
<div>
<!-- -->
<!-- 顶部条件 -->
<div style="display: flex">
<el-checkbox
class="isFilter"
v-model="queryFormData.isFilter"
label="过滤隐私用户"
:label="t('hostsList.filterPrivateUsers')"
size="large"
border
/>
<el-input
v-model="queryFormData.coinMin"
placeholder="最小金币"
:placeholder="t('hostsList.minCoins')"
size="large"
style="width: 180px"
type="number"
@@ -22,7 +22,7 @@
<el-input
v-model="queryFormData.coinMax"
placeholder="最大金币"
:placeholder="t('hostsList.maxCoins')"
size="large"
style="width: 180px"
class="right-input"
@@ -32,7 +32,7 @@
<el-input
v-model="queryFormData.levelMin"
placeholder="最小等级"
:placeholder="t('hostsList.minLevel')"
size="large"
style="width: 180px"
class="right-input"
@@ -42,7 +42,7 @@
<el-input
v-model="queryFormData.levelMax"
placeholder="最大等级"
:placeholder="t('hostsList.maxLevel')"
size="large"
style="width: 180px"
class="right-input"
@@ -57,49 +57,64 @@
type="primary"
>
<div>
{{ streamdialogVisibletext ? "已指定直播间" : "指定直播间" }}
</div></el-button
>
{{
streamdialogVisibletext
? t('hostsList.specifiedRooms')
: t('hostsList.specifyRooms')
}}
</div>
</el-button>
<div
class="right-input right-text"
style="width: 160px; height: 50px; line-height: 50px"
>
总数{{ getBrotherInfodata.total }}
{{ t('hostsList.total') }}{{ getBrotherInfodata.total }}
</div>
<div
class="right-input right-text"
style="width: 160px; height: 50px; line-height: 50px"
>
有效数{{ getBrotherInfodata.valid }}
{{ t('hostsList.valid') }}{{ getBrotherInfodata.valid }}
</div>
<el-button class="serch-button right-input" type="primary" @click="Resetss"
>重置</el-button
<el-button
class="serch-button right-input"
type="primary"
@click="Resetss"
>
{{ t('hostsList.reset') }}
</el-button>
<el-button
v-show="queryFormData.isRunning"
class="serch-button right-input"
type="primary"
@click="getBigBrother"
>开始</el-button
>
{{ t('hostsList.start') }}
</el-button>
<el-button
v-show="!queryFormData.isRunning"
class="serch-button right-input"
type="primary"
@click="BigBrotherstop"
>结束</el-button
>
{{ t('hostsList.end') }}
</el-button>
</div>
<!-- `````````````````````````````````````````````````````````````````````````````````````````````````` -->
<div style="width: 100%; border-bottom: 1px solid #e9e9e9; margin-top: 30px"></div>
<!-- ···································································································· -->
<div
style="width: 100%; border-bottom: 1px solid #e9e9e9; margin-top: 30px"
></div>
<!-- 第二行筛选 -->
<div style="display: flex; margin-top: 30px; flex-wrap: wrap">
<el-select
v-model="searchForm.region"
filterable
placeholder="选择国家"
:placeholder="t('hostsList.selectCountry')"
size="large"
style="width: 160px"
>
@@ -113,57 +128,73 @@
<el-input
v-model="searchForm.displayId"
placeholder="大哥id"
:placeholder="t('hostsList.bigBrotherId')"
size="large"
style="width: 160px"
class="right-input"
clearable
/>
<el-button class="serch-button right-input" type="primary" @click="serch"
>查询</el-button
<el-button
class="serch-button right-input"
type="primary"
@click="serch"
>
{{ t('hostsList.search') }}
</el-button>
<el-button class="serch-button" type="primary" @click="reset"> 重置 </el-button>
<el-button class="serch-button" type="primary" @click="reset">
{{ t('hostsList.reset') }}
</el-button>
<el-button
class="put-button"
:disabled="tableData.length == 0"
type="primary"
@click="exportList"
>导出Excel数据</el-button
>
{{ t('hostsList.exportExcel') }}
</el-button>
<el-button
@click="filterdialogVisible = true"
class="put-button buttoMore-filters"
type="primary"
><img class="filters-img" src="@/assets/filter.png" />
<div style="margin-left: 10px">更多筛选</div></el-button
>
<img class="filters-img" src="@/assets/filter.png" />
<div style="margin-left: 10px">
{{ t('hostsList.moreFilters') }}
</div>
</el-button>
<el-button
class="serch-button right-input"
style="width: 150px"
type="primary"
@click="openTikTok"
>打开 TikTok 登录</el-button
>
{{ t('hostsList.openTikTok') }}
</el-button>
<div
class="right-input right-text"
style="width: auto; height: 50px; line-height: 50px"
>
当前网络{{ countryData }}
{{ t('hostsList.currentNetwork') }}{{ countryData }}
</div>
<div
class="right-input right-text"
style="width: auto; height: 50px; line-height: 50px"
>
运行时间{{ String(hourstuo).padStart(2, "0") }}:{{
String(minutestuo).padStart(2, "0")
}}:{{ String(secondstuo).padStart(2, "0") }}
{{ t('hostsList.runningTime') }}
{{ String(hourstuo).padStart(2, '0') }}:{{
String(minutestuo).padStart(2, '0')
}}:{{ String(secondstuo).padStart(2, '0') }}
</div>
</div>
<!-- ····················································································································· -->
<!-- 表格 -->
<div class="hostTable center-justify">
<el-table
ref="multipleTableRef"
@@ -176,9 +207,17 @@
>
<!-- <el-table-column type="selection" width="35" /> -->
<el-table-column fixed prop="displayId" label="Id" :width="screenWidth">
<el-table-column
fixed
prop="displayId"
:label="t('hostsList.id')"
:width="screenWidth"
>
<template #default="scope">
<div class="hostIdText" @click="openHTML(scope.row.displayId)">
<div
class="hostIdText"
@click="openHTML(scope.row.displayId)"
>
{{ scope.row.displayId }}
</div>
</template>
@@ -186,10 +225,9 @@
<el-table-column
prop="hostDisplayId"
label="所在直播间主播id"
:label="t('hostsList.hostId')"
:width="screenWidth"
>
<!-- @click="openhostDisplayId(scope.row.hostDisplayId)" -->
<template #default="scope">
<div
class="hostIdText"
@@ -207,11 +245,15 @@
:label="label.paramCodeMeaning"
:width="screenWidth"
>
<template v-if="label.paramCode != 'createDt'" #default="scope"> </template>
<template
v-if="label.paramCode != 'createDt'"
#default="scope"
>
</template>
</el-table-column>
</el-table>
</div>
<!-- ······································································································································ -->
<!-- 分页 -->
<div class="center-justify" style="margin-top: 30px">
<el-pagination
@@ -226,21 +268,33 @@
/>
</div>
<!-- ·······································································弹窗······································································· -->
<el-dialog v-model="filterdialogVisible" width="800px" :before-close="handleClose">
<!-- 更多筛选弹窗 -->
<el-dialog
v-model="filterdialogVisible"
width="800px"
:before-close="handleClose"
>
<el-row :gutter="20">
<el-col :span="4">
<!-- <label>选择筛选条件</label> -->
<div style="height: 100%; padding-top: 10px" class="center-justify">时间</div>
<div
style="height: 100%; padding-top: 10px"
class="center-justify"
>
{{ t('hostsList.time') }}
</div>
</el-col>
<el-col :span="10">
<div><label>开始时间/结束时间</label></div>
<div>
<label>
{{ t('hostsList.startTime') }}/{{ t('hostsList.endTime') }}
</label>
</div>
<el-date-picker
v-model="createTimes"
type="datetimerange"
value-format="YYYY-MM-DD HH:mm:ss"
placeholder="选择查询时间"
:placeholder="t('hostsList.selectTime')"
size="large"
style="width: 600px; margin-top: 10px"
/>
@@ -259,37 +313,47 @@
</div>
</el-col>
<el-col :span="10">
<div><label>最小值</label></div>
<div>
<label>{{ t('hostsList.minValue') }}</label>
</div>
<el-input
type="number"
:oninput="'if(value.length>9)value=value.slice(0,9)'"
v-model.number="searchForm[field.minModel]"
placeholder="请输入最小值"
:placeholder="t('hostsList.enterMinValue')"
/>
</el-col>
<el-col :span="10">
<div><label>最大值</label></div>
<div>
<label>{{ t('hostsList.maxValue') }}</label>
</div>
<el-input
type="number"
:oninput="'if(value.length>9)value=value.slice(0,9)'"
v-model.number="searchForm[field.maxModel]"
placeholder="请输入最大值"
:placeholder="t('hostsList.enterMaxValue')"
/>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="4">
<!-- <label>选择筛选条件</label> -->
<div style="height: 100%; padding-top: 10px" class="center-justify">排序</div>
<div
style="height: 100%; padding-top: 10px"
class="center-justify"
>
{{ t('hostsList.sort') }}
</div>
</el-col>
<el-col :span="10">
<div><label>排序类型</label></div>
<div>
<label>{{ t('hostsList.sortType') }}</label>
</div>
<el-select
v-model="sortData.sortName"
filterable
placeholder="请选择"
:placeholder="t('hostsList.pleaseSelect')"
style="width: 240px"
>
<el-option
@@ -301,18 +365,20 @@
</el-select>
</el-col>
<el-col :span="10">
<div><label>升序/降序</label></div>
<div>
<label>{{ t('hostsList.sortOrder') }}</label>
</div>
<el-select
v-model="sortData.sort"
filterable
placeholder="请选择"
:placeholder="t('hostsList.pleaseSelect')"
style="width: 240px"
>
<el-option
v-for="item in [
{ label: '升序', value: 'asc' },
{ label: '降序', value: 'desc' },
{ label: t('hostsList.ascending'), value: 'asc' },
{ label: t('hostsList.descending'), value: 'desc' },
]"
:key="item.value"
:label="item.label"
@@ -324,42 +390,81 @@
<template #footer>
<span class="dialog-footer">
<el-button type="primary" @click="reset"> 重置 </el-button>
<!-- <el-button @click="filterdialogVisible = false">取消</el-button> -->
<el-button type="primary" @click="handelClick"> 确认 </el-button>
<el-button type="primary" @click="reset">
{{ t('hostsList.reset') }}
</el-button>
<el-button type="primary" @click="handelClick">
{{ t('hostsList.confirm') }}
</el-button>
</span>
</template>
</el-dialog>
<el-dialog v-model="streamdialogVisible" width="800px" :before-close="handleClose">
<!-- 指定直播间弹窗 -->
<el-dialog
v-model="streamdialogVisible"
width="800px"
:before-close="handleClose"
>
<div class="specify-dialog">
<el-input
v-model="textarea"
style="width: 100%"
:rows="15"
type="textarea"
placeholder="请输入直播间id多个id用回车键隔开"
:placeholder="t('hostsList.enterRoomIds')"
@input="handleInput"
/>
<div class="specify-footer">
<el-button class="specify-button" @click="specifyCancel"
>取消指定直播间</el-button
>
<el-button class="specify-button" type="primary" @click="specifyreset">
重置
<el-button class="specify-button" @click="specifyCancel">
{{ t('hostsList.cancelSpecify') }}
</el-button>
<el-button class="specify-button" type="primary" @click="specifyClick">
确认
<el-button
class="specify-button"
type="primary"
@click="specifyreset"
>
{{ t('hostsList.specifyReset') }}
</el-button>
<el-button
class="specify-button"
type="primary"
@click="specifyClick"
>
{{ t('hostsList.specifyConfirm') }}
</el-button>
<el-button
class="specify-button"
type="primary"
@click="specifyClickStart"
>
{{ t('hostsList.specifyStart') }}
</el-button>
</div>
</div>
</el-dialog>
</div>
</div>
<!-- 网络不可访问弹窗 -->
<el-dialog
v-model="Inaccessible"
width="800px"
:before-close="handleClose"
>
<div class="inaccessible-dialog">
<img class="inaccessible-img" src="@/assets/wifi.png" />
</div>
<div class="inaccessible-dialog">
{{ t('hostsList.networkFailed') }}
</div>
</el-dialog>
</template>
<script setup>
// import { getToken, setToken, removeToken } from '@/utils/storage'
import { useI18n } from 'vue-i18n';
import {
tkhostdata,
dicts,
@@ -369,6 +474,7 @@ import {
managerhosts,
upholdinfo,
getCountryinfo,
tokenVerification,
accountName,
} from "@/api/account";
import { usePythonBridge } from "@/utils/pythonBridge";
@@ -383,56 +489,64 @@ import { color } from "echarts";
import { getCountryName } from "@/utils/countryUtil";
import { ElLoading } from "element-plus";
const { t } = useI18n();
const Inaccessible = ref(false);
// 网络检测
const checkVPN = async () => {
try {
const timeout = new Promise(
(_, reject) => setTimeout(() => reject(new Error("请求超时")), 10000)
);
const response = await Promise.race([
fetch("https://www.google.com", { method: "HEAD", mode: "no-cors" }),
timeout,
]);
if (response && response.type === "opaque") {
Inaccessible.value = false;
} else {
Inaccessible.value = true;
}
} catch (error) {
Inaccessible.value = true;
}
};
// 长按进入直播间
function handleLongPress(event) {
openAnchorIdRooms(event);
}
// 复制单元格内容
function handleCellDbClick(row, column, cell, event) {
const text = cell?.textContent?.trim();
if (!text) {
ElMessage({
type: "warning",
message: "无内容可复制",
message: t("hostsList.noContentToCopy"),
});
return;
}
copyToClipboard(text);
}
//复制到剪切板
async function copyToClipboard(text) {
try {
// 尝试使用现代Clipboard API
if (navigator.clipboard) {
await navigator.clipboard.writeText(text);
setClipboards(text)
.then((res) => {
ElMessage({
type: "success",
message: "复制成功",
message: t("hostsList.copySuccess"),
});
return;
}
// 备用方法使用document.execCommand
const textarea = document.createElement("textarea");
textarea.value = text;
document.body.appendChild(textarea);
textarea.select();
if (document.execCommand("copy")) {
ElMessage({
type: "success",
message: "复制成功",
});
} else {
throw new Error("execCommand failed");
}
document.body.removeChild(textarea);
} catch (err) {
console.error("复制失败:", err);
})
.catch((err) => {
ElMessage({
type: "error",
message: "复制失败",
message: t("hostsList.copyFailed"),
});
});
}
}
// ip 国家
@@ -452,41 +566,43 @@ const getIpInfo = async () => {
countryData.value = getCountryName(data.country);
} catch (error) {
console.error("请求出错:", error);
ElMessageBox.prompt("请输入将要获取国家的中文名", "获取国家失败", {
confirmButtonText: "确认",
cancelButtonText: "取消",
ElMessageBox.prompt(
t("hostsList.pleaseEnterCountryName"),
t("hostsList.getCountryFailed"),
{
confirmButtonText: t("hostsList.confirm"),
cancelButtonText: t("hostsList.cancel"),
showClose: false,
closeOnClickModal: false,
showCancelButton: false,
}).then(({ value }) => {
}
).then(({ value }) => {
countryData.value = value;
});
// .catch(() => {
// ElMessage({
// type: 'info',
// message: 'Input canceled',
// })
// })
}
};
// 打开 TikTok 登录
function openTikTok() {
loginTikTok();
}
// 重置
function Resetss() {
queryFormData.value = {};
}
// 大哥 climb
const queryFormData = ref({
coinMin: "",
coinMax: "",
levelMin: "",
levelMax: "",
isFilter: false,
isRunning: true,
anchor_ids: [],
coinMin: "", //打赏的金币最小值
coinMax: "", //打赏的金币最大值
levelMin: "", //等级最小值
levelMax: "", //等级最大值
isFilter: false, //是否筛选
isRunning: true, //是否在运行
anchor_ids: [], //指定直播间id
});
// 时间
const timerId = ref(null);
const getBrotherInfodata = ref({
@@ -498,7 +614,7 @@ const getBrotherInfodata = ref({
function BigBrotherstop() {
const loading = ElLoading.service({
lock: true,
text: "正在停止...",
text: t("hostsList.stopping"),
background: "rgba(0, 0, 0, 0.7)",
});
stopTimerfun();
@@ -520,19 +636,40 @@ function BigBrotherstop() {
});
}
//指定直播间
function specifyClick() {
// 指定直播间开始
function specifyClickStart() {
if (textarea.value == "") {
ElMessage({
type: "error",
message: "请输入直播间id",
message: t("hostsList.enterRoomId"),
});
return;
}
setStorageStreamId(textarea.value).then((res) => {});
queryFormData.value.anchor_ids = textarea.value.split("\n");
streamdialogVisible.value = false;
streamdialogVisibletext.value = true;
getBigBrother();
}
function specifyClick() {
if (
textarea.value == "" ||
textarea.value == null ||
textarea.value == undefined ||
textarea.value.length == 0
) {
streamdialogVisibletext.value = false;
streamdialogVisible.value = false;
queryFormData.value.anchor_ids = [];
} else {
streamdialogVisibletext.value = true;
streamdialogVisible.value = false;
queryFormData.value = {
...queryFormData.value,
anchor_ids: textarea.value.split("\n").filter((id) => id.trim() !== ""),
};
}
}
// 指定直播间重置
@@ -551,14 +688,19 @@ function specifyCancel() {
function handleInput() {
streamdialogVisibletext.value = false;
}
//获取主播列表
//开始爬取
// 获取主播列表 - 开始爬取
function getBigBrother() {
const loading = ElLoading.service({
lock: true,
text: "正在启动...",
text: t("hostsList.starting"),
background: "rgba(0, 0, 0, 0.7)",
});
const storageobject = ref({
key: "UserSettings",
data: queryFormData.value,
});
storageSetInfos(storageobject.value).then((res) => {});
queryFormData.value.tenantId = userInfo.value.tenantId;
queryFormData.value.region = countryData.value;
startTimerfun();
@@ -603,6 +745,9 @@ const {
setStorageStreamId,
getStorageStreamId,
openAnchorIdRooms,
storageSetInfos,
readSetInfos,
setClipboards,
} = usePythonBridge();
let num = ref(0);
@@ -611,15 +756,15 @@ const userInfo = ref({});
// 主播列表 DOM
const multipleTableRef = ref(null);
let labelList = ref([
{ paramCode: "userIdStr", paramCodeMeaning: "用户id" },
{ paramCode: "level", paramCodeMeaning: "等级" },
{ paramCode: "fansLevel", paramCodeMeaning: "粉丝团等级" },
{ paramCode: "hostcoins", paramCodeMeaning: "打赏的金币" },
{ paramCode: "hostDisplayId", paramCodeMeaning: "所在直播间主播id" },
{ paramCode: "region", paramCodeMeaning: "地区" },
{ paramCode: "followerCount", paramCodeMeaning: "粉丝数" },
{ paramCode: "followingCount", paramCodeMeaning: "关注数" },
{ paramCode: "createTime", paramCodeMeaning: "创建时间" },
{ paramCode: "userIdStr", paramCodeMeaning: t("hostsList.userId") },
{ paramCode: "level", paramCodeMeaning: t("hostsList.level") },
{ paramCode: "fansLevel", paramCodeMeaning: t("hostsList.fansLevel") },
{ paramCode: "hostcoins", paramCodeMeaning: t("hostsList.coins") },
{ paramCode: "region", paramCodeMeaning: t("hostsList.region") },
{ paramCode: "followerCount", paramCodeMeaning: t("hostsList.followerCount") },
{ paramCode: "followingCount", paramCodeMeaning: t("hostsList.followingCount") },
{ paramCode: "createTime", paramCodeMeaning: t("hostsList.createTime") },
{ paramCode: "totalGiftCoins", paramCodeMeaning: t("hostsList.totalGiftCoins") },
]);
const tableData = ref([]);
@@ -630,18 +775,17 @@ const createTimes = ref([]);
const page = ref(1);
const pageSize = ref(10);
const fields = [
// { label: "打赏的金币", minModel: "hostcoinsMin", maxModel: "hostcoinsMax" },
{ label: "等级", minModel: "levelMin", maxModel: "levelMax" },
{ label: t("hostsList.level"), minModel: "levelMin", maxModel: "levelMax" },
];
// 排序
let sortData = ref({ sortName: "createTime", sort: "desc" });
// 排序类型
let sortNameOptions = ref([
{ label: "创建时间", type: "createTime" },
{ label: "打赏的金币", type: "hostsCoins" },
{ label: "打赏金币总和", type: "totalGiftCoins" },
{ label: "等级", type: "level" },
{ label: t("hostsList.createTime"), type: "createTime" },
{ label: t("hostsList.coins"), type: "hostsCoins" },
{ label: t("hostsList.totalGiftCoins"), type: "totalGiftCoins" },
{ label: t("hostsList.level"), type: "level" },
]);
// 是否在运行
let isRunnings = ref(false);
@@ -672,15 +816,49 @@ let version = ref("0.0.0");
const lastVisibleTime = ref(null);
function tokenVerificationfun(params) {
tokenVerification(params)
.then((res) => {})
.catch((err) => {});
}
onMounted(() => {
window.addEventListener("resize", handleResize);
window.addEventListener("visibilitychange", handleVisibilityChange);
setTimeout(() => {
getUserdata();
getStorageStreamId(1).then((res) => {
textarea.value = res == "" ? "" : JSON.parse(res);
readSetInfos("UserSettings").then((res) => {
const storageData = (queryFormData.value =
res == ""
? {
coinMin: "",
coinMax: "",
levelMin: "",
levelMax: "",
isFilter: false,
isRunning: true,
anchor_ids: [],
}
: JSON.parse(res));
if (
storageData.anchor_ids == "" ||
storageData.anchor_ids == null ||
storageData.anchor_ids == undefined ||
storageData.anchor_ids.length == 0
) {
streamdialogVisibletext.value = false;
textarea.value = "";
} else {
streamdialogVisibletext.value = true;
textarea.value = storageData.anchor_ids.join("\n");
}
});
}, 500);
setInterval(() => {
checkVPN();
tokenVerificationfun();
}, 10000);
});
onBeforeUnmount(() => {
@@ -691,13 +869,13 @@ onBeforeUnmount(() => {
function handleVisibilityChange() {
if (isRunnings.value) {
if (document.hidden) {
// 页面变为不可见
lastVisibleTime.value = Date.now();
stopTimerfun();
} else {
// 页面重新可见
if (lastVisibleTime.value) {
const hiddenDuration = Math.floor((Date.now() - lastVisibleTime.value) / 1000);
const hiddenDuration = Math.floor(
(Date.now() - lastVisibleTime.value) / 1000
);
secondstuo.value += hiddenDuration % 60;
minutestuo.value += Math.floor(hiddenDuration / 60) % 60;
hourstuo.value += Math.floor(hiddenDuration / 3600);
@@ -749,6 +927,7 @@ function serch() {
function exportList() {
exportToExcel(requestParams.value);
}
// 分页每页条数
function handleSizeChange(val) {
console.log(`${val} items per page`);
@@ -766,13 +945,12 @@ function handleSelectionChange(data) {
data.forEach((item) => {
selectHostList.value.push(item.hostId);
});
// multipleTableRef.value = data
// console.log(multipleTableRef.value)
}
// 时间格式化
function formatDate(date) {
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, "0"); // 月份从 0开始需要+1
const month = String(date.getMonth() + 1).padStart(2, "0");
const day = String(date.getDate()).padStart(2, "0");
const hours = String(date.getHours()).padStart(2, "0");
const minutes = String(date.getMinutes()).padStart(2, "0");
@@ -780,43 +958,42 @@ function formatDate(date) {
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
}
// 获取主播列表
//记录请求参数
let requestParams = ref({});
const getlist = () => {
loading.value = true;
tkhostdata({
tenantId: Number(userInfo.value.tenantId),
sort: sortData.value.sort, //正序倒序
sortName: sortData.value.sortName, //排序类型
sort: sortData.value.sort,
sortName: sortData.value.sortName,
current: page.value,
pageSize: pageSize.value,
createTimeStart: createTimes.value[0],
createTimeEnd: createTimes.value[1],
...searchForm.value, //筛选条件
...searchForm.value,
}).then((res) => {
loading.value = false;
console.log(res);
if (res) {
requestParams.value = res.records;
console.log(res.records);
total.value = Number(res.total);
tableData.value = res.records.map((item) => ({
level: item.level, // 等级
fansLevel: item.fansLevel, // 粉丝团等级
createTime: formatDate(new Date(item.createTime)), // 创建时间
followerCount: item.followerCount, // 粉丝数
followingCount: item.followingCount, // 关注数
hostDisplayId: item.hostDisplayId, // 所在直播间主播id
hostcoins: item.hostcoins, // 打赏的金币
region: item.region, // 地区
totalGiftCoins: item.totalGiftCoins, // 打赏金币总和
userIdStr: item.userIdStr, // 用户id
level: item.level,
fansLevel: item.fansLevel,
createTime: formatDate(new Date(item.createTime)),
followerCount: item.followerCount,
followingCount: item.followingCount,
hostDisplayId: item.hostDisplayId,
hostcoins: item.hostcoins,
region: item.region,
totalGiftCoins: item.totalGiftCoins,
userIdStr: item.userIdStr,
displayId: item.displayId,
}));
}
});
};
function handelClick() {
filterdialogVisible.value = false;
}
@@ -837,17 +1014,25 @@ function filterTag(value, row) {
return row.useable === value;
}
const { locale } = useI18n();
// 获取国家
function getCountry() {
getCountryinfo({})
.then((res) => {
res.forEach((item) => {
if (item.countryGroupName) {
if (locale.value === 'en-US') {
options.value.push({
value: item.countryGroupName,
label: item.countryNameEnglish,
});
} else if (locale.value === 'zh-CN') {
options.value.push({
value: item.countryGroupName,
label: item.countryGroupName,
});
}
}
});
})
.catch((err) => {
@@ -865,7 +1050,6 @@ function closePopover(hostId, paramCode) {
function openHTML(id) {
console.log(id);
givePyAnchorId(id);
}
function openhostDisplayId(hostDisplayId) {
@@ -873,6 +1057,7 @@ function openhostDisplayId(hostDisplayId) {
}
</script>
<style lang="less">
.hostList {
box-sizing: border-box;
@@ -993,4 +1178,19 @@ function openhostDisplayId(hostDisplayId) {
width: 200px;
height: 50px;
}
.inaccessible-dialog {
width: 100%;
height: 200px;
display: flex;
justify-content: center;
align-items: center;
font-size: 20px;
color: #666;
text-align: center;
}
.inaccessible-img {
width: 200px;
height: 200px;
}
</style>

View File

@@ -11,12 +11,13 @@
<!-- <div style="position: absolute; bottom: 0; right: 0;">{{ version }}</div> -->
</div>
<div class="footer">
到期时间{{ time }}
{{ $t('common.expirationtime') }}{{ time }}
</div>
</div>
</template>
<script setup>
import { useI18n } from 'vue-i18n';
import { ref, reactive, onMounted } from "vue";
// import Sidebar from '../components/Sidebar.vue';
import { RouterLink, RouterView } from 'vue-router'
@@ -26,6 +27,7 @@ import { getUser } from "@/utils/storage";
// import workbenches from '@/views/hosts/workbenches.vue'
import { tokenStore,UserStore } from '@/stores/notice'
const userCache = UserStore()
const { t } = useI18n();
const time = ref(formatTimestamp(userCache.user.brotherExpireTime))
// 时间格式化方法 - 将12位时间戳转为YYYY-MM-DD HH:mm:ss格式
function formatTimestamp(timestamp) {