暂存
This commit is contained in:
parent
dcad444645
commit
aab593f281
@ -8,7 +8,11 @@
|
||||
"pages": [
|
||||
{
|
||||
"path": "pages/index/index",
|
||||
"type": "page"
|
||||
"type": "page",
|
||||
"style": {
|
||||
"navigationStyle": "custom",
|
||||
"enablePullDownRefresh":false
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
|
@ -1,17 +1,111 @@
|
||||
<template>
|
||||
<div class="outer-layer">
|
||||
<div>
|
||||
<tm-navbar :hideBack="false" hideHome :title="123"> </tm-navbar>
|
||||
</div>
|
||||
<div class="root">
|
||||
<div class="searchRoot">
|
||||
<tm-input placeholder="请输入…" color="#F9F9FD" :round="1" prefix="tmicon-search" prefixColor="#46299D" ></tm-input>
|
||||
</div>
|
||||
<div class="contentRoot">
|
||||
<div class="chatItem" >
|
||||
<div class="avatarImg">
|
||||
<tm-image preview :width="96" :height="96" :src="userInfo.Avatar"></tm-image>
|
||||
</div>
|
||||
<div class="chatInfo" >
|
||||
<div class="chatInfo_1" >
|
||||
<div class="flex items-center">
|
||||
<div class="text-[#000000] text-[32rpx] font-bold opacity-90" >泰丰国际(600)</div>
|
||||
<div>
|
||||
<div class="companyTag" >公司</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-[#000000] text-[28rpx] font-medium opacity-26" >12:00</div>
|
||||
</div>
|
||||
<div class="chatInfo_2 w-full mr-[6rpx]">
|
||||
<div class="w-full chatInfo_2_1 textEllipsis" >欢迎加入欢迎加入欢迎加入欢迎加入欢迎加入欢迎加入欢迎加入欢迎加入</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
import XTabbar from "@/components/x-tabbar/index.vue"
|
||||
import { tabbar } from '@/config/tabbar/index.js'
|
||||
import {useStatus} from "@/store/status"
|
||||
import { useChatList } from "@/store/chatList/index.js";
|
||||
import {useAuth} from "@/store/auth";
|
||||
|
||||
const {tabBarIndex}= useStatus()
|
||||
const {userInfo}=useAuth()
|
||||
|
||||
</script>
|
||||
<template>
|
||||
<div class="flex flex-col h-[100vh]" >
|
||||
|
||||
123
|
||||
</div>
|
||||
</template>
|
||||
<style scoped lang="scss">
|
||||
.outer-layer {
|
||||
overflow-y: auto;
|
||||
flex: 1;
|
||||
background-image: url("@/static/image/clockIn/z3280@3x.png");
|
||||
background-size: cover;
|
||||
padding: 0 32rpx 20rpx 32rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.root {
|
||||
flex: 1;
|
||||
padding: 20rpx 0;
|
||||
}
|
||||
.searchRoot {
|
||||
background-color: #fff;
|
||||
padding: 22rpx 18rpx;
|
||||
}
|
||||
.contentRoot {
|
||||
margin-top: 20rpx;
|
||||
background-color: #fff;
|
||||
}
|
||||
.chatItem{
|
||||
width: 100%;
|
||||
padding: 30rpx 16rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.avatarImg{
|
||||
height: 96rpx;
|
||||
width: 96rpx;
|
||||
}
|
||||
.chatInfo{
|
||||
flex:1;
|
||||
margin-left: 20rpx;
|
||||
}
|
||||
.chatInfo_1{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.chatInfo_2{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-top: 6rpx;
|
||||
}
|
||||
.chatInfo_2_1{
|
||||
font-size: 28rpx;
|
||||
color: #000000;
|
||||
opacity: 40%;
|
||||
|
||||
}
|
||||
.companyTag{
|
||||
width: 76rpx;
|
||||
height: 38rpx;
|
||||
border: 1px solid #7A58DE;
|
||||
font-size: 24rpx;
|
||||
text-align: center;
|
||||
border-radius: 6rpx;
|
||||
color: #7A58DE;
|
||||
font-weight: bold;
|
||||
}
|
||||
.textEllipsis {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 1;
|
||||
-webkit-box-orient: vertical;
|
||||
}
|
||||
</style>
|
||||
|
163
src/plugins/websocket.ts
Normal file
163
src/plugins/websocket.ts
Normal file
@ -0,0 +1,163 @@
|
||||
const cache = new Set()
|
||||
|
||||
const maxAttempts = 100
|
||||
|
||||
const defaultEvent = {
|
||||
onError: (evt: any) => console.error('WebSocket Error:', evt),
|
||||
onOpen: (evt: any) => console.log('WebSocket Opened:', evt),
|
||||
onClose: (evt: any) => console.log('WebSocket Closed:', evt)
|
||||
}
|
||||
|
||||
class WsSocket {
|
||||
connect: WebSocket | null = null
|
||||
|
||||
config: any = {
|
||||
heartbeat: {
|
||||
setInterval: null,
|
||||
pingInterval: 20000,
|
||||
pingTimeout: 60000
|
||||
},
|
||||
reconnect: {
|
||||
lockReconnect: false,
|
||||
setTimeout: null,
|
||||
interval: [2000, 2500, 3000, 3000, 5000, 8000], // Exponential backoff
|
||||
attempts: maxAttempts
|
||||
}
|
||||
}
|
||||
|
||||
lastTime: number = 0
|
||||
|
||||
onCallBacks: Record<string, Function> = {}
|
||||
|
||||
defaultEvent: Record<string, Function> = defaultEvent
|
||||
|
||||
constructor(
|
||||
private urlCallBack: () => string,
|
||||
private events: Partial<typeof defaultEvent>
|
||||
) {
|
||||
this.events = { ...this.defaultEvent, ...events }
|
||||
}
|
||||
|
||||
on(event: string, callback: Function): this {
|
||||
this.onCallBacks[event] = callback
|
||||
return this
|
||||
}
|
||||
|
||||
loadSocket(): void {
|
||||
this.connect = new WebSocket(this.urlCallBack())
|
||||
this.connect.onerror = this.onError.bind(this)
|
||||
this.connect.onopen = this.onOpen.bind(this)
|
||||
this.connect.onmessage = this.onMessage.bind(this)
|
||||
this.connect.onclose = this.onClose.bind(this)
|
||||
}
|
||||
|
||||
connection(): void {
|
||||
this.connect === null && this.loadSocket()
|
||||
}
|
||||
|
||||
reconnect(): void {
|
||||
if (this.config.reconnect.lockReconnect || this.config.reconnect.attempts <= 0) return
|
||||
|
||||
this.config.reconnect.lockReconnect = true
|
||||
this.config.reconnect.attempts--
|
||||
|
||||
const delay = this.config.reconnect.interval.shift()
|
||||
|
||||
this.config.reconnect.setTimeout = setTimeout(() => {
|
||||
console.log(new Date().toLocaleString(), 'Attempting to reconnect to WebSocket...')
|
||||
this.connection()
|
||||
}, delay || 10000)
|
||||
}
|
||||
|
||||
onParse(evt: MessageEvent): any {
|
||||
return JSON.parse(evt.data)
|
||||
}
|
||||
|
||||
onOpen(evt: Event): void {
|
||||
this.lastTime = Date.now()
|
||||
|
||||
this.events.onOpen?.(evt)
|
||||
|
||||
this.config.reconnect.interval = [1000, 1000, 3000, 5000, 10000]
|
||||
this.config.reconnect.lockReconnect = false
|
||||
this.config.reconnect.attempts = maxAttempts
|
||||
|
||||
this.heartbeat()
|
||||
}
|
||||
|
||||
onClose(evt: CloseEvent): void {
|
||||
this.events.onClose?.(evt)
|
||||
this.connect = null
|
||||
|
||||
this.config.heartbeat.setInterval && clearInterval(this.config.heartbeat.setInterval)
|
||||
|
||||
this.config.reconnect.lockReconnect = false
|
||||
|
||||
if (evt.code !== 1000) {
|
||||
this.reconnect()
|
||||
}
|
||||
}
|
||||
|
||||
onError(evt: Event): void {
|
||||
this.events.onError?.(evt)
|
||||
}
|
||||
|
||||
onMessage(evt: MessageEvent): void {
|
||||
this.lastTime = Date.now()
|
||||
|
||||
const data = this.onParse(evt)
|
||||
|
||||
if (data.event === 'pong') {
|
||||
return
|
||||
}
|
||||
|
||||
if (data.ackid) {
|
||||
this.connect?.send(`{"event":"ack","ackid":"${data.ackid}"}`)
|
||||
|
||||
if (cache.has(data.ackid)) return
|
||||
|
||||
cache.add(data.ackid)
|
||||
}
|
||||
|
||||
if (this.onCallBacks[data.event]) {
|
||||
this.onCallBacks[data.event](data.payload, evt.data)
|
||||
} else {
|
||||
console.warn(`WsSocket message event [${data.event}] not bound...`)
|
||||
}
|
||||
}
|
||||
|
||||
heartbeat(): void {
|
||||
this.config.heartbeat.setInterval && clearInterval(this.config.heartbeat.setInterval)
|
||||
|
||||
this.config.heartbeat.setInterval = setInterval(() => {
|
||||
this.ping()
|
||||
}, this.config.heartbeat.pingInterval)
|
||||
}
|
||||
|
||||
ping(): void {
|
||||
this.connect?.send(JSON.stringify({ event: 'ping' }))
|
||||
}
|
||||
|
||||
send(message: any): void {
|
||||
if (this.connect && this.connect.readyState === WebSocket.OPEN) {
|
||||
this.connect.send(typeof message === 'string' ? message : JSON.stringify(message))
|
||||
} else {
|
||||
alert('WebSocket 连接已关闭')
|
||||
}
|
||||
}
|
||||
|
||||
close(): void {
|
||||
this.connect?.close()
|
||||
this.config.heartbeat.setInterval && clearInterval(this.config.heartbeat.setInterval)
|
||||
}
|
||||
|
||||
emit(event: string, payload: any): void {
|
||||
if (this.connect && this.connect.readyState === WebSocket.OPEN) {
|
||||
this.connect.send(JSON.stringify({ event, payload }))
|
||||
} else {
|
||||
console.error('WebSocket connection closed...', this.connect)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default WsSocket
|
BIN
src/static/image/chatList/zu4989@2x.png
Normal file
BIN
src/static/image/chatList/zu4989@2x.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.2 KiB |
BIN
src/static/image/chatList/zu4991@2x.png
Normal file
BIN
src/static/image/chatList/zu4991@2x.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.6 KiB |
BIN
src/static/image/chatList/zu4992@2x.png
Normal file
BIN
src/static/image/chatList/zu4992@2x.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.1 KiB |
BIN
src/static/image/chatList/zu5296@2x.png
Normal file
BIN
src/static/image/chatList/zu5296@2x.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.0 KiB |
@ -7,12 +7,38 @@ export const useAuth = createGlobalState(() => {
|
||||
const refreshToken = useStorage('refreshToken', '', uniStorage)
|
||||
const userInfo = useStorage('userInfo', {}, uniStorage)
|
||||
const leaderList = useStorage('leaderList', [], uniStorage)
|
||||
const myCompany = useStorage('myCompany','', uniStorage)
|
||||
const isLeader=ref(false)
|
||||
// const leaderList=ref([])
|
||||
const getUserInfo=async ()=>{
|
||||
const data={
|
||||
ID:userInfo.value.ID
|
||||
}
|
||||
const res= await userInfoApi(data)
|
||||
if (res.status===0){
|
||||
userInfo.value=res.data
|
||||
}
|
||||
}
|
||||
const getUserLeader=async ()=>{
|
||||
const data={
|
||||
departmentId:userInfo.value.PositionUsers?.map(x=>x.DepartmentId)
|
||||
}
|
||||
|
||||
const res= await userLeaderApi(data)
|
||||
if (res.status===0){
|
||||
isLeader.value=!!res.data.departmentLeaders?.find((x) => {
|
||||
return x.userID === userInfo.value.ID
|
||||
})
|
||||
leaderList.value=res.data.departmentLeaders
|
||||
myCompany.value=res.data.company
|
||||
}
|
||||
|
||||
}
|
||||
return {
|
||||
leaderList,
|
||||
|
||||
myCompany,
|
||||
getUserLeader,
|
||||
getUserInfo,
|
||||
userInfo,
|
||||
token,
|
||||
refreshToken,
|
||||
|
20
src/store/chatList/index.js
Normal file
20
src/store/chatList/index.js
Normal file
@ -0,0 +1,20 @@
|
||||
import {createGlobalState,useStorage} from '@vueuse/core'
|
||||
import {uniStorage} from "@/utils/uniStorage.js"
|
||||
|
||||
import {ref} from 'vue'
|
||||
export const useChatList = createGlobalState(() => {
|
||||
// const token = useStorage('token', '', uniStorage)
|
||||
// const refreshToken = useStorage('refreshToken', '', uniStorage)
|
||||
// const userInfo = useStorage('userInfo', {}, uniStorage)
|
||||
// const leaderList = useStorage('leaderList', [], uniStorage)
|
||||
// const isLeader=ref(false)
|
||||
// const leaderList=ref([])
|
||||
|
||||
return {
|
||||
// leaderList,
|
||||
|
||||
// userInfo,
|
||||
// token,
|
||||
// refreshToken,
|
||||
}
|
||||
})
|
Loading…
Reference in New Issue
Block a user