ソースを参照

开发录音录像播放功能

vothin 2 年 前
コミット
a2df05f1b2

+ 11 - 5
languages/en.js

@@ -144,7 +144,10 @@ module.exports = {
     byPerson: 'By Person',
     byEvent: 'By Event',
     export: 'Export',
-    icon: 'Icon'
+    icon: 'Icon',
+    play: 'Play',
+    pause: 'Pause',
+    noFile: 'File does not exist, cannot be played'
   },
   member: {
     face: 'Avatar',
@@ -548,7 +551,8 @@ module.exports = {
     MaxNum: 'Maximum response time',
     MaxNum2: 'Maximum on time',
     SumNum: 'Total call time',
-    total: 'Total'
+    total: 'Total',
+    recordPlay: 'Play the audio recording'
   },
   frameGroup: {
     frameGroupAdd: 'New area',
@@ -816,11 +820,13 @@ module.exports = {
     organizationAdd: 'New Organization',
     boardShowEmptyBed: 'The board shows empty beds',
     nursingColorRgb: 'Nursing door light color',
-    twoColorDoorLightValid: 'Two-color door lights are supported or not',
+    twoColorDoorLightValid: 'Two-color door lights are supported',
     support: 'Support two-color door lights',
-    customerNameHidden: 'Enable user name hiding',
+    customerNameHidden: 'Turn on user name hide',
     hidden: 'Turn on user name hide',
-    channelImHistoryStoreDays: 'The number of days that channel messages are retained'
+    channelImHistoryStoreDays: 'The number of days that channel messages are retained',
+    recordEnabled: 'Turn on the audio and video recording function',
+    recordAble: 'Turn on the audio and video recording function'
   },
   role: {
     roleName: 'Role name',

+ 11 - 5
languages/zh-CN.js

@@ -145,7 +145,10 @@ module.exports = {
     byPerson: '按人',
     byEvent: '按事件',
     export: '导出',
-    icon: '图标'
+    icon: '图标',
+    play: '播放',
+    pause: '暂停',
+    noFile: '文件不存在,无法播放'
   },
   member: {
     face: '头像',
@@ -549,7 +552,8 @@ module.exports = {
     MaxNum: '最大响应时间',
     MaxNum2: '最大接通时间',
     SumNum: '总通话时间',
-    total: '总量'
+    total: '总量',
+    recordPlay: '播放录音录像'
   },
   frameGroup: {
     frameGroupAdd: '新建区域',
@@ -817,11 +821,13 @@ module.exports = {
     organizationAdd: '新建组织',
     boardShowEmptyBed: '看板显示空床',
     nursingColorRgb: '护理门灯颜色',
-    twoColorDoorLightValid: '是否支持双色门灯',
+    twoColorDoorLightValid: '支持双色门灯',
     support: '支持双色门灯',
-    customerNameHidden: '是否开启用户名隐藏',
+    customerNameHidden: '开启用户名隐藏',
     hidden: '开启用户名隐藏',
-    channelImHistoryStoreDays: '频道留言保留天数'
+    channelImHistoryStoreDays: '频道留言保留天数',
+    recordEnabled: '开启录音录像功能',
+    recordAble: '开启录音录像功能'
   },
   role: {
     roleName: '角色名称',

+ 8 - 0
src/api/ncs_interaction.js

@@ -59,3 +59,11 @@ export function getListByHonePage(partId) {
     loading: true
   })
 }
+export function getStreaming(partId, id) {
+  return request({
+    url: `/ncs/record/get_record/${partId}/${id}`,
+    method: 'get',
+    loading: true
+  })
+}
+

+ 62 - 0
src/components/AgGridCellRender/RecordButtonCellRender.vue

@@ -0,0 +1,62 @@
+<template>
+  <el-button v-if="show" :type="buttonType" :size="buttonSize" :icon="icon" :disabled="disabled" @click="buttonClick" ></el-button>
+  <span v-else-if="!show">{{ value }}</span>
+</template>
+
+<script>
+export default {
+  name: "RecordButtonCellRender",
+  data() {
+    return {
+      buttonType: 'primary',
+      buttonSize: 'mini',
+      label: 'button',
+      disabled: false,
+      show: true,
+      param: {},
+      icon: ''
+    }
+  },
+  beforeMount() {
+  },
+  mounted() {
+    const { buttonType, buttonSize, label, disabled, show, value, icon } = this.params
+    if (buttonType) {
+      this.buttonType = buttonType
+    }
+    if (buttonSize) {
+      this.buttonSize = buttonSize
+    }
+    if (label) {
+      this.label = label
+    }
+    if (disabled !== undefined) {
+      this.disabled = disabled
+    }
+    if (show !== undefined) {
+      this.show = show
+    }
+    if (value !== undefined) {
+      this.value = value
+    }
+    if (icon !== undefined) {
+      this.icon = icon
+    }
+  },
+  methods: {
+    buttonClick() {
+      console.log('click', typeof this.params.onClick === 'function')
+
+      if (typeof this.params.onClick === 'function') {
+        console.log(this.params.node.data)
+        this.params.onClick(this.params.node.data)
+        // this.params.context.componentParent.showDetail(this.params.node.data)
+      }
+    }
+  }
+}
+</script>
+
+<style scoped>
+
+</style>

+ 167 - 5
src/views/ncs-interaction/index.vue

@@ -61,6 +61,62 @@
         @current-change="handlePageCurrentChange"
       />
     </ag-grid-layout>
+      <el-dialog :v-loading="this.loading" :title="this.$t('interaction.recordPlay')" :visible.sync="dialogVisible" :before-close="stop" width="70%">
+        <template>
+          <el-row v-if="this.streamingType">
+            <el-col :span="12">
+              <video
+                :src="this.srcStreaming1"
+                autoplay="autoplay"
+                controls="controls"
+                ref="video1"
+                style="width: 98%"
+              >
+              </video>
+            </el-col>
+
+            <el-col :span="12">
+              <video
+                :src="this.srcStreaming2"
+                autoplay="autoplay"
+                controls="controls"
+                ref="video2"
+                style="width: 98%"
+              >
+              </video>
+            </el-col>
+          </el-row>
+
+          <el-row v-else>
+
+            <el-col :span="12">
+              <audio
+                  :src="this.srcStreaming1"
+                  autoplay="autoplay"
+                  controls="controls"
+                  ref="audio1"
+                  style="width: 98%"
+              >
+              </audio>
+            </el-col>
+
+            <el-col :span="12">
+              <audio
+                  :src="this.srcStreaming2"
+                  autoplay="autoplay"
+                  controls="controls"
+                  ref="audio2"
+                  style="width: 98%"
+              >
+              </audio>
+            </el-col>
+          </el-row>
+
+          <div slot="footer" class="dialog-footer" style="text-align: center">
+            <el-button ref="play" type="primary" @click="onclick('onclick')"> {{ this.buttonStr }} </el-button>
+          </div>
+        </template>
+      </el-dialog>
 
   </div>
 </template>
@@ -69,12 +125,18 @@
 import * as API_interaction from '@/api/ncs_interaction'
 import { unixToDate } from '@/utils/Foundation'
 import { AG_GRID_LOCALE_CN } from '@/utils/AgGridVueLocaleCn'
-import { returnDeviceType } from '@/utils/device_type'
 import {DEVICE_TYPE} from "@/utils/enum/DeviceTypeEnum";
 import {TCP_TYPE} from "@/utils/enum/TcpTypeEnum";
+import ButtonCellRender from "@/components/AgGridCellRender/ButtonCellRender";
+import RecordButtonCellRender from "@/components/AgGridCellRender/RecordButtonCellRender";
+import RadioFilter from "@/components/AgGridCustomFilter/RadioFilter";
+import ListFilter from "@/components/AgGridCustomFilter/ListFilter";
+import * as API_Part from "@/api/ncs_partInfo";
+const DeviceUrl = domain.DeviceUrl
 
 export default {
   name: 'Index',
+  components: { ButtonCellRender, RadioFilter, ListFilter, RecordButtonCellRender },
   data() {
     return {
       pickerOptions: {
@@ -128,7 +190,16 @@ export default {
       tcpActionTransfer: [
         { key: 'TCP反馈', value: 'CALLBACK' }
       ],
-      queryResult: '-1'
+      queryResult: '-1',
+      srcStreaming1: '',
+      srcStreaming2: '',
+      stream1: '',
+      stream2: '',
+      beginSeconds: 0,
+      buttonStr: this.$t('action.play'),
+      dialogVisible: false,
+      streamingType: true,
+      recordDir: '',
     }
   },
   computed: {
@@ -138,6 +209,15 @@ export default {
   },
   beforeMount() {
     this.gridOptions = {
+      // onCellClicked: function (event) {
+      //   console.log(event)
+      //   if (event.data.action_type === TCP_TYPE.VOICE ||
+      //       event.data.action_type === TCP_TYPE.VIDEO ||
+      //       event.data.action_type === TCP_TYPE.PHONE
+      //   ) {
+      //     this.getStreaming(event.data);
+      //   }
+      // }
     }
     this.columnDefs = [
       {
@@ -154,10 +234,25 @@ export default {
       { headerName: this.$t('interaction.toMemberName'), field: 'toMemberName', sortable: false, valueFormatter: this.formatterToName, minWidth: 150 },
       { headerName: this.$t('interaction.actionType'), field: 'action_type', sortable: true, valueFormatter: this.formatterType, width: 100 },
       { headerName: this.$t('interaction.actionEnd'), field: 'action_end', sortable: true, cellRenderer: this.formatterResult, width: 100 },
-      { headerName: this.$t('interaction.data'), field: 'data', sortable: true, width: 120 },
+      { headerName: this.$t('interaction.data'), field: 'data',
+        cellRendererFramework: 'RecordButtonCellRender',
+        cellRendererParams: param => {
+          return {
+            onClick: this.getStreaming,
+            icon: 'el-icon-caret-right',
+            buttonType: 'primary',
+            buttonSize: 'mini',
+            value: param.value,
+            show: param.data.action_type === TCP_TYPE.VOICE ||
+                param.data.action_type === TCP_TYPE.VIDEO
+          }
+        },
+        sortable: true,
+        width: 120
+      },
       { headerName: this.$t('interaction.createDate'), field: 'create_date', sortable: true, valueFormatter: this.formatterDate, width: 150 },
       { headerName: this.$t('interaction.fromDevice'), field: 'from_device_type', sortable: true, valueFormatter: this.formatterDeviceType, width: 120 },
-      { headerName: this.$t('interaction.toDevice'), field: 'to_device_type', sortable: true, valueFormatter: this.formatterDeviceType, width: 120 }
+      { headerName: this.$t('interaction.toDevice'), field: 'to_device_type', sortable: true, valueFormatter: this.formatterDeviceType, width: 120 },
     ]
     this.defaultColDef = {
       filter: false,
@@ -177,6 +272,7 @@ export default {
     window.onresize = this.windowResize
     this.gridApi = this.gridOptions.api
     this.getList()
+    // this.$refs.video2.addEventListener("pause", this.pause)
   },
   methods: {
     windowResize() {
@@ -439,7 +535,73 @@ export default {
           return v[j]
         }
       }))
-    }
+    },
+    getStreaming(params) {
+      this.loading = true
+
+      // const url = '/upload/rec/1.webm'
+      // const url2 = '/upload/rec/1.webm'
+      API_interaction.getStreaming(params.part_id, params.id).then(res => {
+        this.loading = false
+        if (res.length !== 0) {
+          if (res[0].endsWith("webm")) {
+            this.streamingType = true
+          } else if (resp[0].endsWith("opus")) {
+            this.streamingType = false
+          }
+
+          this.srcStreaming1 = DeviceUrl + res[0]
+          this.srcStreaming2 = DeviceUrl + res[1]
+          console.log(this.srcStreaming1)
+          console.log(this.srcStreaming2)
+          this.dialogVisible = true
+        } else {
+          this.$message(this.$t('action.noFile'))
+        }
+      }).catch(response => {
+        this.$message({
+          type: 'info',
+          message: response.message
+        })
+      })
+    },
+    onclick() {
+      if (this.buttonStr === this.$t('action.play')) {
+        this.buttonStr = this.$t('action.pause')
+
+        // const time = this.$refs.video1.duration - this.$refs.video2.duration  // 总时长差
+        if (this.streamingType) {
+          this.$refs.video1.play()
+          this.$refs.video2.play()
+        } else {
+          this.$refs.audio1.play()
+          this.$refs.audio2.play()
+        }
+      } else if (this.buttonStr === this.$t('action.pause')) {
+        this.buttonStr = this.$t('action.play')
+        if (this.streamingType) {
+          this.$refs.video1.pause()
+          this.$refs.video2.pause()
+        } else {
+          this.$refs.audio1.pause()
+          this.$refs.audio2.pause()
+        }
+      }
+    },
+    stop() {
+      if (this.streamingType) {
+        this.$refs.video1.currentTime = 0
+        this.$refs.video2.currentTime = 0
+        this.$refs.video1.pause()
+        this.$refs.video2.pause()
+      } else {
+        this.$refs.audio1.currentTime = 0
+        this.$refs.audio2.currentTime = 0
+        this.$refs.audio1.pause()
+        this.$refs.audio2.pause()
+      }
+      this.dialogVisible = false
+    },
   }
 }
 </script>

+ 7 - 0
src/views/ncs-orginazition/components/partInfoEdit.vue

@@ -319,6 +319,12 @@
             <el-form-item :label="this.$t('partInfo.channelImHistoryStoreDays')" prop="channel_im_history_store_days">
               <el-input-number v-model="formmodel.channel_im_history_store_days" :min="1" :max="1000" :label="this.$t('partInfo.channelImHistoryStoreDays')" />
             </el-form-item>
+
+            <el-col :span="8">
+              <el-form-item :label="this.$t('partInfo.recordEnabled')" prop="record_enabled">
+                <el-checkbox v-model="formmodel.record_enabled" :true-label="1" :false-label="0">{{ this.$t('partInfo.recordAble') }}</el-checkbox>
+              </el-form-item>
+            </el-col>
           </el-row>
 
 
@@ -639,6 +645,7 @@ export default {
                 customize_role_call_fifth: 0,
                 customer_name_hidden: 0,
                 channel_im_history_store_days: 30,
+                record_enabled: false,
                 auto_accept: 0,
                 door_nurse_title: '呼叫护士',
                 door_nurse_valid: 1,