call.js 13 KB

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