Smart-visit-Detail.vue 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. <template>
  2. <el-dialog v-model="state.dialogVisible" width="60%" draggable title="回访明细" append-to-body destroy-on-close @close="close">
  3. <el-form :model="state.queryParams" ref="queryParamsRef" inline @submit.native.prevent>
  4. <el-form-item label="关键词" prop="Keyword">
  5. <el-input v-model="state.queryParams.Keyword" placeholder="工单标题/工单编码" clearable @keyup.enter="handleQuery" />
  6. </el-form-item>
  7. <el-form-item label="任务状态" prop="AiOrderVisitState">
  8. <el-select v-model="state.queryParams.AiOrderVisitState" placeholder="请选择任务状态" @change="handleQuery" clearable>
  9. <el-option v-for="item in aiOrderVisitState" :value="item.key" :key="item.key" :label="item.value" />
  10. </el-select>
  11. </el-form-item>
  12. <el-form-item>
  13. <el-button type="primary" @click="handleQuery" :loading="state.loading"> <SvgIcon name="ele-Search" class="mr5" />查询 </el-button>
  14. <el-button @click="resetQuery(queryParamsRef)" :loading="state.loading" class="default-button">
  15. <SvgIcon name="ele-Refresh" class="mr5" />重置
  16. </el-button>
  17. </el-form-item>
  18. </el-form>
  19. <ProTable
  20. ref="proTableRef"
  21. :columns="columns"
  22. :data="state.tableData"
  23. @updateTable="queryList"
  24. :loading="state.loading"
  25. :total="state.total"
  26. v-model:page-index="state.queryParams.PageIndex"
  27. v-model:page-size="state.queryParams.PageSize"
  28. :toolButton="['refresh', 'setting', 'exportCurrent', 'exportAll']"
  29. :exportMethod="getSmartVisitDetailExport"
  30. :exportParams="requestParams"
  31. >
  32. <template #operation="{ row }">
  33. <template>
  34. <el-button type="primary" @click="onPlaySoundRecording(row)" title="播放录音" link v-if="row.recordUrl">播放录音</el-button>
  35. <el-button link type="primary" @click="onDownload(row)" title="下载录音" v-if="row.recordUrl"> 下载录音 </el-button>
  36. </template>
  37. </template>
  38. <template #title="{ row }">
  39. <order-detail :order="row.order" @updateList="queryList">{{ row.order?.title }}</order-detail>
  40. </template>
  41. </ProTable>
  42. </el-dialog>
  43. </template>
  44. <script setup lang="tsx">
  45. import { formatDate } from '@/utils/formatTime';
  46. import { ElMessageBox, FormInstance } from 'element-plus';
  47. import { defineAsyncComponent, reactive, ref } from 'vue';
  48. import { getSmartVisitBaseData, getSmartVisitDetail, getSmartVisitDetailExport, getSmartVisitExport } from '@/api/smartVisit';
  49. import { downloadFileByStream } from '@/utils/tools';
  50. import { getCurrentCityConfig } from '@/utils/appConfig';
  51. import {fileDownload} from "@/api/public/file";
  52. const OrderDetail = defineAsyncComponent(() => import('@/components/OrderDetail/index.vue')); // 工单详情
  53. const PlayRecord = defineAsyncComponent(() => import('@/views/tels/callLog/component/Play-record.vue')); // 播放录音
  54. const state = reactive({
  55. queryParams: {
  56. // 查询条件
  57. PageIndex: 1,
  58. PageSize: 10,
  59. Keyword: null, // 关键字
  60. id: '',
  61. AiOrderVisitState: null,
  62. },
  63. tableData: [], //表格
  64. loading: false, // 加载
  65. total: 0, // 总数
  66. dialogVisible: false, // 弹窗
  67. });
  68. const columns = ref<any[]>([
  69. { prop: 'order.no', label: '工单编码', width: 140 },
  70. {
  71. label: '标题',
  72. prop: 'title',
  73. width: 200,
  74. },
  75. { prop: 'aiOrderVisitStateText', label: '外呼状态' },
  76. {
  77. label: '是否成功',
  78. prop: 'isSuccessText',
  79. },
  80. { prop: 'outerNo', label: '外呼电话',minWidth: 120 },
  81. { prop: 'fromName', label: '姓名' },
  82. { prop: 'fromGenderText', label: '性别' },
  83. { prop: 'callTimes', label: '重拨次数' },
  84. {
  85. label: '外呼时间',
  86. prop: 'callTime',
  87. width: 160,
  88. render: (scope: any) => {
  89. return <span>{formatDate(scope.row.callTime, 'YYYY-mm-dd HH:MM:SS')}</span>;
  90. },
  91. },
  92. {
  93. label: '受理时间',
  94. prop: 'startTime',
  95. width: 160,
  96. render: (scope: any) => {
  97. return <span>{formatDate(scope.row.startTime, 'YYYY-mm-dd HH:MM:SS')}</span>;
  98. },
  99. },
  100. {
  101. label: '办结时间',
  102. prop: 'filedTime',
  103. width: 160,
  104. render: (scope: any) => {
  105. return <span>{formatDate(scope.row.filedTime, 'YYYY-mm-dd HH:MM:SS')}</span>;
  106. },
  107. },
  108. {
  109. label: '话务员评价',
  110. prop: 'seatEvaluateText',
  111. width: 120,
  112. },
  113. {
  114. label: '部门办件结果',
  115. prop: 'orgProcessingResults',
  116. width: 140,
  117. },
  118. {
  119. label: '部门是否联系',
  120. prop: 'isContact',
  121. minWidth: 120,
  122. },
  123. {
  124. label: '处理结果',
  125. prop: 'volved',
  126. },
  127. // { prop: 'operation', label: '操作', fixed: 'right', width: 160, align: 'center' },
  128. ]);
  129. // 页面基础数据
  130. const aiOrderVisitState = ref([]);
  131. const getBaseData = async () => {
  132. try {
  133. const { result } = await getSmartVisitBaseData();
  134. aiOrderVisitState.value = result.aiOrderVisitState;
  135. } catch (e) {
  136. console.log(e);
  137. }
  138. };
  139. // 打开弹窗
  140. const openDialog = (row?: any) => {
  141. if (row) {
  142. state.dialogVisible = true;
  143. getBaseData();
  144. state.queryParams.id = row.id;
  145. queryList();
  146. }
  147. };
  148. // 手动查询,将页码设置为1
  149. const handleQuery = () => {
  150. state.queryParams.PageIndex = 1;
  151. queryList();
  152. };
  153. // 查询智能回访明细表
  154. const requestParams = ref({});
  155. const queryList = async () => {
  156. state.loading = true;
  157. try {
  158. state.tableData = [];
  159. requestParams.value = state.queryParams;
  160. const res = await getSmartVisitDetail(state.queryParams);
  161. state.tableData = res.result.items ?? [];
  162. state.total = res.result.total ?? 0;
  163. state.loading = false;
  164. } catch (e) {
  165. console.log(e);
  166. state.loading = false;
  167. state.tableData = [];
  168. }
  169. };
  170. const close = () => {
  171. queryParamsRef.value?.resetFields();
  172. queryParamsRef.value?.resetFields();
  173. };
  174. // 播放录音
  175. const playRecordRef = ref<RefType>();
  176. const {recordPrefix,recordDownLoadPrefix} = getCurrentCityConfig();
  177. const onPlaySoundRecording = (val: any) => {
  178. playRecordRef.value.openDialog(recordPrefix + val.recordingAbsolutePath);
  179. };
  180. // 下载录音
  181. const onDownload = (row: any) => {
  182. ElMessageBox.confirm(`您确定要下载此录音吗?`, '提示', {
  183. confirmButtonText: '确认',
  184. cancelButtonText: '取消',
  185. type: 'warning',
  186. draggable: true,
  187. cancelButtonClass: 'default-button',
  188. autofocus: false,
  189. })
  190. .then(() => {
  191. fileDownload({ path: recordDownLoadPrefix + row.recordingAbsolutePath }).then((res: any) => {
  192. downloadFileByStream(res, row.recordingFileName);
  193. });
  194. })
  195. .catch(() => {});
  196. };
  197. // 重置所有工单列表
  198. const queryParamsRef = ref<RefType>();
  199. const resetQuery = (formEl: FormInstance | undefined) => {
  200. if (!formEl) return;
  201. formEl.resetFields();
  202. queryList();
  203. };
  204. defineExpose({
  205. openDialog,
  206. });
  207. </script>