im-ui-mobile 0.0.3 → 0.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +2 -6
- package/src/components/chat-box/index.vue +167 -0
- package/src/components/chat-item/index.vue +105 -0
- package/src/components/chat-message-item/index.vue +129 -0
- package/src/index.ts +38 -0
- package/src/types/index.ts +183 -0
- package/src/types/recorder.ts +21 -0
- package/src/types/user.ts +19 -0
- package/src/utils/auth.ts +32 -0
- package/src/utils/datetime.ts +153 -0
- package/src/utils/emotion.ts +99 -0
- package/src/utils/enums.ts +76 -0
- package/src/utils/env.ts +23 -0
- package/src/utils/eventBus/EventBusImpl.ts +183 -0
- package/src/utils/eventBus/EventCallback.ts +2 -0
- package/src/utils/eventBus/GlobalEventCallback.ts +2 -0
- package/src/utils/eventBus/IEventBus.ts +11 -0
- package/src/utils/eventBus/IEventListener.ts +5 -0
- package/src/utils/eventBus/index.ts +6 -0
- package/src/utils/htmlEscape.ts +148 -0
- package/src/utils/index.ts +15 -0
- package/src/utils/messageType.ts +135 -0
- package/src/utils/recorderApp.ts +110 -0
- package/src/utils/recorderH5.ts +202 -0
- package/src/utils/request.ts +82 -0
- package/src/utils/requestx.ts +92 -0
- package/src/utils/url.ts +23 -0
- package/src/utils/useDynamicRefs.ts +31 -0
- package/src/utils/websocket.ts +248 -0
package/package.json
CHANGED
|
@@ -1,16 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "im-ui-mobile",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.5",
|
|
4
4
|
"description": "A Uniapp instant messaging component library based on Vue3.0+typescript",
|
|
5
5
|
"main": "index.ts",
|
|
6
6
|
"module": "dist/im-ui-mobile.es.js",
|
|
7
7
|
"types": "dist/index.d.ts",
|
|
8
8
|
"files": [
|
|
9
|
-
"
|
|
10
|
-
"index.d.ts",
|
|
11
|
-
"components/",
|
|
12
|
-
"types/",
|
|
13
|
-
"utils/"
|
|
9
|
+
"src/"
|
|
14
10
|
],
|
|
15
11
|
"scripts": {
|
|
16
12
|
"build": "vite build",
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
<!-- packages/chat-box/index.vue -->
|
|
2
|
+
<template>
|
|
3
|
+
<div class="u-im-chat-box">
|
|
4
|
+
<div class="u-im-chat-box__header">
|
|
5
|
+
<div class="u-im-chat-box__title">{{ title }}</div>
|
|
6
|
+
<div class="u-im-chat-box__actions">
|
|
7
|
+
<slot name="header-actions"></slot>
|
|
8
|
+
</div>
|
|
9
|
+
</div>
|
|
10
|
+
|
|
11
|
+
<div class="u-im-chat-box__messages" ref="messagesRef">
|
|
12
|
+
<div class="u-im-chat-box__loading" v-if="loading">
|
|
13
|
+
<u-loading-icon size="24" />
|
|
14
|
+
</div>
|
|
15
|
+
<chat-message-item v-for="(message, index) in messages" :key="message.id || index"
|
|
16
|
+
:position="message.position" :type="message.type" :content="message.content" :avatar="message.avatar"
|
|
17
|
+
:show-avatar="shouldShowAvatar(message, index)" :status="message.status" :duration="message.duration" />
|
|
18
|
+
</div>
|
|
19
|
+
|
|
20
|
+
<div class="u-im-chat-box__input">
|
|
21
|
+
<div class="u-im-chat-box__tools">
|
|
22
|
+
<slot name="input-tools"></slot>
|
|
23
|
+
</div>
|
|
24
|
+
<div class="u-im-chat-box__textarea">
|
|
25
|
+
<u-textarea v-model="inputText" :placeholder="placeholder" :maxlength="maxlength" :auto-height="true"
|
|
26
|
+
@confirm="handleSend" />
|
|
27
|
+
</div>
|
|
28
|
+
<div class="u-im-chat-box__send">
|
|
29
|
+
<u-button type="primary" size="small" @click="handleSend">发送</u-button>
|
|
30
|
+
</div>
|
|
31
|
+
</div>
|
|
32
|
+
</div>
|
|
33
|
+
</template>
|
|
34
|
+
|
|
35
|
+
<script setup lang="ts">
|
|
36
|
+
import { ref, nextTick, watch, onMounted } from 'vue'
|
|
37
|
+
import ChatMessageItem from '../chat-message-item/index.vue'
|
|
38
|
+
|
|
39
|
+
interface Message {
|
|
40
|
+
id?: string | number
|
|
41
|
+
position: 'left' | 'right'
|
|
42
|
+
type: 'text' | 'image' | 'voice' | 'file'
|
|
43
|
+
content: string
|
|
44
|
+
avatar?: string
|
|
45
|
+
status?: 'sending' | 'success' | 'failed'
|
|
46
|
+
duration?: number
|
|
47
|
+
timestamp?: number
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
interface ChatBoxProps {
|
|
51
|
+
title?: string
|
|
52
|
+
messages?: Message[]
|
|
53
|
+
placeholder?: string
|
|
54
|
+
maxlength?: number
|
|
55
|
+
loading?: boolean
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const props = withDefaults(defineProps<ChatBoxProps>(), {
|
|
59
|
+
title: '聊天',
|
|
60
|
+
messages: () => [],
|
|
61
|
+
placeholder: '请输入消息...',
|
|
62
|
+
maxlength: 1000,
|
|
63
|
+
loading: false
|
|
64
|
+
})
|
|
65
|
+
|
|
66
|
+
const emit = defineEmits<{
|
|
67
|
+
send: [message: string]
|
|
68
|
+
loadMore: []
|
|
69
|
+
}>()
|
|
70
|
+
|
|
71
|
+
const inputText = ref('')
|
|
72
|
+
const messagesRef = ref<HTMLElement>()
|
|
73
|
+
|
|
74
|
+
const handleSend = () => {
|
|
75
|
+
if (inputText.value.trim()) {
|
|
76
|
+
emit('send', inputText.value.trim())
|
|
77
|
+
inputText.value = ''
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const shouldShowAvatar = (message: Message, index: number): boolean => {
|
|
82
|
+
if (index === 0) return true
|
|
83
|
+
const prevMessage = props.messages[index - 1]
|
|
84
|
+
if (prevMessage.position !== message.position ||
|
|
85
|
+
prevMessage.avatar !== message.avatar ||
|
|
86
|
+
(message.timestamp && prevMessage.timestamp &&
|
|
87
|
+
message.timestamp - prevMessage.timestamp > 300000)) // 5分钟
|
|
88
|
+
{
|
|
89
|
+
return true
|
|
90
|
+
}
|
|
91
|
+
return false
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const scrollToBottom = () => {
|
|
95
|
+
nextTick(() => {
|
|
96
|
+
if (messagesRef.value) {
|
|
97
|
+
messagesRef.value.scrollTop = messagesRef.value.scrollHeight
|
|
98
|
+
}
|
|
99
|
+
})
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
watch(() => props.messages, () => {
|
|
103
|
+
scrollToBottom()
|
|
104
|
+
}, { deep: true })
|
|
105
|
+
|
|
106
|
+
onMounted(() => {
|
|
107
|
+
scrollToBottom()
|
|
108
|
+
})
|
|
109
|
+
</script>
|
|
110
|
+
|
|
111
|
+
<style scoped>
|
|
112
|
+
.u-im-chat-box {
|
|
113
|
+
display: flex;
|
|
114
|
+
flex-direction: column;
|
|
115
|
+
height: 600px;
|
|
116
|
+
border: 1px solid #e4e7ed;
|
|
117
|
+
border-radius: 8px;
|
|
118
|
+
overflow: hidden;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
.u-im-chat-box__header {
|
|
122
|
+
display: flex;
|
|
123
|
+
justify-content: space-between;
|
|
124
|
+
align-items: center;
|
|
125
|
+
padding: 12px 16px;
|
|
126
|
+
background-color: #f5f7fa;
|
|
127
|
+
border-bottom: 1px solid #e4e7ed;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
.u-im-chat-box__title {
|
|
131
|
+
font-size: 16px;
|
|
132
|
+
font-weight: 500;
|
|
133
|
+
color: #303133;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
.u-im-chat-box__messages {
|
|
137
|
+
flex: 1;
|
|
138
|
+
padding: 16px;
|
|
139
|
+
overflow-y: auto;
|
|
140
|
+
background-color: #fafafa;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
.u-im-chat-box__loading {
|
|
144
|
+
display: flex;
|
|
145
|
+
justify-content: center;
|
|
146
|
+
padding: 16px;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
.u-im-chat-box__input {
|
|
150
|
+
border-top: 1px solid #e4e7ed;
|
|
151
|
+
background-color: #fff;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
.u-im-chat-box__tools {
|
|
155
|
+
padding: 8px 16px;
|
|
156
|
+
border-bottom: 1px solid #e4e7ed;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
.u-im-chat-box__textarea {
|
|
160
|
+
padding: 12px 16px;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
.u-im-chat-box__send {
|
|
164
|
+
padding: 0 16px 12px;
|
|
165
|
+
text-align: right;
|
|
166
|
+
}
|
|
167
|
+
</style>
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
<!-- packages/chat-item/index.vue -->
|
|
2
|
+
<template>
|
|
3
|
+
<div class="u-im-chat-item" :class="[`u-im-chat-item--${type}`]" @click="handleClick">
|
|
4
|
+
<div class="u-im-chat-item__avatar">
|
|
5
|
+
<u-avatar :src="avatar" size="40" />
|
|
6
|
+
</div>
|
|
7
|
+
<div class="u-im-chat-item__content">
|
|
8
|
+
<div class="u-im-chat-item__header">
|
|
9
|
+
<span class="u-im-chat-item__name">{{ name }}</span>
|
|
10
|
+
<span class="u-im-chat-item__time">{{ time }}</span>
|
|
11
|
+
</div>
|
|
12
|
+
<div class="u-im-chat-item__message">
|
|
13
|
+
<span class="u-im-chat-item__text">{{ lastMessage }}</span>
|
|
14
|
+
<u-badge v-if="unreadCount > 0" :value="unreadCount" max="99" class="u-im-chat-item__badge" />
|
|
15
|
+
</div>
|
|
16
|
+
</div>
|
|
17
|
+
</div>
|
|
18
|
+
</template>
|
|
19
|
+
|
|
20
|
+
<script setup lang="ts">
|
|
21
|
+
import { withDefaults } from 'vue'
|
|
22
|
+
|
|
23
|
+
interface ChatItemProps {
|
|
24
|
+
type?: 'default' | 'group'
|
|
25
|
+
avatar?: string
|
|
26
|
+
name: string
|
|
27
|
+
time: string
|
|
28
|
+
lastMessage: string
|
|
29
|
+
unreadCount?: number
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// const props =
|
|
33
|
+
withDefaults(defineProps<ChatItemProps>(), {
|
|
34
|
+
type: 'default',
|
|
35
|
+
avatar: '',
|
|
36
|
+
unreadCount: 0
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
const emit = defineEmits<{
|
|
40
|
+
click: [event: MouseEvent]
|
|
41
|
+
}>()
|
|
42
|
+
|
|
43
|
+
const handleClick = (event: MouseEvent) => {
|
|
44
|
+
emit('click', event)
|
|
45
|
+
}
|
|
46
|
+
</script>
|
|
47
|
+
|
|
48
|
+
<style scoped>
|
|
49
|
+
.u-im-chat-item {
|
|
50
|
+
display: flex;
|
|
51
|
+
padding: 12px 16px;
|
|
52
|
+
cursor: pointer;
|
|
53
|
+
transition: background-color 0.3s;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
.u-im-chat-item:hover {
|
|
57
|
+
background-color: #f5f7fa;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
.u-im-chat-item__avatar {
|
|
61
|
+
margin-right: 12px;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.u-im-chat-item__content {
|
|
65
|
+
flex: 1;
|
|
66
|
+
min-width: 0;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
.u-im-chat-item__header {
|
|
70
|
+
display: flex;
|
|
71
|
+
justify-content: space-between;
|
|
72
|
+
align-items: center;
|
|
73
|
+
margin-bottom: 4px;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
.u-im-chat-item__name {
|
|
77
|
+
font-size: 16px;
|
|
78
|
+
font-weight: 500;
|
|
79
|
+
color: #303133;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
.u-im-chat-item__time {
|
|
83
|
+
font-size: 12px;
|
|
84
|
+
color: #909399;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
.u-im-chat-item__message {
|
|
88
|
+
display: flex;
|
|
89
|
+
justify-content: space-between;
|
|
90
|
+
align-items: center;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
.u-im-chat-item__text {
|
|
94
|
+
font-size: 14px;
|
|
95
|
+
color: #606266;
|
|
96
|
+
overflow: hidden;
|
|
97
|
+
text-overflow: ellipsis;
|
|
98
|
+
white-space: nowrap;
|
|
99
|
+
flex: 1;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
.u-im-chat-item__badge {
|
|
103
|
+
margin-left: 8px;
|
|
104
|
+
}
|
|
105
|
+
</style>
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
<!-- packages/chat-message-item/index.vue -->
|
|
2
|
+
<template>
|
|
3
|
+
<div class="u-im-message-item" :class="[`u-im-message-item--${position}`]">
|
|
4
|
+
<div class="u-im-message-item__avatar" v-if="showAvatar">
|
|
5
|
+
<u-avatar :src="avatar" size="32" />
|
|
6
|
+
</div>
|
|
7
|
+
<div class="u-im-message-item__content">
|
|
8
|
+
<div class="u-im-message-item__bubble" :class="[`u-im-message-item__bubble--${type}`]">
|
|
9
|
+
<div v-if="type === 'text'" class="u-im-message-item__text">
|
|
10
|
+
{{ content }}
|
|
11
|
+
</div>
|
|
12
|
+
<div v-else-if="type === 'image'" class="u-im-message-item__image">
|
|
13
|
+
<u-image :src="content" width="200" height="150" mode="aspectFill" />
|
|
14
|
+
</div>
|
|
15
|
+
<div v-else-if="type === 'voice'" class="u-im-message-item__voice">
|
|
16
|
+
<u-icon name="play-circle" size="20" />
|
|
17
|
+
<span class="u-im-message-item__duration">{{ duration }}''</span>
|
|
18
|
+
</div>
|
|
19
|
+
</div>
|
|
20
|
+
<div class="u-im-message-item__status" v-if="position === 'right'">
|
|
21
|
+
<u-icon v-if="status === 'sending'" name="loading" size="16" color="#909399" />
|
|
22
|
+
<u-icon v-else-if="status === 'success'" name="checkmark" size="16" color="#67C23A" />
|
|
23
|
+
<u-icon v-else-if="status === 'failed'" name="close" size="16" color="#F56C6C" />
|
|
24
|
+
</div>
|
|
25
|
+
</div>
|
|
26
|
+
</div>
|
|
27
|
+
</template>
|
|
28
|
+
|
|
29
|
+
<script setup lang="ts">
|
|
30
|
+
import { withDefaults } from 'vue'
|
|
31
|
+
|
|
32
|
+
type MessageType = 'text' | 'image' | 'voice' | 'file'
|
|
33
|
+
type MessagePosition = 'left' | 'right'
|
|
34
|
+
type MessageStatus = 'sending' | 'success' | 'failed'
|
|
35
|
+
|
|
36
|
+
interface ChatMessageItemProps {
|
|
37
|
+
position?: MessagePosition
|
|
38
|
+
type?: MessageType
|
|
39
|
+
content: string
|
|
40
|
+
avatar?: string
|
|
41
|
+
showAvatar?: boolean
|
|
42
|
+
status?: MessageStatus
|
|
43
|
+
duration?: number
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// const props =
|
|
47
|
+
withDefaults(defineProps<ChatMessageItemProps>(), {
|
|
48
|
+
position: 'left',
|
|
49
|
+
type: 'text',
|
|
50
|
+
showAvatar: true,
|
|
51
|
+
status: 'success',
|
|
52
|
+
duration: 0
|
|
53
|
+
})
|
|
54
|
+
</script>
|
|
55
|
+
|
|
56
|
+
<style scoped>
|
|
57
|
+
.u-im-message-item {
|
|
58
|
+
display: flex;
|
|
59
|
+
margin-bottom: 16px;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.u-im-message-item--left {
|
|
63
|
+
justify-content: flex-start;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
.u-im-message-item--right {
|
|
67
|
+
justify-content: flex-end;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
.u-im-message-item--right .u-im-message-item__content {
|
|
71
|
+
flex-direction: row-reverse;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
.u-im-message-item__avatar {
|
|
75
|
+
margin: 0 8px;
|
|
76
|
+
align-self: flex-end;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
.u-im-message-item__content {
|
|
80
|
+
display: flex;
|
|
81
|
+
align-items: flex-end;
|
|
82
|
+
max-width: 70%;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
.u-im-message-item__bubble {
|
|
86
|
+
padding: 8px 12px;
|
|
87
|
+
border-radius: 8px;
|
|
88
|
+
position: relative;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
.u-im-message-item__bubble--text {
|
|
92
|
+
background-color: #f0f2f5;
|
|
93
|
+
color: #303133;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
.u-im-message-item--right .u-im-message-item__bubble--text {
|
|
97
|
+
background-color: #409eff;
|
|
98
|
+
color: #fff;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
.u-im-message-item__image {
|
|
102
|
+
border-radius: 4px;
|
|
103
|
+
overflow: hidden;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
.u-im-message-item__voice {
|
|
107
|
+
display: flex;
|
|
108
|
+
align-items: center;
|
|
109
|
+
gap: 8px;
|
|
110
|
+
padding: 8px 16px;
|
|
111
|
+
background-color: #f0f2f5;
|
|
112
|
+
border-radius: 16px;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
.u-im-message-item--right .u-im-message-item__voice {
|
|
116
|
+
background-color: #409eff;
|
|
117
|
+
color: #fff;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
.u-im-message-item__duration {
|
|
121
|
+
font-size: 12px;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
.u-im-message-item__status {
|
|
125
|
+
margin: 0 4px;
|
|
126
|
+
display: flex;
|
|
127
|
+
align-items: center;
|
|
128
|
+
}
|
|
129
|
+
</style>
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { App } from 'vue'
|
|
2
|
+
import ChatItem from './components/chat-item/index.vue'
|
|
3
|
+
import ChatMessageItem from './components/chat-message-item/index.vue'
|
|
4
|
+
import ChatBox from './components/chat-box/index.vue'
|
|
5
|
+
|
|
6
|
+
// 导出类型
|
|
7
|
+
export * from './types'
|
|
8
|
+
|
|
9
|
+
// 导出工具函数
|
|
10
|
+
export * from './utils'
|
|
11
|
+
|
|
12
|
+
// 重要:为组件添加名称,以支持开发环境
|
|
13
|
+
ChatItem.name = 'ChatItem'
|
|
14
|
+
ChatMessageItem.name = 'ChatMessageItem'
|
|
15
|
+
ChatBox.name = 'ChatBox'
|
|
16
|
+
|
|
17
|
+
const components = [
|
|
18
|
+
ChatItem,
|
|
19
|
+
ChatMessageItem,
|
|
20
|
+
ChatBox
|
|
21
|
+
]
|
|
22
|
+
|
|
23
|
+
const install = (app: App): void => {
|
|
24
|
+
components.forEach(component => {
|
|
25
|
+
app.component(component.name || '', component)
|
|
26
|
+
})
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export {
|
|
30
|
+
ChatItem,
|
|
31
|
+
ChatMessageItem,
|
|
32
|
+
ChatBox,
|
|
33
|
+
install
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export default {
|
|
37
|
+
install
|
|
38
|
+
}
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import type { RTC_STATE, MESSAGE_TYPE } from '../utils/enums'
|
|
2
|
+
|
|
3
|
+
export * from './user'
|
|
4
|
+
export * from './recorder'
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* 通话模式类型
|
|
8
|
+
*/
|
|
9
|
+
export type RtcMode = 'audio' | 'video' | 'voice'
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* RTC 信息接口
|
|
13
|
+
*/
|
|
14
|
+
export interface RtcInfo {
|
|
15
|
+
friend: Friend
|
|
16
|
+
mode: RtcMode
|
|
17
|
+
state: RTC_STATE
|
|
18
|
+
isHost?: boolean
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* 聊天
|
|
23
|
+
*/
|
|
24
|
+
export interface Chat {
|
|
25
|
+
id?: string | number
|
|
26
|
+
targetId: number
|
|
27
|
+
type: 'PRIVATE' | 'GROUP'
|
|
28
|
+
showName: string
|
|
29
|
+
headImage: string
|
|
30
|
+
isDnd: boolean
|
|
31
|
+
lastContent: string
|
|
32
|
+
lastSendTime?: number
|
|
33
|
+
unreadCount: number
|
|
34
|
+
hotMinIdx: number
|
|
35
|
+
readedMessageIdx: number
|
|
36
|
+
messages: Message[]
|
|
37
|
+
atMe: boolean
|
|
38
|
+
atAll: boolean
|
|
39
|
+
stored: boolean
|
|
40
|
+
delete: boolean
|
|
41
|
+
lastTimeTip?: number
|
|
42
|
+
sendNickName?: string
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* 消息
|
|
47
|
+
*/
|
|
48
|
+
export interface Message {
|
|
49
|
+
id?: number
|
|
50
|
+
tmpId?: number
|
|
51
|
+
type: number
|
|
52
|
+
content: string
|
|
53
|
+
sendTime?: number
|
|
54
|
+
selfSend?: boolean
|
|
55
|
+
status?: number
|
|
56
|
+
sendNickName?: string
|
|
57
|
+
atUserIds?: number[]
|
|
58
|
+
sendId?: number
|
|
59
|
+
recvId?: number
|
|
60
|
+
groupId?: number
|
|
61
|
+
receipt?: boolean
|
|
62
|
+
receiptOk?: boolean
|
|
63
|
+
readedCount?: number
|
|
64
|
+
quoteMessage?: Message
|
|
65
|
+
fileId?: string
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* 好友信息接口
|
|
70
|
+
*/
|
|
71
|
+
export interface Friend {
|
|
72
|
+
id: number
|
|
73
|
+
nickName: string
|
|
74
|
+
headImage?: string
|
|
75
|
+
online: boolean
|
|
76
|
+
onlineWeb: boolean
|
|
77
|
+
onlineApp: boolean
|
|
78
|
+
isDnd: boolean
|
|
79
|
+
deleted?: boolean
|
|
80
|
+
remarkName?: string
|
|
81
|
+
gender?: number
|
|
82
|
+
signature?: string
|
|
83
|
+
remarkNickName?: string
|
|
84
|
+
showNickName?: string
|
|
85
|
+
[key: string]: any
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* 在线终端信息接口
|
|
90
|
+
*/
|
|
91
|
+
export interface OnlineTerminal {
|
|
92
|
+
userId: string | number
|
|
93
|
+
terminals: number[]
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* 菜单项
|
|
98
|
+
*/
|
|
99
|
+
export interface MenuItem {
|
|
100
|
+
key: string
|
|
101
|
+
name: string
|
|
102
|
+
icon?: string
|
|
103
|
+
color?: string
|
|
104
|
+
[key: string]: any
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export interface WebRTCMessage {
|
|
108
|
+
type: number
|
|
109
|
+
content: string
|
|
110
|
+
sendId: number
|
|
111
|
+
selfSend?: boolean
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export interface GroupMember {
|
|
115
|
+
id?: number
|
|
116
|
+
userId: number
|
|
117
|
+
showNickName: string
|
|
118
|
+
headImage?: string
|
|
119
|
+
quit?: boolean
|
|
120
|
+
[key: string]: any
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* 群组信息接口
|
|
125
|
+
*/
|
|
126
|
+
export interface Group {
|
|
127
|
+
id: number
|
|
128
|
+
ownerId: number
|
|
129
|
+
isBanned?: boolean
|
|
130
|
+
reason?: string
|
|
131
|
+
name: string
|
|
132
|
+
headImage: string
|
|
133
|
+
isDnd: boolean
|
|
134
|
+
quit?: boolean
|
|
135
|
+
topMessage?: string
|
|
136
|
+
memberCount?: number
|
|
137
|
+
createTime?: number
|
|
138
|
+
showGroupName: string
|
|
139
|
+
headImageThumb?: string
|
|
140
|
+
remarkGroupName?: string
|
|
141
|
+
remarkNickName?: string
|
|
142
|
+
notice?: string
|
|
143
|
+
[key: string]: any
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* 上传图片相应数据
|
|
148
|
+
*/
|
|
149
|
+
export interface UploadImageResponse {
|
|
150
|
+
originUrl: string
|
|
151
|
+
thumbUrl: string
|
|
152
|
+
[key: string]: any
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* 发送消息项
|
|
157
|
+
*/
|
|
158
|
+
export interface SubmitItem {
|
|
159
|
+
type: MESSAGE_TYPE // 'text' | 'image' | 'file'
|
|
160
|
+
content: string | ImageItem | FileItem
|
|
161
|
+
atUserIds?: number[]
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
export interface ImageItem {
|
|
165
|
+
fileId: number
|
|
166
|
+
file: File
|
|
167
|
+
url: string
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
export interface FileItem {
|
|
171
|
+
fileId: number
|
|
172
|
+
file: File
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
export interface ApiResponse<T = any> {
|
|
176
|
+
data?: T
|
|
177
|
+
code?: number
|
|
178
|
+
message?: string
|
|
179
|
+
success?: boolean
|
|
180
|
+
timestamp?: number
|
|
181
|
+
path?: string
|
|
182
|
+
}
|
|
183
|
+
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// -----------------------------
|
|
2
|
+
// Recorder
|
|
3
|
+
// -----------------------------
|
|
4
|
+
export interface RecorderError {
|
|
5
|
+
errMsg: string;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export interface UploadRecorderFileResponse {
|
|
9
|
+
code: number;
|
|
10
|
+
data: string;
|
|
11
|
+
message?: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface UploadRecorderFileResult {
|
|
15
|
+
duration: number;
|
|
16
|
+
url: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface RecorderFile {
|
|
20
|
+
tempFilePath: string;
|
|
21
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 用户信息接口
|
|
3
|
+
*/
|
|
4
|
+
export interface UserInfo {
|
|
5
|
+
id: number
|
|
6
|
+
nickName: string
|
|
7
|
+
headImage: string
|
|
8
|
+
headImageThumb?: string
|
|
9
|
+
email?: string
|
|
10
|
+
phone?: string
|
|
11
|
+
gender?: number
|
|
12
|
+
signature?: string
|
|
13
|
+
isBanned?: boolean
|
|
14
|
+
reason?: string
|
|
15
|
+
userName?: string
|
|
16
|
+
sex?: number
|
|
17
|
+
online?: boolean
|
|
18
|
+
[key: string]: any
|
|
19
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export const setToken = (value: string) => {
|
|
2
|
+
uni.setStorageSync("accessToken", value);
|
|
3
|
+
};
|
|
4
|
+
|
|
5
|
+
export const getToken = (): string => {
|
|
6
|
+
return uni.getStorageSync("accessToken") || "";
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export const setRefreshToken = (value: string) => {
|
|
10
|
+
uni.setStorageSync("refreshToken", value);
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export const getRefreshToken = (): string => {
|
|
14
|
+
return uni.getStorageSync("refreshToken") || "";
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export const clearToken = () => {
|
|
18
|
+
uni.removeStorageSync("accessToken");
|
|
19
|
+
uni.removeStorageSync("refreshToken");
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export const setAuth = (data: any) => {
|
|
23
|
+
setToken(data.accessToken)
|
|
24
|
+
setRefreshToken(data.refreshToken)
|
|
25
|
+
uni.setStorageSync('expired', +new Date() + Number(data.expiresIn) * 60 * 60)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export const isAuthed = () => {
|
|
29
|
+
const expired = uni.getStorageSync('expired')
|
|
30
|
+
const token = getToken()
|
|
31
|
+
return !(!expired || expired < +new Date() || !token)
|
|
32
|
+
}
|