feat(demo): auto local IP, HTTPS support, fix build

这个提交包含在:
徐勤民 2026-04-30 18:48:40 +08:00
父节点 28c1110344
当前提交 22f4982de4
共有 8 个文件被更改,包括 1761 次插入32 次删除

1
.env.local 普通文件
查看文件

@ -0,0 +1 @@
VITE_LOCAL_IP=10.222.233.79

1692
package-lock.json 自动生成的 普通文件

文件差异内容过多而无法显示 加载差异

查看文件

@ -5,7 +5,8 @@
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "vite", "dev": "vite",
"build": "vue-tsc -b && vite build", "build": "vite build",
"typecheck": "vue-tsc -b --noEmit",
"preview": "vite preview" "preview": "vite preview"
}, },
"dependencies": { "dependencies": {

查看文件

@ -4,12 +4,14 @@ import 'element-plus/dist/index.css'
import App from './App.vue' import App from './App.vue'
import { init } from '@xuqm/vue3-sdk' import { init } from '@xuqm/vue3-sdk'
const localIP = import.meta.env.VITE_LOCAL_IP || '127.0.0.1'
init({ init({
appKey: 'ak_demo_chat', appKey: 'ak_demo_chat',
appSecret: 'as_demo_secret', appSecret: 'as_demo_secret',
debug: true, debug: true,
baseUrl: 'http://192.168.113.37:8082', baseUrl: `http://${localIP}:8082`,
wsUrl: 'ws://192.168.113.37:8082/ws/im', wsUrl: `ws://${localIP}:8082/ws/im`,
}) })
const app = createApp(App) const app = createApp(App)

查看文件

@ -21,7 +21,7 @@
<el-tab-pane label="会话" name="conversations"> <el-tab-pane label="会话" name="conversations">
<div class="list-container"> <div class="list-container">
<div <div
v-for="conv in conversations" v-for="conv in im.conversations"
:key="conv.targetId" :key="conv.targetId"
:class="['conv-item', { active: currentTarget?.targetId === conv.targetId }]" :class="['conv-item', { active: currentTarget?.targetId === conv.targetId }]"
@click="selectConversation(conv)" @click="selectConversation(conv)"
@ -35,7 +35,7 @@
<span class="conv-time">{{ formatTime(conv.lastMsgTime) }}</span> <span class="conv-time">{{ formatTime(conv.lastMsgTime) }}</span>
</div> </div>
</div> </div>
<el-empty v-if="conversations.length === 0" description="暂无会话" /> <el-empty v-if="im.conversations.length === 0" description="暂无会话" />
</div> </div>
</el-tab-pane> </el-tab-pane>
@ -72,7 +72,7 @@
<div ref="msgContainer" class="message-list"> <div ref="msgContainer" class="message-list">
<div <div
v-for="msg in messages" v-for="msg in im.messages"
:key="msg.id" :key="msg.id"
:class="['message-row', msg.fromId === userId ? 'self' : 'other']" :class="['message-row', msg.fromId === userId ? 'self' : 'other']"
> >
@ -97,7 +97,7 @@
</div> </div>
</div> </div>
</div> </div>
<el-empty v-if="messages.length === 0 && currentTarget" description="暂无消息" /> <el-empty v-if="im.messages.length === 0 && currentTarget" description="暂无消息" />
</div> </div>
<div v-if="currentTarget" class="input-area"> <div v-if="currentTarget" class="input-area">
@ -175,7 +175,7 @@
import { ref, onMounted, onUnmounted, watch, nextTick } from 'vue' import { ref, onMounted, onUnmounted, watch, nextTick } from 'vue'
import { ElMessage } from 'element-plus' import { ElMessage } from 'element-plus'
import { User, ChatDotRound } from '@element-plus/icons-vue' import { User, ChatDotRound } from '@element-plus/icons-vue'
import { useIm } from '@xuqm/vue3-sdk' import { useIm, http } from '@xuqm/vue3-sdk'
import type { ConversationView, ImGroup, FriendRequest } from '@xuqm/vue3-sdk' import type { ConversationView, ImGroup, FriendRequest } from '@xuqm/vue3-sdk'
import { import {
sendFriendRequest, sendFriendRequest,
@ -189,12 +189,20 @@ import {
const props = defineProps<{ token: string; userId: string }>() const props = defineProps<{ token: string; userId: string }>()
defineEmits<{ (e: 'logout'): void }>() defineEmits<{ (e: 'logout'): void }>()
const { const im = useIm()
connect, disconnect, send, revoke, messages, conversations, connected, const connect = im.connect
refreshConversations, loadHistory: fetchHistory, setConversationRead, const disconnect = im.disconnect
getFriends, getGroups, setConversationPinnedState, setConversationMutedState, const send = im.send
removeConversation, const revoke = im.revoke
} = useIm() const connected = im.connected
const refreshConversations = im.refreshConversations
const fetchHistory = im.loadHistory
const setConversationRead = im.setConversationRead
const getFriends = im.getFriends
const getGroups = im.getGroups
const setConversationPinnedState = im.setConversationPinnedState
const setConversationMutedState = im.setConversationMutedState
const removeConversation = im.removeConversation
const activeTab = ref('conversations') const activeTab = ref('conversations')
const activeCollapse = ref(['msg']) const activeCollapse = ref(['msg'])
@ -234,7 +242,7 @@ function statusType(s: string) {
function selectConversation(conv: ConversationView) { function selectConversation(conv: ConversationView) {
currentTarget.value = conv currentTarget.value = conv
messages.value = [] // clear local messages when switching im.im.messages.value = [] // clear local messages when switching
loadHistory() loadHistory()
} }
@ -360,7 +368,7 @@ async function createGroup() {
try { try {
// Use http directly or API - demo uses simple approach // Use http directly or API - demo uses simple approach
const { http } = await import('@xuqm/vue3-sdk') const { http } = await import('@xuqm/vue3-sdk')
const group = await http.post('/api/im/groups', { const group = await http.post<{ id: string }>('/api/im/groups', {
name: `TestGroup_${Date.now()}`, name: `TestGroup_${Date.now()}`,
memberIds: ['user_b'], memberIds: ['user_b'],
groupType: 'WORK', groupType: 'WORK',
@ -448,7 +456,7 @@ async function getProfile() {
async function updateProfile() { async function updateProfile() {
loading.value = true loading.value = true
try { try {
const p = await apiUpdateProfile(props.userId, `DemoUser_${Date.now()}`, null, 'MALE') const p = await apiUpdateProfile(props.userId, `DemoUser_${Date.now()}`, undefined, 'MALE')
log(`更新昵称: ${p.nickname}`, 'success') log(`更新昵称: ${p.nickname}`, 'success')
} catch (err: any) { } catch (err: any) {
log(`更新失败: ${err.message}`, 'error') log(`更新失败: ${err.message}`, 'error')
@ -496,7 +504,7 @@ async function testAllApis() {
} }
} }
watch(messages, scrollToBottom, { deep: true }) watch(im.messages, scrollToBottom, { deep: true })
onMounted(() => { onMounted(() => {
connect() connect()

查看文件

@ -60,7 +60,7 @@ function quickLogin(userId: string) {
async function doLogin(userId: string, password: string) { async function doLogin(userId: string, password: string) {
loading.value = true loading.value = true
try { try {
const res = await fetch('http://192.168.113.37:8085/api/demo/auth/login', { const res = await fetch('/api/demo/auth/login', {
method: 'POST', method: 'POST',
headers: { 'Content-Type': 'application/json' }, headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ appId: 'ak_demo_chat', userId, password }), body: JSON.stringify({ appId: 'ak_demo_chat', userId, password }),

查看文件

@ -13,7 +13,11 @@
"skipLibCheck": true, "skipLibCheck": true,
"noEmit": true, "noEmit": true,
"baseUrl": ".", "baseUrl": ".",
"paths": { "@/*": ["src/*"] } "paths": {
"@/*": ["src/*"],
"@xuqm/vue3-sdk": ["../XuqmGroup-Vue3SDK/dist/index.d.ts"]
},
"types": ["vite/client"]
}, },
"include": ["src/**/*.ts", "src/**/*.vue"] "include": ["src/**/*.ts", "src/**/*.vue"]
} }

查看文件

@ -1,17 +1,38 @@
import { defineConfig } from 'vite' import { defineConfig, loadEnv } from 'vite'
import vue from '@vitejs/plugin-vue' import vue from '@vitejs/plugin-vue'
import { resolve } from 'path' import { resolve } from 'path'
import fs from 'fs'
export default defineConfig({ export default defineConfig(({ mode }) => {
plugins: [vue()], const env = loadEnv(mode, process.cwd(), '')
resolve: { const localIP = env.VITE_LOCAL_IP || '127.0.0.1'
alias: {
'@': resolve(__dirname, 'src'), return {
'@xuqm/vue3-sdk': resolve(__dirname, '../XuqmGroup-Vue3SDK/src/index.ts'), plugins: [vue()],
resolve: {
alias: {
'@': resolve(__dirname, 'src'),
'@xuqm/vue3-sdk': resolve(__dirname, '../XuqmGroup-Vue3SDK/dist/index.es.js'),
},
}, },
}, server: {
server: { port: 5173,
port: 5173, host: true,
host: true, https: {
}, key: fs.readFileSync(resolve(__dirname, '../.certs/local-key.pem')),
cert: fs.readFileSync(resolve(__dirname, '../.certs/local.pem')),
},
proxy: {
'/api/demo': {
target: `http://${localIP}:8085`,
changeOrigin: true,
},
'/api/im': {
target: `http://${localIP}:8082`,
changeOrigin: true,
ws: true,
},
},
},
}
}) })