diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..ad1ddec --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,70 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## 项目概述 + +yolo-web-frontend 是一个 Vue 3 Web 前端应用,主要作为 Electron 桌面应用的 UI 层运行,提供 TikTok 自动化管理功能。 + +## 常用命令 + +```bash +npm run dev # 启动开发服务器 (端口 5173) +npm run build # 生产环境构建 (输出到 dist/) +npm run preview # 预览生产构建 +``` + +## 技术栈 + +- **框架**: Vue 3 + Composition API (` + + diff --git a/src/components/pk-mini/chat/MiniPKMessage.vue b/src/components/pk-mini/chat/MiniPKMessage.vue new file mode 100644 index 0000000..d0c754c --- /dev/null +++ b/src/components/pk-mini/chat/MiniPKMessage.vue @@ -0,0 +1,427 @@ + + + + + diff --git a/src/components/pk-mini/chat/PKMessage.vue b/src/components/pk-mini/chat/PKMessage.vue new file mode 100644 index 0000000..9ad4a9f --- /dev/null +++ b/src/components/pk-mini/chat/PKMessage.vue @@ -0,0 +1,116 @@ + + + + + diff --git a/src/components/pk-mini/chat/PictureMessage.vue b/src/components/pk-mini/chat/PictureMessage.vue new file mode 100644 index 0000000..7b7df6c --- /dev/null +++ b/src/components/pk-mini/chat/PictureMessage.vue @@ -0,0 +1,54 @@ + + + + + diff --git a/src/components/pk-mini/chat/VoiceMessage.vue b/src/components/pk-mini/chat/VoiceMessage.vue new file mode 100644 index 0000000..1b1fdbd --- /dev/null +++ b/src/components/pk-mini/chat/VoiceMessage.vue @@ -0,0 +1,91 @@ + + + + + diff --git a/src/components/pk-mini/mine/AnchorLibrary.vue b/src/components/pk-mini/mine/AnchorLibrary.vue new file mode 100644 index 0000000..cd73ca8 --- /dev/null +++ b/src/components/pk-mini/mine/AnchorLibrary.vue @@ -0,0 +1,442 @@ + + + + + diff --git a/src/components/pk-mini/mine/PKRecord.vue b/src/components/pk-mini/mine/PKRecord.vue new file mode 100644 index 0000000..e049a42 --- /dev/null +++ b/src/components/pk-mini/mine/PKRecord.vue @@ -0,0 +1,478 @@ + + + + + diff --git a/src/components/pk-mini/mine/PKmessage.vue b/src/components/pk-mini/mine/PKmessage.vue new file mode 100644 index 0000000..efe7e22 --- /dev/null +++ b/src/components/pk-mini/mine/PKmessage.vue @@ -0,0 +1,883 @@ + + + + + diff --git a/src/components/pk-mini/mine/PointsList.vue b/src/components/pk-mini/mine/PointsList.vue new file mode 100644 index 0000000..a554fe3 --- /dev/null +++ b/src/components/pk-mini/mine/PointsList.vue @@ -0,0 +1,151 @@ + + + + + diff --git a/src/layout/WorkbenchLayout.vue b/src/layout/WorkbenchLayout.vue index 11942a6..5af6837 100644 --- a/src/layout/WorkbenchLayout.vue +++ b/src/layout/WorkbenchLayout.vue @@ -53,6 +53,17 @@ 主播列表 + + +
@@ -117,15 +128,20 @@
-
+ + +
+ +
@@ -138,6 +154,7 @@ import TkWorkbenches from '@/views/tk/Workbenches.vue' import HostsList from '@/views/tk/HostsList.vue' import ConfigPage from '@/pages/ConfigPage.vue' import FanWorkbench from '@/views/tk/FanWorkbench.vue' +import PkMiniWorkbench from '@/views/pk-mini/PkMiniWorkbench.vue' import PermissionMask from '@/components/PermissionMask.vue' // 占位图片 - 无权限时显示的工作台截图 diff --git a/src/locales/en.js b/src/locales/en.js index b78b84a..6dbf8fc 100644 --- a/src/locales/en.js +++ b/src/locales/en.js @@ -179,5 +179,62 @@ export default { 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" + }, + // PK Mini module translations + pkMini: { + // Navigation + pkHall: 'PK Hall', + todayPK: 'Today PK', + forum: 'In-site Message', + message: 'Message', + mine: 'Mine', + // PK Hall + selectCountry: 'Select Country', + selectGender: 'Select Gender', + male: 'Male', + female: 'Female', + minCoin: 'Min Coins', + maxCoin: 'Max Coins', + search: 'Search', + reset: 'Reset', + pkTime: 'PK Time', + goldCoin: 'Gold Coins', + session: 'Session', + send: 'Send', + selectHostToChat: 'Select a host to start chatting', + // Mine page + anchorLibrary: 'Anchor Library', + pkInfo: 'PK Info', + pkRecord: 'PK Record', + pointsList: 'Points List', + myPoints: 'My Points', + totalPoints: 'Total Points', + addAnchor: 'Add Anchor', + deleteAnchor: 'Delete', + noAnchor: 'No anchors yet', + noPkInfo: 'No PK info yet', + noPkRecord: 'No PK record yet', + noPoints: 'No points record yet', + // Status + pending: 'Pending', + matched: 'Matched', + closed: 'Closed', + accepted: 'Accepted', + rejected: 'Rejected', + waitConfirm: 'Wait Confirm', + // Message + noConversation: 'No conversations', + selectConversation: 'Select a conversation to start chatting', + inputMessage: 'Enter message...', + sendImage: 'Send Image', + // Common + confirm: 'Confirm', + cancel: 'Cancel', + delete: 'Delete', + edit: 'Edit', + save: 'Save', + loading: 'Loading...', + noData: 'No data', + noNotice: 'No in-site messages' } } \ No newline at end of file diff --git a/src/locales/zh.js b/src/locales/zh.js index b8bc986..de34039 100644 --- a/src/locales/zh.js +++ b/src/locales/zh.js @@ -159,16 +159,62 @@ export default { }, 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: "韩国", 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: "津巴布韦" + }, + // PK Mini 模块翻译 + pkMini: { + // 导航 + pkHall: 'PK大厅', + todayPK: '今日PK', + forum: '站内信', + message: '消息', + mine: '我的', + // PK 大厅 + selectCountry: '选择国家', + selectGender: '选择性别', + male: '男', + female: '女', + minCoin: '最小金币数', + maxCoin: '最大金币数', + search: '搜索', + reset: '重置', + pkTime: 'PK时间', + goldCoin: '金币', + session: '场次', + send: '发送', + selectHostToChat: '选择左侧主播开始聊天', + // 我的页面 + anchorLibrary: '主播库', + pkInfo: 'PK信息', + pkRecord: 'PK记录', + pointsList: '积分列表', + myPoints: '我的积分', + totalPoints: '总积分', + addAnchor: '添加主播', + deleteAnchor: '删除', + noAnchor: '暂无主播', + noPkInfo: '暂无发布的 PK', + noPkRecord: '暂无 PK 记录', + noPoints: '暂无积分记录', + // 状态 + pending: '等待匹配', + matched: '已匹配', + closed: '已关闭', + accepted: '已同意', + rejected: '已拒绝', + waitConfirm: '待确认', + // 消息 + noConversation: '暂无会话', + selectConversation: '选择左侧会话开始聊天', + inputMessage: '输入消息...', + sendImage: '发送图片', + // 通用 + confirm: '确认', + cancel: '取消', + delete: '删除', + edit: '编辑', + save: '保存', + loading: '加载中...', + noData: '暂无数据', + noNotice: '暂无站内信' } } \ No newline at end of file diff --git a/src/stores/pk-mini/notice.js b/src/stores/pk-mini/notice.js new file mode 100644 index 0000000..4ffdb36 --- /dev/null +++ b/src/stores/pk-mini/notice.js @@ -0,0 +1,45 @@ +import { defineStore } from 'pinia' + +export const pkNoticeStore = defineStore('pkNoticeNum', { + state: () => { + return { data: { num: 0 } } + }, + actions: { + increment() { + this.data.num++ + } + } +}) + +export const pkTokenStore = defineStore('pkToken', { + state: () => { + return { token: '' } + }, + actions: { + setToken(token) { + this.token = token + } + } +}) + +export const pkUserStore = defineStore('pkUser', { + state: () => { + return { user: {} } + }, + actions: { + setUser(user) { + this.user = user + } + } +}) + +export const pkIMloginStore = defineStore('pkIMlogin', { + state: () => { + return { IMstate: false } + }, + actions: { + setIMstate(state) { + this.IMstate = state + } + } +}) diff --git a/src/utils/pk-mini/countryUtil.js b/src/utils/pk-mini/countryUtil.js new file mode 100644 index 0000000..7074c58 --- /dev/null +++ b/src/utils/pk-mini/countryUtil.js @@ -0,0 +1,136 @@ +// 国家数据 - 简化版本,直接内嵌数据 +const zhCountries = { + "CN": "中国", + "US": "美国", + "JP": "日本", + "KR": "韩国", + "GB": "英国", + "DE": "德国", + "FR": "法国", + "IT": "意大利", + "ES": "西班牙", + "RU": "俄罗斯", + "BR": "巴西", + "IN": "印度", + "AU": "澳大利亚", + "CA": "加拿大", + "MX": "墨西哥", + "ID": "印度尼西亚", + "TH": "泰国", + "VN": "越南", + "MY": "马来西亚", + "SG": "新加坡", + "PH": "菲律宾", + "TW": "中国台湾", + "HK": "中国香港", + "AE": "阿联酋", + "SA": "沙特阿拉伯", + "TR": "土耳其", + "EG": "埃及", + "ZA": "南非", + "NG": "尼日利亚", + "AR": "阿根廷", + "CL": "智利", + "CO": "哥伦比亚", + "PE": "秘鲁", + "PL": "波兰", + "NL": "荷兰", + "BE": "比利时", + "SE": "瑞典", + "NO": "挪威", + "DK": "丹麦", + "FI": "芬兰", + "AT": "奥地利", + "CH": "瑞士", + "PT": "葡萄牙", + "GR": "希腊", + "CZ": "捷克", + "RO": "罗马尼亚", + "HU": "匈牙利", + "UA": "乌克兰", + "IL": "以色列", + "PK": "巴基斯坦", + "BD": "孟加拉国", + "NZ": "新西兰" +} + +const enCountries = { + "CN": "China", + "US": "United States", + "JP": "Japan", + "KR": "South Korea", + "GB": "United Kingdom", + "DE": "Germany", + "FR": "France", + "IT": "Italy", + "ES": "Spain", + "RU": "Russia", + "BR": "Brazil", + "IN": "India", + "AU": "Australia", + "CA": "Canada", + "MX": "Mexico", + "ID": "Indonesia", + "TH": "Thailand", + "VN": "Vietnam", + "MY": "Malaysia", + "SG": "Singapore", + "PH": "Philippines", + "TW": "Taiwan", + "HK": "Hong Kong", + "AE": "UAE", + "SA": "Saudi Arabia", + "TR": "Turkey", + "EG": "Egypt", + "ZA": "South Africa", + "NG": "Nigeria", + "AR": "Argentina", + "CL": "Chile", + "CO": "Colombia", + "PE": "Peru", + "PL": "Poland", + "NL": "Netherlands", + "BE": "Belgium", + "SE": "Sweden", + "NO": "Norway", + "DK": "Denmark", + "FI": "Finland", + "AT": "Austria", + "CH": "Switzerland", + "PT": "Portugal", + "GR": "Greece", + "CZ": "Czech Republic", + "RO": "Romania", + "HU": "Hungary", + "UA": "Ukraine", + "IL": "Israel", + "PK": "Pakistan", + "BD": "Bangladesh", + "NZ": "New Zealand" +} + +// 创建中文名称到国家代码的映射 +const zhNameToCode = {} +Object.entries(zhCountries).forEach(([code, zhName]) => { + zhNameToCode[zhName] = code +}) + +// 获取国家名称数组,value 固定为中文名称,label 根据当前语言变化 +export function getCountryNamesArray() { + const currentLanguage = localStorage.getItem('language') || 'ZH' + + return Object.entries(zhCountries).map(([code, zhName]) => ({ + value: zhName, + label: currentLanguage === 'ZH' ? zhName : enCountries[code] + })) +} + +// 根据中文名称获取当前语言环境的翻译 +export function translateCountryName(zhName) { + const currentLanguage = localStorage.getItem('language') || 'ZH' + const code = zhNameToCode[zhName] + + if (!code) return zhName + + return currentLanguage === 'ZH' ? zhName : enCountries[code] +} diff --git a/src/utils/pk-mini/goeasy.js b/src/utils/pk-mini/goeasy.js new file mode 100644 index 0000000..4e771b8 --- /dev/null +++ b/src/utils/pk-mini/goeasy.js @@ -0,0 +1,212 @@ +import GoEasy from 'goeasy' +import { pkIMloginStore } from '@/stores/pk-mini/notice.js' + +// PK Mini 模块专用 GoEasy 实例 +let pkGoEasyInstance = null + +// 获取或创建 PK GoEasy 实例 +export function getPkGoEasy() { + if (!pkGoEasyInstance) { + pkGoEasyInstance = GoEasy.getInstance({ + host: 'hangzhou.goeasy.io', + appkey: 'PC-a88037e060ed4753bb316ac7239e62d9', + modules: ['im'] + }) + } + return pkGoEasyInstance +} + +// 初始化 PK GoEasy (在 PkMiniWorkbench 挂载时调用) +export function initPkGoEasy() { + return getPkGoEasy() +} + +// 链接 IM (登录 IM) +export function goEasyLink(data) { + const goeasy = getPkGoEasy() + const counter = pkIMloginStore() + return new Promise((resolve, reject) => { + goeasy.connect({ + id: data.id, + data: { avatar: data.avatar, nickname: data.nickname }, + otp: data.key, + onSuccess: function () { + console.log('PK IM 连接成功') + counter.setIMstate(true) + resolve(true) + }, + onFailed: function (error) { + console.log('PK IM 连接失败,错误码:' + error.code + ',错误信息:' + error.content) + reject(error) + }, + onProgress: function (attempts) { + console.log('PK IM 正在重连中...') + } + }) + }) +} + +// 断开 IM +export function goEasyDisConnect() { + const goeasy = getPkGoEasy() + return new Promise((resolve, reject) => { + goeasy.disconnect({ + onSuccess: function () { + resolve(true) + }, + onFailed: function (error) { + console.log('断开失败, code:' + error.code + ',error:' + error.content) + reject(error) + } + }) + }) +} + +// 获取会话列表 +export function goEasyGetConversations() { + const goeasy = getPkGoEasy() + const im = goeasy.im + return new Promise((resolve, reject) => { + im.latestConversations({ + onSuccess: function (result) { + resolve(result) + }, + onFailed: function (error) { + console.log('获取会话列表失败,错误码:' + error.code + ' content:' + error.content) + reject(error) + } + }) + }) +} + +// 获取指定会话的消息列表 +export function goEasyGetMessages(data) { + const goeasy = getPkGoEasy() + const im = goeasy.im + return new Promise((resolve, reject) => { + im.history({ + id: data.id, + type: GoEasy.IM_SCENE.PRIVATE, + lastTimestamp: data.timestamp, + limit: 30, + onSuccess: function (result) { + resolve(result.content) + }, + onFailed: function (error) { + console.log('获取消息列表失败,错误码:' + error.code + ' content:' + error.content) + reject(error) + } + }) + }) +} + +// 发送文本消息 +export function goEasySendMessage(data) { + const goeasy = getPkGoEasy() + const im = goeasy.im + let textMessage = im.createTextMessage({ + text: data.text, + to: { + type: GoEasy.IM_SCENE.PRIVATE, + id: data.id, + data: { avatar: data.avatar, nickname: data.nickname } + } + }) + return new Promise((resolve, reject) => { + im.sendMessage({ + message: textMessage, + onSuccess: function () { + resolve(textMessage) + }, + onFailed: function (error) { + console.log('Failed to send private message,code:' + error.code + ' ,error ' + error.content) + reject(error) + } + }) + }) +} + +// 发送图片消息 +export function goEasySendImageMessage(data) { + const goeasy = getPkGoEasy() + const im = goeasy.im + const message = im.createImageMessage({ + file: data.imagefile, + to: { + type: GoEasy.IM_SCENE.PRIVATE, + id: data.id, + data: { avatar: data.avatar, nickname: data.nickname } + } + }) + return new Promise((resolve, reject) => { + im.sendMessage({ + message: message, + onSuccess: function () { + resolve(message) + }, + onFailed: function (error) { + console.log('Failed to send message,code:' + error.code + ',error' + error.content) + reject(error) + } + }) + }) +} + +// 发送 PK 消息 +export function goEasySendPKMessage(data) { + const goeasy = getPkGoEasy() + const im = goeasy.im + const customData = { + id: data.msgid, + pkIdA: data.pkIdA, + pkIdB: data.pkIdB + } + + const order = { + customData: customData, + link: 'https://vv-1317974657.cos.ap-shanghai.myqcloud.com/util/pk.png', + text: 'PK' + } + + const customMessage = im.createCustomMessage({ + type: 'pk', + payload: order, + to: { + type: GoEasy.IM_SCENE.PRIVATE, + id: data.id, + data: { avatar: data.avatar, nickname: data.nickname } + } + }) + + return new Promise((resolve, reject) => { + im.sendMessage({ + message: customMessage, + onSuccess: function () { + resolve(customMessage) + }, + onFailed: function (error) { + console.log('Failed to send message,code:' + error.code + ',error' + error.content) + reject(error) + } + }) + }) +} + +// 消息已读 +export function goEasyMessageRead(data) { + const goeasy = getPkGoEasy() + const im = goeasy.im + return new Promise((resolve, reject) => { + im.markMessageAsRead({ + id: data.id, + type: GoEasy.IM_SCENE.PRIVATE, + onSuccess: function () { + resolve(true) + }, + onFailed: function (error) { + console.log('标记私聊已读失败', error) + reject(error) + } + }) + }) +} diff --git a/src/utils/pk-mini/storage.js b/src/utils/pk-mini/storage.js new file mode 100644 index 0000000..72f4232 --- /dev/null +++ b/src/utils/pk-mini/storage.js @@ -0,0 +1,79 @@ +// PK Mini 模块专用 Storage 工具 +// 使用 pk_mini_ 前缀避免与主项目冲突 + +const PREFIX = 'pk_mini_' + +export function setStorage(key, value) { + localStorage.setItem(PREFIX + key, JSON.stringify(value)) +} + +export function getStorage(key) { + const value = localStorage.getItem(PREFIX + key) + if (value) { + try { + return JSON.parse(value) + } catch (e) { + return value + } + } + return null +} + +export function getPromiseStorage(key) { + return new Promise((resolve, reject) => { + const value = getStorage(key) + if (value) { + resolve(value) + } else { + reject(new Error('Key not found: ' + key)) + } + }) +} + +export function clearStorage(key) { + localStorage.removeItem(PREFIX + key) +} + +export function getPromiseSessionStorage(key) { + return new Promise((resolve, reject) => { + const value = sessionStorage.getItem(PREFIX + key) + if (value) { + try { + resolve(JSON.parse(value)) + } catch (e) { + resolve(value) + } + } else { + reject(new Error('Key not found: ' + key)) + } + }) +} + +export function setSessionStorage(key, value) { + sessionStorage.setItem(PREFIX + key, JSON.stringify(value)) +} + +// 获取主项目的用户数据(用于获取 token 和用户信息) +// 主项目使用 'user' 键存储用户信息 +export function getMainUserData() { + // 优先从 'user' 获取(主项目当前使用的键) + let userData = localStorage.getItem('user') + if (userData) { + try { + return JSON.parse(userData) + } catch (e) { + // 解析失败,继续尝试其他键 + } + } + + // 兼容:尝试从 'user_data' 获取(旧键名) + userData = localStorage.getItem('user_data') + if (userData) { + try { + return JSON.parse(userData) + } catch (e) { + return null + } + } + return null +} diff --git a/src/utils/pk-mini/timeConversion.js b/src/utils/pk-mini/timeConversion.js new file mode 100644 index 0000000..3ae7cd8 --- /dev/null +++ b/src/utils/pk-mini/timeConversion.js @@ -0,0 +1,13 @@ +// 时间戳转换为本地时间,格式为 YYYY/MM/DD hh:mm +export function TimestamptolocalTime(date) { + if (!date || isNaN(date)) return '' + + const d = new Date(date) + const year = d.getFullYear() + const month = String(d.getMonth() + 1).padStart(2, '0') + const day = String(d.getDate()).padStart(2, '0') + const hours = String(d.getHours()).padStart(2, '0') + const minutes = String(d.getMinutes()).padStart(2, '0') + + return `${year}/${month}/${day} ${hours}:${minutes}` +} diff --git a/src/utils/pk-mini/timeDisplay.js b/src/utils/pk-mini/timeDisplay.js new file mode 100644 index 0000000..055610a --- /dev/null +++ b/src/utils/pk-mini/timeDisplay.js @@ -0,0 +1,27 @@ +// 记录上次调用时间 +let lastTimestamp = null + +/** + * 比较时间戳是否超过 5 分钟 + * @param {number} timestamp - 要比较的时间戳(毫秒) + * @returns {boolean} - 是否超过 5 分钟或第一次调用 + */ +export function timeDisplay(timestamp) { + // 第一次调用直接返回 true + if (lastTimestamp === null) { + lastTimestamp = timestamp + return true + } + + // 计算时间差(毫秒) + const timeDiff = Math.abs(timestamp - lastTimestamp) + lastTimestamp = timestamp + + // 5 分钟 = 300,000 毫秒 + return timeDiff > 300000 +} + +// 重置时间戳(在组件卸载时调用) +export function resetTimeDisplay() { + lastTimestamp = null +} diff --git a/src/views/pk-mini/Forum.vue b/src/views/pk-mini/Forum.vue new file mode 100644 index 0000000..2db7d31 --- /dev/null +++ b/src/views/pk-mini/Forum.vue @@ -0,0 +1,94 @@ + + + + + diff --git a/src/views/pk-mini/Message.vue b/src/views/pk-mini/Message.vue new file mode 100644 index 0000000..cd45a81 --- /dev/null +++ b/src/views/pk-mini/Message.vue @@ -0,0 +1,346 @@ + + + + + diff --git a/src/views/pk-mini/Mine.vue b/src/views/pk-mini/Mine.vue new file mode 100644 index 0000000..2fcbf34 --- /dev/null +++ b/src/views/pk-mini/Mine.vue @@ -0,0 +1,142 @@ + + + + + diff --git a/src/views/pk-mini/PkHall.vue b/src/views/pk-mini/PkHall.vue new file mode 100644 index 0000000..1e0a682 --- /dev/null +++ b/src/views/pk-mini/PkHall.vue @@ -0,0 +1,865 @@ + + + + + diff --git a/src/views/pk-mini/PkMiniWorkbench.vue b/src/views/pk-mini/PkMiniWorkbench.vue new file mode 100644 index 0000000..26dc00d --- /dev/null +++ b/src/views/pk-mini/PkMiniWorkbench.vue @@ -0,0 +1,107 @@ + + + + +