Explorar el Código

完善监听电话的绑定反馈

chenyidong hace 3 meses
padre
commit
38cd47f257
Se han modificado 4 ficheros con 265 adiciones y 151 borrados
  1. 1 0
      App.vue
  2. 1 1
      pages/clueDetail/tabs/callRecord/index.vue
  3. 29 9
      pages/uploadRecord/index.vue
  4. 234 141
      store/modules/call.js

+ 1 - 0
App.vue

@@ -64,6 +64,7 @@
64 64
 			this.$store.dispatch("call/startPhoneListener");
65 65
 			
66 66
 			this.startKeepLive();
67
+			
67 68
 
68 69
 
69 70
 			// #endif

+ 1 - 1
pages/clueDetail/tabs/callRecord/index.vue

@@ -18,7 +18,7 @@
18 18
 							<uni-icons type="trash" size="20" color="#ff6666"></uni-icons>
19 19
 						</view>
20 20
 					</view>
21
-					<view class="file_name">{{data.fileName}}</view>
21
+					<view class="file_name" v-if="data.type === '3'">{{data.fileName}}</view>
22 22
 					<view class="call_file">
23 23
 						<view class="audio-container">
24 24
 							<audio :src="data.fileUrl" controls ></audio>

+ 29 - 9
pages/uploadRecord/index.vue

@@ -7,6 +7,15 @@
7 7
 		</u-navbar>
8 8
 		<view class="form_wrap">
9 9
 			<u--form labelPosition="left" labelWidth="80" :model="form" :rules="rules" ref="form" class="form_wrap">
10
+				
11
+				<u-form-item label="线索id">
12
+					{{clueDetail && clueDetail.id ? clueDetail.id : "-"}}
13
+				</u-form-item>
14
+				
15
+				<u-form-item label="线索名称">
16
+					{{clueDetail && clueDetail.name ? clueDetail.name : "-"}}
17
+				</u-form-item>
18
+				
10 19
 				<u-form-item label="操作人">
11 20
 					{{userInfo.nickName}}
12 21
 				</u-form-item>
@@ -100,6 +109,7 @@
100 109
 					caller : '',
101 110
 					callee : ''
102 111
 				},
112
+				clueDetail : {},
103 113
 				// 对话框相关状态
104 114
 				showConfirmDialog: false,
105 115
 				selectedFile: {
@@ -113,20 +123,22 @@
113 123
 				const storeFormData = this.storeForm;
114 124
 				this.form = {
115 125
 					...this.form,
116
-					clueId: this.form.clueId, 
117 126
 					caller: storeFormData.caller || '',
118 127
 					callee: storeFormData.callee || '',
119
-					fileUrl: this.form.fileUrl,
120
-					fileName: this.form.fileName,
121
-					remark: this.form.remark,
122
-					type: this.form.type,
123
-					list: this.form.list
128
+					fileUrl: storeFormData.fileUrl,
129
+					fileName: storeFormData.fileName,
130
+					remark: storeFormData.remark,
131
+					type: storeFormData.type,
132
+					list: storeFormData.list
124 133
 				};
134
+				
135
+				uni.$u.api.getClueMainInfoById({id : this.form.clueId}).then(({data})=>{
136
+					this.clueDetail = data;
137
+				})
138
+				
125 139
 				if(!this.form.callee){
126 140
 					// 没有准备被叫号码 直接去查线索的telephone
127
-					uni.$u.api.getClueMainInfoById({id : this.form.clueId}).then(({data})=>{
128
-						this.form.callee = data.telephone;
129
-					})
141
+					this.form.callee = this.clueDetail.telephone;
130 142
 				};
131 143
 				if(!this.form.caller){
132 144
 					// 没有准备主叫号码 直接去尝试获取
@@ -134,6 +146,11 @@
134 146
 						this.form.caller = phone;
135 147
 					})
136 148
 				}
149
+				if(storeFormData.fileUrl){
150
+					// 初始化带了fileUrl 说明是从监听那边跳转的
151
+					this.handleFileChange({ filePath : storeFormData.fileUrl , fileName : storeFormData.fileName });
152
+				}
153
+				this.$store.dispatch("call/resetForm");
137 154
 			},
138 155
 			
139 156
 			handleFileChange(file){
@@ -182,6 +199,9 @@
182 199
 			},
183 200
 			
184 201
 			handleNavSaveClick() {
202
+				if(!this.form.clueId){
203
+					uni.$u.toast("相关线索id为空");
204
+				}
185 205
 				this.$refs.form.validate().then(async () => {
186 206
 					await uni.$u.api.saveClueFile(this.form);
187 207
 					uni.$u.toast("保存成功");

+ 234 - 141
store/modules/call.js

@@ -8,7 +8,9 @@ import {
8 8
 	allRecorderFilesAction
9 9
 } from '@/uni_modules/yao-lister';
10 10
 import permision from "@/js_sdk/wa-permission/permission.js";
11
-import { formatPhoneNumber, simpleDebounce } from '../../utils/util';
11
+import {
12
+	formatPhoneNumber
13
+} from '../../utils/util';
12 14
 
13 15
 export default {
14 16
 	namespaced: true,
@@ -23,12 +25,12 @@ export default {
23 25
 		isPhoneListening: false, // 电话监听状态
24 26
 		form: {
25 27
 			clueId: undefined,
26
-			fileUrl : undefined,
27
-			fileName : undefined,
28
-			type : '3',
29
-			list : [],
30
-			caller : '',
31
-			callee : ''
28
+			fileUrl: undefined,
29
+			fileName: undefined,
30
+			type: '3',
31
+			list: [],
32
+			caller: '',
33
+			callee: ''
32 34
 		},
33 35
 	},
34 36
 	mutations: {
@@ -64,77 +66,109 @@ export default {
64 66
 		},
65 67
 	},
66 68
 	actions: {
67
-		getFileList({dispatch,state, commit}) {
68
-			dispatch("checkStoragePermission").then(()=>{
69
-				if(state.hasStoragePermission){
70
-					allRecorderFilesAction(res => {
71
-						if(res && res.length > 0) {
72
-							// 将文件路径数组转换为包含filePath和fileName的对象数组
73
-							const fileListPromise = res.map(filePath => {
74
-								return new Promise((resolve) => {
75
-									// 从路径中提取文件名
76
-									const fileName = filePath.split('/').pop();
77
-									
78
-									// 获取文件信息,包括创建时间
79
-									plus.io.resolveLocalFileSystemURL(filePath, (entry) => {
80
-										entry.getMetadata((metadata) => {
81
-											resolve({
82
-												filePath: filePath,
83
-												fileName: fileName,
84
-												createTime: metadata.modificationTime ? metadata.modificationTime : 0, // 文件创建时间
85
-											});
86
-										}, (error) => {
87
-											// 如果获取metadata失败,返回基本信息
88
-											resolve({
89
-												filePath: filePath,
90
-												fileName: fileName,
91
-												createTime: 0, // 设为0,排序时会在最前面
69
+		// 获取文件列表 - 返回Promise方式
70
+		getFileList({
71
+			dispatch,
72
+			state,
73
+			commit
74
+		}) {
75
+			return new Promise((resolve, reject) => {
76
+				dispatch("checkStoragePermission").then(() => {
77
+					if (state.hasStoragePermission) {
78
+						allRecorderFilesAction(res => {
79
+							if (res && res.length > 0) {
80
+								// 将文件路径数组转换为包含filePath和fileName的对象数组
81
+								const fileListPromise = res.map(filePath => {
82
+									return new Promise((resolve) => {
83
+										// 从路径中提取文件名
84
+										const fileName = filePath.split('/')
85
+											.pop();
86
+
87
+										// 获取文件信息,包括创建时间
88
+										plus.io.resolveLocalFileSystemURL(
89
+											filePath, (entry) => {
90
+												entry.getMetadata((
91
+													metadata) => {
92
+													resolve({
93
+														filePath: filePath,
94
+														fileName: fileName,
95
+														createTime: metadata
96
+															.modificationTime ?
97
+															metadata
98
+															.modificationTime :
99
+															0, // 文件创建时间
100
+													});
101
+												}, (error) => {
102
+													// 如果获取metadata失败,返回基本信息
103
+													resolve({
104
+														filePath: filePath,
105
+														fileName: fileName,
106
+														createTime: 0, // 设为0,排序时会在最前面
107
+													});
108
+												});
109
+											}, (error) => {
110
+												// 如果解析文件路径失败,返回基本信息
111
+												resolve({
112
+													filePath: filePath,
113
+													fileName: fileName,
114
+													createTime: 0,
115
+													size: 0
116
+												});
92 117
 											});
93
-										});
94
-									}, (error) => {
95
-										// 如果解析文件路径失败,返回基本信息
96
-										resolve({
97
-											filePath: filePath,
98
-											fileName: fileName,
99
-											createTime: 0,
100
-											size: 0
101
-										});
102 118
 									});
103 119
 								});
104
-							});
105
-							
106
-							// 等待所有文件信息获取完成后进行排序
107
-							Promise.all(fileListPromise).then((fileList) => {
108
-								// 按创建时间排序,最新的文件排在前面(降序)
109
-								fileList.sort((a, b) => {
110
-									return b.createTime - a.createTime;
120
+
121
+								// 等待所有文件信息获取完成后进行排序
122
+								Promise.all(fileListPromise).then((fileList) => {
123
+									// 按创建时间排序,最新的文件排在前面(降序)
124
+									fileList.sort((a, b) => {
125
+										return b.createTime - a.createTime;
126
+									});
127
+
128
+									// 提交文件列表到state
129
+									commit('SET_FILE_LIST', {
130
+										data: fileList
131
+									});
132
+									// 返回文件列表
133
+									resolve(fileList);
134
+								}).catch((error) => {
135
+									console.error('获取文件列表失败:', error);
136
+									// 即使排序失败,也尝试提交原始列表
137
+									const fallbackFileList = res.map(filePath => {
138
+										const fileName = filePath.split('/')
139
+											.pop();
140
+										return {
141
+											filePath: filePath,
142
+											fileName: fileName
143
+										};
144
+									});
145
+									commit('SET_FILE_LIST', {
146
+										data: fallbackFileList
147
+									});
148
+									resolve(fallbackFileList);
111 149
 								});
112
-								
113
-								// 提交文件列表到state
114
-								commit('SET_FILE_LIST', { data: fileList });
115
-							}).catch((error) => {
116
-								console.error('获取文件列表失败:', error);
117
-								// 即使排序失败,也尝试提交原始列表
118
-								const fallbackFileList = res.map(filePath => {
119
-									const fileName = filePath.split('/').pop();
120
-									return {
121
-										filePath: filePath,
122
-										fileName: fileName
123
-									};
150
+							} else {
151
+								// 没有文件时返回空数组
152
+								commit('SET_FILE_LIST', {
153
+									data: []
124 154
 								});
125
-								commit('SET_FILE_LIST', { data: fallbackFileList });
126
-							});
127
-						}
128
-					})
129
-				}else{
130
-					dispatch("requestStoragePermission");
131
-				}
132
-			})
133
-			
155
+								resolve([]);
156
+							}
157
+						})
158
+					} else {
159
+						dispatch("requestStoragePermission");
160
+						reject(new Error('没有文件访问权限'));
161
+					}
162
+				}).catch(error => {
163
+					reject(error);
164
+				});
165
+			});
134 166
 		},
135 167
 
136 168
 		// 获取用户手机号码
137
-		getUserPhoneNumber({ commit }) {
169
+		getUserPhoneNumber({
170
+			commit
171
+		}) {
138 172
 			return new Promise((resolve, reject) => {
139 173
 				// 首先检查权限
140 174
 				permision.requestAndroidPermission('android.permission.READ_PHONE_NUMBERS')
@@ -144,41 +178,20 @@ export default {
144 178
 							try {
145 179
 								const main = plus.android.runtimeMainActivity();
146 180
 								const Context = plus.android.importClass('android.content.Context');
147
-								const TelephonyManager = plus.android.importClass('android.telephony.TelephonyManager');
148
-								
181
+								const TelephonyManager = plus.android.importClass(
182
+									'android.telephony.TelephonyManager');
183
+
149 184
 								const telephonyManager = main.getSystemService(Context.TELEPHONY_SERVICE);
150 185
 								const phoneNumber = telephonyManager.getLine1Number();
151
-								
186
+
152 187
 								if (phoneNumber && phoneNumber.trim() !== '') {
153 188
 									// 移除国际区号,保留手机号码
154 189
 									const cleanPhoneNumber = formatPhoneNumber(phoneNumber);
155 190
 									commit('SET_CALLER_PHONE', cleanPhoneNumber);
156 191
 									resolve(cleanPhoneNumber);
157 192
 								} else {
158
-									// 如果获取不到手机号码,尝试使用备选方法
159
-									try {
160
-										const SubscriptionManager = plus.android.importClass('android.telephony.SubscriptionManager');
161
-										const subscriptionManager = main.getSystemService(Context.TELEPHONY_SERVICE);
162
-										const activeSubscriptionInfoList = subscriptionManager.getActiveSubscriptionInfoList();
163
-										
164
-										if (activeSubscriptionInfoList && activeSubscriptionInfoList.size() > 0) {
165
-											const subscriptionInfo = activeSubscriptionInfoList.get(0);
166
-											const number = subscriptionInfo.getNumber();
167
-											if (number && number.trim() !== '') {
168
-												// 移除国际区号,保留手机号码
169
-												const cleanPhoneNumber = formatPhoneNumber(number);
170
-												commit('SET_CALLER_PHONE', cleanPhoneNumber);
171
-												resolve(cleanPhoneNumber);
172
-											} else {
173
-												reject(new Error('无法获取手机号码:SIM卡可能未激活或号码无效'));
174
-											}
175
-										} else {
176
-											reject(new Error('无法获取手机号码:未检测到有效的SIM卡'));
177
-										}
178
-									} catch (fallbackError) {
179
-										console.error('备选方法获取手机号码失败:', fallbackError);
180
-										reject(new Error('无法获取手机号码:设备可能不支持或运营商限制'));
181
-									}
193
+									// 获取不到手机号码
194
+									reject(new Error('无法获取手机号码:设备可能不支持'));
182 195
 								}
183 196
 							} catch (error) {
184 197
 								console.error('获取手机号码失败:', error);
@@ -195,8 +208,24 @@ export default {
195 208
 			});
196 209
 		},
197 210
 
211
+		resetForm({
212
+			commit
213
+		}) {
214
+			commit("SET_FORM", {
215
+				clueId: undefined,
216
+				fileUrl: undefined,
217
+				fileName: undefined,
218
+				type: '3',
219
+				list: [],
220
+				caller: '',
221
+				callee: ''
222
+			})
223
+		},
224
+
198 225
 		// 检查所有权限状态
199
-		checkAllPermissions({ commit }) {
226
+		checkAllPermissions({
227
+			commit
228
+		}) {
200 229
 			return new Promise((resolve, reject) => {
201 230
 				try {
202 231
 					// 检查通话自动录音状态
@@ -208,8 +237,7 @@ export default {
208 237
 						commit('SET_STORAGE_PERMISSION', storagePermission);
209 238
 
210 239
 						// 检查其他权限
211
-						const permissions = [
212
-							{
240
+						const permissions = [{
213 241
 								id: 'android.permission.READ_PHONE_STATE',
214 242
 								mutation: 'SET_READ_PHONE_STATE_PERMISSION'
215 243
 							},
@@ -230,16 +258,19 @@ export default {
230 258
 						const permissionPromises = permissions.map(perm => {
231 259
 							return permision.requestAndroidPermission(perm.id).then(result => {
232 260
 								commit(perm.mutation, result === 1);
233
-								return { id: perm.id, granted: result === 1 };
261
+								return {
262
+									id: perm.id,
263
+									granted: result === 1
264
+								};
234 265
 							});
235 266
 						});
236 267
 
237 268
 						Promise.all(permissionPromises).then(results => {
238
-								resolve({
239
-									autoRecordStatus,
240
-									storagePermission,
241
-									permissions: results
242
-								});
269
+							resolve({
270
+								autoRecordStatus,
271
+								storagePermission,
272
+								permissions: results
273
+							});
243 274
 						});
244 275
 					});
245 276
 				} catch (error) {
@@ -249,7 +280,9 @@ export default {
249 280
 		},
250 281
 
251 282
 		// 检查文件访问权限
252
-		checkStoragePermission({ commit }) {
283
+		checkStoragePermission({
284
+			commit
285
+		}) {
253 286
 			return new Promise((resolve) => {
254 287
 				let hasPermission = false;
255 288
 				try {
@@ -266,13 +299,15 @@ export default {
266 299
 
267 300
 							if (androidVersion >= 11) {
268 301
 								// Android 11及以上版本,使用MANAGE_EXTERNAL_STORAGE权限
269
-								const Environment = plus.android.importClass('android.os.Environment');
302
+								const Environment = plus.android.importClass(
303
+									'android.os.Environment');
270 304
 								hasPermission = Environment.isExternalStorageManager();
271 305
 								commit('SET_STORAGE_PERMISSION', hasPermission);
272 306
 								resolve(hasPermission);
273 307
 							} else {
274 308
 								// Android 11以下版本,使用READ_EXTERNAL_STORAGE权限
275
-								permision.requestAndroidPermission('android.permission.READ_EXTERNAL_STORAGE')
309
+								permision.requestAndroidPermission(
310
+										'android.permission.READ_EXTERNAL_STORAGE')
276 311
 									.then(result => {
277 312
 										hasPermission = result === 1;
278 313
 										commit('SET_STORAGE_PERMISSION', hasPermission);
@@ -310,38 +345,29 @@ export default {
310 345
 		},
311 346
 
312 347
 		// 启动电话监听
313
-		startPhoneListener({ commit, dispatch , state }) {
348
+		startPhoneListener({
349
+			commit,
350
+			dispatch,
351
+			state
352
+		}) {
314 353
 			try {
315
-				if(state.isPhoneListening){
354
+				if (state.isPhoneListening) {
316 355
 					// 已经开启监听就不要了
317 356
 					return;
318 357
 				}
319
-				dispatch("checkAllPermissions").finally(()=>{
358
+				// 用于记录上一个状态,检测通话结束
359
+				let previousState = null;
360
+				dispatch("checkAllPermissions").finally(() => {
320 361
 					startPhoneListener(res => {
321
-						simpleDebounce(()=>{
322
-							// 毕竟重复监听 套一个防抖
323
-							dispatch("handleCallBack");
324
-						},500)
325
-						// 14:44:54.429 空闲状态,  监听结果============================== at store/modules/call.js:324
326
-						
327
-						// 14:47:29.570 state=12== 2 13417106969
328
-						
329
-						// 14:47:29.570 phoneState 通话中
330
-						
331
-						// 14:47:29.571 通话中,  监听结果============================== at store/modules/call.js:324
332
-						
333
-						// 14:47:35.712 state=12== 0 13417106969
334
-						
335
-						// 14:47:35.713 phoneState 空闲状态
336
-						
337
-						// 14:47:35.728 空闲状态,  监听结果============================== at store/modules/call.js:324
338
-						
339
-						// 14:47:36.220 state=12== 0 13417106969
340
-						
341
-						// 14:47:36.220 phoneState 空闲状态
342
-						
343
-						// 14:47:36.220 空闲状态,  监听结果============================== at store/modules/call.js:324
344
-						console.log(res, "监听结果==============================");
362
+						if (state.form.clueId) {
363
+							// 是通过app监听打出去触发;
364
+							dispatch("handleCallBack", {
365
+								currentState: res,
366
+								previousState
367
+							});
368
+						}
369
+						// 更新上一个状态
370
+						previousState = res;
345 371
 						commit('SET_PHONE_LISTENING_STATUS', true);
346 372
 					});
347 373
 				});
@@ -351,14 +377,78 @@ export default {
351 377
 				throw error;
352 378
 			}
353 379
 		},
354
-		handleCallBack(){
355
-			
380
+		handleCallBack({
381
+			dispatch,
382
+			commit,
383
+			state
384
+		}, {
385
+			currentState,
386
+			previousState
387
+		} = {}) {
388
+			if (previousState && currentState) {
389
+				if (previousState === '通话中') {
390
+					if (currentState === '空闲状态') {
391
+						// 延迟一下再获取,确保录音文件已经生成
392
+						setTimeout(() => {
393
+							dispatch('getLatestRecordingFile').then((file) => {
394
+								uni.showModal({
395
+									title: '检测您的拨号行为,是否上传录音?',
396
+									content: '最新一条电话录音:' + file.fileName +",是否前往关联?",
397
+									success: function (res) {
398
+										if (res.confirm) {
399
+											uni.navigateTo({
400
+												url: `/pages/uploadRecord/index?clueId=${state.form.clueId}`
401
+											})
402
+										} else if (res.cancel) {
403
+											dispatch("resetForm");
404
+										}
405
+									}
406
+								});
407
+							}).catch(error => {
408
+								uni.$u.toast('获取录音文件失败:' + error);
409
+							});
410
+						}, 2000); // 延迟1秒获取
411
+					}
412
+				}
413
+			}
414
+		},
415
+
416
+		// 获取最新的录音文件并赋值给form
417
+		getLatestRecordingFile({
418
+			commit,
419
+			state
420
+		}) {
421
+			return new Promise((resolve, reject) => {
422
+				// 获取文件列表 - 使用return Promise的方式
423
+				this.dispatch('call/getFileList').then((fileList) => {
424
+					if (fileList && fileList.length > 0) {
425
+						// 获取最新创建的录音文件(索引0是最新的)
426
+						const latestFile = fileList[0];
427
+
428
+						// 更新form中的fileUrl和fileName
429
+						const updatedForm = {
430
+							...state.form,
431
+							fileUrl: latestFile.filePath,
432
+							fileName: latestFile.fileName
433
+						};
434
+
435
+						commit('SET_FORM', updatedForm);
436
+						resolve(latestFile);
437
+					} else {
438
+						reject(new Error('未找到录音文件'));
439
+					}
440
+				}).catch(error => {
441
+					console.error('获取文件列表失败:', error);
442
+					reject(error);
443
+				});
444
+			});
356 445
 		},
357 446
 		// 停止电话监听
358
-		stopPhoneListener({ commit }) {
447
+		stopPhoneListener({
448
+			commit
449
+		}) {
359 450
 			try {
360 451
 				stopPhoneListener(res => {
361
-					console.log(res, "3123123123");
362 452
 					commit('SET_PHONE_LISTENING_STATUS', false);
363 453
 				});
364 454
 			} catch (error) {
@@ -369,7 +459,10 @@ export default {
369 459
 		},
370 460
 
371 461
 		// 切换电话监听状态
372
-		togglePhoneListener({ state, dispatch }) {
462
+		togglePhoneListener({
463
+			state,
464
+			dispatch
465
+		}) {
373 466
 			if (state.isPhoneListening) {
374 467
 				return dispatch('stopPhoneListener');
375 468
 			} else {