index.vue 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  1. <script setup>
  2. import { useRoute } from 'vue-router';
  3. import { ElMessage } from 'element-plus';
  4. import { workbenchApi } from '@/api/voice/workbench';
  5. import useVoiceStore from "@/store/modules/voice";
  6. import AudioPlayer from '@/components/AudioPlayer';
  7. import CustomRowItem from '@/components/CustomRowItem';
  8. import VoiceToText from '@/components/VoiceToText';
  9. import { watch, watchEffect } from 'vue';
  10. const emit = defineEmits(['onEnd'])
  11. const props = defineProps({
  12. noInit: {
  13. type: Boolean,
  14. default: false
  15. },
  16. data: {
  17. type: Object,
  18. default: () => ({})
  19. }
  20. })
  21. const voiceStore = useVoiceStore();
  22. const route = useRoute();
  23. const audioPlayerRef = ref(null);
  24. const remark = ref('');
  25. const callDetails = ref({});
  26. const dialogVisible = ref(false);
  27. const categoryTypeEnum = {
  28. 0: '人工客服',
  29. 1: '机器人',
  30. 2: '机器人转人工'
  31. }
  32. const typeEnum = {
  33. 0: '白名单',
  34. 1: 'AI客服',
  35. 2: '传统服务'
  36. }
  37. watch(() => props.data, () => {
  38. // console.log("中间层", props.data);
  39. // // times: audioPlayerRef.value.durationTime
  40. // callDetails.value = {...props.data };
  41. })
  42. watchEffect(() => {
  43. // times: audioPlayerRef.value.durationTime
  44. callDetails.value = {...props.data };
  45. })
  46. const durationTime = computed(() => {
  47. const durationTime = audioPlayerRef.value?.durationTime;
  48. return durationTime ? durationTime: '00:00';
  49. })
  50. // 编辑
  51. const handleEdit = () => {
  52. dialogVisible.value = true;
  53. remark.value = callDetails.value.remark;
  54. }
  55. // 弹窗 - 确定
  56. const onDialogConfirm = () => {
  57. const { id } = callDetails.value;
  58. workbenchApi.putCallRecord({ id, remark: remark.value }).then(() => {
  59. dialogVisible.value = false;
  60. callDetails.value.remark = remark.value;
  61. ElMessage({
  62. message: '备注更改成功',
  63. type: 'success',
  64. })
  65. })
  66. }
  67. // 弹窗 - 取消
  68. const onDialogCancel = () => {
  69. dialogVisible.value = false;
  70. remark.value = callDetails.value.remark;
  71. }
  72. // 拨打电话
  73. const onConfirm = () => {
  74. voiceStore.onMakingCall(callDetails.value.phone);
  75. }
  76. // 语音转换文字
  77. const onVoiceParsed = ({ parsedVoiceContent, id }) => {
  78. emit('onEnd', { parsedVoiceContent, id });
  79. }
  80. // onMounted(async () => {
  81. // if (props.noInit) return;
  82. // const { id } = route.query;
  83. // const { data } = await workbenchApi.getCallRecordDetails(id);
  84. // callDetails.value = data;
  85. // });
  86. </script>
  87. <template>
  88. <div class="details-inner">
  89. <el-descriptions title="">
  90. <el-descriptions-item label="呼入分类" label-class-name="custom-label" class-name="custom-colums"
  91. v-if="callDetails.category != 1">
  92. <span class="text-[#FF3636]">{{ typeEnum[callDetails.type] }}</span>
  93. </el-descriptions-item>
  94. <el-descriptions-item label="客服" label-class-name="custom-label" class-name="custom-colums">
  95. {{ callDetails.userName }}
  96. </el-descriptions-item>
  97. <el-descriptions-item label="服务类型" label-class-name="custom-label" class-name="custom-colums">
  98. {{ categoryTypeEnum[callDetails.serviceCategory] }}
  99. </el-descriptions-item>
  100. <el-descriptions-item label="通话发起时间" label-class-name="custom-label" class-name="custom-colums">
  101. {{ callDetails.timeBegin }}
  102. </el-descriptions-item>
  103. <el-descriptions-item label="通话结束时间" label-class-name="custom-label" class-name="custom-colums">
  104. {{ callDetails.timeEnd }}
  105. </el-descriptions-item>
  106. <el-descriptions-item label="通话时长" label-class-name="custom-label" class-name="custom-colums">
  107. <!-- {{ callDetails.times }} -->
  108. {{ durationTime }}
  109. </el-descriptions-item>
  110. <el-descriptions-item label="通话类型" label-class-name="custom-label" class-name="custom-colums">
  111. {{ callDetails.category == 0 ? '呼入' : '呼出' }}
  112. </el-descriptions-item>
  113. <el-descriptions-item label="通话状态" label-class-name="custom-label" class-name="custom-colums">
  114. {{ callDetails.status == 0 ? '未接听' : '已接通' }}
  115. </el-descriptions-item>
  116. <el-descriptions-item label="业务类型" label-class-name="custom-label" class-name="custom-colums"
  117. v-if="callDetails.category != 1">{{ callDetails.bussinessType }}</el-descriptions-item>
  118. <el-descriptions-item label="电话号码" label-class-name="custom-label" class-name="custom-colums">
  119. <div class="inline-block">
  120. <div class="flex items-center space-x-[4px]">
  121. <span>{{ callDetails.phone }}</span>
  122. <el-popconfirm width="250" icon-color="#626AEF" title="请确认,是否呼叫该电话号码?" @confirm="onConfirm">
  123. <template #reference>
  124. <img src="@/assets/images/workbench/icon-call-square.svg" alt="" class="cursor-pointer" v-if="voiceStore.isAuthPane">
  125. </template>
  126. <template #actions="{ confirm, cancel }">
  127. <el-button size="small" @click="cancel">否</el-button>
  128. <el-button type="primary" size="small" @click="confirm">是</el-button>
  129. </template>
  130. </el-popconfirm>
  131. </div>
  132. </div>
  133. </el-descriptions-item>
  134. </el-descriptions>
  135. <custom-row-item label="备注">
  136. <div class="space-x-[14px] flex items-center">
  137. <span class="custom-colums">{{ callDetails.remark ? callDetails.remark : '暂无' }}</span>
  138. <span class="text-[#165DFF] text-[14px] cursor-pointer" @click="handleEdit">编辑</span>
  139. </div>
  140. </custom-row-item>
  141. <custom-row-item label="通话录音" v-if="callDetails.url">
  142. <VoiceToText @on-parsed="onVoiceParsed" :content="callDetails.parsedVoiceContent" :id="callDetails.id">
  143. <AudioPlayer :audioUrl="callDetails.url" ref="audioPlayerRef"></AudioPlayer>
  144. </VoiceToText>
  145. </custom-row-item>
  146. <el-dialog v-model="dialogVisible" title="编辑备注" width="530" modal-class="custom-workbench-dialog" align-center>
  147. <template #header>
  148. <div class="dialog-header">
  149. <h4>编辑备注</h4>
  150. </div>
  151. </template>
  152. <div class="dialog-body">
  153. <el-input type="textarea" :autosize="{ minRows: 6, maxRows: 6 }" resize="none" v-model="remark"></el-input>
  154. </div>
  155. <template #footer>
  156. <div class="dialog-footer space-x-[14px]">
  157. <div class="custom-btn custom-btn_primary" @click="onDialogConfirm">确定</div>
  158. <div class="custom-btn custom-btn_default" @click="onDialogCancel">取消</div>
  159. </div>
  160. </template>
  161. </el-dialog>
  162. </div>
  163. </template>
  164. <style lang="scss" scoped>
  165. .details-inner {
  166. :deep(.custom-label) {
  167. display: inline-block;
  168. width: 84px;
  169. color: #86909C;
  170. box-sizing: border-box;
  171. font-size: 14px;
  172. font-weight: normal;
  173. line-height: 23px;
  174. text-align: left;
  175. }
  176. :deep(.custom-colums) {
  177. font-size: 14px;
  178. color: #1D2129;
  179. }
  180. .record-box {
  181. width: 100%;
  182. padding: 16px;
  183. border-radius: 8px;
  184. background: linear-gradient(90deg, #F6F5F8 0%, #FFF 100%);
  185. .record-play-control {
  186. display: flex;
  187. align-items: center;
  188. padding: 0;
  189. font-size: 14px;
  190. }
  191. .record-play-content {
  192. padding-top: 12px;
  193. color: #4E5969;
  194. font-family: "PingFang SC";
  195. font-size: 13px;
  196. line-height: 20px;
  197. }
  198. }
  199. }
  200. .dialog-footer {
  201. display: flex;
  202. justify-content: center;
  203. }
  204. :deep(.el-textarea__inner) {
  205. background: #f2f4f7;
  206. }
  207. </style>