瀏覽代碼

Merge branch 'develop' into feature/1.3.7-languages-20221025

vothin 2 年之前
父節點
當前提交
e9b9f3faf9

+ 17 - 8
languages/en.js

@@ -117,17 +117,17 @@ module.exports = {
     uploaderImgMsg2: 'Please upload an image with an aspect ratio of 1:1',
     uploaderImgMsg3: 'The height of the image must be between 100 and 500! ',
     uploadFile: 'Upload file',
-    uploadAPK: 'APK file upload',
+    uploadAPK: 'APK/IMG file upload',
     uploadFileMsg: 'Drag file here, or',
     uploadFileMsg2: 'Click to upload',
     uploadFileMsg3: 'Only mp3 or flac files can be uploaded',
     uploadFileMsg4: 'The upload attachment size cannot exceed 50MB!',
-    uploadFileMsg5: 'Only upload APK files',
+    uploadFileMsg5: 'Only upload APK/IMG files',
     uploadFileName: 'File name',
     uploadFileNameMsg: 'The file name cannot be empty',
     uploadFileUrl: 'File path',
     uploadFileUrlMsg: 'The file path cannot be empty, please upload the file',
-    uploadFileUrlMsg2: 'Please upload the APK file',
+    uploadFileUrlMsg2: 'Please upload the APK/IMG file',
     uploadFileAuthor: 'Uploaded by',
     uploadFileDate: 'Upload Date',
     uploadVersionNo: 'Version number',
@@ -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',
@@ -809,6 +813,7 @@ module.exports = {
     sickbed: '5-inch bed extension APP',
     sevensickbed: '7 inch bed extension APP',
     vsickbed: ' Visual version of Bed extension',
+    linuxsickbed: 'Linux bed extension APP',
     mobiledevice: 'Mobile device',
     visitation: 'Visitor',
     transferDevice: 'Transfer box',
@@ -816,11 +821,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',
@@ -942,6 +949,8 @@ module.exports = {
   },
   relativeNameType: {
     CHILDREN: 'Child',
+    BOY: 'Boy',
+    GIRL: 'Girl',
     HUSBAND: 'Husband',
     WIFE: 'Wife',
     FATHER: 'Father',

+ 18 - 8
languages/zh-CN.js

@@ -118,17 +118,17 @@ module.exports = {
     uploaderImgMsg2: '请上传宽高比为1:1的图片',
     uploaderImgMsg3: '图片高度必须在100~500之间!',
     uploadFile: '上传文件',
-    uploadAPK: 'APK文件上传',
+    uploadAPK: 'APK/IMG文件上传',
     uploadFileMsg: '将文件拖到此处,或',
     uploadFileMsg2: '点击上传',
     uploadFileMsg3: '只能上传mp3或flac文件',
     uploadFileMsg4: '上传附件大小不能超过 50MB!',
-    uploadFileMsg5: '只能上传APK文件',
+    uploadFileMsg5: '只能上传APK/IMG文件',
     uploadFileName: '文件名称',
     uploadFileNameMsg: '文件名称不能为空',
     uploadFileUrl: '文件路径',
     uploadFileUrlMsg: '文件路径不能为空,请上传文件',
-    uploadFileUrlMsg2: '请上传APK文件',
+    uploadFileUrlMsg2: '请上传APK/IMG文件',
     uploadFileAuthor: '上传者',
     uploadFileDate: '上传日期',
     uploadVersionNo: '版本数字',
@@ -145,7 +145,11 @@ module.exports = {
     byPerson: '按人',
     byEvent: '按事件',
     export: '导出',
-    icon: '图标'
+    icon: '图标',
+    excelUpload: '上传excel表',
+    play: '播放',
+    pause: '暂停',
+    noFile: '文件不存在,无法播放'
   },
   member: {
     face: '头像',
@@ -549,7 +553,8 @@ module.exports = {
     MaxNum: '最大响应时间',
     MaxNum2: '最大接通时间',
     SumNum: '总通话时间',
-    total: '总量'
+    total: '总量',
+    recordPlay: '播放录音录像'
   },
   frameGroup: {
     frameGroupAdd: '新建区域',
@@ -809,6 +814,7 @@ module.exports = {
     vdoor: '门口机可视版',
     sickbed: '5寸床位分机APP',
     sevensickbed: '7寸床位分机APP',
+    linuxsickbed: 'Linux床位分机APP',
     vsickbed: '床位分机可视版',
     mobiledevice: '移动设备',
     vistitation: '探视机',
@@ -817,11 +823,13 @@ module.exports = {
     organizationAdd: '新建组织',
     boardShowEmptyBed: '看板显示空床',
     nursingColorRgb: '护理门灯颜色',
-    twoColorDoorLightValid: '是否支持双色门灯',
+    twoColorDoorLightValid: '支持双色门灯',
     support: '支持双色门灯',
-    customerNameHidden: '是否开启用户名隐藏',
+    customerNameHidden: '开启用户名隐藏',
     hidden: '开启用户名隐藏',
-    channelImHistoryStoreDays: '频道留言保留天数'
+    channelImHistoryStoreDays: '频道留言保留天数',
+    recordEnabled: '开启录音录像功能',
+    recordAble: '开启录音录像功能'
   },
   role: {
     roleName: '角色名称',
@@ -943,6 +951,8 @@ module.exports = {
   },
   relativeNameType: {
     CHILDREN: '孩子',
+    BOY: '男孩',
+    GIRL: '女孩',
     HUSBAND: '丈夫',
     WIFE: '妻子',
     FATHER: '父亲',

+ 15 - 15
package-lock.json

@@ -7253,10 +7253,6 @@
       "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=",
       "dev": true
     },
-    "eve": {
-      "version": "git://github.com/adobe-webplatform/eve.git#eef80ed8d188423c2272746fb8ae5cc8dad84cb1",
-      "from": "git://github.com/adobe-webplatform/eve.git#eef80ed"
-    },
     "event-pubsub": {
       "version": "4.3.0",
       "resolved": "https://registry.npmjs.org/event-pubsub/-/event-pubsub-4.3.0.tgz",
@@ -8174,7 +8170,8 @@
         "ansi-regex": {
           "version": "2.1.1",
           "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
-          "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8="
+          "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
+          "optional": true
         },
         "is-fullwidth-code-point": {
           "version": "1.0.0",
@@ -8200,6 +8197,7 @@
           "version": "3.0.1",
           "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
           "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
+          "optional": true,
           "requires": {
             "ansi-regex": "^2.0.0"
           }
@@ -12495,7 +12493,8 @@
     "npm-normalize-package-bin": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz",
-      "integrity": "sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA=="
+      "integrity": "sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA==",
+      "optional": true
     },
     "npm-packlist": {
       "version": "1.4.8",
@@ -13255,7 +13254,8 @@
       "version": "2.2.2",
       "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz",
       "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==",
-      "dev": true
+      "dev": true,
+      "optional": true
     },
     "pify": {
       "version": "4.0.1",
@@ -14391,13 +14391,6 @@
       "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==",
       "dev": true
     },
-    "raphael": {
-      "version": "git+https://github.com/nhn/raphael.git#78a6ed3ec269f33b6457b0ec66f8c3d1f2ed70e0",
-      "from": "git+https://github.com/nhn/raphael.git#2.2.0-c",
-      "requires": {
-        "eve": "git://github.com/adobe-webplatform/eve.git#eef80ed8d188423c2272746fb8ae5cc8dad84cb1"
-      }
-    },
     "raw-body": {
       "version": "2.4.0",
       "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz",
@@ -16637,6 +16630,7 @@
           "version": "2.9.0",
           "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz",
           "integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==",
+          "optional": true,
           "requires": {
             "safe-buffer": "^5.1.2",
             "yallist": "^3.0.0"
@@ -17015,10 +17009,16 @@
       "integrity": "sha512-DUJIutBG/tOdvJnGCo1PcBhFyGBWsY8VIMdXe3WRtGXynMwOcC5cojYpULf3qFJ4Jj1Riv3/kbF6Ygmi+BpjCw==",
       "requires": {
         "core-js": "^3.6.4",
-        "raphael": "git+https://github.com/nhn/raphael.git#78a6ed3ec269f33b6457b0ec66f8c3d1f2ed70e0",
         "tui-code-snippet": "^2.3.1"
       },
       "dependencies": {
+        "raphael": {
+          "version": "git+https://github.com/nhn/raphael.git#78a6ed3ec269f33b6457b0ec66f8c3d1f2ed70e0",
+          "from": "git+https://github.com/nhn/raphael.git#78a6ed3ec269f33b6457b0ec66f8c3d1f2ed70e0",
+          "requires": {
+            "eve": "git://github.com/adobe-webplatform/eve.git#eef80ed"
+          }
+        },
         "tui-code-snippet": {
           "version": "2.3.2",
           "resolved": "https://registry.npmjs.org/tui-code-snippet/-/tui-code-snippet-2.3.2.tgz",

+ 11 - 0
src/api/ncs_excel.js

@@ -0,0 +1,11 @@
+import request from '@/utils/request'
+
+/** 插入表格数据 **/
+export function getExcelFile(params) {
+  return request({
+    url: '/ncs/excel/excel_file',
+    method: 'post',
+    loading: false,
+    data: params
+  })
+}

+ 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>

+ 2 - 0
src/utils/enum/RelativeNameTypeEnum

@@ -4,6 +4,8 @@ import i18n from '@/utils/i18n'
 export const RELATIVE_NAME_TYPE = createEnum(
     {
         CHILDREN: [ '孩子', i18n.t('relativeNameType.CHILDREN') ],
+        BOY: [ '男孩', i18n.t('relativeNameType.BOY') ],
+        GIRL: [ '女孩', i18n.t('relativeNameType.GIRL') ],
         HUSBAND: [ '丈夫', i18n.t('relativeNameType.HUSBAND') ],
         WIFE: [ '妻子', i18n.t('relativeNameType.WIFE') ],
         FATHER: [ '父亲', i18n.t('relativeNameType.FATHER') ],

+ 2 - 2
src/utils/request.js

@@ -15,13 +15,13 @@ const apiMode = domain.apiMode
 const service = axios.create({
   baseURL: serverUrl, // url = base url + request url
   // withCredentials: true, // send cookies when cross-domain requests
-  timeout: 5000, // request timeout
+  timeout: 30000, // request timeout
   paramsSerializer: params => qs.stringify(params, { arryFormat: 'repeat' })
 })
 
 export const mediaRequest = axios.create({
   baseURL: domain.mediaUrl,
-  timeout: 5000,
+  timeout: 30000,
   headers: {
     'Content-Type': 'application/json;charset=UTF-8'
   },

+ 19 - 2
src/views/customer/components/customerManager.vue

@@ -1471,11 +1471,28 @@ export default {
       return RELATIVE_NAME_TYPE.getDescFromValue(row.relative_name) ? RELATIVE_NAME_TYPE.getDescFromValue(row.relative_name) : row.relative_name
     },
     relativeNameChange(val) {
-      if (val === RELATIVE_NAME_TYPE.CHILDREN) {
+
+      if (val === RELATIVE_NAME_TYPE.CHILDREN || val === RELATIVE_NAME_TYPE.BOY || val === RELATIVE_NAME_TYPE.GIRL) {
         this.relativeRules.mobile[0].required = false
         this.relativeRules.mobile[0].validator = (rule, value, callback) => { callback() }
         this.isChild = true
-      } else {
+        if (val === RELATIVE_NAME_TYPE.BOY) {
+          this.relativeFormModel.sex = 1
+        } else if (val === RELATIVE_NAME_TYPE.GIRL) {
+          this.relativeFormModel.sex = 0
+        }
+      }
+      else if (val === RELATIVE_NAME_TYPE.HUSBAND || val === RELATIVE_NAME_TYPE.FATHER) {
+        this.relativeRules.mobile[0].required = true
+        this.isChild = false
+        this.relativeFormModel.sex = 1
+      }
+      else if (val === RELATIVE_NAME_TYPE.WIFE || val === RELATIVE_NAME_TYPE.MOTHER) {
+        this.relativeRules.mobile[0].required = true
+        this.isChild = false
+        this.relativeFormModel.sex = 0
+      }
+      else {
         this.relativeRules.mobile[0].required = true
         this.isChild = false
       }

+ 79 - 4
src/views/customer/components/elderlyCareManager.vue

@@ -132,7 +132,9 @@
                                 <el-col :span="12">
                                     <el-form-item :label="this.$t('customerManage.idNo')">
                                         <el-input v-model="formmodel.id_no" clearable :placeholder="this.$t('customerManage.inputIdNo')"
-                                                  :maxlength="20"/>
+                                                  :maxlength="20"
+                                                  @blur="onBlurCard"
+                                        />
                                     </el-form-item>
                                 </el-col>
                             </el-row>
@@ -265,6 +267,7 @@
                                     prop="relative_name"
                                     :label="this.$t('customerManage.relativeName')"
                                     width="180"
+                                    :formatter="formatterRelativeName"
                             />
                             <el-table-column
                                     prop="mobile"
@@ -293,8 +296,11 @@
                                 </el-col>
                                 <el-col :span="12">
                                     <el-form-item :label="this.$t('customerManage.relativeName')" prop="relative_name">
-                                        <el-input v-model="relativeFormModel.relative_name" clearable
-                                                  :placeholder="this.$t('customerManage.inputRelativeName')" :maxlength="20"/>
+<!--                                        <el-input v-model="relativeFormModel.relative_name" clearable-->
+<!--                                                  :placeholder="this.$t('customerManage.inputRelativeName')" :maxlength="20"/>-->
+                                      <el-select v-model="relativeFormModel.relative_name" :placeholder="this.$t('customerManage.choiceRelativeName')" clearable  @change="relativeNameChange">
+                                        <el-option v-for="(item, index) in Object.keys(relativeNameTypeEnum)" :key="index" :label="relativeNameTypeEnum[item]" :value="item" />
+                                      </el-select>
                                     </el-form-item>
                                 </el-col>
                             </el-row>
@@ -312,6 +318,19 @@
                                                   :maxlength="20"/>
                                     </el-form-item>
                                 </el-col>
+                              <el-col :span="12">
+                                <el-form-item v-if="isChild"
+                                              :label="this.$t('member.birthday2')" prop="birthday">
+                                  <el-date-picker
+                                      v-model="relativeFormModel.birthday"
+                                      type="date"
+                                      :editable="false"
+                                      value-format="timestamp"
+                                      :placeholder="this.$t('member.choiceBirthday2')"
+                                      :picker-options="{ disabledDate(time) { return time.getTime() > Date.now() }}"
+                                  />
+                                </el-form-item>
+                              </el-col>
                             </el-row>
                             <el-form-item>
                                 <el-button type="primary" @click="addRelative">{{ this.$t('action.add') }}</el-button>
@@ -498,6 +517,7 @@
     import myMap from '@/views/customer/myMap'
     import * as API_SystemConfig from '@/api/ncs_systemconfig'
     import { getDevicesByUuid } from '@/api/initialize'
+    import {RELATIVE_NAME_TYPE} from "@/utils/enum/RelativeNameTypeEnum";
     const serverUrl = domain.serverUrl
     export default {
         name: 'ElderlyCareManager',
@@ -653,7 +673,9 @@
               locationShow: false,
               isCloud: false,
               boolDevice: false,
-              mapUrl: null
+              mapUrl: null,
+              relativeNameTypeEnum: RELATIVE_NAME_TYPE.getValueList(),
+              isChild: false,
             }
         },
         computed: {
@@ -1423,6 +1445,35 @@
                     return this.$t('member.unknown')
                 }
             },
+          formatterRelativeName(row) {
+            return RELATIVE_NAME_TYPE.getDescFromValue(row.relative_name) ? RELATIVE_NAME_TYPE.getDescFromValue(row.relative_name) : row.relative_name
+          },
+          relativeNameChange(val) {
+            if (val === RELATIVE_NAME_TYPE.CHILDREN || val === RELATIVE_NAME_TYPE.BOY || val === RELATIVE_NAME_TYPE.GIRL) {
+              this.relativeRules.mobile[0].required = false
+              this.relativeRules.mobile[0].validator = (rule, value, callback) => { callback() }
+              this.isChild = true
+              if (val === RELATIVE_NAME_TYPE.BOY) {
+                this.relativeFormModel.sex = 1
+              } else if (val === RELATIVE_NAME_TYPE.GIRL) {
+                this.relativeFormModel.sex = 0
+              }
+            }
+            else if (val === RELATIVE_NAME_TYPE.HUSBAND || val === RELATIVE_NAME_TYPE.FATHER) {
+              this.relativeRules.mobile[0].required = true
+              this.isChild = false
+              this.relativeFormModel.sex = 1
+            }
+            else if (val === RELATIVE_NAME_TYPE.WIFE || val === RELATIVE_NAME_TYPE.MOTHER) {
+              this.relativeRules.mobile[0].required = true
+              this.isChild = false
+              this.relativeFormModel.sex = 0
+            }
+            else {
+              this.relativeRules.mobile[0].required = true
+              this.isChild = false
+            }
+          },
             /** 信息变化后操作,如床位状态改变,传入的空间结构变化了 **/
             infoChanged() {
                 this.getEmptyBeds().then(() => {
@@ -1551,6 +1602,30 @@
             API_SystemConfig.cloud().then(r => {
               this.isCloud = r
             })
+          },
+          onBlurCard() {
+            if (this.formmodel.id_type === "身份证") {
+              const val = this.formmodel.id_no.length
+              const idNo = this.formmodel.id_no
+              let sex = null
+
+              if (val === 18) {
+                this.formmodel.birthday = new Date(idNo.substring(6, 10) + '-' + idNo.substring(10, 12) + '-' + idNo.substring(12, 14)).getTime()
+                this.birthdayChange(this.formmodel.birthday)
+                sex = idNo.substring(16, 17)
+              }
+              if (val === 15) {
+                this.formmodel.birthday = new Date( '19' + idNo.substring(6, 8) + '-' + idNo.substring(8, 10) + '-' + idNo.substring(10, 12)).getTime()
+                this.birthdayChange(this.formmodel.birthday)
+                sex = idNo.substring(13, 14)
+              }
+
+              if (sex % 2 === 0) {
+                this.formmodel.sex = 0
+              } else {
+                this.formmodel.sex = 1
+              }
+            }
           }
         }
     }

+ 78 - 4
src/views/customer/components/patientManager.vue

@@ -131,7 +131,9 @@
                                 <el-col :span="12">
                                     <el-form-item :label="this.$t('customerManage.idNo')">
                                         <el-input v-model="formmodel.id_no" clearable :placeholder="this.$t('customerManage.inputIdNo')"
-                                                  :maxlength="20"/>
+                                                  :maxlength="20"
+                                                  @blur="onBlurCard"
+                                        />
                                     </el-form-item>
                                 </el-col>
                             </el-row>
@@ -285,6 +287,7 @@
                                     prop="relative_name"
                                     :label="this.$t('customerManage.relativeName')"
                                     width="180"
+                                    :formatter="formatterRelativeName"
                             />
                             <el-table-column
                                     prop="mobile"
@@ -313,8 +316,9 @@
                                 </el-col>
                                 <el-col :span="12">
                                     <el-form-item :label="this.$t('customerManage.relativeName')" prop="relative_name">
-                                        <el-input v-model="relativeFormModel.relative_name" clearable
-                                                  :placeholder="this.$t('customerManage.inputRelativeName')" :maxlength="20"/>
+                                      <el-select v-model="relativeFormModel.relative_name" :placeholder="this.$t('customerManage.choiceRelativeName')" clearable  @change="relativeNameChange">
+                                        <el-option v-for="(item, index) in Object.keys(relativeNameTypeEnum)" :key="index" :label="relativeNameTypeEnum[item]" :value="item" />
+                                      </el-select>
                                     </el-form-item>
                                 </el-col>
                             </el-row>
@@ -332,6 +336,19 @@
                                                   :maxlength="20"/>
                                     </el-form-item>
                                 </el-col>
+                              <el-col :span="12">
+                                <el-form-item v-if="isChild"
+                                              :label="this.$t('member.birthday2')" prop="birthday">
+                                  <el-date-picker
+                                      v-model="relativeFormModel.birthday"
+                                      type="date"
+                                      :editable="false"
+                                      value-format="timestamp"
+                                      :placeholder="this.$t('member.choiceBirthday2')"
+                                      :picker-options="{ disabledDate(time) { return time.getTime() > Date.now() }}"
+                                  />
+                                </el-form-item>
+                              </el-col>
                             </el-row>
                             <el-form-item>
                                 <el-button type="primary" @click="addRelative">{{ this.$t('action.add') }}</el-button>
@@ -516,6 +533,8 @@
     import * as shop_API from "@/api/ncs_shop";
     import myMapHtml from '@/views/customer/myMapHtml'
     import {getDevicesByUuid} from "@/api/initialize";
+    import {RELATIVE_NAME_TYPE} from "@/utils/enum/RelativeNameTypeEnum";
+    import {CHILDBIRTH_TYPE} from "@/utils/enum/ChildbirthTypeEnum";
     const serverUrl = domain.serverUrl
     export default {
         name: 'PatientManager',
@@ -676,7 +695,9 @@
                 deleted: this.$t('action.delete'),
                 qrCode: null,
                 boolDevice: false,
-                mapUrl: null
+                mapUrl: null,
+              relativeNameTypeEnum: RELATIVE_NAME_TYPE.getValueList(),
+              isChild: false,
             }
         },
         computed: {
@@ -1486,6 +1507,35 @@
                     return this.$t('member.unknown')
                 }
             },
+          formatterRelativeName(row) {
+            return RELATIVE_NAME_TYPE.getDescFromValue(row.relative_name) ? RELATIVE_NAME_TYPE.getDescFromValue(row.relative_name) : row.relative_name
+          },
+          relativeNameChange(val) {
+            if (val === RELATIVE_NAME_TYPE.CHILDREN || val === RELATIVE_NAME_TYPE.BOY || val === RELATIVE_NAME_TYPE.GIRL) {
+              this.relativeRules.mobile[0].required = false
+              this.relativeRules.mobile[0].validator = (rule, value, callback) => { callback() }
+              this.isChild = true
+              if (val === RELATIVE_NAME_TYPE.BOY) {
+                this.relativeFormModel.sex = 1
+              } else if (val === RELATIVE_NAME_TYPE.GIRL) {
+                this.relativeFormModel.sex = 0
+              }
+            }
+            else if (val === RELATIVE_NAME_TYPE.HUSBAND || val === RELATIVE_NAME_TYPE.FATHER) {
+              this.relativeRules.mobile[0].required = true
+              this.isChild = false
+              this.relativeFormModel.sex = 1
+            }
+            else if (val === RELATIVE_NAME_TYPE.WIFE || val === RELATIVE_NAME_TYPE.MOTHER) {
+              this.relativeRules.mobile[0].required = true
+              this.isChild = false
+              this.relativeFormModel.sex = 0
+            }
+            else {
+              this.relativeRules.mobile[0].required = true
+              this.isChild = false
+            }
+          },
             /** 信息变化后操作,如床位状态改变,传入的空间结构变化了 **/
             infoChanged() {
                 this.getEmptyBeds().then(() => {
@@ -1630,6 +1680,30 @@
                 this.partFrames = [...res]
               })
             }
+          },
+          onBlurCard() {
+            if (this.formmodel.id_type === "身份证") {
+              const val = this.formmodel.id_no.length
+              const idNo = this.formmodel.id_no
+              let sex = null
+
+              if (val === 18) {
+                this.formmodel.birthday = new Date(idNo.substring(6, 10) + '-' + idNo.substring(10, 12) + '-' + idNo.substring(12, 14)).getTime()
+                this.birthdayChange(this.formmodel.birthday)
+                sex = idNo.substring(16, 17)
+              }
+              if (val === 15) {
+                this.formmodel.birthday = new Date( '19' + idNo.substring(6, 8) + '-' + idNo.substring(8, 10) + '-' + idNo.substring(10, 12)).getTime()
+                this.birthdayChange(this.formmodel.birthday)
+                sex = idNo.substring(13, 14)
+              }
+
+              if (sex % 2 === 0) {
+                this.formmodel.sex = 0
+              } else {
+                this.formmodel.sex = 1
+              }
+            }
           }
         }
     }

+ 168 - 6
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() {
@@ -403,7 +499,7 @@ export default {
           _this.$message.info('请选择时间范围!')
           return
         }
-        params.page_size = 1000
+        params.page_size = this.pageData.data_total
         params.page_no = 1
         API_interaction.getList(params).then(res => {
           _this.loading = false
@@ -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 (res[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>

+ 13 - 5
src/views/ncs-orginazition/components/AppVersionManager.vue

@@ -85,12 +85,20 @@ export default {
     /** 文件上传之前的校验 */
     handleShopLogoBefore(file) {
       const isImg = file.type === 'application/vnd.android.package-archive'
-      const ext = file.name.substring(file.name.lastIndexOf('.') + 1).toLowerCase() === 'apk'
-      const isapk = isImg || ext
-      if (!isapk) {
-        this.$message.error(this.$t('action.uploadFileMsg5'))
+      if (isImg) {
+        const ext = file.name.substring(file.name.lastIndexOf('.') + 1).toLowerCase() === 'apk'
+        const isapk = isImg || ext
+        if (!isapk) {
+          this.$message.error(this.$t('action.uploadFileMsg5'))
+        }
+        return isapk
+      } else {
+        const ext = file.name.substring(file.name.lastIndexOf('.') + 1).toLowerCase() === 'img'
+        if (!ext) {
+          this.$message.error(this.$t('action.uploadFileMsg5'))
+        }
+        return ext
       }
-      return isapk
     },
     getAppVersion() {
       const params = {

+ 72 - 17
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>
 
 
@@ -505,19 +511,39 @@
               </el-form-item>
             </el-col>
           </el-row>
-          <el-form-item :label="this.$t('action.icon')">
-            <el-upload
-                class="avatar-uploader"
-                :action="`${uploadurl}?scene=avatar`"
-                :show-file-list="false"
-                :on-success="uploaded"
-                :before-upload="handleShopLogoBefore"
-            >
-              <img v-if="imageUrl" :src="imageUrl" class="avatar">
-              <i v-else class="el-icon-plus avatar-uploader-icon" />
-            </el-upload>
-          </el-form-item>
 
+          <el-row>
+            <el-col :span="8">
+              <el-form-item :label="this.$t('action.icon')">
+                <el-upload
+                    class="avatar-uploader"
+                    :action="`${uploadurl}?scene=avatar`"
+                    :show-file-list="false"
+                    :on-success="uploaded"
+                    :before-upload="handleShopLogoBefore"
+                >
+                  <img v-if="imageUrl" :src="imageUrl" class="avatar">
+                  <i v-else class="el-icon-plus avatar-uploader-icon" />
+                </el-upload>
+              </el-form-item>
+            </el-col>
+
+            <el-col :span="8">
+              <el-form-item :label="this.$t('action.excelUpload')">
+                <el-upload
+                    class="excel-uploader"
+                    :action="`${excelUploadUrl}`"
+                    :show-file-list="false"
+                    :on-success="excelUploaded"
+                    :before-upload="handleExcelBefore"
+                    :limit="1"
+                >
+                  <el-button size="small" type="primary">{{ this.$t('action.uploadFile') }}</el-button>
+                </el-upload>
+                <el-link :href="excelUploadDemo" type="primary" target="_blank" icon="el-icon-download" :underline="false">excel表格模板</el-link>
+              </el-form-item>
+            </el-col>
+          </el-row>
         </fieldset>
 
         <el-form-item align="center" class="margin-top-sm">
@@ -541,12 +567,14 @@ import {bindDeviceTransAudio, init485Device, initData, initDeviceList} from '@/a
 import * as API_Clerk from '@/api/ncs_clerk'
 import * as API_SystemConfig from '@/api/ncs_systemconfig'
 import * as API_Device from '@/api/ncs_device'
+import * as API_Excel from "@/api/ncs_excel";
 const serverUrl = domain.serverUrl
+const DeviceUrl = domain.DeviceUrl
 export default {
   name: 'PartInfoEdit',
   props: {
     partId: {
-      type: String,
+      type: Number,
       default: null
     }
   },
@@ -572,15 +600,18 @@ export default {
       otherHostDevice: [],
       uploadurl: serverUrl + '/ncs/upload/uploadFile',
       imageUrl: '',
+      excelUploadUrl: DeviceUrl + '/ncs/excel/upload/' + this.partId,
+      excelUploadDemo: serverUrl + '/upload/excel/demo/excel_demo.xlsx',
     }
   },
   async mounted() {
     this.isShow = JSON.parse(Storage.getItem('calling_user')).username === 'superadmin'
     // this.nurseLevel0Config = await API_Nurse.getNurseConfigs(this.partId, 0)
     this.getPartInfo()
-    this.getPartents()
+    this.getParents()
     this.getRoles({ page_size: 200, page_no: 1, fixedCondition: ' shop_id = -1 and role_name<>"护士"', sort: ' role_id', dir: 'desc' })
-    this.getOtherHostDevice(this.$store.getters.partId)
+    this.getOtherHostDevice(this.partId)
+    console.log(this.excelUploadUrl)
   },
   methods: {
     getPartInfo() {
@@ -639,6 +670,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,
@@ -734,7 +766,7 @@ export default {
       })
     },
     /** 获取上级机构数组 特指医院 **/
-    getPartents() {
+    getParents() {
       API_Part.listByType(6).then(res => {
         this.parents = [...res]
       })
@@ -807,7 +839,6 @@ export default {
       }
     },
     getOtherHostDevice(part_id) {
-      console.log("111111111")
       const _this = this
       API_Device.getOtherHostDevice(part_id).then(r => {
         _this.otherHostDevice = r
@@ -863,6 +894,30 @@ export default {
         reader.readAsDataURL(file)
       })
     },
+    excelUploaded(res) {
+      console.log(res)
+      let param = {}
+      param.part_id = this.partId
+      param.filename = res
+      API_Excel.getExcelFile(param).then(r => {
+        console.log(r)
+      })
+    },
+    handleExcelBefore(file) {
+      console.log(file)
+      const extension = file.name.split('.')[1] === 'xls'
+      const extension2 = file.name.split('.')[1] === 'xlsx'
+      const isLt5M = file.size / 1024 / 1024 < 5
+      if (!extension && !extension2) {
+        this.$message.info("上传文件只能是xls、xlsx格式!")
+        return false
+      }
+      if (!isLt5M) {
+        this.$message.info("上传文件大小不能超过5M!")
+        return false
+      }
+      return true
+    }
   }
 }
 </script>

+ 5 - 0
src/views/ncs-orginazition/partInfoSetting.vue

@@ -59,6 +59,11 @@
           <app-version-manager :part-id="part_id" :device-type="104" />
         </keep-alive>
       </el-tab-pane>
+      <el-tab-pane :label="this.$t('partInfo.linuxsickbed')" name="linuxsickbed">
+        <keep-alive>
+          <app-version-manager :part-id="part_id" :device-type="304" />
+        </keep-alive>
+      </el-tab-pane>
       <el-tab-pane :label="this.$t('partInfo.mobiledevice')" name="mobiledevice">
         <keep-alive>
           <app-version-manager :part-id="part_id" :device-type="7" />