im-ui-mobile 0.0.48 → 0.0.49
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/components/im-chat-item/im-chat-item.vue +5 -5
- package/components/im-chat-message-item/im-chat-message-item.vue +7 -7
- package/components/im-chat-record/im-chat-record.vue +2 -2
- package/libs/index.ts +1 -1
- package/package.json +1 -1
- package/types/index.d.ts +0 -5
- package/utils/auth.ts +0 -32
- package/utils/datetime.ts +0 -153
- package/utils/dom.ts +0 -148
- package/utils/emoji.ts +0 -99
- package/utils/enums.ts +0 -76
- package/utils/env.ts +0 -23
- package/utils/messageType.ts +0 -135
- package/utils/recorderApp.ts +0 -110
- package/utils/recorderH5.ts +0 -172
- package/utils/requester.ts +0 -88
- package/utils/url.ts +0 -23
- package/utils/useDynamicRefs.ts +0 -31
- package/utils/websocket.ts +0 -248
package/utils/messageType.ts
DELETED
|
@@ -1,135 +0,0 @@
|
|
|
1
|
-
// 消息类型
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* 消息类型枚举
|
|
5
|
-
* 消息类型范围
|
|
6
|
-
*/
|
|
7
|
-
export enum MessageTypeRange {
|
|
8
|
-
NORMAL_MIN = 0,
|
|
9
|
-
NORMAL_MAX = 9,
|
|
10
|
-
STATUS_MIN = 10,
|
|
11
|
-
STATUS_MAX = 19,
|
|
12
|
-
TIP_MIN = 20,
|
|
13
|
-
TIP_MAX = 29,
|
|
14
|
-
ACTION_MIN = 40,
|
|
15
|
-
ACTION_MAX = 49,
|
|
16
|
-
RTC_PRIVATE_MIN = 100,
|
|
17
|
-
RTC_PRIVATE_MAX = 199,
|
|
18
|
-
RTC_GROUP_MIN = 200,
|
|
19
|
-
RTC_GROUP_MAX = 299
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* 是否普通消息
|
|
24
|
-
* @param type - 消息类型
|
|
25
|
-
* @returns 是否是普通消息
|
|
26
|
-
*/
|
|
27
|
-
const isNormal = (type: number): boolean => {
|
|
28
|
-
return type >= MessageTypeRange.NORMAL_MIN && type <= MessageTypeRange.NORMAL_MAX;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* 是否状态消息
|
|
33
|
-
* @param type - 消息类型
|
|
34
|
-
* @returns 是否是状态消息
|
|
35
|
-
*/
|
|
36
|
-
const isStatus = (type: number): boolean => {
|
|
37
|
-
return type >= MessageTypeRange.STATUS_MIN && type <= MessageTypeRange.STATUS_MAX;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* 是否提示消息
|
|
42
|
-
* @param type - 消息类型
|
|
43
|
-
* @returns 是否是提示消息
|
|
44
|
-
*/
|
|
45
|
-
const isTip = (type: number): boolean => {
|
|
46
|
-
return type >= MessageTypeRange.TIP_MIN && type <= MessageTypeRange.TIP_MAX;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* 是否操作交互类消息
|
|
51
|
-
* @param type - 消息类型
|
|
52
|
-
* @returns 是否是操作交互类消息
|
|
53
|
-
*/
|
|
54
|
-
const isAction = (type: number): boolean => {
|
|
55
|
-
return type >= MessageTypeRange.ACTION_MIN && type <= MessageTypeRange.ACTION_MAX;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
/**
|
|
59
|
-
* 是否单人通话信令
|
|
60
|
-
* @param type - 消息类型
|
|
61
|
-
* @returns 是否是单人通话信令
|
|
62
|
-
*/
|
|
63
|
-
const isRtcPrivate = (type: number): boolean => {
|
|
64
|
-
return type >= MessageTypeRange.RTC_PRIVATE_MIN && type <= MessageTypeRange.RTC_PRIVATE_MAX;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
/**
|
|
68
|
-
* 是否多人通话信令
|
|
69
|
-
* @param type - 消息类型
|
|
70
|
-
* @returns 是否是多人通话信令
|
|
71
|
-
*/
|
|
72
|
-
const isRtcGroup = (type: number): boolean => {
|
|
73
|
-
return type >= MessageTypeRange.RTC_GROUP_MIN && type <= MessageTypeRange.RTC_GROUP_MAX;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
/**
|
|
77
|
-
* 获取消息类型分类
|
|
78
|
-
* @param type - 消息类型
|
|
79
|
-
* @returns 消息类型分类名称
|
|
80
|
-
*/
|
|
81
|
-
const getMessageCategory = (type: number): string => {
|
|
82
|
-
if (isNormal(type)) return 'normal';
|
|
83
|
-
if (isStatus(type)) return 'status';
|
|
84
|
-
if (isTip(type)) return 'tip';
|
|
85
|
-
if (isAction(type)) return 'action';
|
|
86
|
-
if (isRtcPrivate(type)) return 'rtc_private';
|
|
87
|
-
if (isRtcGroup(type)) return 'rtc_group';
|
|
88
|
-
return 'unknown';
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
/**
|
|
92
|
-
* 验证消息类型是否有效
|
|
93
|
-
* @param type - 消息类型
|
|
94
|
-
* @returns 是否是有效的消息类型
|
|
95
|
-
*/
|
|
96
|
-
const isValidMessageType = (type: number): boolean => {
|
|
97
|
-
return isNormal(type) ||
|
|
98
|
-
isStatus(type) ||
|
|
99
|
-
isTip(type) ||
|
|
100
|
-
isAction(type) ||
|
|
101
|
-
isRtcPrivate(type) ||
|
|
102
|
-
isRtcGroup(type);
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
/**
|
|
106
|
-
* 获取所有支持的消息类型范围
|
|
107
|
-
* @returns 消息类型范围描述对象
|
|
108
|
-
*/
|
|
109
|
-
const getMessageTypeRanges = (): Array<{
|
|
110
|
-
category: string;
|
|
111
|
-
min: number;
|
|
112
|
-
max: number;
|
|
113
|
-
description: string;
|
|
114
|
-
}> => {
|
|
115
|
-
return [
|
|
116
|
-
{ category: 'normal', min: MessageTypeRange.NORMAL_MIN, max: MessageTypeRange.NORMAL_MAX, description: '普通消息' },
|
|
117
|
-
{ category: 'status', min: MessageTypeRange.STATUS_MIN, max: MessageTypeRange.STATUS_MAX, description: '状态消息' },
|
|
118
|
-
{ category: 'tip', min: MessageTypeRange.TIP_MIN, max: MessageTypeRange.TIP_MAX, description: '提示消息' },
|
|
119
|
-
{ category: 'action', min: MessageTypeRange.ACTION_MIN, max: MessageTypeRange.ACTION_MAX, description: '操作交互类消息' },
|
|
120
|
-
{ category: 'rtc_private', min: MessageTypeRange.RTC_PRIVATE_MIN, max: MessageTypeRange.RTC_PRIVATE_MAX, description: '单人通话信令' },
|
|
121
|
-
{ category: 'rtc_group', min: MessageTypeRange.RTC_GROUP_MIN, max: MessageTypeRange.RTC_GROUP_MAX, description: '多人通话信令' }
|
|
122
|
-
];
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
export default {
|
|
126
|
-
isNormal,
|
|
127
|
-
isStatus,
|
|
128
|
-
isTip,
|
|
129
|
-
isAction,
|
|
130
|
-
isRtcPrivate,
|
|
131
|
-
isRtcGroup,
|
|
132
|
-
getMessageCategory,
|
|
133
|
-
isValidMessageType,
|
|
134
|
-
getMessageTypeRanges
|
|
135
|
-
};
|
package/utils/recorderApp.ts
DELETED
|
@@ -1,110 +0,0 @@
|
|
|
1
|
-
import type { RecorderError, UploadRecorderFileResult, UploadRecorderFileResponse,RecorderFile } from '../libs'
|
|
2
|
-
import { getToken } from './auth'
|
|
3
|
-
import env from './env'
|
|
4
|
-
|
|
5
|
-
// 获取录音管理器
|
|
6
|
-
const rc = uni.getRecorderManager();
|
|
7
|
-
|
|
8
|
-
// 录音开始时间
|
|
9
|
-
let startTime: Date | null = null;
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* 检查是否支持录音功能
|
|
13
|
-
*/
|
|
14
|
-
const checkIsEnable = (): boolean => {
|
|
15
|
-
// 这里可以添加更详细的兼容性检查
|
|
16
|
-
return true;
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* 开始录音
|
|
21
|
-
*/
|
|
22
|
-
const start = (): Promise<void> => {
|
|
23
|
-
return new Promise((resolve, reject) => {
|
|
24
|
-
// 录音开始回调
|
|
25
|
-
rc.onStart(() => {
|
|
26
|
-
startTime = new Date();
|
|
27
|
-
resolve();
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
// 录音错误回调
|
|
31
|
-
rc.onError((e: RecorderError) => {
|
|
32
|
-
console.log("录音错误:", e);
|
|
33
|
-
reject(e);
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
// 开始录音
|
|
37
|
-
rc.start({
|
|
38
|
-
format: "mp3" as const, // 录音格式,可选值:aac/mp3
|
|
39
|
-
});
|
|
40
|
-
});
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* 停止录音
|
|
45
|
-
*/
|
|
46
|
-
const close = (): void => {
|
|
47
|
-
rc.stop();
|
|
48
|
-
};
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* 上传录音文件
|
|
52
|
-
*/
|
|
53
|
-
const upload = (): Promise<UploadRecorderFileResult> => {
|
|
54
|
-
return new Promise((resolve, reject) => {
|
|
55
|
-
// 录音停止回调
|
|
56
|
-
rc.onStop((wavFile: RecorderFile) => {
|
|
57
|
-
// 检查是否有开始时间
|
|
58
|
-
if (!startTime) {
|
|
59
|
-
reject(new Error("录音开始时间未记录"));
|
|
60
|
-
return;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
// 获取令牌
|
|
64
|
-
const accessToken = getToken();
|
|
65
|
-
if (!accessToken) {
|
|
66
|
-
reject(new Error("未找到访问令牌"));
|
|
67
|
-
return;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
// 上传文件
|
|
71
|
-
uni.uploadFile({
|
|
72
|
-
url: env.BaseApiUrl + "/file/upload",
|
|
73
|
-
header: {
|
|
74
|
-
accessToken: accessToken,
|
|
75
|
-
},
|
|
76
|
-
filePath: wavFile.tempFilePath,
|
|
77
|
-
name: "file",
|
|
78
|
-
success: (res) => {
|
|
79
|
-
try {
|
|
80
|
-
const r: UploadRecorderFileResponse = JSON.parse(res.data);
|
|
81
|
-
|
|
82
|
-
if (r.code !== 200) {
|
|
83
|
-
reject(new Error(r.message || "上传失败"));
|
|
84
|
-
return;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
// 计算录音时长
|
|
88
|
-
const duration =
|
|
89
|
-
(new Date().getTime() - startTime!.getTime()) / 1000;
|
|
90
|
-
|
|
91
|
-
const data: UploadRecorderFileResult = {
|
|
92
|
-
duration: Math.round(duration),
|
|
93
|
-
url: r.data,
|
|
94
|
-
};
|
|
95
|
-
|
|
96
|
-
resolve(data);
|
|
97
|
-
} catch (error) {
|
|
98
|
-
console.error(error);
|
|
99
|
-
reject(new Error("解析响应数据失败"));
|
|
100
|
-
}
|
|
101
|
-
},
|
|
102
|
-
fail: (e) => {
|
|
103
|
-
reject(e);
|
|
104
|
-
},
|
|
105
|
-
});
|
|
106
|
-
});
|
|
107
|
-
});
|
|
108
|
-
};
|
|
109
|
-
|
|
110
|
-
export default { checkIsEnable, start, close, upload };
|
package/utils/recorderH5.ts
DELETED
|
@@ -1,172 +0,0 @@
|
|
|
1
|
-
import type { UploadRecorderFileResult, UploadRecorderFileResponse } from '../libs'
|
|
2
|
-
import { getToken } from './auth'
|
|
3
|
-
import env from './env'
|
|
4
|
-
|
|
5
|
-
// 全局变量声明
|
|
6
|
-
let rc: MediaRecorder | null = null;
|
|
7
|
-
let duration: number = 0;
|
|
8
|
-
let chunks: Blob[] = [];
|
|
9
|
-
let stream: MediaStream | null = null;
|
|
10
|
-
let startTime: number | null = null;
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* 检查是否支持录音功能
|
|
14
|
-
*/
|
|
15
|
-
const checkIsEnable = (): boolean => {
|
|
16
|
-
// 获取当前来源
|
|
17
|
-
const origin = window.location.origin;
|
|
18
|
-
|
|
19
|
-
// 检查 HTTPS 环境
|
|
20
|
-
if (
|
|
21
|
-
origin.indexOf("https") === -1 &&
|
|
22
|
-
origin.indexOf("localhost") === -1 &&
|
|
23
|
-
origin.indexOf("127.0.0.1") === -1
|
|
24
|
-
) {
|
|
25
|
-
uni.showToast({
|
|
26
|
-
title: "请在https环境中使用录音功能",
|
|
27
|
-
icon: "error" as any,
|
|
28
|
-
});
|
|
29
|
-
return false;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
// 检查浏览器支持
|
|
33
|
-
if (!navigator.mediaDevices || !window.MediaRecorder) {
|
|
34
|
-
uni.showToast({
|
|
35
|
-
title: "当前浏览器不支持录音",
|
|
36
|
-
icon: "error" as any,
|
|
37
|
-
});
|
|
38
|
-
return false;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
return true;
|
|
42
|
-
};
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* 开始录音
|
|
46
|
-
*/
|
|
47
|
-
const start = (): Promise<void> => {
|
|
48
|
-
return navigator.mediaDevices
|
|
49
|
-
.getUserMedia({ audio: true })
|
|
50
|
-
.then((audioStream: MediaStream) => {
|
|
51
|
-
startTime = new Date().getTime();
|
|
52
|
-
chunks = [];
|
|
53
|
-
stream = audioStream;
|
|
54
|
-
rc = new MediaRecorder(stream);
|
|
55
|
-
rc.start();
|
|
56
|
-
})
|
|
57
|
-
.catch((error: Error) => {
|
|
58
|
-
console.error("获取麦克风权限失败:", error);
|
|
59
|
-
throw new Error("无法访问麦克风,请检查权限设置");
|
|
60
|
-
});
|
|
61
|
-
};
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
* 停止录音
|
|
65
|
-
*/
|
|
66
|
-
const close = (): void => {
|
|
67
|
-
if (stream) {
|
|
68
|
-
stream.getTracks().forEach((track: MediaStreamTrack) => {
|
|
69
|
-
track.stop();
|
|
70
|
-
});
|
|
71
|
-
stream = null;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
if (rc && rc.state !== "inactive") {
|
|
75
|
-
rc.stop();
|
|
76
|
-
}
|
|
77
|
-
};
|
|
78
|
-
|
|
79
|
-
/**
|
|
80
|
-
* 上传录音文件
|
|
81
|
-
*/
|
|
82
|
-
const upload = (): Promise<UploadRecorderFileResult> => {
|
|
83
|
-
return new Promise((resolve, reject) => {
|
|
84
|
-
if (!rc) {
|
|
85
|
-
reject(new Error("录音未开始"));
|
|
86
|
-
return;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
// 设置数据可用回调
|
|
90
|
-
rc.ondataavailable = (e: BlobEvent) => {
|
|
91
|
-
chunks.push(e.data);
|
|
92
|
-
};
|
|
93
|
-
|
|
94
|
-
// 设置录音停止回调
|
|
95
|
-
rc.onstop = () => {
|
|
96
|
-
try {
|
|
97
|
-
// 检查是否有录音数据
|
|
98
|
-
if (chunks.length === 0 || !chunks[0].size) {
|
|
99
|
-
chunks = [];
|
|
100
|
-
reject(new Error("没有录音数据"));
|
|
101
|
-
return;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
// 计算录音时长
|
|
105
|
-
if (!startTime) {
|
|
106
|
-
reject(new Error("录音开始时间未记录"));
|
|
107
|
-
return;
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
duration = (new Date().getTime() - startTime) / 1000;
|
|
111
|
-
|
|
112
|
-
// 创建 Blob 和 File 对象
|
|
113
|
-
const newBlob = new Blob(chunks, { type: "audio/mpeg" });
|
|
114
|
-
const name = new Date().getTime() + ".mp3"; // 使用时间戳作为文件名
|
|
115
|
-
const file = new File([newBlob], name, { type: "audio/mpeg" });
|
|
116
|
-
|
|
117
|
-
// 获取令牌
|
|
118
|
-
const accessToken = getToken();
|
|
119
|
-
if (!accessToken) {
|
|
120
|
-
reject(new Error("未找到访问令牌"));
|
|
121
|
-
return;
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
// 上传文件
|
|
125
|
-
uni.uploadFile({
|
|
126
|
-
url: env.BaseApiUrl + "/file/upload",
|
|
127
|
-
header: {
|
|
128
|
-
accessToken: accessToken,
|
|
129
|
-
},
|
|
130
|
-
file: file,
|
|
131
|
-
name: "file",
|
|
132
|
-
success: (res) => {
|
|
133
|
-
try {
|
|
134
|
-
const r: UploadRecorderFileResponse = JSON.parse(res.data);
|
|
135
|
-
|
|
136
|
-
if (r.code !== 200) {
|
|
137
|
-
console.log("上传失败:", res);
|
|
138
|
-
reject(new Error(r.message || "上传失败"));
|
|
139
|
-
} else {
|
|
140
|
-
const data: UploadRecorderFileResult = {
|
|
141
|
-
duration: Math.round(duration),
|
|
142
|
-
url: r.data,
|
|
143
|
-
};
|
|
144
|
-
resolve(data);
|
|
145
|
-
}
|
|
146
|
-
} catch (error) {
|
|
147
|
-
console.error(error);
|
|
148
|
-
reject(new Error("解析响应数据失败"));
|
|
149
|
-
}
|
|
150
|
-
},
|
|
151
|
-
fail: (e: any) => {
|
|
152
|
-
reject(new Error(e.errMsg || "上传失败"));
|
|
153
|
-
},
|
|
154
|
-
});
|
|
155
|
-
} catch (error) {
|
|
156
|
-
reject(error);
|
|
157
|
-
} finally {
|
|
158
|
-
// 清理资源
|
|
159
|
-
chunks = [];
|
|
160
|
-
startTime = null;
|
|
161
|
-
rc = null;
|
|
162
|
-
}
|
|
163
|
-
};
|
|
164
|
-
|
|
165
|
-
// 如果录音还在进行中,停止它
|
|
166
|
-
if (rc.state === "recording") {
|
|
167
|
-
rc.stop();
|
|
168
|
-
}
|
|
169
|
-
});
|
|
170
|
-
};
|
|
171
|
-
|
|
172
|
-
export default { checkIsEnable, start, close, upload };
|
package/utils/requester.ts
DELETED
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
import type { Response } from '../libs/index'
|
|
2
|
-
import { getToken, clearToken } from './auth'
|
|
3
|
-
|
|
4
|
-
export default class Requester {
|
|
5
|
-
private baseURL: string
|
|
6
|
-
private options: UniApp.RequestOptions
|
|
7
|
-
private timeout: number
|
|
8
|
-
private headers: Record<string, string>
|
|
9
|
-
private accessToken: string = getToken()
|
|
10
|
-
|
|
11
|
-
constructor(baseURL: string, timeout = 10000, options: Partial<UniApp.RequestOptions> = {} as Partial<UniApp.RequestOptions>) {
|
|
12
|
-
this.baseURL = baseURL
|
|
13
|
-
this.options = options as UniApp.RequestOptions
|
|
14
|
-
this.timeout = timeout
|
|
15
|
-
this.headers = {
|
|
16
|
-
'Content-Type': 'application/json',
|
|
17
|
-
'Authorization': `Bearer ${this.accessToken}`,
|
|
18
|
-
'AccessToken': this.accessToken,
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
// 设置 token
|
|
23
|
-
setToken(token: string) {
|
|
24
|
-
this.headers['Authorization'] = `Bearer ${token}`
|
|
25
|
-
this.headers['AccessToken'] = token
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
// 基础请求方法
|
|
29
|
-
async request<T = any>(options: Partial<UniApp.RequestOptions>): Promise<Response<T>> {
|
|
30
|
-
this.options = { ...this.options, ...options }
|
|
31
|
-
this.options.url = this.baseURL + this.options.url
|
|
32
|
-
return new Promise<Response<T>>((resolve, reject) => {
|
|
33
|
-
uni.request({
|
|
34
|
-
timeout: this.timeout,
|
|
35
|
-
header: this.headers,
|
|
36
|
-
...this.options,
|
|
37
|
-
success: (res) => {
|
|
38
|
-
const data = res.data as Response<T>
|
|
39
|
-
data.result = data.result || (res.data as any).data
|
|
40
|
-
|
|
41
|
-
if (data.code >= 200 && data.code < 300) {
|
|
42
|
-
resolve(data)
|
|
43
|
-
} else if ((data).code === 401) {
|
|
44
|
-
// 清除用户信息,提示登录
|
|
45
|
-
uni.showToast({
|
|
46
|
-
icon: 'none',
|
|
47
|
-
title: '请先登录',
|
|
48
|
-
})
|
|
49
|
-
setTimeout(() => {
|
|
50
|
-
clearToken()
|
|
51
|
-
uni.removeStorageSync('expired')
|
|
52
|
-
uni.removeStorageSync("user")
|
|
53
|
-
uni.setStorageSync('keepLoggedIn', false)
|
|
54
|
-
reject(res)
|
|
55
|
-
}, 1000)
|
|
56
|
-
} else {
|
|
57
|
-
uni.showToast({
|
|
58
|
-
icon: 'none',
|
|
59
|
-
title: (data).message || '请求错误',
|
|
60
|
-
})
|
|
61
|
-
console.error('请求错误', res)
|
|
62
|
-
reject(res)
|
|
63
|
-
}
|
|
64
|
-
},
|
|
65
|
-
fail: (err) => {
|
|
66
|
-
reject(err)
|
|
67
|
-
}
|
|
68
|
-
})
|
|
69
|
-
})
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
// 快捷方法
|
|
73
|
-
get<T = any>(url: string, data?: any, options?: Partial<UniApp.RequestOptions>) {
|
|
74
|
-
return this.request<T>({ url, method: 'GET', data, ...options })
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
post<T = any>(url: string, data?: any, options?: Partial<UniApp.RequestOptions>) {
|
|
78
|
-
return this.request<T>({ url, method: 'POST', data, ...options })
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
put<T = any>(url: string, data?: any, options?: Partial<UniApp.RequestOptions>) {
|
|
82
|
-
return this.request<T>({ url, method: 'PUT', data, ...options })
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
delete<T = any>(url: string, data?: any, options?: Partial<UniApp.RequestOptions>) {
|
|
86
|
-
return this.request<T>({ url, method: 'DELETE', data, ...options })
|
|
87
|
-
}
|
|
88
|
-
}
|
package/utils/url.ts
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
// 使用正则表达式匹配更广泛的URL格式(此正则由deepseek生成)
|
|
2
|
-
const regex = /(\b(https?|ftp|file):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|]|\bwww\.[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/ig;
|
|
3
|
-
|
|
4
|
-
const containUrl = (content: string): boolean => {
|
|
5
|
-
return regex.test(content);
|
|
6
|
-
};
|
|
7
|
-
|
|
8
|
-
const replaceURLWithHTMLLinks = (content: string, color: string = ''): string => {
|
|
9
|
-
return content.replace(regex, (url: string) => {
|
|
10
|
-
// 如果URL不以http(s)://开头,则添加http://前缀
|
|
11
|
-
let fullUrl = url;
|
|
12
|
-
if (!url.startsWith("http")) {
|
|
13
|
-
fullUrl = "http://" + url;
|
|
14
|
-
}
|
|
15
|
-
const colorStyle = color ? `color: ${color};` : '';
|
|
16
|
-
return `<a href="${fullUrl}" target="_blank" style="${colorStyle}text-decoration: underline;">${url}</a>`;
|
|
17
|
-
});
|
|
18
|
-
};
|
|
19
|
-
|
|
20
|
-
export default {
|
|
21
|
-
containUrl,
|
|
22
|
-
replaceURLWithHTMLLinks
|
|
23
|
-
};
|
package/utils/useDynamicRefs.ts
DELETED
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import { ref } from 'vue'
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* 使用动态Refs(组合式函数)
|
|
5
|
-
*/
|
|
6
|
-
export function useDynamicRefs<T = any>() {
|
|
7
|
-
const refs = ref(new Map<string, T>());
|
|
8
|
-
|
|
9
|
-
const setRef = (key: string) => (el: T) => {
|
|
10
|
-
if (el) {
|
|
11
|
-
refs.value.set(key, el as any);
|
|
12
|
-
} else {
|
|
13
|
-
refs.value.delete(key);
|
|
14
|
-
}
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
const getRef = (key: string): T | undefined => {
|
|
18
|
-
return refs.value.get(key) as any;
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
const getAllRefs = () => {
|
|
22
|
-
return refs.value;
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
return {
|
|
26
|
-
refs,
|
|
27
|
-
setRef,
|
|
28
|
-
getRef,
|
|
29
|
-
getAllRefs
|
|
30
|
-
};
|
|
31
|
-
}
|