123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332 |
- <script setup>
- import { workbenchApi } from '@/api/voice/workbench';
- import RecordCardItem from './components/RecordCardItem';
- import CallView from '@/components/CallView';
- const queryParams = ref({
- pageNum: 1,
- pageSize: 10,
- category: 0,
- phone: ''
- });
- const { proxy } = getCurrentInstance();
- const tabCallRecordList = ref([]);
- const tabCurrentActive = ref(null);
- const callDetails = ref({});
- const isTransitionVoiceStatus = ref(false);
- const total = ref(0);
- const loading = ref(false);
- const tabEnum = ['通话呼入', '通话呼出'];
- const disabled = computed(() => loading.value || total.value == tabCallRecordList.value.length);
- const getTimeOfDayGreeting = () => {
- const date = new Date();
- const hour = date.getHours();
- if (hour >= 0 && hour < 12) {
- return "上午好";
- } else if (hour >= 12 && hour < 18) {
- return "下午好";
- } else {
- return "晚上好";
- }
- }
- // 切换tabs
- const handleChangeTab = (index) => {
- if ( queryParams.value.category != index ) {
- queryParams.value.pageNum = 1;
- queryParams.value.category = index;
- queryParams.value.phone = '';
- tabCurrentActive.value = null;
- tabCallRecordList.value = [];
- initTabsData();
- getTimeOfDayGreeting();
- }
- }
- // 选中通话记录
- const hanldeTabItem = async (id) => {
- if ( !isTransitionVoiceStatus.value ) {
- const { data } = await workbenchApi.getCallRecordDetails(id);
- callDetails.value = data;
- tabCurrentActive.value = id;
- } else {
- proxy.$modal.msgWarning("当前语音正在转换中,请稍后");
- }
- }
- // 搜索
- const onSearch = ( type ) => {
- if ( type === 'refresh' ) {
- queryParams.value.phone = '';
- }
- queryParams.value.pageNum = 1;
- tabCallRecordList.value = [];
- tabCurrentActive.value = null;
- initTabsData();
- }
- // 语音转化完成
- const handleVoiceParsed = ({ parsedVoiceContent }) => {
- callDetails.value.parsedVoiceContent = parsedVoiceContent;
- }
- const initTabsData = async () => {
- loading.value = true;
- const { rows, total: t } = await workbenchApi.getCallRecordList(queryParams.value);
- tabCallRecordList.value = [...tabCallRecordList.value, ...rows];
- total.value = t;
- loading.value = false;
- }
- onMounted(async () => {
- initTabsData();
- });
- const loadMoreData = () => {
- queryParams.value.pageNum += 1;
- initTabsData();
- }
- </script>
- <template>
- <div class="workbench-viewport space-x-[16px]">
- <div class="record-section">
- <ul class="tabs-nav space-x-[48px]">
- <li v-for="item, index in tabEnum" :class="['tabs-nav-item', { active: queryParams.category === index }]"
- :key="item" @click="handleChangeTab(index)">{{ item }}</li>
- </ul>
- <div class="tabs-content">
- <div class="search-inp-wrapper">
- <div class="search-inp">
- <input type="text" class="inp" placeholder="请输入电话号码" v-model.trim="queryParams.phone">
- <div class="btn" @click="onSearch">搜索</div>
- </div>
- <el-tooltip
- effect="dark"
- content="刷新"
- placement="top"
- >
- <el-icon style="cursor: pointer;" @click="onSearch('refresh')"><Refresh /></el-icon>
- </el-tooltip>
- </div>
- <div class="search-result-wrapper">
- <el-scrollbar height="100%">
- <div
- class="search-result-inner space-y-[8px]"
- v-infinite-scroll="loadMoreData"
- :infinite-scroll-disabled="disabled"
- v-show="tabCallRecordList.length"
- >
- <RecordCardItem
- v-for="item, index in tabCallRecordList"
- :data="item"
- :index="index"
- :active="tabCurrentActive === item.id"
- :key="item.id"
- @on-click="hanldeTabItem(item.id)"
- ></RecordCardItem>
- <div class="flex justify-center text-[#999] text-[12px]">
- <p class="pb-[6px]" v-if="loading">Loading...</p>
- </div>
- </div>
-
- <div class="flex items-center justify-center pt-[100px]" v-show="!tabCallRecordList.length">
- <span class="text-[#999] text-[14px]">暂无数据</span>
- </div>
- </el-scrollbar>
- </div>
- </div>
- </div>
- <div class="details-section">
- <div class="empty-wrapper" v-show="!callDetails.id || tabCurrentActive === null">
- <img src="@/assets/images/workbench/img-empty.png" alt="">
- <p class="empty-text">
- <span>Hi, {{ getTimeOfDayGreeting() }}~</span>
- <span>欢迎登录智能语音客服</span>
- </p>
- </div>
- <div class="details-wrapper" v-show="callDetails.id && tabCurrentActive !== null">
- <h4 class="title">通话详情</h4>
- <el-scrollbar class="details-scrollbar">
- <CallView :data="callDetails" noInit @on-end="handleVoiceParsed" v-model="isTransitionVoiceStatus"></CallView>
- </el-scrollbar>
- </div>
- </div>
- </div>
- </template>
- <style lang="scss" scoped>
- $primaryColor: #165DFF;
- .workbench-viewport {
- display: flex;
- height: 100%;
- background: #eceff6;
- .record-section {
- flex-shrink: 0;
- width: 292px;
- height: 100%;
- border-radius: 8px;
- background: linear-gradient(180deg, #FFF 0%, #FFF 100%);
- .tabs-nav {
- display: flex;
- align-items: center;
- justify-content: center;
- height: 46px;
- padding-top: 15px;
- border-bottom: 1px solid #E5E6EB;
- font-size: 14px;
- line-height: 20px;
- color: #4E5969;
- .tabs-nav-item {
- position: relative;
- cursor: pointer;
- &.active {
- color: $primaryColor;
- font-weight: bold;
- &::after {
- position: absolute;
- left: 0;
- bottom: -6px;
- content: ' ';
- display: block;
- width: 100%;
- height: 2px;
- background: $primaryColor;
- }
- }
- }
- }
- .tabs-content {
- height: calc(100% - 46px);
- .search-inp-wrapper {
- display: flex;
- align-items: center;
- justify-content: space-between;
- padding: 12px 22px;
- .search-inp {
- display: flex;
- align-items: center;
- height: 34px;
- padding: 2px;
- border-radius: 8px;
- background: #F2F4F7;
- .inp {
- width: 100%;
- padding: 0 10px;
- background: transparent;
- outline: none;
- font-size: 13px;
- color: #1D2129;
- }
- .btn {
- flex-shrink: 0;
- width: 52px;
- height: 30px;
- border-radius: 8px;
- background: #165DFF;
- color: #FFF;
- font-size: 13px;
- line-height: 30px;
- text-align: center;
- cursor: pointer;
- }
- }
- }
- .search-result-wrapper {
- height: calc(100% - 58px);
- .search-result-inner {
- padding: 0 22px;
- }
- }
- }
- }
- .details-section {
- width: 100%;
- min-width: 700px;
- height: 100%;
- border-radius: 8px;
- overflow: hidden;
- padding: 20px;
- background: #fff;
- .details-scrollbar {
- height: calc(100% - 50px);
- }
- .empty-wrapper {
- display: flex;
- align-items: center;
- justify-content: center;
- flex-flow: column;
- width: 100%;
- height: 100%;
- .empty-text {
- span {
- display: block;
- text-align: center;
- font-weight: bold;
- font-size: 24px;
- line-height: 32px;
- &:nth-child(1) {
- color: #165DFF;
- }
- &:nth-child(2) {
- color: #1D2129;
- }
- }
- }
- }
- .details-wrapper {
- height: 100%;
- .title {
- margin-bottom: 24px;
- color: #1D2129;
- font-size: 18px;
- font-weight: bold;
- line-height: 26px;
- }
- }
- }
- }
- .dialog-footer {
- display: flex;
- justify-content: center;
- }
- :deep(.el-textarea__inner) {
- background: #f2f4f7;
- }
- </style>
|