index.vue 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649
  1. <template>
  2. <div class="tels-callLog-container layout-pd">
  3. <el-card shadow="never">
  4. <el-tabs v-model="state.queryParams.type" @tab-change="changeTba">
  5. <el-tab-pane name="0" label="全部"></el-tab-pane>
  6. <el-tab-pane name="1" label="呼入"></el-tab-pane>
  7. <el-tab-pane name="2" label="呼出"></el-tab-pane>
  8. <el-tab-pane name="3" label="未接"></el-tab-pane>
  9. </el-tabs>
  10. <el-form :model="state.queryParams" ref="ruleFormRef" @submit.native.prevent label-width="20px">
  11. <el-row :gutter="10">
  12. <el-col :xs="24" :sm="12" :md="12" :lg="6" :xl="6">
  13. <el-form-item prop="CPN">
  14. <el-input v-model="state.queryParams.CPN" placeholder="主叫号码" clearable @keyup.enter="handleQuery" />
  15. </el-form-item>
  16. </el-col>
  17. <el-col :xs="24" :sm="12" :md="12" :lg="6" :xl="6">
  18. <el-form-item prop="CDPN">
  19. <el-input v-model="state.queryParams.CDPN" placeholder="被叫号码" clearable @keyup.enter="handleQuery" />
  20. </el-form-item>
  21. </el-col>
  22. <el-col :xs="24" :sm="12" :md="12" :lg="6" :xl="6" v-show="['0', '1', '3'].includes(state.queryParams.type)">
  23. <el-form-item prop="TelNo">
  24. <el-input v-model="state.queryParams.TelNo" placeholder="响应分机" clearable @keyup.enter="handleQuery" />
  25. </el-form-item>
  26. </el-col>
  27. <el-col :xs="24" :sm="12" :md="12" :lg="6" :xl="6">
  28. <el-form-item prop="gateway">
  29. <el-input v-model="state.queryParams.gateway" placeholder="中继号码" clearable @keyup.enter="handleQuery" />
  30. </el-form-item>
  31. </el-col>
  32. <transition name="el-zoom-in-top">
  33. <el-col :xs="24" :sm="12" :md="12" :lg="6" :xl="6" v-show="!searchCol">
  34. <el-form-item prop="UserName">
  35. <el-input v-model="state.queryParams.UserName" placeholder="话务员名称" clearable @keyup.enter="handleQuery" />
  36. </el-form-item>
  37. </el-col>
  38. </transition>
  39. <transition name="el-zoom-in-top">
  40. <el-col :xs="24" :sm="12" :md="12" :lg="6" :xl="6" v-show="!searchCol && ['0', '3'].includes(state.queryParams.type)">
  41. <el-form-item prop="CallDirection">
  42. <el-select v-model="state.queryParams.CallDirection" placeholder="电话方向" clearable class="w100" @change="handleQuery">
  43. <el-option v-for="item in state.callDirection" :value="item.key" :key="item.key" :label="item.value" />
  44. </el-select>
  45. </el-form-item>
  46. </el-col>
  47. </transition>
  48. <transition name="el-zoom-in-top">
  49. <el-col :xs="24" :sm="12" :md="12" :lg="6" :xl="6" v-show="!searchCol && ['0'].includes(state.queryParams.type)">
  50. <el-form-item prop="OnState">
  51. <el-select v-model="state.queryParams.OnState" placeholder="通话结果" clearable class="w100" @change="handleQuery">
  52. <el-option v-for="item in state.onState" :value="item.key" :key="item.key" :label="item.value" />
  53. </el-select>
  54. </el-form-item>
  55. </el-col>
  56. </transition>
  57. <transition name="el-zoom-in-top">
  58. <el-col :xs="24" :sm="12" :md="12" :lg="6" :xl="6" v-show="!searchCol && ['0', '1', '2'].includes(state.queryParams.type)">
  59. <el-form-item prop="EndBy">
  60. <el-select v-model="state.queryParams.EndBy" placeholder="挂机类型" clearable class="w100" @change="handleQuery">
  61. <el-option v-for="item in state.endByOptions" :value="item.key" :key="item.key" :label="item.value" />
  62. </el-select>
  63. </el-form-item>
  64. </el-col>
  65. </transition>
  66. <transition name="el-zoom-in-top">
  67. <el-col :xs="24" :sm="12" :md="12" :lg="6" :xl="6" v-show="!searchCol && ['0', '1', '3'].includes(state.queryParams.type)">
  68. <el-form-item prop="ivrTime">
  69. <el-date-picker
  70. v-model="state.queryParams.ivrTime"
  71. type="datetimerange"
  72. unlink-panels
  73. range-separator="至"
  74. start-placeholder="ivr开始时间"
  75. end-placeholder="ivr结束时间"
  76. :shortcuts="shortcuts"
  77. @change="timeStartChangeIvr"
  78. value-format="YYYY-MM-DD[T]HH:mm:ss"
  79. />
  80. </el-form-item>
  81. </el-col>
  82. </transition>
  83. <transition name="el-zoom-in-top">
  84. <el-col :xs="24" :sm="12" :md="12" :lg="6" :xl="6" v-show="!searchCol && ['0', '1', '3'].includes(state.queryParams.type)">
  85. <el-form-item prop="callTime">
  86. <el-date-picker
  87. v-model="state.queryParams.callTime"
  88. type="datetimerange"
  89. unlink-panels
  90. range-separator="至"
  91. start-placeholder="队列开始时间"
  92. end-placeholder="队列结束时间"
  93. :shortcuts="shortcuts"
  94. @change="timeStartChangeCall"
  95. value-format="YYYY-MM-DD[T]HH:mm:ss"
  96. />
  97. </el-form-item>
  98. </el-col>
  99. </transition>
  100. <transition name="el-zoom-in-top">
  101. <el-col :xs="24" :sm="12" :md="12" :lg="6" :xl="6" v-show="!searchCol">
  102. <el-form-item prop="crTime">
  103. <el-date-picker
  104. v-model="state.queryParams.crTime"
  105. type="datetimerange"
  106. unlink-panels
  107. range-separator="至"
  108. start-placeholder="应答开始时间"
  109. end-placeholder="应答结束时间"
  110. :shortcuts="shortcuts"
  111. @change="timeStartChange"
  112. value-format="YYYY-MM-DD[T]HH:mm:ss"
  113. />
  114. </el-form-item>
  115. </el-col>
  116. </transition>
  117. <transition name="el-zoom-in-top">
  118. <el-col :xs="24" :sm="12" :md="12" :lg="6" :xl="6" v-show="!searchCol && ['0', '1', '2'].includes(state.queryParams.type)">
  119. <el-form-item prop="OrderNo">
  120. <el-input v-model="state.queryParams.OrderNo" placeholder="工单编码" clearable @keyup.enter="handleQuery" />
  121. </el-form-item>
  122. </el-col>
  123. </transition>
  124. <transition name="el-zoom-in-top">
  125. <el-col :xs="24" :sm="12" :md="12" :lg="6" :xl="6" v-show="!searchCol && ['0', '1', '2'].includes(state.queryParams.type)">
  126. <el-form-item prop="Title">
  127. <el-input v-model="state.queryParams.Title" placeholder="工单标题" clearable @keyup.enter="handleQuery" />
  128. </el-form-item>
  129. </el-col>
  130. </transition>
  131. </el-row>
  132. <div class="w100 ml20">
  133. <el-button type="primary" @click="handleQuery" :loading="state.loading"> <SvgIcon name="ele-Search" class="mr5" />查询 </el-button>
  134. <el-button @click="resetQuery(ruleFormRef)" class="default-button" :loading="state.loading">
  135. <SvgIcon name="ele-Refresh" class="mr5" />重置
  136. </el-button>
  137. <el-button link type="primary" @click="closeSearch" :loading="state.loading">
  138. {{ searchCol ? '展开' : '收起' }}
  139. <SvgIcon :class="{ 'is-reverse': searchCol }" name="ele-ArrowUp" class="mr5 arrow" size="18px" />
  140. </el-button>
  141. </div>
  142. </el-form>
  143. </el-card>
  144. <el-card shadow="never">
  145. <ProTable
  146. ref="proTableRef"
  147. :columns="columns"
  148. :data="state.tableData"
  149. @updateTable="queryList"
  150. :loading="state.loading"
  151. :total="state.total"
  152. v-model:page-index="state.queryParams.PageIndex"
  153. v-model:page-size="state.queryParams.PageSize"
  154. :key="Math.random()"
  155. >
  156. <!-- 表格操作 -->
  157. <template #operation="{ row }">
  158. <template v-if="['0', '1'].includes(state.queryParams.type)">
  159. <el-button link type="primary" @click="onCreate(row)" title="创建失联工单" v-auth="'tels:callLog:connectOrder'" v-if="!row.externalId">
  160. 失联工单
  161. </el-button>
  162. <el-button link type="primary" @click="onConnect(row)" title="关联业务" v-auth="'tels:callLog:connect'" v-if="!row.externalId">
  163. 关联业务
  164. </el-button>
  165. <el-button type="primary" @click="onPlaySoundRecording(row)" title="播放录音" link v-if="row.recordingAbsolutePath">播放录音</el-button>
  166. <el-button link type="primary" @click="onDownload(row)" title="下载录音" v-if="row.recordingAbsolutePath"> 下载录音 </el-button>
  167. </template>
  168. <template v-else>
  169. <el-button type="primary" @click="onPlaySoundRecording(row)" title="播放录音" link v-if="row.recordingAbsolutePath">播放录音</el-button>
  170. <el-button link type="primary" @click="onDownload(row)" title="下载录音" v-if="row.recordingAbsolutePath"> 下载录音 </el-button>
  171. </template>
  172. </template>
  173. <template #title="{ row }">
  174. <order-detail :order="row.order" @updateList="queryList">{{ row.order?.title }}</order-detail>
  175. </template>
  176. </ProTable>
  177. </el-card>
  178. <!-- 播放录音 -->
  179. <play-record ref="playRecordRef" />
  180. <!-- 业务关联 -->
  181. <connect-business ref="connectBusinessRef" @updateList="queryList" />
  182. </div>
  183. </template>
  184. <script lang="tsx" setup name="callLog">
  185. import { defineAsyncComponent, onMounted, reactive, ref } from 'vue';
  186. import type { FormInstance } from 'element-plus';
  187. import { ElMessageBox } from 'element-plus';
  188. import { downloadFileByStream } from '@/utils/tools';
  189. import { callBaseData, callLogPaged } from '@/api/tels/callLog';
  190. import { formatDate } from '@/utils/formatTime';
  191. import { shortcuts } from '@/utils/constants';
  192. import other from '@/utils/other';
  193. import { useRouter } from 'vue-router';
  194. import { fileDownload } from '@/api/public/file';
  195. // 引入组件
  196. const PlayRecord = defineAsyncComponent(() => import('@/views/tels/callLog/component/Play-record.vue')); // 播放录音
  197. const ConnectBusiness = defineAsyncComponent(() => import('@/views/tels/callLog/component/Connect-business.vue')); // 关联工单还是回访
  198. const OrderDetail = defineAsyncComponent(() => import('@/components/OrderDetail/index.vue')); // 工单详情
  199. const proTableRef = ref<RefType>(); // 表格ref
  200. // 表格配置项
  201. const columns = ref<any[]>([
  202. { prop: 'cpn', label: '主叫', width: 120 },
  203. { prop: 'cdpn', label: '被叫', width: 120 },
  204. { prop: 'ringTimes', label: '响铃次数', width: 110 },
  205. { prop: 'gateway', label: '中继号', width: 120 },
  206. { prop: 'duration', label: '通话时间(秒)', width: 120 },
  207. { prop: 'onStateText', label: '通话结果' },
  208. { prop: 'callDirectionText', label: '电话方向' },
  209. { prop: 'endByText', label: '挂机类型', width: 120 },
  210. {
  211. prop: 'beginIvrTime',
  212. label: 'ivr开始时间',
  213. width: 170,
  214. render: (scope) => <span>{formatDate(scope.row.beginIvrTime, 'YYYY-mm-dd HH:MM:SS')}</span>,
  215. },
  216. {
  217. prop: 'endIvrTime',
  218. label: 'ivr结束时间',
  219. width: 170,
  220. render: (scope) => <span>{formatDate(scope.row.endIvrTime, 'YYYY-mm-dd HH:MM:SS')}</span>,
  221. },
  222. {
  223. prop: 'beginQueueTime',
  224. label: '队列开始时间',
  225. width: 170,
  226. render: (scope) => <span>{formatDate(scope.row.beginQueueTime, 'YYYY-mm-dd HH:MM:SS')}</span>,
  227. },
  228. {
  229. prop: 'endQueueTime',
  230. label: '队列结束时间',
  231. width: 170,
  232. render: (scope) => {
  233. return <span>{formatDate(scope.row.endQueueTime, 'YYYY-mm-dd HH:MM:SS')}</span>;
  234. },
  235. },
  236. {
  237. prop: 'createdTime',
  238. label: '应答开始时间',
  239. width: 170,
  240. render: (scope) => <span>{formatDate(scope.row.createdTime, 'YYYY-mm-dd HH:MM:SS')}</span>,
  241. },
  242. {
  243. prop: 'answeredTime',
  244. label: '应答时间',
  245. width: 170,
  246. render: (scope) => <span>{formatDate(scope.row.answeredTime, 'YYYY-mm-dd HH:MM:SS')}</span>,
  247. },
  248. { prop: 'overTime', label: '应答结束时间', width: 170, render: (scope) => <span>{formatDate(scope.row.overTime, 'YYYY-mm-dd HH:MM:SS')}</span> },
  249. { prop: 'operation', label: '操作', fixed: 'right', width: 240, align: 'center' },
  250. ]);
  251. // 定义变量内容
  252. const state = reactive({
  253. queryParams: {
  254. PageIndex: 1, // 当前页
  255. PageSize: 10, // 每页条数
  256. type: '0',
  257. StaffNo: null, // 分机号
  258. CPN: null, // 中继号码
  259. CDPN: null, // 分机号
  260. callDirection: null, // 呼叫类型
  261. OnState: null, // 结果
  262. crTime: [],
  263. callTime: [],
  264. ivrTime: [],
  265. },
  266. tableData: [], // 列表数据
  267. loading: false, // 加载
  268. total: 0, // 总条数
  269. callDirection: [],
  270. onState: [],
  271. endByOptions: [],
  272. });
  273. const ruleFormRef = ref<FormInstance>(); // 表单ref
  274. const searchCol = ref(true); // 展开/收起
  275. // 展开/收起
  276. const closeSearch = () => {
  277. searchCol.value = !searchCol.value;
  278. };
  279. const handleTimeChange = (val: string[], startKey: string, endKey: string) => {
  280. if (val) {
  281. state.queryParams[startKey] = val[0];
  282. state.queryParams[endKey] = val[1];
  283. } else {
  284. state.queryParams[startKey] = '';
  285. state.queryParams[endKey] = '';
  286. }
  287. handleQuery();
  288. };
  289. // IVR时间段
  290. const timeStartChangeIvr = (val: string[]) => {
  291. handleTimeChange(val, 'BeginIvrTime', 'EndIvrTime');
  292. };
  293. // 队列时间段
  294. const timeStartChangeCall = (val: string[]) => {
  295. handleTimeChange(val, 'BeginQueueTime', 'EndQueueTime');
  296. };
  297. // 通话时间段
  298. const timeStartChange = (val: string[]) => {
  299. handleTimeChange(val, 'AnsweredTime', 'OverTime');
  300. };
  301. // 全部表头
  302. const allColumns = [
  303. { prop: 'cpn', label: '主叫号码', width: 120 },
  304. { prop: 'cdpn', label: '被叫号码', width: 120 },
  305. { prop: 'order.no', label: '工单编码', width: 150 },
  306. { prop: 'title', label: '工单标题', width: 300 },
  307. { prop: 'telNo', label: '响应分机', width: 120 },
  308. { prop: 'gateway', label: '中继号码', width: 120 },
  309. { prop: 'userName', label: '话务员', width: 120 },
  310. { prop: 'duration', label: '通话时间(秒)', width: 120 },
  311. { prop: 'onStateText', label: '通话结果' },
  312. { prop: 'callDirectionText', label: '电话方向' },
  313. { prop: 'endByText', label: '挂机类型', width: 120 },
  314. {
  315. prop: 'beginIvrTime',
  316. label: 'ivr开始时间',
  317. width: 170,
  318. render: (scope) => <span>{formatDate(scope.row.beginIvrTime, 'YYYY-mm-dd HH:MM:SS')}</span>,
  319. },
  320. {
  321. prop: 'endIvrTime',
  322. label: 'ivr结束时间',
  323. width: 170,
  324. render: (scope) => <span>{formatDate(scope.row.endIvrTime, 'YYYY-mm-dd HH:MM:SS')}</span>,
  325. },
  326. {
  327. prop: 'beginQueueTime',
  328. label: '队列开始时间',
  329. width: 170,
  330. render: (scope) => <span>{formatDate(scope.row.beginQueueTime, 'YYYY-mm-dd HH:MM:SS')}</span>,
  331. },
  332. {
  333. prop: 'endQueueTime',
  334. label: '队列结束时间',
  335. width: 170,
  336. render: (scope) => {
  337. return <span>{formatDate(scope.row.endQueueTime, 'YYYY-mm-dd HH:MM:SS')}</span>;
  338. },
  339. },
  340. {
  341. prop: 'beginRingTime',
  342. label: '开始振铃时间',
  343. width: 170,
  344. render: (scope) => {
  345. return <span>{formatDate(scope.row.beginRingTime, 'YYYY-mm-dd HH:MM:SS')}</span>;
  346. },
  347. },
  348. {
  349. prop: 'endRingTimg',
  350. label: '结束振铃时间',
  351. width: 170,
  352. render: (scope) => {
  353. return <span>{formatDate(scope.row.endRingTimg, 'YYYY-mm-dd HH:MM:SS')}</span>;
  354. },
  355. },
  356. {
  357. prop: 'createdTime',
  358. label: '应答开始时间',
  359. width: 170,
  360. render: (scope) => <span>{formatDate(scope.row.createdTime, 'YYYY-mm-dd HH:MM:SS')}</span>,
  361. },
  362. {
  363. prop: 'answeredTime',
  364. label: '应答时间',
  365. width: 170,
  366. render: (scope) => <span>{formatDate(scope.row.answeredTime, 'YYYY-mm-dd HH:MM:SS')}</span>,
  367. },
  368. { prop: 'overTime', label: '应答结束时间', width: 170, render: (scope) => <span>{formatDate(scope.row.overTime, 'YYYY-mm-dd HH:MM:SS')}</span> },
  369. { prop: 'operation', label: '操作', fixed: 'right', width: 310, align: 'center' },
  370. ];
  371. // 呼入表头
  372. const inColumns = [
  373. { prop: 'cpn', label: '主叫号码', width: 120 },
  374. { prop: 'cdpn', label: '被叫号码', width: 120 },
  375. { prop: 'order.no', label: '工单编码', width: 150 },
  376. { prop: 'title', label: '工单标题', width: 300 },
  377. { prop: 'telNo', label: '响应分机', width: 120 },
  378. { prop: 'gateway', label: '中继号码', width: 120 },
  379. { prop: 'userName', label: '话务员', width: 120 },
  380. { prop: 'duration', label: '通话时间(秒)', width: 120 },
  381. { prop: 'endByText', label: '挂机类型', width: 120 },
  382. {
  383. prop: 'beginIvrTime',
  384. label: 'ivr开始时间',
  385. width: 170,
  386. render: (scope) => <span>{formatDate(scope.row.beginIvrTime, 'YYYY-mm-dd HH:MM:SS')}</span>,
  387. },
  388. {
  389. prop: 'endIvrTime',
  390. label: 'ivr结束时间',
  391. width: 170,
  392. render: (scope) => <span>{formatDate(scope.row.endIvrTime, 'YYYY-mm-dd HH:MM:SS')}</span>,
  393. },
  394. {
  395. prop: 'beginQueueTime',
  396. label: '队列开始时间',
  397. width: 170,
  398. render: (scope) => <span>{formatDate(scope.row.beginQueueTime, 'YYYY-mm-dd HH:MM:SS')}</span>,
  399. },
  400. {
  401. prop: 'endQueueTime',
  402. label: '队列结束时间',
  403. width: 170,
  404. render: (scope) => {
  405. return <span>{formatDate(scope.row.endQueueTime, 'YYYY-mm-dd HH:MM:SS')}</span>;
  406. },
  407. },
  408. {
  409. prop: 'beginRingTime',
  410. label: '开始振铃时间',
  411. width: 170,
  412. render: (scope) => {
  413. return <span>{formatDate(scope.row.beginRingTime, 'YYYY-mm-dd HH:MM:SS')}</span>;
  414. },
  415. },
  416. {
  417. prop: 'endRingTimg',
  418. label: '结束振铃时间',
  419. width: 170,
  420. render: (scope) => {
  421. return <span>{formatDate(scope.row.endRingTimg, 'YYYY-mm-dd HH:MM:SS')}</span>;
  422. },
  423. },
  424. {
  425. prop: 'createdTime',
  426. label: '应答开始时间',
  427. width: 170,
  428. render: (scope) => <span>{formatDate(scope.row.createdTime, 'YYYY-mm-dd HH:MM:SS')}</span>,
  429. },
  430. {
  431. prop: 'answeredTime',
  432. label: '应答时间',
  433. width: 170,
  434. render: (scope) => <span>{formatDate(scope.row.answeredTime, ' YYYY-mm-dd HH:MM:SS')}</span>,
  435. },
  436. { prop: 'overTime', label: '应答结束时间', width: 170, render: (scope) => <span>{formatDate(scope.row.overTime, 'YYYY-mm-dd HH:MM:SS')}</span> },
  437. { prop: 'operation', label: '操作', fixed: 'right', width: 310, align: 'center' },
  438. ];
  439. // 呼出表头
  440. const outColumns = [
  441. { prop: 'cpn', label: '主叫号码', width: 120 },
  442. { prop: 'cdpn', label: '被叫号码', width: 120 },
  443. { prop: 'telNo', label: '响应分机' },
  444. { prop: 'gateway', label: '中继号码', width: 120 },
  445. { prop: 'userName', label: '话务员' },
  446. { prop: 'duration', label: '通话时间(秒)', width: 120 },
  447. { prop: 'endByText', label: '挂机类型', width: 120 },
  448. {
  449. prop: 'createdTime',
  450. label: '应答开始时间',
  451. width: 170,
  452. render: (scope) => <span>{formatDate(scope.row.createdTime, 'YYYY-mm-dd HH:MM:SS')}</span>,
  453. },
  454. {
  455. prop: 'answeredTime',
  456. label: '应答时间',
  457. width: 170,
  458. render: (scope) => <span>{formatDate(scope.row.answeredTime, 'YYYY-mm-dd HH:MM:SS')}</span>,
  459. },
  460. { prop: 'overTime', label: '应答结束时间', width: 170, render: (scope) => <span>{formatDate(scope.row.overTime, 'YYYY-mm-dd HH:MM:SS')}</span> },
  461. { prop: 'operation', label: '操作', fixed: 'right', width: 180, align: 'center' },
  462. ];
  463. // 未接表头
  464. const noColumns = [
  465. { prop: 'cpn', label: '主叫号码', width: 120 },
  466. { prop: 'cdpn', label: '被叫号码', width: 120 },
  467. { prop: 'telNo', label: '响应分机' },
  468. { prop: 'gateway', label: '中继号码', width: 120 },
  469. { prop: 'userName', label: '话务员' },
  470. { prop: 'callDirectionText', label: '电话方向' },
  471. {
  472. prop: 'beginIvrTime',
  473. label: 'ivr开始时间',
  474. width: 170,
  475. render: (scope) => <span>{formatDate(scope.row.beginIvrTime, 'YYYY-mm-dd HH:MM:SS')}</span>,
  476. },
  477. {
  478. prop: 'endIvrTime',
  479. label: 'ivr结束时间',
  480. width: 170,
  481. render: (scope) => <span>{formatDate(scope.row.endIvrTime, 'YYYY-mm-dd HH:MM:SS')}</span>,
  482. },
  483. {
  484. prop: 'beginQueueTime',
  485. label: '队列开始时间',
  486. width: 170,
  487. render: (scope) => <span>{formatDate(scope.row.beginQueueTime, 'YYYY-mm-dd HH:MM:SS')}</span>,
  488. },
  489. {
  490. prop: 'endQueueTime',
  491. label: '队列结束时间',
  492. width: 170,
  493. render: (scope) => {
  494. return <span>{formatDate(scope.row.endQueueTime, 'YYYY-mm-dd HH:MM:SS')}</span>;
  495. },
  496. },
  497. {
  498. prop: 'beginRingTime',
  499. label: '开始振铃时间',
  500. width: 170,
  501. render: (scope) => {
  502. return <span>{formatDate(scope.row.beginRingTime, 'YYYY-mm-dd HH:MM:SS')}</span>;
  503. },
  504. },
  505. {
  506. prop: 'endRingTimg',
  507. label: '结束振铃时间',
  508. width: 170,
  509. render: (scope) => {
  510. return <span>{formatDate(scope.row.endRingTimg, 'YYYY-mm-dd HH:MM:SS')}</span>;
  511. },
  512. },
  513. {
  514. prop: 'createdTime',
  515. label: '应答开始时间',
  516. width: 170,
  517. render: (scope) => <span>{formatDate(scope.row.createdTime, 'YYYY-mm-dd HH:MM:SS')}</span>,
  518. },
  519. { prop: 'overTime', label: '应答结束时间', width: 170, render: (scope) => <span>{formatDate(scope.row.overTime, 'YYYY-mm-dd HH:MM:SS')}</span> },
  520. ];
  521. const changeTba = () => {
  522. ruleFormRef.value.resetFields();
  523. handleQuery();
  524. };
  525. // 手动查询,将页码设置为1
  526. const handleQuery = () => {
  527. state.queryParams.PageIndex = 1;
  528. queryList();
  529. };
  530. /** 通话记录列表 */
  531. const queryList = async () => {
  532. state.loading = true;
  533. try {
  534. let request = other.deepClone(state.queryParams);
  535. Reflect.deleteProperty(request, 'crTime'); // 删除无用的参数
  536. Reflect.deleteProperty(request, 'callTime'); // 删除无用的参数
  537. Reflect.deleteProperty(request, 'ivrTime'); // 删除无用的参数
  538. Reflect.deleteProperty(request, 'type'); // 删除无用的参数
  539. switch (state.queryParams.type) {
  540. case '0':
  541. columns.value = allColumns;
  542. break;
  543. case '1':
  544. columns.value = inColumns;
  545. request.CallDirection = 0;
  546. break;
  547. case '2':
  548. columns.value = outColumns;
  549. request.CallDirection = 1;
  550. break;
  551. case '3':
  552. columns.value = noColumns;
  553. request.OnState = 2;
  554. break;
  555. default:
  556. columns.value = allColumns;
  557. break;
  558. }
  559. const response = await callLogPaged(request);
  560. state.tableData = response.result?.items ?? [];
  561. state.total = response.result?.total ?? 0;
  562. state.loading = false;
  563. } catch (e) {
  564. state.loading = false;
  565. console.log(e);
  566. }
  567. };
  568. /** 重置按钮操作 */
  569. const resetQuery = (formEl: FormInstance | undefined) => {
  570. if (!formEl) return;
  571. formEl.resetFields();
  572. state.queryParams.BeginIvrTime = null;
  573. state.queryParams.EndIvrTime = null;
  574. state.queryParams.BeginQueueTime = null;
  575. state.queryParams.EndQueueTime = null;
  576. state.queryParams.AnsweredTime = null;
  577. state.queryParams.OverTime = null;
  578. queryList();
  579. };
  580. // 播放录音
  581. const playRecordRef = ref<RefType>();
  582. const onPlaySoundRecording = (val: any) => {
  583. playRecordRef.value.openDialog(import.meta.env.VITE_RECORD_PREFIX + val.recordingAbsolutePath);
  584. };
  585. // 下载录音
  586. const onDownload = (row: any) => {
  587. ElMessageBox.confirm(`您确定要下载此录音吗?`, '提示', {
  588. confirmButtonText: '确认',
  589. cancelButtonText: '取消',
  590. type: 'warning',
  591. draggable: true,
  592. cancelButtonClass: 'default-button',
  593. autofocus: false,
  594. })
  595. .then(() => {
  596. fileDownload({ path: import.meta.env.VITE_RECORD_DOWNLOAD_PREFIX + row.recordingAbsolutePath }).then((res: any) => {
  597. downloadFileByStream(res, row.recordingFileName);
  598. });
  599. })
  600. .catch(() => {});
  601. };
  602. // 关联业务
  603. const connectBusinessRef = ref<RefType>();
  604. const onConnect = (row: any) => {
  605. connectBusinessRef.value.openDialog(row);
  606. };
  607. // 失联工单
  608. const router = useRouter();
  609. const onCreate = (row: any) => {
  610. router.push({
  611. name: 'orderAccept',
  612. state: {
  613. createBy: 'tel',
  614. fromTel: row.cpn,
  615. telGuid: row.callAccept,
  616. transfer: row.gateway,
  617. telArea: '',
  618. },
  619. params: {
  620. callId: row.callAccept,
  621. tagsViewName: '创建失联工单',
  622. },
  623. });
  624. };
  625. // 基础信息
  626. const getBaseData = async () => {
  627. const response = await callBaseData();
  628. state.callDirection = response.result.callDirection;
  629. state.onState = response.result.onState;
  630. state.endByOptions = response.result.endBy;
  631. };
  632. onMounted(() => {
  633. getBaseData();
  634. queryList();
  635. });
  636. </script>
  637. <style lang="scss" scoped>
  638. .arrow {
  639. transition: transform var(--el-transition-duration);
  640. cursor: pointer;
  641. }
  642. .arrow.is-reverse {
  643. transform: rotateZ(-180deg);
  644. }
  645. </style>